ASP.NET Core MVC之ViewComponents(视图组件)知多少?
前言
大概一个来星期未更新博客了,久违了各位,关于SQL Server性能优化会和ASP.NET Core MVC穿插来讲,如果你希望我分享哪些内容可以在评论下方提出来,我会筛选并看看技术文档来对你的内容进行解答,借此希望我们能共同进步和学习。本节我们来讲讲ASP.NET Core MVC中的视图组件。
Web应用程序下管理ViewComponents
我是奔着项目用到了哪些就会去写对应的技术博客,在我们项目中利用视图组件来加载权限菜单,这一块是我老大所做,我也就粗略看了看使用方法并未深入借此机会去学习学习,最近老大要我研究.net core中的加密和解密,我也在摸索着并学习着后续可能再来详细讲讲.net core中的加密和解密。视图组件类似于我们之前ASP.NET MVC中的部分视图,不过其功能比部分视图更加强大,它不会依赖于强类型视图,也和部分视图一样重在重用,到底多强大我们下面一起来见识下。首先我们过一过基本原理。通过调用 InvokeAsync 方法来调用视图组件,此方法定义在 IViewComponentHelper 接口中,如下:
视图组件并不直接处理请求,主要可以用来初始化数据或者获取数据后并通过上述方法来进行渲染,从上述方法参数中并未包含任何http请求信息而得知。那么问题来了,视图组件是如何进行查找哪些是视图组件呢,也就是说从哪些路径去查找呢,从如何两个路径去查找视图组件。
Views/<controller_name>/Components/<view_component_name>/<view_name>
Views/Shared/Components/<view_component_name>/<view_name>
默认的视图组件名称为Default,所以我们可以根据视图页定义为Default.cshtml,当然我们也可以自定义。虽然上述有两种查找视图组件的形式,但是.net core团队推荐我们以如下路径形式来放置视图组件。
Views/Shared/Components/<view_component_name>/<view_name>
看到官网写的那么多还不容易理解,这里我们约定规则组件类以ViewComponent结尾。我将用最浅显的实例来让看这篇文章的园友快速上手。首先我们建立一个组件类。
public class PersonViewComponent : ViewComponent { }
直接看下图按照上述所讲。
我们定义了一个组件控制器如下:
[Route("[Controller]")] public class ViewComponentController : Controller { [HttpGet("[action]")] public IActionResult Index() { return View(); } }
然后在其Index方法里面来调用组件。
@await Component.InvokeAsync("Person")
此时你将看到如下错误:
上述说明未调用InvokeAsync方法,接下来我们在组件类里面写一个InvokeAsync方法。此时将演变成如下这样:
public class PersonViewComponent : ViewComponent { public Task<string> InvokeAsync() { return Task.FromResult("Jeffcky from cnblogs"); } }
此时则成功,如下:
上述我们只是演示其冰山一角,上述只是直接返回一个字符串而已。要是返回视图该如何操作呢?我们来看看:
public class PersonViewComponent : ViewComponent { private IBlogRepository _blogRepository; public PersonViewComponent(IBlogRepository blogRepository) { _blogRepository = blogRepository; } public async Task<IViewComponentResult> InvokeAsync() { var blogs = await GetBlogsAsync(); return View(blogs); } private Task<List<Blog>> GetBlogsAsync() { var blogs = _blogRepository.GetAll().Take(10).ToList(); return Task.FromResult(blogs); } }
接下来在返回的默认组件名称为Default.cshtml中获取数据并遍历:
@{ Layout = null; } @using EFCore.Model.Entities @model List<Blog> <h3>Best sellers</h3> <ul style="padding-left:0;list-style-type:none;"> @foreach (var blog in Model) { <li>@blog.Name-@blog.Url</li> } </ul>
上述我们需要通过返回类型为IViewComponentResult 来加载视图。
单独建立类库管理ViewComponents
上述我们操作视图组件是在Web应用程序下轻而易举,如果是将视图组件作为一个类库来管理,这就有点难度了,为了方便管理视图组件我们尝试将视图组件单独建立一个类库来管理,此时我们又该如何操作呢,我们来看看,首先请确保.net core版本为1.1,1.0版本未测试,通过如下位置来看当前版本或者到 C:\Program Files\dotnet 查看版本:
第一步:此时我们建立一个组件类库并将视图文件全部归纳到类库下,如图:
第二步:在组件类库中projecy.json添加MVC包,如下:
"Microsoft.AspNetCore.Mvc": "1.1.0",
第三步:继续在project.json中添加查找组件视图选项,如下:
"buildOptions": { "embed": "Views/**/*.cshtml" }
【注意】一定要记得添加上述选项,否则出现如下错误
第四步:接下来则是在Web下引用该类库并解析上述类库程序集将其视图组件进行嵌入,需要下载如下程序包
第五步:接下来我们去利用FileProvider去加载组件程序集获取组件中派生自ViewComponent的类,如下:
var assmebly = typeof(ComponentLibrary.PersonViewComponent).GetTypeInfo().Assembly; var embeddedFileProvider = new EmbeddedFileProvider(assmebly, "ComponentLibrary"); services.Configure<RazorViewEngineOptions>(options => { options.FileProviders.Add(embeddedFileProvider); });
最后一步:改写调用InvokeAsync方法参数,如下:
@await Component.InvokeAsync("ComponentLibrary.Person")
此时让我联想到ASP.NET MVC中控制器约定以Contrller结尾,否则查找不到,那么对于视图组件约定规范也是以ViewComponent结尾,那么打破这种约定是否好使呢,我们试试看。我们将视图组件修改如下:
public class PersonComponent : ViewComponent {...}
其余也一并进行对应修改,同时对调用方法也进行如下修改:
@await Component.InvokeAsync(nameof(ComponentLibrary.PersonComponent))
经过检验也是准确无误,但是还是按照约定规范来,这里只是做一个验证而已。对于视图组件介绍到此结束,其他比较基本的东西就不再叙述,比如可以和部分视图一样在控制器方法中进行调用组件,如下:
public IActionResult TestViewComponent() { return ViewComponent("", ""); }
以及视图组件还有中还可以进行参数传递,和部分视图别无二致,部分视图有的视图组件都有,而视图组件有的部分视图肯定没有,由此知,视图组件的强大。
总结
本节比较详细的讲述了视图组件的基本使用以及扩展深入将其隔离开来单独建立一个视图组件类库,希望对阅读本文的你有所帮助。