zoukankan      html  css  js  c++  java
  • [译]View components and Inject in ASP.NET MVC 6

    原文:http://www.asp.net/vnext/overview/aspnet-vnext/vc

    介绍view components

    view components (VCs) 类似于partial views, 但是VCs更加强大. 可以简单的把VC想象成一个mini的控制器.当你认为使用partial太复杂的时候你可以考虑使用VCs,例如:

    • 动态导航菜单Dynamic navigation menus
    • 标签云(从数据库获取数据)
    • 登录面板
    • 购物车
    • 最近发布的文章
    • 博客的其它边栏

    VC由两部分组成, 继承自ViewComponent的类和Razor视图.

    View Component类可以通过下面的方式创建:

    • 继承ViewComponent.
    • [ViewComponent] attribute 装饰类, 或者继承在一个被[ViewComponent]装饰的类.
    • 创建一个类, 类名以ViewComponent结尾.

    和控制器一样VCs必须是public的类.

    添加view component类

    1. 创建一个文件夹名为ViewComponents. View component 类可以包含在任何文件夹下.
    2. ViewComponents 文件夹下常见一个类文件名为PriorityListViewComponent.cs.
    3. PriorityListViewComponent.cs 内容如下:
      using System.Linq;
      using Microsoft.AspNet.Mvc;
      using TodoList.Models;
      
      namespace TodoList.ViewComponents
      {
        public class PriorityListViewComponent : ViewComponent
        {
          private readonly ApplicationDbContext db;
      
          public PriorityListViewComponent(ApplicationDbContext context)
          {
            db = context;
          }
      
          public IViewComponentResult Invoke(int maxPriority)
          {
            var items = db.TodoItems.Where(x => x.IsDone == false &&
                                              x.Priority <= maxPriority);
      
            return View(items);
          }
        }
      }

    备注:

    • 因为类名PriorityListViewComponentViewComponent 结尾, 在视图中我们可以使用字符串 "PriorityList".
    • [ViewComponent] attribute 被使用来改变他的引用名. 例如, 我们有一个类名为XYZ,  我们应用ViewComponent attribute:
      [ViewComponent(Name = "PriorityList")]
      public class XYZ : ViewComponent
      上面的[ViewComponent] attribute 告诉view component选择器当查找视图关联的component的使用 使用PriorityList, 在视图中使用字符串"PriorityList" 来关联相应的类.
    • component使用构造函数注入.
    • Invoke 暴露一个方法在相应的视图中被调用, invoke可以包含任意参数. Invoke对应的异步方法是InvokeAsync

    添加 view component view

    1. 在 ViewsTodo 文件夹下面创建文件夹名为Components. 注意了必须名为Components.
    2. ViewsTodoComponents 文件夹下面创建文件夹名为PriorityList. 这个文件夹的名字必须和view component 类的名字匹配, 或者类名的前缀匹配(如果类名使用 ViewComponent 后缀). 如果你使用了ViewComponent attribute, 名字必须和attribute 名匹配. 
    3. 在 ViewsTodoComponentsPriorityList 文件夹下创建Default.cshtml Razor视图文件 , 添加如下内容:
      @model IEnumerable<TodoList.Models.TodoItem>
      
      <h3>Priority Items</h3>
      <ul>
          @foreach (var todo in Model)
          {
              <li>@todo.Title</li>
          }
      </ul>
    4. views odoindex.cshtml 文件中调用VC:
      @{
        ViewBag.Title = "ToDo Page";
      }
      
      <div class="jumbotron">
        <h1>ASP.NET vNext</h1>
      </div>
      
      <div class="row">
        <div class="col-md-4">
          @if (Model.Count == 0)
          {
            <h4>No Todo Items</h4>
          }
          else
          {
            <table>
              <tr><th>TODO</th><th></th></tr>
              @foreach (var todo in Model)
              {
                <tr>
                  <td>@todo.Title </td>
                  <td>
                    @Html.ActionLink("Details", "Details", "Todo", new { id = todo.Id }) |
                    @Html.ActionLink("Edit", "Edit", "Todo", new { id = todo.Id }) |
                    @Html.ActionLink("Delete", "Delete", "Todo", new { id = todo.Id })
                  </td>
                </tr>
              }
            </table>
                    }
          <div>@Html.ActionLink("Create New Todo", "Create", "Todo") </div>
        </div>
      
        <div class="col-md-4">
          @Component.Invoke("PriorityList", 1)   
        </div>
      
      </div>
      @await Component.InvokeAsync() 是对应的异步方法. 第一个参数是要调用的component的名字. 后面的参数是传到component类的参数. 

    注意: 一般来说View Component 视图加在ViewsShared 文件夹下, 因为VCs一般没有指定controller.

    添加InvokeAsyn component

    更新VC类如下:

    using System.Linq;
    using Microsoft.AspNet.Mvc;
    using TodoList.Models;
    using System.Threading.Tasks;
    
    namespace TodoList.ViewComponents
    {
        public class PriorityListViewComponent : ViewComponent
        {
            private readonly ApplicationDbContext db;
    
            public PriorityListViewComponent(ApplicationDbContext context)
            {
                db = context;
            }
    
            // Synchronous Invoke removed.
            
            public async Task<IViewComponentResult> InvokeAsync(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);
            }
    
            private Task<IQueryable<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
            {
                return Task.FromResult(GetItems(maxPriority, isDone));
    
            }
            private IQueryable<TodoItem> GetItems(int maxPriority, bool isDone)
            {
                var items = db.TodoItems.Where(x => x.IsDone == isDone &&
                                                    x.Priority <= maxPriority);
    
                string msg = "Priority <= " + maxPriority.ToString() +
                             " && isDone == " + isDone.ToString();
                ViewBag.PriorityMessage = msg;
    
                return items;
            }
    
        }
    }
    注意: 同步的Invoke方法被移除了. 当调用数据库的时候使用异步InvokeAsync是最佳实践.

    更新VC Razor视图如下 :

    @model IEnumerable<TodoList.Models.TodoItem>
    
    <h4>@ViewBag.PriorityMessage</h4>
    <ul>
        @foreach (var todo in Model)
        {
            <li>@todo.Title</li>
        }
    </ul>

    最后, 更新views odoindex.cshtml 视图文件:

        @* Markup removed for brevity. *@
        
        <div class="col-md-4">
            @await Component.InvokeAsync("PriorityList", 2, true)
        </div>
    </div>

    指定view的名字

    一个复杂的VC可能会根据不同的条件指定使用非默认的视图. 下面的代码展示如何指定view的名字:

    public async Task<IViewComponentResult> InvokeAsync(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);
    }

    复制 ViewsTodoComponentsPriorityListDefault.cshtml 文件到ViewsTodoComponentsPriorityListPVC.cshtml . 改变PVC视图的内容以示区分:

    @model IEnumerable<TodoList.Models.TodoItem>
    
    <h2> PVC Named Priority Component View</h2>
    <h4>@ViewBag.PriorityMessage</h4>
    <ul>
        @foreach (var todo in Model)
        {
            <li>@todo.Title</li>
        }
    </ul>

    最后, 更新 ViewsTodoIndex.cshtml :

    @await Component.InvokeAsync("PriorityList",  4, true)

    注入服务到视图中去

    ASP.NET MVC 6 支持注入服务到视图中使用. 服务必须是非抽象和公开的. 在这个例子中, 我们穿件一个简单的类暴露todo的数量, 完成的数量等.

      1. 创建一个文件夹名为Services,添加一个名为StatisticsService.cs 的文件.

    The StatisticsService class:

    using System.Linq;
    using System.Threading.Tasks;
    using TodoList.Models;
    
    namespace TodoList.Services
    {
      public class StatisticsService
      {
        private readonly ApplicationDbContext db;
    
        public StatisticsService(ApplicationDbContext context)
        {
          db = context;
        }
    
        public async Task<int> GetCount()
        {
          return await Task.FromResult(db.TodoItems.Count());
        }
    
        public async Task<int> GetCompletedCount()
        {
          return await Task.FromResult(
              db.TodoItems.Count(x => x.IsDone == true));
        }
    
        public async Task<double> GetAveragePriority()
        {
          return await Task.FromResult(
              db.TodoItems.Average(x =>
                         (double?)x.Priority) ?? 0.0);
        }
      }
    }
    1. 更新Index视图. 在最上面添加如下注入语句:

      @inject TodoList.Services.StatisticsService Statistics

      在下面调用StatisticsService:

      <div>@Html.ActionLink("Create New Todo", "Create", "Todo") </div>
          </div>
           
          <div class="col-md-4">
              @await Component.InvokeAsync("PriorityList", 4, true)
      
            <h3>Stats</h3>
            <ul>
              <li>Items: @await Statistics.GetCount()</li>
              <li>Completed:@await Statistics.GetCompletedCount()</li>
              <li>Average Priority:@await Statistics.GetAveragePriority()</li>
            </ul>
          </div>
      </div>

      完整代码如下:

      @inject TodoList.Services.StatisticsService Statistics
      @{
          ViewBag.Title = "Home Page";
      }
      
      <div class="jumbotron">
          <h1>ASP.NET vNext</h1>
      </div>
      
      <div class="row">
          <div class="col-md-4">
              @if (Model.Count == 0)
              {
                  <h4>No Todo Items</h4>
              }
              else
              {
                  <table>
                      <tr><th>TODO</th><th></th></tr>
                      @foreach (var todo in Model)
                      {
                          <tr>
                              <td>@todo.Title </td>
                              <td>
                                  @Html.ActionLink("Details", "Details", "Todo", new { id = todo.Id }) |
                                  @Html.ActionLink("Edit", "Edit", "Todo", new { id = todo.Id }) |
                                  @Html.ActionLink("Delete", "Delete", "Todo", new { id = todo.Id })
                              </td>
                          </tr>
                      }
                  </table>
                                  }
              <div>@Html.ActionLink("Create New Todo", "Create", "Todo") </div>
          </div>
           
          <div class="col-md-4">
              @await Component.InvokeAsync("PriorityList", 4, true)
      
            <h3>Stats</h3>
            <ul>
              <li>Items: @await Statistics.GetCount()</li>
              <li>Completed:@await Statistics.GetCompletedCount()</li>
              <li>Average Priority:@await Statistics.GetAveragePriority()</li>
            </ul>
          </div>
      </div>
    2. Startup.cs 文件中注册StatisticsService类:

      // This method gets called by the runtime.
      public void ConfigureServices(IServiceCollection services)
      {
        // Add EF services to the services container.
        services.AddEntityFramework(Configuration)
            .AddSqlServer()
            .AddDbContext<ApplicationDbContext>();
      
        // Add Identity services to the services container.
        services.AddDefaultIdentity<ApplicationDbContext, ApplicationUser, IdentityRole>(Configuration);
      
        // Add MVC services to the services container.
        services.AddMvc();
      
        services.AddTransient<TodoList.Services.StatisticsService>();
      }
     
  • 相关阅读:
    简单工厂模式
    单例模式
    Quartz.NET总结(三)Quartz 配置
    Quartz.NET总结(二)CronTrigger和Cron表达式
    ORACLE跨数据库查询的方法
    github使用个人总结
    ffmpeg 下载安装和简单应用
    Python 安装与环境变量配置
    Sublime text 3 汉化教程
    给大家分享两套WordPress收费主题
  • 原文地址:https://www.cnblogs.com/irocker/p/view-components-and-inject-in-aspnet-mvc6.html
Copyright © 2011-2022 走看看