原文: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. Python之禅+八荣八耻

    Python之禅 (The Zen of Python):是Python语言的指导原则,可以在Python命令行输入import this显示. import this >>> Th ...

  2. Android成长日记-ContextMenu实现上下文菜单

    一. ContextMenu的组成 标题以及标题图标 菜单内容 菜单内容的点击事件 二. ContextMenu与OptionMenu的区别 OptionMenu对应的是activity,一个acti ...

  3. Myeclipse 加载ojdbc14.jar步骤

    目的:加载驱动程序,需要找到驱动的具体位置,就是找到其驱动的类名,Class.forName("oracle.jdbc.driver.OracleDriver");//加载并注册驱 ...

  4. CentOS加载U盘

    概述: 把CentOS设置成了启动进入命令行,结果不知道在哪儿找U盘了,于是搜集了一些命令. 1. 查看分区信息,以确定那个是U盘 使用root执行fdisk -l,确定U盘是sdb1 2. 挂载U盘 ...

  5. 常用RSS订阅地址

    随着Google Reader关门大吉,转战鲜果网了,RSS订阅地址经过几次折腾,丢的没剩几个了,写个文章记录一下吧,随时补充. --PS-- ,微信.微博之类的是社交平台,不能很好的梳理知识,一直用 ...

  6. Mysql 列转行统计查询 、行转列统计查询

      -- ---------------------------- -- Table structure for `TabName` -- ---------------------------- D ...

  7. 01C语言基础知识

    C语言知识要点总结 1在C语言中,关系运算的结果为“真”,就返回1,"假"就返回0 printf("input value is %d" , 5 > 4) ...

  8. python运维开发坎坷之路-01

    前言 2014年9月,新疆乌鲁木齐,在51CTO学院看着alex老师的python教学视频,不得不说这是我第一次接触python这门高级语言,从最开始的一无所知到现在能够用python写脚本,再到未来 ...

  9. rhino(犀牛) --- color control

    create color materials, if "材料赋予方式" is "图层", the color of "材质" is show ...

  10. 初学angular-简单的angular指令

    实现一个简单的input清空内容,且清空对应ngModel 前台部分 <html ng-app="hpapp"> <head> <meta chars ...