ASP.NET MVC 6 一些不曉得的寫法

weixin_34067049發表於2015-02-25

今天在看 Scott Guthrie 的一篇博文《Introducing ASP.NET 5》,在 MVC 6 中,發現有些之前不曉得的寫法,這邊簡單記錄下,算是對自己知識的補充,有些我並沒有進行嘗試,因為我使用的 Visual Studio 2015 CTP 5,但是有些並沒有支援(下面第一點),現在 Visual Studio 2015 已經更新到 CTP 6 了,本來還想嘗試下,看了下 4.6G 的大小,想想還是算了。

Scott Guthrie 博文中,大部分是對 ASP.NET 5 的綜述,有些內容之前微軟都已經發布過了,我只看了自己看興趣的地方,當然評論內容也是不能漏掉的,除了這篇博文,我還搜刮了其他博文的一些內容,下面簡單介紹下。

1. 統一開發模型

普通寫法:

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
    @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
    </div>
</div>

另類寫法:

<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="UserName" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="UserName" class="form-control" />
        <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
</div>

上面一般是我們在 View 寫表單程式碼時候的寫法,很明顯,第二種比第一種更加簡潔!

2. Dependency injection (DI) 寫法

在 MVC 6 中是支援 DI 的,像 services.AddMvc(); 就是 MVC 6 使用自帶的 IoC 進行注入,當然,除了注入這些 MVC 系統元件,我是沒有在 ConfigureServices 中使用過自定義的物件注入,所以,我也是第一次曉得注入使用寫法,示例:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddTransient<TimeService>();
}

TimeService 是一個自定義的型別,使用 AddTransient 方法,在 ConfigureServices 中進行註冊。

public class HomeController : Controller
{
    [Activate]
    public TimeService TimeService { get; set; }
 
    // Code removed for brevity
}

Activate 為注入物件屬性,當然,你也可以使用建構函式進行注入,只不過是麻煩些。

@using WebApplication23
@inject TimeService TimeSvc
 
<h3>@ViewBag.Message</h3>
 
<h3>
    @TimeSvc.Ticks From Razor
</h3>

上面為獲取注入的物件,關鍵字為 inject。

3. View components 的一些內容

View components(VCs) ,我是第一次看到這個詞,當然更沒用過,component 是要素、組成、零件的意思,View components 可以理解為檢視的補充,微軟在介紹的時候,用到了一個詞 mini-controller,可以看作是“微型控制器”,其實,像 @Html.LabelFor 這種寫法也可以看作是 VC,說通俗一點,就是我們針對專案,寫的一些幫助類。

建立 ViewComponent:

using System.Linq;
using Microsoft.AspNet.Mvc;
using TodoList.Models;

namespace TodoList.ViewComponents
{
  //[ViewComponent(Name = "PriorityList")]
  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);
    }
  }
}

建立的 PriorityListViewComponent 需要繼承 ViewComponent,ViewComponent 是對 ViewComponent 名字的重寫。

@{
  ViewBag.Title = "ToDo Page";
}

<div class="jumbotron">
  <h1>ASP.NET vNext</h1>
</div>

<div class="row">
  <div class="col-md-4">
    @Component.Invoke("PriorityList", 1)   
  </div>
</div>

上面是 ViewComponent 的呼叫程式碼,寫法是 Component.Invoke,第一個引數是 ViewComponent 的類名,也可以是屬性的重寫名,第二個引數是優先順序值,用於過濾我們要處理的項集合。

這是 ViewComponent Invoke 同步寫法,也是最簡單的一種,但是這種寫法,現在已經在 MVC 6 中被移除了,說明:The synchronous Invoke method has been removed. A best practice is to use asynchronous methods when calling a database.

InvokeAsync 寫法:

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);
}

呼叫程式碼:

@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>
@await Component.InvokeAsync("PriorityList",  4, true)

注意 ViewBag.PriorityMessage 的值,上面程式碼指定了檢視名稱。

4. 注入一個服務到檢視

服務注入到檢視,就是使用的上面第二點 DI 寫法,示例服務:

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));
    }
  }
}

ConfigureServices 中註冊:

// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
  // Add MVC services to the services container.
  services.AddMvc();

  services.AddTransient<TodoList.Services.StatisticsService>();
}

呼叫程式碼:

@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">
        @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>

參考資料:

相關文章