ASP.NET MVC의 개별 어셈블리에서 뷰


48

별도의 어셈블리를 플러그인 할 수있는 웹 응용 프로그램을 만들려고합니다. 내가 플러그인 어셈블리에서 컨트롤러를 생성하는 데 사용하는 종속성 삽입을 위해 Unity와 결합 된 MVC 미리보기 4를 사용하고 있습니다. 내보기 엔진으로 WebForms (기본 aspx) 사용하고 있습니다.

뷰를 사용하려는 경우 ASPX 부분의 동적 컴파일로 인해 핵심 프로젝트에 정의 된 뷰에 고정되어 있습니다. 전체 배포 단계를 거치지 않고도 ASPX 파일을 다른 어셈블리에 포함 할 수있는 적절한 방법을 찾고 있습니다. 나는 명백한 것을 놓치고 있는가? 또는 프로그래밍 방식으로 내 견해를 만드는 데 의존해야합니까?


업데이트 : 수락 된 답변을 변경했습니다. Dale의 대답은 매우 철저하지만 다른 가상 경로 공급자와 함께 솔루션을 찾았습니다. 그것은 매력처럼 작동하며, 코드에서 약 20 줄 정도 밖에 걸리지 않습니다.

  0

같은 것을 함께 공유 뷰를 시작하는 데 필요한 강력한 입력을 다시 얻으려면, 지정되지 않은 개체로 처리됩니다? 24 oct. 082008-10-24 11:35:48

  0

@jmcd : 보이는 것처럼 보입니다. 25 may. 092009-05-25 13:33:49

  0

게시 할 수있는 샘플 코드가 있습니까? 11 jan. 102010-01-11 20:52:22

  0

내가 시도한 프로젝트가 중단되어 준비가 된 예제 코드가 없습니다. 그러나 스파크 뷰 엔진은 이것을 허용합니다 (http://www.sparkviewengine.com). 거기에 내가 생각하는 모듈이라는 샘플이 있습니다.이 모듈은 서로 다른 어셈블리의 영역을 구분합니다. 11 jan. 102010-01-11 22:56:09

15

이것은 기본적으로 WebForms에서 UserControl ASCX 파일을 DLL로 컴파일하려는 사람들과 동일한 문제입니다. 나는 당신을 위해 아마도이 http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx을 찾았습니다. 내가 찾는 데 조금 더 가까이 왔어요 :


12
protected void Application_Start() 
{ 
    WebFormViewEngine engine = new WebFormViewEngine(); 

    engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" }; 
    engine.PartialViewLocationFormats = engine.ViewLocationFormats; 

    ViewEngines.Engines.Clear(); 
    ViewEngines.Engines.Add(engine); 

    RegisterRoutes(RouteTable.Routes); 
} 

webforms viewengine에 너무 많이 붙지 않았다면 말이죠.

최근 Spark 뷰 엔진을 사용해 보았습니다. 완전히 위협적인 것 외에도 위협을 받았다하더라도 webforms로 돌아 가지 않을 것입니다. 또한 응용 프로그램의 모듈성을위한 아주 좋은 후크를 제공합니다. 그들의 문서에있는 예제는 Windsor를 IoC 컨테이너로 사용하지만 다른 접근 방법을 원한다면 더 어려울 것이라고 상상할 수 없습니다.

  0

WebFormviewEngine을 만드는 대신 다음과 같이 RazorViewEngine을 가져 와서 동일한 작업을 수행 할 수 있습니다. RazorViewEngine engine = ViewEngines.Engines.OfType <RazorViewEngine>(). First(); 그런 다음 언급 된 속성에 대한 추가 경로를 연결하면됩니다. 30 nov. 142014-11-30 15:52:39


2

모든 여전히 성배를 찾고있는 당신을 할 수있는 별도의 '항상 복사'로보기의 '복사 출력'속성을 설정


29

여러 부분 샘플에서 제대로 작동하려면 너무 오래 걸렸으므로 공유 라이브러리의 Views 폴더에서 뷰를 가져 오는 데 필요한 전체 코드는 일반 Views 폴더와 동일하게 구성되지만 모든 설정이 필요합니다 임베디드 리소스로 구축 할 수 있습니다. 일반적인 파일이없는 경우에만 포함 된 파일을 사용합니다.

위해 Application_Start의 첫 번째 줄 :

HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider()); 

VirtualPathProvider

public class EmbeddedVirtualFile : VirtualFile 
{ 
    public EmbeddedVirtualFile(string virtualPath) 
     : base(virtualPath) 
    { 
    } 

