-->

剃刀发电机:如何使用视图在库中编译为用于主在主MVC项目定义的局部视图(Razor Generato

2019-08-03 03:48发布

我们有一个ASP.NET MVC应用程序4在它周围3000景色。 我们已经决定将这套意见分成分离的DLL和与RazorGenerator编译。 我们只保留主_Layout.cshtml并在主MVC项目相关文件。

我们无法加载DLL从局部视图,在主MVC项目主视图在一起。 详细描述如下。

什么是已经完成:

  1. 意见成功编译成DLL文件(我已经证实,他们是二进制)

  2. 在创建对象PrecompiledMvc​​Engine和用于容纳在Global.asax.cs中使用以下代码中的Application_Start视图每个DLL注册:

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

该错误消息说:视图“〜/查看/ 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项目与另一个项目中定义的部分编译视图主视图?

Answer 1:

在应用程序启动,当你的应用程序调用该行...

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

包含您的外部视图的组件可能已经尚未加载,并且因此不包括作为视图引擎。 其实我建议不要使用AppDomain.CurrentDomain.GetAssemblies()反正,因为这将包括在启动时加载的所有程序集。

该解决方案是将补充RazorGenerator.Mvc 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设置,增加了一个显著的性能开销。



Answer 2:

术语

BaseMvc - 剃刀生成的视图,控制器等
ConsumerMvc - 已为此项目和引用布局BaseMvc

摘要

在创建基本控制器视图的递送。 该视图使用一个布局,其存在于经由_ViewStart.cshtml在BaseMvc的ConsumerMvc。 对于我的情况我有项目,不同的布局,因此“指针”布局视图。 我认为这是个有用的例子。

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

在代码注释的参考链接: 重写鉴于ASP.NET MVC的网站无法正常工作

ConsumerMvc例

/Views/Shared/_Layout_Component.cshtml

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

我的网址

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



Answer 3:

并非在所有组件加载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);
}


文章来源: Razor Generator: how to use view compiled in a library as the partial view for master defined in main mvc project