C# 使用自定义Razor视图引擎处理布局属性
我已经实现了一个多租户视图引擎,与这里描述的类似:C# 使用自定义Razor视图引擎处理布局属性,c#,asp.net-mvc,razor,multi-tenant,viewengine,C#,Asp.net Mvc,Razor,Multi Tenant,Viewengine,我已经实现了一个多租户视图引擎,与这里描述的类似: 这使我可以覆盖视图的搜索位置,如下所示: MasterLocationFormats = new[] { "~/Views/%1/{1}/{0}.cshtml", "~/Views/%1/Shared/{0}.cshtml", "~/Views/Default/{1}/{0}.cshtml", "~/Views/Default/Shared/{0}.cshtm
MasterLocationFormats = new[]
{
"~/Views/%1/{1}/{0}.cshtml",
"~/Views/%1/Shared/{0}.cshtml",
"~/Views/Default/{1}/{0}.cshtml",
"~/Views/Default/Shared/{0}.cshtml",
};
Layout = "~/Views/Default/Shared/_MyLyout.cshtml";
Layout = "~/Views/%1/Shared/_MyLyout.cshtml";
其中,%1
被替换为活动租户的正确文件夹。这是一个很好的例外问题。当我在视图上定义布局路径时,如下所示:
MasterLocationFormats = new[]
{
"~/Views/%1/{1}/{0}.cshtml",
"~/Views/%1/Shared/{0}.cshtml",
"~/Views/Default/{1}/{0}.cshtml",
"~/Views/Default/Shared/{0}.cshtml",
};
Layout = "~/Views/Default/Shared/_MyLyout.cshtml";
Layout = "~/Views/%1/Shared/_MyLyout.cshtml";
这有点违背了拥有多租户的目的,因为我必须硬编码布局页面的确切位置。我希望能够做到以下几点:
MasterLocationFormats = new[]
{
"~/Views/%1/{1}/{0}.cshtml",
"~/Views/%1/Shared/{0}.cshtml",
"~/Views/Default/{1}/{0}.cshtml",
"~/Views/Default/Shared/{0}.cshtml",
};
Layout = "~/Views/Default/Shared/_MyLyout.cshtml";
Layout = "~/Views/%1/Shared/_MyLyout.cshtml";
如果我想让租户拥有一个布局页面,我将如何支持这一点
我尝试过摆弄我忽略的视图引擎方法:
- CreatePartialView
- CreateView
- 文件存在
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." );
}
这与萨拉瓦南的建议相似。然后,我可以使用以下代码在视图中设置布局:
Layout = Html.GetLayoutPageForTenant( "_Home" );
不幸的是,这重复了自定义视图引擎所做的工作,这似乎是错误的做法。我想提出以下想法 在我们设置布局页面的
\u ViewStart.cshtml
文件中,您可以使用类似的方法,使用基于租户的布局url,或者通过从数据库中获取来在控制器中填充文件夹名称
@{
Layout = ViewBag.TenantLayoutPageUrl;
}
或
如果您有一些静态租户数据表示,比如静态Identity
类,它将跟踪租户的定制,那么我们可以使用它并最小化到数据库的往返
请分享您对此实施的想法,以便对社区有用
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">
公共类CustomWebViewPage:WebViewPage
{
公共覆盖无效ExecutePageHierarchy()
{
if(Context.Items[“\uu MainView”]==null)
{
this.Layout=String.Format(“~/Views/Shared/{0}/_Layout.cshtml”,ViewContext.Controller.GetType().Namespace);
Context.Items[“\uu MainView”]=“非空”;
}
base.ExecutePageHierarchy();
}
公共覆盖无效执行()
{
}
}
公共类CustomWebViewPage:WebViewPage
{
公共覆盖无效ExecutePageHierarchy()
{
if(Context.Items[“\uu MainView”]==null)
{
this.Layout=String.Format(“~/Views/Shared/{0}/_Layout.cshtml”,ViewContext.Controller.GetType().Namespace);
Context.Items[“\uu MainView”]=“非空”;
}
base.ExecutePageHierarchy();
}
公共覆盖无效执行()
{
}
}
您可以在租户视图文件夹(~/views/%1/\u ViewStart.cshtml
)中添加以下内容。每个租户都可以管理自己的布局文件
@{
Layout = VirtualPathUtility.GetDirectory(PageContext.Page.VirtualPath) + "Shared/_Layout.cshtml";
}
这种方法的唯一问题是,并非每个租户都有自己的自定义布局页面。如果找不到自定义布局页,我仍然希望搜索默认为默认文件夹。@Sparafusile:在这种情况下,我们可以在ViewBag中使用回退id。因此,在控制器中,我们将检查租户是否有自定义布局页面,如果有,我们将在视图包中设置该文件夹,否则我们将设置租户的文件夹名称<代码>ViewBag.TenantFolderName=“defaultPath”;如果(tenant Has customFolder){ViewBag.TenantFolderName=TenantFolderName;}IMHO,这将是故障保护。虽然我同意这可以工作,但它有点违背了自定义视图引擎在控制器中完成所有工作的目的。我将继续寻找更优雅的解决方案。当然,我们将等待更好的解决方案。我也将从中学习。@Sparafusile:谢谢你分享你的想法。如果您愿意分享您实现的逻辑,请与我们分享。这是一个有趣的想法,但我希望能够使用默认视图的自定义布局和/或使用自定义视图的默认布局。除非我误解了你的答案,否则我不能用你的代码来做。@Sparafusile你可以这样做,你可以把
\u ViewStart.cshtml
放在任何你需要自定义的文件夹中,你甚至可以把它放在controller文件夹或默认文件夹中。默认情况下,Razor Engine搜索控制器文件夹的起始页(\u ViewStart.cshtml
),如果找不到,请尝试父文件夹,依此类推,直到应用程序根目录。