Razor生成器:如何使用库中编译的视图作为主mvc项目中定义的主视图的部分视图
我们有一个ASP.NETMVC4应用程序,其中包含大约3000个视图。我们决定将这组视图拆分为单独的DLL,并使用RazorGenerator进行编译。我们只在主MVC项目中保留main _Layout.cshtml和相关文件 我们不能在主MVC项目中从DLL加载部分视图和主视图。详细说明如下 已经完成的操作:Razor生成器:如何使用库中编译的视图作为主mvc项目中定义的主视图的部分视图,razor,asp.net-mvc-4,viewengine,razorgenerator,Razor,Asp.net Mvc 4,Viewengine,Razorgenerator,我们有一个ASP.NETMVC4应用程序,其中包含大约3000个视图。我们决定将这组视图拆分为单独的DLL,并使用RazorGenerator进行编译。我们只在主MVC项目中保留main _Layout.cshtml和相关文件 我们不能在主MVC项目中从DLL加载部分视图和主视图。详细说明如下 已经完成的操作: 视图成功编译成DLL(我已经确认它们是二进制的) 使用Global.asax.cs中的应用程序_Start中的以下代码,为每个包含视图的DLL创建并注册预编译MVCEngine对象:
var view = "~/Views/" + partialName + ".cshtml";
return View(view, "~/Views/Shared/_Layout.cshtml", model);
错误消息显示:
找不到视图“~/Views/Partial.cshtml”或其主视图,或者没有视图引擎支持搜索的位置。搜索了以下地点:
~/Views/Partial.cshtml
~/Views/Shared/\u Layout.cshtml
当我试图通过指定以下任一项单独加载视图时:
return View("~/Views/Shared/_Layout.cshtml", model);
或
,则会找到正确的视图。但是我需要把它们装在一起。当我在主MVC项目中拥有所有必需的.cshtml文件时,代码就可以工作了
请注意,已编译DLL中的视图具有与控制器操作中指定的路径相同的PageVirtualPath属性,例如:
namespace SomeBaseNamespace.Views
{
[GeneratedCode("RazorGenerator", "1.5.0.0"), PageVirtualPath("~/Views/Partial.cshtml")]
public class Partial : WebViewPage<PartialModel>
{
[CompilerGenerated]
private static class <Execute>o__SiteContainer3
{
// logic
}
public override void Execute()
{
// logic
}
}
}
namespace SomeBaseNamespace.Views
{
[GeneratedCode(“RazorGenerator”,“1.5.0.0”),PageVirtualPath(“~/Views/Partial.cshtml”)]
公共类部分:WebViewPage
{
[编译生成]
私有静态类o__SiteContainer3
{
//逻辑
}
公共覆盖无效执行()
{
//逻辑
}
}
}
总而言之,问题是如何调用存储在主MVC项目中的主视图,以及在另一个项目中定义的部分编译视图?调用
应用程序启动时,并非所有程序集都被加载。添加一个额外的处理程序:
AppDomain.CurrentDomain.AssemblyLoad += (sender, args) =>
{
// ...
// some code determining whether we've got an assembly with views
// ...
var engine = new PrecompiledMvcEngine(args.LoadedAssembly);
engine.UsePhysicalViewsIfNewer = true;
ViewEngines.Engines.Insert(0, engine);
// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
术语
BaseMvc-具有Razor生成的视图、控制器等
ConsumerMvc-具有此项目的布局并参考BaseMvc
总结
在基本控制器中创建视图的传递。该视图使用一个布局,该布局通过BaseMvc中的_ViewStart.cshtml显示在ConsumerMvc中。对于我的情况,我有不同布局的项目,因此有“指针”布局视图。我认为这是一个有用的例子
BaseMvc示例
我创建了一个区域
,以便设置默认布局
/Areas/Components/controller/ShoppingController.cs
public ActionResult Basket()
{
return View();
}
/Areas/Components/Views/Shopping/Basket.cshtml
Welcome to the Basket!
@{
//-- NOTE: "Layout_Component.cshtml" do not exist in the BaseMVC project. I did not
// experiment with having it in both projects. A tip if you do is to ensure both
// the base and consumer _Layout_Component.cshtml files are both razor
// generated to allow the razor generator to handle the overrride. See
// my other SO answer linked below.
Layout = "~/Views/Shared/_Layout_Component.cshtml";
}
@{
Layout = "~/Views/Shared/_Layout_ConsumerMvc.cshtml";
}
@RenderBody()
/Areas/Components/Views/_ViewStart.cshtml
Welcome to the Basket!
@{
//-- NOTE: "Layout_Component.cshtml" do not exist in the BaseMVC project. I did not
// experiment with having it in both projects. A tip if you do is to ensure both
// the base and consumer _Layout_Component.cshtml files are both razor
// generated to allow the razor generator to handle the overrride. See
// my other SO answer linked below.
Layout = "~/Views/Shared/_Layout_Component.cshtml";
}
@{
Layout = "~/Views/Shared/_Layout_ConsumerMvc.cshtml";
}
@RenderBody()
代码注释中引用的链接:
ConsumerMvc示例
/Views/Shared/\u Layout\u Component.cshtml
Welcome to the Basket!
@{
//-- NOTE: "Layout_Component.cshtml" do not exist in the BaseMVC project. I did not
// experiment with having it in both projects. A tip if you do is to ensure both
// the base and consumer _Layout_Component.cshtml files are both razor
// generated to allow the razor generator to handle the overrride. See
// my other SO answer linked below.
Layout = "~/Views/Shared/_Layout_Component.cshtml";
}
@{
Layout = "~/Views/Shared/_Layout_ConsumerMvc.cshtml";
}
@RenderBody()
我的网址
http://www.consumermvc.example.com/Components/Shopping/Basket
在应用程序启动时,当您的应用程序调用此线路时
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
包含外部视图的程序集可能尚未加载,因此不包括在视图引擎中。实际上,我建议不要使用AppDomain.CurrentDomain.GetAssemblies()
,因为这将包括启动时加载的所有程序集
解决方案是将NuGet包添加到包含编译视图的每个项目中。这将以类似于您的方式添加以下应用程序启动代码
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(SomeBaseNamespace.Views.RazorGeneratorMvcStart), "Start")]
namespace SomeBaseNamespace.Views
{
public static class RazorGeneratorMvcStart
{
public static void Start()
{
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly)
{
UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
};
ViewEngines.Engines.Insert(0, engine);
}
}
}
请注意,这将如何使用当前部件(视图部件)创建视图引擎,并将其添加到静态ViewEngines
集合(包含在主MVC项目中)
投入生产后,我还建议关闭UsePhysicalViewsIfNewer
设置,这会增加大量性能开销。您好,您能做到这一点吗?您有没有想过?我似乎遇到了完全相同的问题。这将添加所有加载的程序集作为视图引擎,这是不推荐的。对于包含在需要之前从未加载过的视图的程序集,这也不起作用。@TomBowers,你说得对,但这是他的问题使用的代码。最好有一个PrecompiledMvcEngine
,可以根据需要添加来自其他程序集的视图。不能对多个程序集使用PrecompiledMvcEngine。对于每个包含编译视图的独立程序集,您需要一个新引擎,如我的回答所示。