Обработка свойств макета с помощью настраиваемого механизма просмотра Razor
Я реализовал механизм просмотра с несколькими арендаторами, подобный тому, что описано здесь:
Позвольте мне переопределить места поиска для просмотра следующим образом:
MasterLocationFormats = new[]
{
"~/Views/%1/{1}/{0}.cshtml",
"~/Views/%1/Shared/{0}.cshtml",
"~/Views/Default/{1}/{0}.cshtml",
"~/Views/Default/Shared/{0}.cshtml",
};
В котором %1
заменяется правильной папкой для активного арендатора. Это работает только прекрасное исключение одной проблемы. Когда я определяю путь Layout на моем представлении следующим образом:
Layout = "~/Views/Default/Shared/_MyLyout.cshtml";
Это как бы побеждает цель иметь многопользовательскую собственность, так как мне приходится жестко кодировать точное местоположение страницы макета. Я хочу иметь возможность сделать что-то вроде этого:
Layout = "~/Views/%1/Shared/_MyLyout.cshtml";
Если бы я хотел разрешить арендаторам иметь одну страницу макета, как бы я мог поддержать это?
Я пробовал использовать методы просмотра, которые я переделывал:
- CreatePartialView
- CreateView
- FileExists
Но ничто, кажется, не указывает на возможность динамически указывать страницу макета.
Update:
Вот что я до сих пор работаю. Я использовал ответ на этот вопрос qaru.site/info/444644/..., слегка модифицированный, чтобы создать помощник 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." );
}
который похож на предложенный саравананом. Затем я могу установить макет на мой взгляд с помощью этого кода:
Layout = Html.GetLayoutPageForTenant( "_Home" );
К сожалению, это дублирует работу, которую делает пользовательский движок просмотра, который кажется неправильным способом.
Ответы
Ответ 1
Я хотел бы предложить следующую идею:
В файле _ViewStart.cshtml
, где мы устанавливаем страницы макета, вы можете использовать что-то вроде этого, с идеей URL-адреса макета на основе Tenant или имени папки заполняется в контроллере, извлекая из базы данных.
@{
Layout = ViewBag.TenantLayoutPageUrl;
}
или
@{
Layout = string.Format("~/Views/{0}/Shared/_MyLyout.cshtml",ViewBag.TenantId);
}
Если у вас есть статические представления данных Tenant, например статический класс Identity
, который будет отслеживать настройку вашего арендатора, мы можем использовать это и свести к минимуму округление до db.
Поделитесь своей идеей с этой реализацией, чтобы она была полезной для сообщества.
Ответ 2
Попробуйте,
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">
Ответ 3
Вы можете добавить следующее _ViewStart.cshtml
в папку просмотра арендаторов (~/Views/%1/_ViewStart.cshtml
). Каждый арендатор может управлять своими файлами макетов.
@{
Layout = VirtualPathUtility.GetDirectory(PageContext.Page.VirtualPath) + "Shared/_Layout.cshtml";
}