    internal static string GetResourceName(string virtualPath) 
    { 
     if (!virtualPath.Contains("/Views/")) 
     { 
      return null; 
     } 



     var resourcename = virtualPath 
      .Substring(virtualPath.IndexOf("Views/")) 
      .Replace("Views/", "OrangeGuava.Common.Views.") 
      .Replace("/", "."); 

     return resourcename; 

    } 


    public override Stream Open() 
    { 
     Assembly assembly = Assembly.GetExecutingAssembly(); 


     var resourcename = GetResourceName(this.VirtualPath); 
     return assembly.GetManifestResourceStream(resourcename); 
    } 




} 

public class EmbeddedViewPathProvider : VirtualPathProvider 
{ 


    private bool ResourceFileExists(string virtualPath) 
    { 

     Assembly assembly = Assembly.GetExecutingAssembly(); 


     var resourcename = EmbeddedVirtualFile.GetResourceName(virtualPath); 
     var result = resourcename != null && assembly.GetManifestResourceNames().Contains(resourcename); 
     return result; 
    } 

    public override bool FileExists(string virtualPath) 
    { 
     return base.FileExists(virtualPath) || ResourceFileExists(virtualPath); 
    } 


    public override VirtualFile GetFile(string virtualPath) 
    { 

     if (!base.FileExists(virtualPath)) 
     { 
      return new EmbeddedVirtualFile(virtualPath); 
     } 
     else 
     { 
      return base.GetFile(virtualPath); 
     } 

    } 

} 

마지막 단계가 작동하려면 루트의 Web.config는 강력한 형식의 MVC를 구문 분석 할 수있는 권한 설정을 포함해야한다는 것입니다 뷰 폴더에있는 뷰는 사용되지 않으므로 다음과 같이 사용하십시오.

<pages 
    validateRequest="false" 
    pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" 
    pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" 
    userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> 
    <controls> 
    <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" /> 
    </controls> 
</pages> 

Mono와 함께 작동하려면 몇 가지 추가 단계가 필요합니다. 먼저, 앱이 아니라 필요에 따라보다 시작될 때 뷰에있는 모든 파일이로드받을 폴더 때문에, GetDirectory를 구현해야합니다

public override VirtualDirectory GetDirectory(string virtualDir) 
    { 
     Log.LogInfo("GetDirectory - " + virtualDir); 
     var b = base.GetDirectory(virtualDir); 
     return new EmbeddedVirtualDirectory(virtualDir, b); 
    } 

public class EmbeddedVirtualDirectory : VirtualDirectory 
{ 
    private VirtualDirectory FileDir { get; set; } 

    public EmbeddedVirtualDirectory(string virtualPath, VirtualDirectory filedir) 
     : base(virtualPath) 
    { 
     FileDir = filedir; 
    } 

    public override System.Collections.IEnumerable Children 
    { 
     get { return FileDir.Children; } 
    } 

    public override System.Collections.IEnumerable Directories 
    { 
     get { return FileDir.Directories; } 
    } 

    public override System.Collections.IEnumerable Files 
    { 
     get { 

      if (!VirtualPath.Contains("/Views/") || VirtualPath.EndsWith("/Views/")) 
      { 
       return FileDir.Files; 
      } 

      var fl = new List<VirtualFile>(); 

      foreach (VirtualFile f in FileDir.Files) 
      { 
       fl.Add(f); 
      } 


      var resourcename = VirtualPath.Substring(VirtualPath.IndexOf("Views/")) 
.Replace("Views/", "OrangeGuava.Common.Views.") 
.Replace("/", "."); 

      Assembly assembly = Assembly.GetExecutingAssembly(); 

      var rfl = assembly.GetManifestResourceNames() 
       .Where(s => s.StartsWith(resourcename)) 
       .Select(s => VirtualPath + s.Replace(resourcename, "")) 
       .Select(s => new EmbeddedVirtualFile(s)); 
      fl.AddRange(rfl); 

      return fl; 
     } 
    } 
} 

마지막으로, 강력한 형식의 뷰는 거의하지만 아주 완벽하게 작동합니다.모델은 여전히 ​​mvc.net의 라우팅 작업 가상 경로 공급자를 사용합니까 그래서 당신은

<% var Model2 = Model as IEnumerable<AppModel>; %> 
+2

뷰에 대해 빌드 동작을 "포함 된 리소스"로 설정하는 것을 잊지 마십시오. 뷰의 폴더도 웹 프로젝트에 존재해야합니다. 필자는 어셈블리 프로젝트의 폴더 Views/Shared/Dynamic.cshtml에 뷰를 넣고 어셈블리를 참조하는 웹 프로젝트에서 Views/Shared를 만들어야합니다. 04 sep. 132013-09-04 06:38:30