端午节在家将一个 asp.net 项目向 asp.net core 迁移时遇到了一个问题,用 view component 取代 Html.RenderAction 之后,运行时 view component 找不到视图文件。

System.InvalidOperationException: The view 'Components/AggSitePostList/PostList' was not found. The following locations were searched:
/Views/AggSite/Components/AggSitePostList/PostList.cshtml
/Views/Shared/Components/AggSitePostList/PostList.cshtml
/Pages/Shared/Components/AggSitePostList/PostList.cshtml
at Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable`1 originalLocations)
at Microsoft.AspNetCore.Mvc.ViewComponents.ViewViewComponentResult.ExecuteAsync(ViewComponentContext context)
at Microsoft.AspNetCore.Mvc.ViewComponents.DefaultViewComponentInvoker.InvokeAsync(ViewComponentContext context)

原先用的是 Html.RenderAction ,视图都放在 Controller 对应的视图路径,对于 AggSiteController ,Html.RenderAction 的视图都放在 /Views/AggSite/ 文件夹中,换成 view component 之后,在 AggSiteController 中运行的 view component 却把 /Views/AggSite/ 置之度外,不把这个路径列为视图文件查找范围。由于视图文件比较多,一个一个创建文件夹并移动视图文件比较麻烦,view compoent 这种不够大度的特性让迁移进程受阻。

有没有什么方法可以让将 /Views/AggSite/ 纳入 view component 搜索视图的范围,让其变得更加宽容呢?

网上搜索后得知原来 ASP.NET Core 料事如神,早已料到这种情况,通过 IViewLocationExpander 提供了对应的扩展能力。

对于这里遇到的问题,只需实现 IViewLocationExpander 接口,在 ExpandViewLocations 方法中添加新的视图路径。

public class ComponentViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
if (context.ControllerName + "Controller" == nameof(AggSiteController)
&& viewLocations.Any(l=>l.Contains("Components/")))
{
var vcLocation = "/Views/AggSite/{0}" + RazorViewEngine.ViewExtension;
viewLocations.ToList().Add(vcLocation);
return viewLocations;
} return viewLocations;
} public void PopulateValues(ViewLocationExpanderContext context) { }
}

然后在 Startup.ConfigureServices 在注册一下

services.Configure<RazorViewEngineOptions>(o =>
{
o.ViewLocationExpanders.Add(new ComponentViewLocationExpander());
});

原以为这种临时铺路的变通方法可以轻松搞定问题,但实际运行时发现问题依旧,此路不通。

被迫在 ComponentViewLocationExpander 中埋点排查问题,埋点日志打印出来后立马发现了其中的蹊跷。

ViewName: Components/AggSitePostList/PostList
viewLocations: /Views/{}/{}.cshtml;/Views/Shared/{}.cshtml;/Pages/Shared/{}.cshtml

原来 view component 的路径信息包含在 ViewName 中,并没有包含在 viewLocations 中,难怪之前的临时铺路不管用。

ViewName 中竟然包含视图文件的路径信息,这种偷懒、投机取巧造成的名不符实,很容易误导人。

知道了问题的真正原因后解决起来就不难了。临时铺路行不通,移花接木任我行,直接修改 ViewName 生成新的 viewLocations 即可。

public class ComponentViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
if (context.ControllerName + "Controller" == nameof(AggSiteController)
&& context.ViewName.Contains("Components/"))
{
var viewName = context.ViewName.Substring(context.ViewName.LastIndexOf("/") + );
return new string[] { "/Views/AggSite/" + viewName + RazorViewEngine.ViewExtension };
} return viewLocations;
} public void PopulateValues(ViewLocationExpanderContext context) { }
}

移花接木:借助 IViewLocationExpander 更换 ASP.NET Core View Component 视图路径的更多相关文章

  1. ASP.NET Core Razor 布局视图 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core Razor 布局视图 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core Razor 布局视图 上一章节中我们学习了如何使用 EF ...

  2. 在Asp.Net Core中取得物理路径

    在Asp.Net Core中取得物理路径: 从ASP.NET Core RC2开始,可以通过注入 IHostingEnvironment 服务对象来取得Web根目录和内容根目录的物理路径,如下所示: ...

  3. ASP.NET Core MVC 之视图组件(View Component)

    1.视图组件介绍 视图组件是 ASP.NET Core MVC 的新特性,类似于局部视图,但它更强大.视图组件不使用模型绑定,并且仅依赖于调用它时所提供的数据. 视图组件特点: 呈块状,而不是整个响应 ...

  4. #asp.net core mvc 的视图注入

    View injection is the most useful feature introduced in ASP.NET Core. 1.添加一个FruitsService public cla ...

  5. [译]ASP.NET Core 2.0 视图引擎

    问题 如何在ASP.NET Core 2.0中使用Razor引擎来创建视图? 答案 新建一个空项目,修改Startup.cs,添加MVC服务和请求中间件: public void ConfigureS ...

  6. [译]ASP.NET Core 2.0 视图组件

    问题 如何在ASP.NET Core 2.0中使用视图组件? 答案 新建一个空项目,修改Startup类并添加MVC服务和中间件: public void ConfigureServices(ISer ...

  7. ASP.NET Core 入门教程 7、ASP.NET Core MVC 分部视图入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)分部视图简介 ASP.NET Core MVC (Razor)分部视图基础教程 ASP.NET Core MVC (Raz ...

  8. ASP.NET Core MVC 之视图(Views)

    ASP.NET Core MVC 控制器可以使用视图返回格式化的结果. 1.什么是视图 在 MVC 中,视图封装了用户与应用交互呈现细节.视图是具有生成要发送到客户端内容的,包含嵌入代码的HTML模板 ...

  9. ASP.NET Core 入门笔记8,ASP.NET Core MVC 分部视图入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)分部视图简介 ASP.NET Core MVC (Razor)分部视图基础教程 ASP.NET Core MVC (Raz ...

随机推荐

  1. iOS开发Quartz2D之八:图形上下文状态栈

    #import "DrawView.h" @implementation DrawView - (void)drawRect:(CGRect)rect { // Drawing c ...

  2. [Now] Configure secrets and environment variables with Zeit’s Now

    Often your project will require some secret keys or tokens - for instance, API keys or database auth ...

  3. [React] Test friendly approach

    Add functional function such as change state, this should have tests covered. For example, in a comp ...

  4. Android的NDK开发(1)————Android JNI简介与调用流程

    1.JNI简介 JNI全称为Java Native Interface(Java本地调用).从Java1.1开始,JNI成为java平台的一部分,它允许Java代码和其他语言写的代码(如C&C ...

  5. android WebView总 结

    浏览器控件是每个开发环境都具备的,这为马甲神功提供了用武之地,windows的有webbrowser,android和ios都有webview.只是其引擎不同,相对于微软的webbrowser,and ...

  6. 【hdu 2176】取(m堆)石子游戏

    Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...

  7. bootstrap, boosting, bagging

    介绍boosting算法的资源: 视频讲义.介绍boosting算法,主要介绍AdaBoosing http://videolectures.net/mlss05us_schapire_b/ 在这个站 ...

  8. 输入框改变placeholder字体颜色

    ::-webkit-input-placeholder {  color: red;}:-moz-placeholder {  color: red;}::-moz-placeholder{color ...

  9. 表达式树Expression

    Expression表达式树动态查询 在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使 ...

  10. lucene 7.x 排序

    一.创建索引 @Test public void indexCreate() throws IOException { //创建分词器 Analyzer analyzer = new Standard ...