我正在尝试创建一个Web应用程序,希望能够在其中插入单独的程序集。 我将MVC Preview 4与Unity结合使用以进行依赖项注入,该过程用于从插件程序集创建控制器。 我正在使用WebForms(默认aspx)作为视图引擎。
如果要使用视图,则由于ASPX部件的动态编译,我将停留在核心项目中定义的视图上。 我正在寻找一种将ASPX文件封装在不同程序集中的正确方法,而不必执行整个部署步骤。 我是否缺少明显的东西? 还是我应该以编程方式创建视图?
更新:我更改了接受的答案。 即使Dale的回答很彻底,我还是选择了其他虚拟路径提供程序来寻求解决方案。 我认为它的工作就像一种魅力,仅占用大约20行代码。
我花了很长时间才能从各个部分样本中正常工作,所以这里是从共享库中的Views文件夹获取视图所需的完整代码,该库的结构与常规Views文件夹相同,但所有内容都设置为嵌入式构建资源。如果普通文件不存在,它将仅使用嵌入式文件。
Application_Start的第一行:
1
| HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider()); |
虚拟路径提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| 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视图,因为不会使用views文件夹中的视图:
1 2 3 4 5 6 7 8 9
| <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>
</controls>
</pages> |
要使其与Mono一起使用,还需要执行几个附加步骤。首先,您需要实现GetDirectory,因为views文件夹中的所有文件都会在应用启动时加载,而不是根据需要加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| 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;
}
}
} |
最后,强类型视图将几乎但不是很完美。模型将被视为未类型化的对象,因此要进行强类型化输入,您需要使用类似以下内容来启动共享视图
1
| <% var Model2 = Model as IEnumerable<AppModel>; %> |
从本质上讲,这与使用WebForms并尝试将其UserControl ASCX文件编译为DLL时遇到的问题相同。我发现此http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx也可能对您有用。
1 2 3 4 5 6 7 8 9 10 11 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视图引擎,那么我离发现它还很近。
我最近尝试了Spark视图引擎。除了非常出色而且即使受到威胁我也不会回到webforms,它还为应用程序的模块化提供了一些非常好的挂钩。他们文档中的示例将Windsor用作IoC容器,但是如果您想采用其他方法,我无法想象它会变得很难。