如何在使用自定义位置时在asp.net core mvc中指定视图位置?

Ron*_*n C 31 asp.net-core-mvc asp.net-core asp.net-core-1.0 asp.net-core-2.1

假设我有一个控制器使用基于属性的路由来处理请求的/ admin/product网址,如下所示:

[Route("admin/[controller]")]        
public class ProductController: Controller {

    // GET: /admin/product
    [Route("")]
    public IActionResult Index() {

        return View();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在让我们说我希望将我的视图组织在一个文件夹结构中,该文件夹结构大致反映了它们相关的url路径.所以我希望这个控制器的视图位于这里:

/Views/Admin/Product.cshtml
Run Code Online (Sandbox Code Playgroud)

更进一步,如果我有这样的控制器:

[Route("admin/marketing/[controller]")]        
public class PromoCodeListController: Controller {

    // GET: /admin/marketing/promocodelist
    [Route("")]
    public IActionResult Index() {

        return View();
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望框架在这里自动查找它的视图:

Views/Admin/Marketing/PromoCodeList.cshtml
Run Code Online (Sandbox Code Playgroud)

理想情况下,用于通知视图位置框架的方法将基于基于属性的路由信息​​以一般方式工作,而不管涉及多少URL段(即,嵌套的程度有多深).

如何指示Core MVC框架(我目前正在使用RC1)在这样的位置查找控制器的视图?

Bri*_*Kay 69

好消息......在ASP.NET Core 2.*中,您不再需要自定义ViewEngine甚至ExpandViewLocations.

使用OdeToCode.AddFeatureFolders包

这是最简单的方法...... K. Scott Allen在OdeToCode.AddFeatureFolders上为您提供了一个nuget包,它是干净的,包括对区域的可选支持.Github:https://github.com/OdeToCode/AddFeatureFolders

安装包,它很简单:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc()
                .AddFeatureFolders();

        ...
    }

    ...
}  
Run Code Online (Sandbox Code Playgroud)

DIY

如果您需要对文件夹结构进行非常精细的控制,或者由于某种原因不允许/不想接受依赖项,请使用此选项.这也很容易,虽然可能比上面的nuget包更加凌乱:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
         ...

         services.Configure<RazorViewEngineOptions>(o =>
         {
             // {2} is area, {1} is controller,{0} is the action    
             o.ViewLocationFormats.Clear(); 
             o.ViewLocationFormats.Add("/Controllers/{1}/Views/{0}" + RazorViewEngine.ViewExtension);
             o.ViewLocationFormats.Add("/Controllers/Shared/Views/{0}" + RazorViewEngine.ViewExtension);

             // Untested. You could remove this if you don't care about areas.
             o.AreaViewLocationFormats.Clear();
             o.AreaViewLocationFormats.Add("/Areas/{2}/Controllers/{1}/Views/{0}" + RazorViewEngine.ViewExtension);
             o.AreaViewLocationFormats.Add("/Areas/{2}/Controllers/Shared/Views/{0}" + RazorViewEngine.ViewExtension);
             o.AreaViewLocationFormats.Add("/Areas/Shared/Views/{0}" + RazorViewEngine.ViewExtension);
        });

        ...         
    }

...
}
Run Code Online (Sandbox Code Playgroud)

就是这样!不需要特殊课程.

处理Resharper/Rider

额外提示:如果你正在使用ReSharper,你可能会注意到在某些地方ReSharper无法找到你的观点并给你恼人的警告.要解决这个问题,请拉入Resharper.Annotations包,并在startup.cs(或其他任何地方)中为每个视图位置添加以下属性之一:

[assembly: AspMvcViewLocationFormat("/Controllers/{1}/Views/{0}.cshtml")]
[assembly: AspMvcViewLocationFormat("/Controllers/Shared/Views/{0}.cshtml")]

[assembly: AspMvcViewLocationFormat("/Areas/{2}/Controllers/{1}/Views/{0}.cshtml")]
[assembly: AspMvcViewLocationFormat("/Controllers/Shared/Views/{0}.cshtml")]
Run Code Online (Sandbox Code Playgroud)

希望这能让一些人感到沮丧,这让我感到沮丧.:)

  • 我喜欢关于ReSharper的_Bonus提示!我突然强调了我对"View"和"PartialView"的所有调用. (4认同)
  • 你是我的英雄.我来到这个问题是因为我想实现基于特征的文件夹结构,你已经完成了.太棒了! (2认同)
  • @JohnHargrove谢谢你的客气话,你度过了艰难的一天:) (2认同)

Ron*_*n C 44

您可以通过实现视图位置扩展器来扩展视图引擎查找视图的位置.以下是一些示例代码来演示该方法:

public class ViewLocationExpander: IViewLocationExpander {

    /// <summary>
    /// Used to specify the locations that the view engine should search to 
    /// locate views.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="viewLocations"></param>
    /// <returns></returns>
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) {
        //{2} is area, {1} is controller,{0} is the action
        string[] locations = new string[] { "/Views/{2}/{1}/{0}.cshtml"};
        return locations.Union(viewLocations);          //Add mvc default locations after ours
    }


    public void PopulateValues(ViewLocationExpanderContext context) {
        context.Values["customviewlocation"] = nameof(ViewLocationExpander);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在ConfigureServices(IServiceCollection services)startup.cs文件的方法中添加以下代码以将其注册到IoC容器.之后立即行动services.AddMvc();

services.Configure<RazorViewEngineOptions>(options => {
        options.ViewLocationExpanders.Add(new ViewLocationExpander());
    });
Run Code Online (Sandbox Code Playgroud)

现在,您可以将所需的任何自定义目录结构添加到视图引擎查找视图和部分视图的位置列表中.只需将其添加到locations string[].此外,您可以将_ViewImports.cshtml文件放在同一目录或任何父目录中,它将被找到并与您在此新目录结构中的视图合并.

更新:
这种方法的一个好处是它提供了比后来在ASP.NET Core 2中引入的方法更多的灵活性(感谢@BrianMacKay记录新方法).因此,例如,此ViewLocationExpander方法不仅允许指定搜索视图和区域的路径层次结构,还允许指定布局和视图组件.您还可以访问完整内容ActionContext以确定适当的路由.这提供了很多灵活性和功率.因此,例如,如果您想通过评估当前请求的路径来确定适当的视图位置,则可以通过访问当前请求的路径context.ActionContext.HttpContext.Request.Path.


Bri*_*izo 21

在.net核心中,您可以指定视图的整个路径.

return View("~/Views/booking/checkout.cshtml", checkoutRequest);

  • 完全正确,但我一直在寻找一种解决方案,让框架在自定义位置自动查找视图,而不必以这种方式指定.对于想要手动指定视图位置的人来说,这是一个很好的解决方案. (5认同)
  • 是的,我比你接受的答案更喜欢你的答案.我正要使用它,直到我意识到它对于我需要的东西来说太过分了.我发布了这个,因为我能够解决我的问题,而无需添加任何自定义代码.也许有人会发现这个方便.感谢您的回答!问候 (3认同)

Mik*_*ike 7

我使用的是核心 3.1,只是在 Startup.cs 的 ConfigureServices 方法中执行此操作。

 services.AddControllersWithViews().AddRazorOptions(
     options => {// Add custom location to view search location
         options.ViewLocationFormats.Add("/Views/Shared/YourLocation/{0}.cshtml");                    
     });
Run Code Online (Sandbox Code Playgroud)

{0} 只是视图名称的占位符。好看又简单。


归档时间:

查看次数:

27687 次

最近记录:

6 年,5 月 前