原文: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. 在 Views\Todo 文件夹下面创建文件夹名为Components. 注意了必须名为Components.
  2. Views\Todo\Components 文件夹下面创建文件夹名为PriorityList. 这个文件夹的名字必须和view component 类的名字匹配, 或者类名的前缀匹配(如果类名使用 ViewComponent 后缀). 如果你使用了ViewComponent attribute, 名字必须和attribute 名匹配. 
  3. 在 Views\Todo\Components\PriorityList 文件夹下创建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\todo\index.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 视图加在Views\Shared 文件夹下, 因为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\todo\index.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);
}

复制 Views\Todo\Components\PriorityList\Default.cshtml 文件到Views\Todo\Components\PriorityList\PVC.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>

最后, 更新 Views\Todo\Index.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>();
    }
 

[译]View components and Inject in ASP.NET MVC 6的更多相关文章

  1. ASP.NET MVC 6 一些不晓得的写法

    今天在看 Scott Guthrie 的一篇博文<Introducing ASP.NET 5>,在 MVC 6 中,发现有些之前不晓得的写法,这边简单记录下,算是对自己知识的补充,有些我并 ...

  2. [转]ASP.NET MVC 入门5、View与ViewData

    view在MVC模式中与用户进行最直接的接触,它负责数据的呈现.这里要注意一点就是,view只是负责数据的呈现,所以我们应该要尽量让view中不涉及业务逻辑的处理. 我们来添加一个Blog首页的vie ...

  3. ASP.NET MVC Overview

    ASP.NET MVC Overview The Model-View-Controller (MVC) architectural pattern separates an application  ...

  4. 【转】ASP.NET MVC 的最佳实践

    [This post is based on a document authored by Ben Grover (a senior developer at Microsoft). It is ou ...

  5. ASP.Net Mvc 5 学习记录2015-9-9

    我之前一直都是学习和开发都采用ASP.Net WebForm,对MVC的一直都是一知半解,最初以为ASP.Net WebForm的N层架构就是MVC.其实N层架构设计思想是"高内聚,低耦合& ...

  6. 自学MVC看这里——全网最全ASP.NET MVC 教程汇总

    MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC.小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC技术的学习者提供一个整合学习入口.本文从 ...

  7. 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC

    系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)— ...

  8. 微冷的雨ASP.NET MVC之葵花宝典(MVC)

    微冷的雨ASP.NET MVC之葵花宝典 By:微冷的雨 第一章 ASP.NET MVC的请求和处理机制. 在MVC中: 01.所有的请求都要归结到控制器(Controller)上. 02.约定优于配 ...

  9. 新作《ASP.NET MVC 5框架揭秘》正式出版

    ASP.NET MVC是一个建立在ASP.NET平台上基于MVC模式的Web开发框架,它提供了一种与Web Form完全不同的开发方式.ASP.NET Web Form借鉴了Windows Form基 ...

随机推荐

  1. Bzoj2753 [SCOI2012]滑雪与时间胶囊

    2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2282  Solved: 796 Descriptio ...

  2. iptables实现反向代理

    拓扑图 实现目标 公网用户通过Firewall服务器(iptables实现)访问内网http服务 配置 #iptables iptables -t nat -A PREROUTING -p tcp - ...

  3. 有关Java的日期处理的一些杂记

    在企业应用开发中,经常会遇到日期的相关处理,说实话JDK自带的日期方法很难用.就我个人而言我一般都会采用joda-time来替代JDK自身的日期. 这篇文章是杂记,所以写的比较零散,希望大家不要见怪. ...

  4. AngularJs $interpolate 和 $parse

    $interpolate 将一个字符串编译成一个插值函数.HTML编译服务使用这个服务完成数据绑定. 使用:$interpolate(text,[mustHaveExpression],[truste ...

  5. Thenao tutorial – indexing

    Theano和numpy一样,支持基本的下标取值方法和高级的下标取值方法. 因为theano中没有boolean类型,所以不支持boolean类型的masks. # head file support ...

  6. web前端环境搭建

    第一部分:浏览器 浏览器推荐chrome浏览器.FireFox浏览器. 1. chrome浏览器因为集成了Google Developer Tools(谷歌开发者工具),因此大受欢迎. 下载地址:ht ...

  7. DNS(企业级)

    构建DNS(企业级) 1.硬件选型 CPU:12C以上配置 内存:16G 网络:千兆 2.初始化系统配置 关闭 iptables service iptables stop chkconfig ipt ...

  8. HTTP常见错误编号

    HTTP 错误 400 400 请求出错 由于语法格式有误,服务器无法理解此请求.不作修改,客户程序就无法重复此请求. HTTP 错误 401 401.1 未授权:登录失败 此错误表明传输给服务器的证 ...

  9. ServiceStack.Text 更快的序列化

    Json.net 是以前最经常用的序列化组件,后来又注意到ServiceStack号称最快的,所以我做了以下测试 1)Json.net using System; using System.Colle ...

  10. 日志分析 第六章 安装elasticsearch

    在这里,以两台es集群为例. es集群健康状况有三种状态,这里我们搭建的es集群,只要两台不同时挂掉,数据不会丢失. green 所有主要分片和复制分片都可用 yellow 所有主要分片可用,但不是所 ...