ASP.NET MVC中的单独程序集中的视图


48

我试图创建一个Web应用程序,我希望能够插入单独的程序集。我使用MVC预览版4与Unity进行依赖注入,我使用它从我的插件程序集创建控制器。我使用WebForms(默认aspx)作为我的视图引擎。

如果我想使用一个视图,由于动态编译ASPX部分,我被卡在核心项目中定义的视图上。我正在寻找一种合适的方法将ASPX文件封装在不同的程序集中,而不必经历整个部署步骤。我错过了明显的东西吗?或者我应该通过编程来创建我的视图?


更新:我改变了接受的答案。尽管Dale的答案非常详尽,但我还是选择了一个不同的虚拟路径提供者来提供解决方案。它的作用就像一个魅力,我认为只需要大约20行代码。

  0

开始共享视图中使用的虚拟路径提供与mvc.net路由还是工作时? 24 10月. 082008-10-24 11:35:48

  0

@jmcd:它看起来像。 25 5月. 092009-05-25 13:33:49

  0

是否有任何示例代码可以发布,允许您完成此操作? 11 1月. 102010-01-11 20:52:22

  0

我尝试过的项目被丢弃,所以我没有准备好示例代码。但是,火花视图引擎也允许这样做(http://www.sparkviewengine.com)。那里有一个叫做模块的例子,我认为这个模块分隔了不同组件中的区域。 11 1月. 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); 
} 

设置“复制到输出”你的观点为“始终复制”

  0

而不是创建一个WebFormviewEngine,你可以这样做RazorViewEngine:RazorViewEngine engine = ViewEngines.Engines.OfType <RazorViewEngine>()。First();然后将其他路径连接到所提及的属性。 30 11月. 142014-11-30 15:52:39


2

的除了你谁仍在寻找圣杯属性:我来有点接近找到它,如果你不太依附webforms viewengine。

我最近试用过Spark viewengine。除了完全真棒,即使我受到威胁,我也不会回到webforms,它也为应用程序的模块化提供了一些非常好的钩子。他们的文档中的例子是使用Windsor作为IoC容器,但如果你想采取另一种方法,我无法想象它会变得更加困难。


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; 
     } 
    } 
} 

最后,强类型的观点几乎但不完全正常工作。模型将被视为无类型的对象,因此要获得强类型回你需要的东西,如

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

记住将视图的构建操作设置为“嵌入式资源”也很重要。视图的文件夹也应该存在于Web项目中。在我的情况下,我把视图放在程序集项目的文件夹Views/Shared/Dynamic.cshtml中,并且必须在引用程序集的web项目中创建Views/Shared。 04 9月. 132013-09-04 06:38:30