Razor 页面视图组件

视图组件与局部页面有着类似的作用,它们代表可重复使用的 UI 片段,可以帮助分解和简化复杂的布局,并且可以在多个页面中重使。如果需要一定的逻辑来获取包含在HTML片段中的数据,比如调用外部数据源(如数据库或Web服务),建议使用视图组件而不是局部页面。视图组件的用例包括数据驱动的菜单、标签云和购物车小部件。

视图组件元素

视图组件由类文件和 .cshtml 视图文件组成。类文件包含用于生成模型的逻辑,而视图文件包含用于生成将插入到调用页面的HTML模板。

类文件必须符合以下规则:

  • 必须继承自ViewComponent 类。
  • 必须以ViewComponent作为类名称的后缀,或者必须用[ViewComponentAttribute](或继承自ViewComponentAttribute)标记修饰。
  • 必须实现返回类型为IViewComponentResultInvokeAsync方法。通常,通过return View(...)方法来实现。

默认情况下,视图文件名为 default.cshtml 。您可以通过将视图文件传递给return View(...)语句来指定替换的名称。视图文件在应用程序文件结构中的位置很重要,因为框架预定义了搜索的位置:

/Pages/Components/<component name>/Default.cshtml /Views/Shared/Components/<component name>/Default.cshtmlll

组件名称是去掉了类名的ViewComponent后缀(如果使用了该规则)。对于 只Razor 页面框架的站点,视图组件视图的推荐位置是 /Pages/Components/ 目录。只有在创建 Razor 页面和 MVC 混合应用程序时,才能推荐使用以 /Views 开头的路径。

演示

以下将演示创建两个视图组件的示例。一个会调用外部的 Web 服务来获取人员名单,并显示他们的名字。另外通过代表一个人的ID参数,从 Web 服务中获取这个人的详细信息,然后显示在小部件中。

本示例中使用的服务API托管在 JSONPlaceholder 上,它可以为开发和测试提供免费的 JSON API。

视图组件不负责调用外部API。这个任务将在一个单独的服务类中执行,该类将通过内置的 依赖注入 框架注入到视图组件中。

  1. 使用Visual Studio或 命令行 创建一个新的叫 RazorPages 的 Razor 页面网站。

  2. 在应用程序的根目录中添加 Domain.cs C#类文件,并文件中所有内容替换为下面内容:

    namespace RazorPages
    {
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string UserName { get; set; }
            public string Email { get; set; }
            public string Phone { get; set; }
            public string Website { get; set; }
            public Address Address { get; set; }
            public Company Company { get; set; }
        }
    
        public class Address
        {
            public string Street { get; set; }
            public string Suite { get; set; }
            public string City { get; set; }
            public string Zipcode { get; set; }
            public Geo Geo { get; set; }
        }
        public class Company
        {
            public string Name { get; set; }
            public string Catchphrase { get; set; }
            public string Bs { get; set; }
        }
        public class Geo
        {
            public float Lat { get; set;}
            public float Lng { get; set; }
        }
    }
    

    这些类映射到由本示例使用API返回的JSON所表示对象结构。

  3. 在根目标添加 Services 文件夹:

    Services folder

  4. Services 文件夹中添加 IUserService.cs 类。将内容替换为如下内容:

    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace RazorPages.Services
    {
        public interface IUserService
        {
            Task<List<User>> GetUsersAsync();
            Task<User> GetUserAsync(int id);
        }
    }
    
    

    这是指定由服务提供操作的接口。

  5. Services 文件夹中添加 UserService.cs 类,并使用以下内容进行替换:

    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    namespace RazorPages.Services
    {
        public class UserService : IUserService
        {
            public async Task<List<User>> GetUsersAsync()
            {
                using (var client = new HttpClient())
                {
                    var endPoint = "https://jsonplaceholder.typicode.com/users";
                    var json = await client.GetStringAsync(endPoint);
                    return JsonConvert.DeserializeObject<List<User>>(json);
                }
            }
    
            public async Task<User> GetUserAsync(int id)
            {
                using (var client = new HttpClient())
                {
                    var endPoint = $"https://jsonplaceholder.typicode.com/users/{id}";
                    var json = await client.GetStringAsync(endPoint);
                    return JsonConvert.DeserializeObject<User>(json);
                }
            }
        }
    }
    
    

    这个类是IUserService接口的一个实现。

  6. 在应用程序的根目录中增加 ViewComponents 文件夹,然后将新目录增加 UsersViewComponent.cs 类,并使用以下内容替换原有内容 :

    using Microsoft.AspNetCore.Mvc;
    using RazorPages.Services;
    using System.Threading.Tasks;
    
    namespace RazorPages.ViewComponents
    {
        public class UsersViewComponent : ViewComponent
        {
            private IUserService _userService;
    
            public UsersViewComponent(IUserService userService)
            {
                _userService = userService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync()
            {
                var users = await _userService.GetUsersAsync();
                return View(users);
            }
        }
    }
    

    这是视图组件的代码部分。它利用内置的依赖注入来解析IUserService接口的实现,并注入到视图组件类的构造函数中的。InvokeAsync方法将从服务中获取List<User>并将其传递给视图。

  7. Pages 文件夹中创建 Components 文件夹,然后将 Users 文件夹添加到新创建的 Components 文件夹中。在 Users 文件夹添加 default.cshtml 文件。生成的文件夹和文件层次结构应如下所示:

    ViewComponents view file

  8. default.cshtml 中的代码替换为以下内容:

    @model List<RazorPages.User>
    <h3>Users</h3>
    <ul>
        @foreach (var user in Model)
        {
            <li>@user.Name</li>
        }
    </ul>
    

    这是视图,并完成视图组件。请注意,视图通过@model指令将接受的模型类型指定为List<User>,它表示从InvokeAsync方法传递给视图的类型。

  9. 打开 Startup.cs 文件并添加 using RazorPages.Services; 命名空间引用,然后修改ConfigureServices方法代码为如下所示:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddTransient<IUserService, UserService>();
    }
    

    这一步注册IUserService到依赖注入容器中,并指定UserService为使用的实现。

  10. 打开 _Layout.cshtml 文件,找到<nav>部分和<environment>标签助手之间的内容,当前内容为如下:

    <div class="container body-content">
    
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2017 - RazorPages</p>
        </footer>
    </div>
    

    将内容修改为如下:

    <div class="container body-content">
        <div class="col-md-9">
            @RenderBody()
        </div>
        <div class="col-md-3">
            @await  Component.InvokeAsync("Users")
        </div>
    </div>
    <hr />
    <footer class="container">
        <p>&copy; 2017 - RazorPages</p>
    </footer>
    

    这会将网站的布局转换为两列,其中页面内容显示在左侧栏中,用户部件显示在右侧栏中。它使用Component.InvokeAsync方法将视图组件的输出呈现给页面。传递给该方法的字符串表示视图组件的名称(去掉“ViewComponent”后缀后的类名)。

  11. 运行该网站以确保一切正常。用户列表应显示在每个页面的右侧:

