如何在MVC 5中创建多租户视图结构

3
我正在构建一个演示项目,其中多个租户将拥有自己的视图集合。此外,如果租户没有专门的视图,将提供默认视图集合。我看过多个关于多租户代码方面的教程,其中每个租户都有自己的数据库。但是视图方面似乎缺乏相关教程。
伪代码如下:
Get Me the User information view
Get tentantname from current context
Check /views/{tentantname}/userinfo/index.cshtml
if found return /views/{tentantname}/userinfo/index.cshtml
else return /views/base/userinfo/index.html

我不确定在哪里处理这段代码?(也许创建一个基础控制器来覆盖对视图的调用)
我应该创建自己的RazorViewEngine吗?
这是在路由配置中处理的吗?(这更多地涉及控制器路由而不是查找视图的位置)
需要覆盖哪个方法?

我已经找到了有关更改所有视图基本目录的教程,但我想逐个处理每个视图的查找。利用正在运行请求的当前上下文中的值。

编辑:参考第一个答案。

对RazorViewEngine所做的更改删除了示例中使用的许多可重写方法。同一作者添加了一个更新http://weblogs.asp.net/imranbaloch/custom-viewengine-aspnet5-mvc6 但这个版本没有涉及视图位置检查和重写。我认为答案在传递给构造函数的参数之一中。我认为如果可以覆盖其中一个参数,就可以完成我的任务。以下是来自元数据的RazorViewEngine:

//
// Summary:
//     Default implementation of Microsoft.AspNet.Mvc.Razor.IRazorViewEngine.
//
// Remarks:
//     For ViewResults returned from controllers, views should be located in Microsoft.AspNet.Mvc.Razor.RazorViewEngine.ViewLocationFormats
//     by default. For the controllers in an area, views should exist in Microsoft.AspNet.Mvc.Razor.RazorViewEngine.AreaViewLocationFormats.
public class RazorViewEngine : IRazorViewEngine, IViewEngine
{
    //
    // Summary:
    //     Initializes a new instance of the Microsoft.AspNet.Mvc.Razor.RazorViewEngine
    //     class.
    //
    // Parameters:
    //   pageFactory:
    //     The page factory used for creating Microsoft.AspNet.Mvc.Razor.IRazorPage instances.
    public RazorViewEngine(IRazorPageFactory pageFactory, IRazorViewFactory viewFactory, IOptions<RazorViewEngineOptions> optionsAccessor, IViewLocationCache viewLocationCache);

    //
    // Summary:
    //     Gets the locations where this instance of Microsoft.AspNet.Mvc.Razor.RazorViewEngine
    //     will search for views within an area.
    //
    // Remarks:
    //     The locations of the views returned from controllers that belong to an area.
    //     Locations are composite format strings (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx),
    //     which contains following indexes: {0} - Action Name {1} - Controller Name {2}
    //     - Area name The values for these locations are case-sensitive on case-senstive
    //     file systems. For example, the view for the Test action of HomeController should
    //     be located at /Views/Home/Test.cshtml. Locations such as /views/home/test.cshtml
    //     would not be discovered
    public virtual IEnumerable<string> AreaViewLocationFormats { get; }
    //
    // Summary:
    //     Gets the locations where this instance of Microsoft.AspNet.Mvc.Razor.RazorViewEngine
    //     will search for views.
    //
    // Remarks:
    //     The locations of the views returned from controllers that do not belong to an
    //     area. Locations are composite format strings (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx),
    //     which contains following indexes: {0} - Action Name {1} - Controller Name The
    //     values for these locations are case-sensitive on case-senstive file systems.
    //     For example, the view for the Test action of HomeController should be located
    //     at /Views/Home/Test.cshtml. Locations such as /views/home/test.cshtml would not
    //     be discovered
    public virtual IEnumerable<string> ViewLocationFormats { get; }

    //
    // Summary:
    //     Gets the case-normalized route value for the specified route key.
    //
    // Parameters:
    //   context:
    //     The Microsoft.AspNet.Mvc.ActionContext.
    //
    //   key:
    //     The route key to lookup.
    //
    // Returns:
    //     The value corresponding to the key.
    //
    // Remarks:
    //     The casing of a route value in Microsoft.AspNet.Mvc.ActionContext.RouteData is
    //     determined by the client. This making constructing paths for view locations in
    //     a case sensitive file system unreliable. Using the Microsoft.AspNet.Mvc.Abstractions.ActionDescriptor.RouteValueDefaults
    //     for attribute routes and Microsoft.AspNet.Mvc.Abstractions.ActionDescriptor.RouteConstraints
    //     for traditional routes to get route values produces consistently cased results.
    public static string GetNormalizedRouteValue(ActionContext context, string key);
    //
    public RazorPageResult FindPage(ActionContext context, string pageName);
    //
    public ViewEngineResult FindPartialView(ActionContext context, string partialViewName);
    //
    public ViewEngineResult FindView(ActionContext context, string viewName);
}

如果您注意到只有一个或两个属性是虚拟的。我认为其中一个构造函数参数可以被覆盖,以便在调用FindView()时可以执行某些操作。目前我不知道,也找不到示例或教程。

1个回答

4

我看了那个教程,但在MVC 5中RazorViewEngine类发生了很大的变化。 特别是唯一的虚拟属性是AreaViewLocationFormats和ViewLocationFormats。FindView不是虚拟的。 我相信构造函数中的一个参数可能是答案,但我很难找到关于它们的信息。(IRazorViewFactory可能是关键)。 - Dan
1
@dan,你有检查View位置扩展器吗?http://weblogs.asp.net/imranbaloch/view-location-expander-aspnet5-mvc6 - Imran Qadir Baksh - Baloch
@user960567 那就是答案!把它放上去,我会给你信用。可惜 Imran 在他的另外两个解决方案中没有链接到这个。我知道这并不复杂。 - Dan
@Dan 可以放心将上面标记为答案。已更新。 - Imran Qadir Baksh - Baloch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接