简体   繁体   English

使用自定义Razor视图引擎处理布局属性

[英]Handling Layout properties with custom Razor view engine

I have implemented a multi-tenant view engine similar to what is described here: 我已经实现了一个类似于这里描述的多租户视图引擎:

Which let me override the search locations for view like this: 让我覆盖视图的搜索位置,如下所示:

    MasterLocationFormats = new[]
    {
        "~/Views/%1/{1}/{0}.cshtml",
        "~/Views/%1/Shared/{0}.cshtml",
        "~/Views/Default/{1}/{0}.cshtml",
        "~/Views/Default/Shared/{0}.cshtml",
    };

In which the %1 is replaced with the correct folder for the active tenant. 其中%1被替换为活动租户的正确文件夹。 This is working just fine exception one problem. 这是一个很好的例外问题。 When I define the Layout path on my view like this: 当我在我的视图上定义布局路径时,如下所示:

Layout = "~/Views/Default/Shared/_MyLyout.cshtml";

It kind of defeats the purpose of having the multi-tenancy since I have have to hard code the exact location of the layout page. 由于我必须硬编码布局页面的确切位置,这有点违背了多租户的目的。 I want to be able to do something like this: 我希望能够做到这样的事情:

Layout = "~/Views/%1/Shared/_MyLyout.cshtml";

If I wanted to allow tenants to have their one layout pages, how would I go about supporting this? 如果我想允许租户拥有他们的一个布局页面,我将如何支持这个?

I have tried fiddling with the view engine methods that I overrode: 我试图摆弄我覆盖的视图引擎方法:

  • CreatePartialView CreatePartialView
  • CreateView CreateView的
  • FileExists 文件已存在

But nothing seems to point itself towards being able to dynamically specify the layout page. 但似乎没有任何东西能够动态指定布局页面。

Update: 更新:

Here's what I have working so far. 这是我到目前为止所做的工作。 I used the answer to this question https://stackoverflow.com/a/9288455/292578 slightly modified to create a HTML helper: 我使用了这个问题的答案https://stackoverflow.com/a/9288455/292578稍加修改以创建一个HTML帮助器:

public static string GetLayoutPageForTenant( this HtmlHelper html, string LayoutPageName )
{
    var layoutLocationFormats = new[]
    {
        "~/Views/{2}/{1}/{0}.cshtml",
        "~/Views/{2}/Shared/{0}.cshtml",
        "~/Views/Default/{1}/{0}.cshtml",
        "~/Views/Default/Shared/{0}.cshtml",
    };

    var controller = html.ViewContext.Controller as MultiTenantController;
    if( controller != null )
    {
        var tenantName = controller.GetTenantSchema();
        var controllerName = html.ViewContext.RouteData.Values["Controller"].ToString();

        foreach( var item in layoutLocationFormats )
        {
            var resolveLayoutUrl = string.Format( item, LayoutPageName, controllerName, tenantName );
            var fullLayoutPath = HostingEnvironment.IsHosted ? HostingEnvironment.MapPath( resolveLayoutUrl ) : System.IO.Path.GetFullPath( resolveLayoutUrl );
            if( File.Exists( fullLayoutPath ) ) return resolveLayoutUrl;
        }
    }

    throw new Exception( "Page not found." );
}

which is similar to what saravanan suggested. 这与saravanan建议的类似。 Then I can set the layout in my view with this code: 然后我可以使用以下代码在我的视图中设置布局:

Layout = Html.GetLayoutPageForTenant( "_Home" );

Unfortunately, this duplicates the work that the custom view engine is doing which seems like the wrong way to go. 不幸的是,这复制了自定义视图引擎正在做的工作,这似乎是错误的方法。

I would like to propose the following idea, 我想提出以下想法,

In the _ViewStart.cshtml file, where we set the layout pages, you can use something like this, with the idea of the Tenant based layout url or the folder name is being filled in the controller by fetching from the DB. 在我们设置布局页面的_ViewStart.cshtml文件中,您可以使用类似这样的内容,通过基于租户的布局URL或文件夹名称通过从DB获取来填充控制器。

@{
    Layout = ViewBag.TenantLayoutPageUrl;
 }

or 要么

 @{
    Layout = string.Format("~/Views/{0}/Shared/_MyLyout.cshtml",ViewBag.TenantId);
 }

If you have some static Tenant data representations, like a static Identity class that will keep track of your tenant's customization, we can use that and minimize the round trip to the db. 如果您有一些静态租户数据表示,例如将跟踪租户自定义的静态Identity类,我们可以使用它并最小化到db的往返。

Please share your idea on this implementation so it will be useful for the community 请分享您对此实施的想法,以便对社区有用

Try, 尝试,

public class CustomWebViewPage : WebViewPage
{
    public override void ExecutePageHierarchy()
    {
        if (Context.Items["__MainView"] == null)
        {
            this.Layout = String.Format("~/Views/Shared/{0}/_Layout.cshtml", ViewContext.Controller.GetType().Namespace);
            Context.Items["__MainView"] = "Not Null";
        }
        base.ExecutePageHierarchy();
    }

    public override void Execute()
    {
    }
}

public class CustomWebViewPage<T> : WebViewPage<T>
{
    public override void ExecutePageHierarchy()
    {
        if (Context.Items["__MainView"] == null)
        {
            this.Layout = String.Format("~/Views/Shared/{0}/_Layout.cshtml", ViewContext.Controller.GetType().Namespace);
            Context.Items["__MainView"] = "Not Null";
        }
        base.ExecutePageHierarchy();
    }

    public override void Execute()
    {
    }
}

<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="Mv4App.CustomWebViewPage">

You can add following _ViewStart.cshtml in the tenant views folder ( ~/Views/%1/_ViewStart.cshtml ). 您可以在租户视图文件夹( ~/Views/%1/_ViewStart.cshtml )中添加以下_ViewStart.cshtml Each tenant can manage their own layout files. 每个租户都可以管理自己的布局文件。

@{
    Layout =  VirtualPathUtility.GetDirectory(PageContext.Page.VirtualPath) + "Shared/_Layout.cshtml";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM