ASP.NET|ASP.NET Core中的Razor页面使用视图组件
视图组件简介
【ASP.NET|ASP.NET Core中的Razor页面使用视图组件】在新的ASP.NET Core MVC中,视图组件类似于局部视图,但它们更强大。视图组件不使用模型绑定,仅依赖于您在调用时提供的数据。
视图组件特性:
- 呈现页面响应的某一部分而不是整个响应
- 包括在控制器和视图之间发现的关注分离和可测试性优势
- 可以具有参数和业务逻辑
- 通常在页面布局中调用
- 动态导航菜单
- 标签云(查询数据库)
- 登录面板
- 购物车
- 最近发表的文章
- 典型博客上的侧边栏内容
- 将在每个页面上呈现的登录面板,并显示要注销或登录的链接,具体取决于用户的登录状态
ViewComponent
继承的方法和属性。创建视图组件 此部分包含创建视图组件的高级功能。在本文的后面,我们将详细介绍每一个步骤,并创建一个视图组件。
视图组件类
视图组件类可以通过以下任何方式来创建:
- 继承自 ViewComponent 类
- 使用
[ViewComponent]
特性来标记一个类,或者继承自具有[ViewComponent]
特性的类 - 创建类的名称以 ViewComponent 后缀结尾
ViewComponentAttribute.Name
属性显式指定名称。视图组件类特性:
- 完美支持构造函数依赖注入
- 不参与控制器生命周期,这意味着您不能在视图组件中使用过滤器
视图组件在
InvokeAsync
方法中定义逻辑,并返回IViewComponentResult
类型。参数直接来自视图组件的调用,而不是模型绑定;视图组件从不直接处理请求;通常视图组件会初始化模型,并通过调用View
方法将其传递给视图。总而言之,视图组件方法特性:- 定义一个返回
IViewComponentResult
的InvokeAsync
方法 - 通常会初始化一个模型,并通过调用
ViewComponent
类型的View
方法将其传递给视图 - 参数来自调用方法,而不是HTTP请求,没有模型绑定
- 不能直接通过HTTP请求访问,它们通常在视图中通过代码调用;视图组件永远不会处理请求
- 在方法签名上重载,而不是当前HTTP请求的任何详细信息
运行时在以下路径中搜索视图:
- Views/
/Components/ / - Views/Shared/Components/
/
View
方法时,可以指定不同的视图名称。我们建议您视图文件命名为Default.cshtml,并使用Views/Shared/Components/
PriorityList
视图组件,视图的路径是Views/Shared/Components/PriorityList/Default.cshtml。调用视图组件 要使用视图组件,请在视图中调用以下代码:
@Component.InvokeAsync("Name of view component", )
参数将被传递给
InvokeAsync
方法,在本文中编写的PriorityList
视图组件在Views/Todo/Index.cshtml视图文件中调用。在下文中,使用两个参数调用InvokeAsync
方法:@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
通过标签帮助器调用视图组件 对于ASP.NET Core 1.1及更高版本,您可以将视图组件作为标签帮助器(Tag Helper)进行调用:
标签帮助器将Pascal命名方式的类型和方法参数被转换成它们的小写短横线命名方式(lower kebab case)。调用视图组件的标签帮助器使用该元素,视图组件约定如下:
注意:为了将视图组件作为标签帮助器,您必须使用
@addTagHelper
指令注册包含视图组件的程序集。例如,如果您的视图组件位于名为“MyWebApp”的程序集中,请将以下指令添加到_ViewImports.cshtml
文件中:@addTagHelper *, MyWebApp
您可以将视图组件作为标签帮助器注册到引用视图组件的任何文件。有关如何注册标签助手的更多信息,请参阅Managing Tag Helper Scope。
本示例中使用的
InvokeAsync
方法:@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
标签帮助器标记:
在上面的示例中,
PriorityList
视图组件变为priority-list
;视图组件的参数作为属性按小写短横线命名方式传递。从控制器直接调用视图组件
视图组件通常在视图调用,但您也可以直接在控制器的方法中调用它们。虽然视图组件被定义为不能像控制器一样直接处理请求,但您可以轻松在控制器的Action方法中实现返回
ViewComponentResult
内容。在下面的示例中,在控制器直接调用视图组件:
public IActionResult IndexVC(){return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false }); }
演练:创建一个简单的视图组件 示例下载,构建和测试入门代码。这是一个简单的项目,
Todo
控制器显示 Todo 项目列表。文章图片
添加ViewComponent类 创建一个 ViewComponents 文件夹并添加以下
PriorityListViewComponent
类:using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ViewComponentSample.Models; namespace ViewComponentSample.ViewComponents{public class PriorityListViewComponent : ViewComponent{private readonly ToDoContext db; public PriorityListViewComponent(ToDoContext context){db = context; }public async TaskInvokeAsync(int maxPriority, bool isDone){var items = await GetItemsAsync(maxPriority, isDone); return View(items); }private Task > GetItemsAsync(int maxPriority, bool isDone){return db.ToDo.Where(x => x.IsDone == isDone &&x.Priority <= maxPriority).ToListAsync(); }}}
代码注意事项:
- 视图组件类可以包含在项目中的任何文件夹中。
- 因为类名称PriorityListViewComponent以后缀ViewComponent结尾,运行时在视图中引用视图组件时使用字符串“PriorityList”。稍后我会详细解释一下。
[ViewComponent]
特性可以更改用于引用视图组件的名称。例如,我们可以该类命名为XYZ
并应用该ViewComponent
属性:[ViewComponent(Name = "PriorityList")]public class XYZ : ViewComponent
[ViewComponent]
特性告诉视图组件选择器在查找与组件关联的视图时使用名称PriorityList
,并在从视图引用组件类时使用字符串“PriorityList”。稍后我会详细解释一下。- 组件使用依赖注入来使
DbContext
可用。 InvokeAsync
是一个可以从视图中调用的公开方法,它可以使用任意数量的参数。InvokeAsync
方法返回满足isDone
和maxPriority
参数的ToDo
集合。
- 创建
Views/Shared/Components
文件夹,此文件夹必须命名为 Components。 - 创建 Views/Shared/Components/PriorityList 文件夹。此文件夹名称必须与视图组件类的名称一致,或者类名称去掉后缀(如果遵循约定在类名称中使用
ViewComponent
后缀)。如果您使用该ViewComponent
特性,则名称需要与特性名称一致。 - 创建一个Views/Shared/Components/PriorityList/Default.cshtml Razor视图:
@model IEnumerable
Priority Items
- @foreach (var todo in Model){
- @todo.Name }
Razor视图会列出TodoItem
并显示它们。如果视图组件InvokeAsync
方法未传递视图的名称(如我们的示例中),则按照约定视图名称为 Default。在本文的后面,我将向您展示如何传递视图的名称。如果视图组件只适用于特定控制器,则可以将其添加到控制器特定的文件夹(Views/Todo/Components/PriorityList/Default.cshtml)。 - 在视图 Views/Todo/index.cshtml 文件底部的
div
元素中包含视图组件的调用@await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false })
@await Component.InvokeAsync
是调用视图组件的语法。第一个参数是我们要调用组件的名称,随后是传递给组件的参数。InvokeAsync
可以包含任意数量的参数。调试应用程序,下图显示了ToDo列表和选择项:
文章图片
您也可以直接在控制器中调用视图组件:
public IActionResult IndexVC(){return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false }); }
文章图片
指定视图名称
复杂视图组件可能需要在某些情况下指定非默认视图。以下代码显示了如何从
InvokeAsync
方法中指定“PVC”视图。修改PriorityListViewComponent
类中的InvokeAsync
方法。public async TaskInvokeAsync(int maxPriority, bool isDone){string MyView = "Default"; // If asking for all completed tasks, render with the "PVC" view.if (maxPriority > 3 && isDone == true){MyView = "PVC"; }var items = await GetItemsAsync(maxPriority, isDone); return View(MyView, items); }
将 Views/Shared/Components/PriorityList/Default.cshtml 文件复制到名为 Views/Shared/Components/PriorityList/PVC.cshtml 视图文件。添加标题以表示正在使用的是PVC视图。
@model IEnumerablePVC Named Priority Component View@ViewBag.PriorityMessage @foreach (var todo in Model){
- @todo.Name
}
修改视图 Views/TodoList/Index.cshtml:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
运行应用程序并验证是PVC视图。
文章图片
如果显示不是PVC视图,请验证您调用视图组件
priority
参数是否为4或更高的。检测视图路径
- 将
priority
参数更改为三个或更小,返回默认视图。 - 临时将 Views/Todo/Components/PriorityList/Default.cshtml 重命名为 1Default.cshtml。
- 调试应用程序,您将收到以下错误:
An unhandled exception occurred while processing the request.
InvalidOperationException: The view 'Components/PriorityList/Default' was not found. The following locations were searched:
/Views/ToDo/Components/PriorityList/Default.cshtml
/Views/Shared/Components/PriorityList/Default.cshtml
EnsureSuccessful
- 将视图 Views/Todo/Components/PriorityList/1Default.cshtml 复制到 Views/Shared/Components/PriorityList/Default.cshtml 。
- 在 Shared 的Todo视图组件视图中添加一些标记,以表示视图来自 Shared 文件夹。
- 测试 Shared 组件视图。
文章图片
避免字符串魔法
如果要编译时安全,则可以使用类名替换硬编码视图组件名称。创建没有以“ViewComponent”后缀的视图组件:
using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ViewComponentSample.Models; namespace ViewComponentSample.ViewComponents{public class PriorityList : ViewComponent{private readonly ToDoContext db; public PriorityList(ToDoContext context){db = context; }public async TaskInvokeAsync(int maxPriority, bool isDone){var items = await GetItemsAsync(maxPriority, isDone); return View(items); }private Task > GetItemsAsync(int maxPriority, bool isDone){return db.ToDo.Where(x => x.IsDone == isDone &&x.Priority <= maxPriority).ToListAsync(); }}}
使用
using
将命名空间添加到您的Razor视图文件,并使用nameof
运算符:@using ViewComponentSample.Models@using ViewComponentSample.ViewComponents@model IEnumerableToDo nameof@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })
其它资源
- 依赖注入视图
- 查看或下载示例代码
推荐阅读
- 【ASP.NET|【ASP.NET Core】MVC模型绑定(非规范正文内容的处理)
- Java|Java 超详细讲解设计模式之中的建造者模式
- python|正则表达式在python中的简单使用(附带例子(正则表达式匹配+数据清洗))
- js高级程序设计|js高级程序设计(第二章)
- JavaScript删除有序数组中的重复项
- ASP.NET|ASP.NET Core项目使用xUnit进行单元测试
- Java|Java 超详细讲解设计模式之中的抽象工厂模式
- WebSocket在实时语音识别中的应用
- HMS|HMS Core视频编辑服务(AI着色, 忆往昔看今朝)
- WebGL 及其在 WebRTC 中的应用