![User View Component](/images/07-08-2017-08-24-53.png)

标签助手和参数传递

第二个例子将演示如何使用标签助手而不是调用Component.InvokeAsync方法,同时将演示传递参数给视图组件。

  1. ViewComponents 文件夹中增加 UserViewComponent.cs 文件,将内容替换为如下内容:

    using Microsoft.AspNetCore.Mvc;
    using RazorPages.Services;
    using System.Threading.Tasks;
    
    namespace RazorPages.ViewComponents
    {
        public class UserViewComponent : ViewComponent
        {
            private IUserService _userService;
    
            public UserViewComponent(IUserService userService)
            {
                _userService = userService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync(int id)
            {
                var user = await _userService.GetUserAsync(id);
                return View(user);
            }
        }
    }
    

    这是视图组件的代码部分。这个组件和前一个组件的唯一区别是该InvokeAsync方法需要传递一个int类型的参数,然后传递给服务方法。

  2. /Pages/Components 文件夹中添加User文件夹。将 Razor 文件 default.cshtml 添加到该文件夹。 Components 文件夹现在的结构应该如下所示:

    user view component

  3. 将新的 default.cshtml 文件中内容替换为如下内容:

    @model RazorPages.User
    
    <h3>Featured User</h3>
    <div>
        <strong>@Model.Name</strong><br />
        @Model.Website<br />
        @Model.Company.Name<br />
    </div>
    
  4. 打开 ViewImports.cshml 文件,并在现有代码中添加下行代码:

    @addTagHelper *, RazorPages
    

    这将注册视图组件标记。

  5. 用以下代码替换@await Component.InvokeAync("Users")布局文件中的调用代码:

    <vc:user id="new Random().Next(1, 10)"></vc:user>
    

    视图组件的名称是在标签助手中指定的,以及InvokeAsync方法的参数。在这种情况下,每次调用组件时都会使用Random类生成从1-10随机数字,导致每次显示页面时都会随机选择一个用户。

  6. 运行应用程序以测试组件是否正常工作,并刷新几次以查看显示的不同用户的详细信息:

    user view component

    如果您喜欢使用Component.InvokeAsync方法,则id参数将作为第二个参数传递:

    @await Component.InvokeAsync("User", new Random().Next(1, 10))
    

如果您在查阅过程中,发现内容存在错误,请到我的博客中留言,谢谢,http://www.cnblogs.com/tdfblog/p/learn-razor-pages.html
最后一次更新时间: 2018-02-09 05:42:51