Razor Generator:如何使用库中编译的视图作为主mvc项目中定义的master的局部视图

时间:2012-11-23 10:38:55

标签: razor asp.net-mvc-4 viewengine razorgenerator

我们有一个ASP.NET MVC 4应用程序,其中包含大约3000个视图。我们决定将这组视图拆分为单独的DLL,并使用RazorGenerator进行编译。我们只在主MVC项目中保留主_Layout.cshtml和相关文件。

我们无法在主MVC项目中将DLL的部分视图与主视图一起加载。详细说明如下。

已完成的工作:

  1. 视图成功编译成DLL(我已经确认它们是二进制文件)

  2. 使用Global.asax.cs中Application_Start中的以下代码为包含视图的每个DLL创建并注册PrecompiledMvc​​Engine对象:

  3. foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        // ...
        // some code determining whether we've got an assembly with views
        // ...
    
        var engine = new PrecompiledMvcEngine(assembly);
        engine.UsePhysicalViewsIfNewer = true;
    
        ViewEngines.Engines.Insert(0, engine);
    
        // StartPage lookups are done by WebPages. 
        VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
    }
    

    什么行不通:

    我无法加载主MVC项目中定义的视图(例如_Layout.cshtml),并在其中一个库中定义了部分视图(比如Partial.cshtml)。我在控制器的操作中使用以下代码来告诉MVC框架我请求了哪个视图:

    var view = "~/Views/" + partialName + ".cshtml";    
    return View(view, "~/Views/Shared/_Layout.cshtml", model);
    

    错误消息说:     未找到视图'〜/ Views / Partial.cshtml'或其主视图或视图引擎不支持搜索的位置。搜索了以下位置: 〜/查看/ Partial.cshtml 〜/查看/共享/ _Layout.cshtml

    当我尝试通过指定:

    单独加载视图时
    return View("~/Views/Shared/_Layout.cshtml", model);
    

    return View(view, model);
    

    ,找到了正确的视图。但是我需要将它们装在一起。当我在主MVC项目中拥有所有必需的.cshtml文件时,代码就可以工作。

    请注意,已编译的DLL中的视图具有与控制器操作中指定的路径相同的PageVirtualPathAttribute,例如:

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

    总之,问题是如何使用另一个项目中定义的部分编译视图调用存储在主MVC项目中的主视图?

3 个答案:

答案 0 :(得分:1)

在应用开始时,当您的应用调用此行时...

04:05:14Z

包含外部视图的程序集可能尚未加载,因此不包含在视图引擎中。我实际上建议不要使用 List<int> listOfCountries = new List<int> { 1,2,3 }; var query = ( from country in context.Countries.AsNoTracking() join car in context.Cars.AsNoTracking() on new { CountryID = country.ID} equals new { CountryID = cars .CountryID } where listOfCountries.Contains(prv.CountryID) select car); ,因为这将包括启动时加载的所有程序集。

解决方案是将RazorGenerator.Mvc NuGet包添加到包含已编译视图的每个项目中。这将以与您类似的方式添加以下应用启动代码...

foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())

请注意这是如何使用当前程序集(您的视图程序集)创建视图引擎,并将其添加到静态AppDomain.CurrentDomain.GetAssemblies()集合(包含在主MVC项目中)。

一旦投入生产,我还建议关闭[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); } } } 设置,这会增加显着的性能开销。

答案 1 :(得分:0)

调用Application_Start时,并非所有程序集都已加载。添加额外的处理程序:

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

答案 2 :(得分:0)

术语

BaseMvc - 使用Razor生成的视图,控制器等 ConsumerMvc - 具有此项目的布局并引用BaseMvc

摘要

在基本控制器中创建视图的传递。该视图使用通过BaseMvc中的_ViewStart.cshtml存在于ConsumerMvc中的布局。对于我的情况,我有不同布局的项目,因此&#34;指针&#34;布局视图。我认为这是一个有用的例子。

BaseMvc示例

我创建了AREA,因此我可以设置默认布局。

<强> /Areas/Components/Controllers/ShoppingController.cs

public ActionResult Basket()
{
    return View();
}

<强> /Areas/Components/Views/Shopping/Basket.cshtml

Welcome to the Basket!

<强> /Areas/Components/Views/_ViewStart.cshtml

@{
    //-- 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";
}

代码评论中引用的链接:Override view in ASP.NET MVC site not working

ConsumerMvc示例

<强> /Views/Shared/_Layout_Component.cshtml

@{
    Layout = "~/Views/Shared/_Layout_ConsumerMvc.cshtml";
}
@RenderBody()

我的网址

http://www.consumermvc.example.com/Components/Shopping/Basket