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

我正在尝试创build一个Web应用程序,我希望能够插入单独的程序集。 我使用MVC预览4与Unity的dependency injection相结合,我用它来从我的插件程序集创build控制器。 我正在使用WebForms(默认aspx)作为我的视图引擎。

如果我想使用视图,由于ASPX部分的dynamic编译,我被困在核心项目中定义的视图中。 我正在寻找一种正确的方法来将ASPX文件封装在不同的程序集中,而不必经历整个部署步骤。 我错过了什么明显的? 或者我应该诉诸以编程方式创build我的意见?


更新:我改变了接受的答案。 虽然戴尔的答案非常详尽,但我还是select了一个不同的虚拟path提供者。 它的作用像一个魅力,我只想在代码中只用了大概20行代码。

从本质上来说,这与WebForms的人们试图将其UserControl ASCX文件编译到DLL中的问题是一样的。 我发现这个http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx也可能适用于你。;

我花了很长时间才能从各种部分样本中正确地工作,所以下面是从共享库中的Views文件夹获取视图所需的完整代码,这些共享库的结构与普通的Views文件夹结构相同,但是一切都设置为embedded资源。 如果通常的文件不存在,它将只使用embedded文件。

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必须包含正确的设置来parsing强types的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; } } } 

最后,强types视图几乎不能完美工作。 模型将被视为一个无types的对象,所以要获得强大的打字回来,你需要开始你的共享视图类似

 <% var Model2 = Model as IEnumerable<AppModel>; %> 
 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,我已经接近find了。

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