我安装了启用多租户模块并设置了 2 个租户的 Orchard CMS。两个租户都使用相同的主题。
我想要的是能够创建视图替代以针对每个租户,例如:
~/Themes/MyTheme/Views/Content.Tenant1.cshtml
将针对租户 1 和
~/Themes/MyTheme/Views/Content.Tenant2.cshtml
租户 2。
我意识到我可以使用 2 个不同(但非常相似)的主题来做到这一点,但这感觉就像是不必要的重复。
我安装了启用多租户模块并设置了 2 个租户的 Orchard CMS。两个租户都使用相同的主题。
我想要的是能够创建视图替代以针对每个租户,例如:
~/Themes/MyTheme/Views/Content.Tenant1.cshtml
将针对租户 1 和
~/Themes/MyTheme/Views/Content.Tenant2.cshtml
租户 2。
我意识到我可以使用 2 个不同(但非常相似)的主题来做到这一点,但这感觉就像是不必要的重复。
我试图在上面实现你的代码,但它只适用于形状。
我想查看 Index-tennant-[TenantName].cshtml 以覆盖 Index.cshtml
为此,我必须覆盖 RazorViewEngineProvider,然后添加额外的路径供 ViewEngine 查找。我使用了 [OrchardSuppressDependency...],因为我不喜欢更改实际的 Orchard CMS 代码,因为这会使以后的任何升级变得更加痛苦。
我希望这可以帮助任何遇到果园多租户问题的人。
[UsedImplicitly]
[OrchardSuppressDependency("Orchard.Mvc.ViewEngines.Razor.RazorViewEngineProvider")]
public class RazorViewEngineProvider : Orchard.Mvc.ViewEngines.Razor.RazorViewEngineProvider, IViewEngineProvider, IShapeTemplateViewEngine
{
private readonly string _tenant;
public RazorViewEngineProvider(ShellSettings shellSettings)
{
_tenant = shellSettings.Name;
}
public new IViewEngine CreateThemeViewEngine(CreateThemeViewEngineParams parameters)
{
var viewEngine = base.CreateThemeViewEngine(parameters);
if (!string.IsNullOrWhiteSpace(_tenant))
{
var razorView = viewEngine as RazorViewEngine;
if (razorView != null)
{
razorView.PartialViewLocationFormats = addTenant(razorView.PartialViewLocationFormats);
razorView.AreaPartialViewLocationFormats = addTenant(razorView.AreaPartialViewLocationFormats);
}
}
return viewEngine;
}
public new IViewEngine CreateModulesViewEngine(CreateModulesViewEngineParams parameters)
{
var viewEngine = base.CreateModulesViewEngine(parameters);
if (!string.IsNullOrWhiteSpace(_tenant))
{
var razorView = viewEngine as RazorViewEngine;
if (razorView != null)
{
razorView.ViewLocationFormats = addTenant(razorView.ViewLocationFormats);
razorView.PartialViewLocationFormats = addTenant(razorView.PartialViewLocationFormats);
razorView.AreaViewLocationFormats = addTenant(razorView.AreaViewLocationFormats);
razorView.AreaPartialViewLocationFormats = addTenant(razorView.AreaPartialViewLocationFormats);
}
}
return viewEngine;
}
private string[] addTenant(string[] views)
{
var tenantedView = new List<string>();
foreach (var view in views)
{
if (view.EndsWith(".cshtml",StringComparison.OrdinalIgnoreCase))
tenantedView.Add(string.Format ("{0}-tenant-{1}.cshtml", view.Substring(0,view.Length - 7) ,_tenant));
tenantedView.Add(view);
}
return tenantedView.ToArray();
}
}
答案当然是继承ShapeDisplayEvents
并绑定到context.ShapeMetadata.OnDisplaying
事件,因此:
public class MultiTenancyAlternatesFactory : ShapeDisplayEvents
{
private readonly ShellSettings _shellSettings;
public MultiTenancyAlternatesFactory(ShellSettings shellSettings)
{
_shellSettings = shellSettings;
}
public override void Displaying(ShapeDisplayingContext context)
{
context.ShapeMetadata.OnDisplaying(displayingContext =>
{
var tenant = _shellSettings.Name;
// look for ContentItem property
ContentItem contentItem = displayingContext.Shape.ContentItem;
// if not, check for ContentPart
if (contentItem == null)
{
ContentPart contentPart = displayingContext.Shape.ContentPart;
if (contentPart != null)
{
contentItem = contentPart.ContentItem;
}
}
var shapeName = displayingContext.ShapeMetadata.Type;
if (contentItem != null)
{
var contentTypeName = contentItem.ContentType;
displayingContext.ShapeMetadata.Alternates.Add(shapeName + "__" + contentTypeName + "__tenant__" + tenant);
}
displayingContext.ShapeMetadata.Alternates.Add(shapeName + "__tenant__" + tenant);
});
}
}