譯文,個人原創(chuàng),轉(zhuǎn)載請注明出處(C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(下)),不對的地方歡迎指出與交流。   

章節(jié)出自《Professional C# 6 and .NET Core 1.0》。水平有限,各位閱讀時仔細分辨,唯望莫誤人子弟。

附英文版原文:Professional C# 6 and .NET Core 1.0 - Chapter 41 ASP.NET MVC

C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(上)

C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(中)

-------------------------

最近兩篇譯文來得比較遲,前一陣子忙起來之后忘記了。

由于有點事情,《Professional C# 6 and .NET Core 1.0》第42、43章譯文,是4月中旬之后的事情了。

Enjoy your reading, enjoy your code!

-------------------------

實現(xiàn)操作過濾器

ASP.NET MVC在許多領(lǐng)域是可擴展的。例如,可以實現(xiàn)控制器工廠來搜索和實例化控制器(接口IControllerFactory)。控制器實現(xiàn) IController 接口。在控制器中查找操作方法可以通過使用IActionInvoker接口來解決??梢允褂脧腁ctionMethodSelectorAttribute派生的屬性類來定義允許的HTTP方法。將HTTP請求映射到參數(shù)的模型綁定器可以通過實現(xiàn)IModelBinder接口自定義。 “模型綁定器”部分使用FormCollectionModelBinder類型。可以使用實現(xiàn)接口 IViewEngine 的不同視圖引擎。本章使用Razor視圖引擎。還可以通過HTML輔助程序、標記助手和操作過濾器進行自定義。大多數(shù)擴展點都超出了本書的范圍,但是操作過濾器是最經(jīng)常實現(xiàn)或使用的,因此這里將介紹這些過濾器。

在執(zhí)行操作之前和之后調(diào)用操作過濾器。它們被分配給使用屬性的控制器或控制器的動作方法。操作過濾器通過創(chuàng)建從基類ActionFilterAttribute派生的類來實現(xiàn)。這個類可以覆蓋基類成員OnActionExecuting,OnActionExecuted,OnResultExecuting和OnResultExecuted。 OnActionExecuting在調(diào)用action方法之前被調(diào)用,并且當action方法被完成時調(diào)用OnActionExecuted。之后,在返回結(jié)果之前,調(diào)用OnResultExecuting方法,最后調(diào)用OnResultExecuted。

在這些方法中,可以訪問Request對象以檢索調(diào)用者的信息。通過Request對象可以根據(jù)瀏覽器決定一些操作,可以訪問路由信息,可以動態(tài)更改視圖結(jié)果等等。以下代碼片段從路由信息訪問變量語言。要將此變量添加到路由,可以如本章前面的“定義路由”部分所述更改路由。通過在路由信息中添加語言變量,如下代碼片段所示可以使用 RouteData.Values 訪問URL提供的值。可以使用檢索到的值更改用戶語言:

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public class LanguageAttribute : ActionFilterAttribute
{
  private string _language = null;
  public override void OnActionExecuting(ActionExecutingContext 
filterContext)
  {
    _language = filterContext.RouteData.Values["language"] == null ?
      null : filterContext.RouteData.Values["language"].ToString();
    //…
  }
  public override void OnResultExecuting(ResultExecutingContext 
filterContext) 
  {
  }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

注意 第28章“本地化”解釋了全球化和本地化,設(shè)置文化和其他區(qū)域細節(jié)。

如以下代碼段所示,創(chuàng)建的操作過濾器屬性類可以將該屬性應(yīng)用于控制器。使用該類的屬性,每個action方法都調(diào)用屬性類的成員。另外,也可以將屬性應(yīng)用于操作方法,因此僅當調(diào)用操作方法時才調(diào)用成員:

[Language]
public class HomeController : Controller
{

ActionFilterAttribute實現(xiàn)幾個接口:IActionFilter,IAsyncActionFilter,IResultFilter,IAsyncResultFilter,IFilter和 IOrderedFilter。
ASP.NET MVC包括一些預(yù)定義的操作過濾器,如 請求 HTTPS 的過濾器,授權(quán)調(diào)用,處理錯誤或緩存數(shù)據(jù)。

將在本章后面的“驗證和授權(quán)”部分中介紹使用特性Authorize。

創(chuàng)建數(shù)據(jù)驅(qū)動的應(yīng)用程序

現(xiàn)在你已經(jīng)閱讀了ASP.NET MVC的所有基礎(chǔ),是時候來看一個使用ADO.NET實體框架的數(shù)據(jù)驅(qū)動的應(yīng)用程序??梢钥吹紸SP.NET MVC結(jié)合數(shù)據(jù)訪問提供的功能。

注意 ADO.NET實體框架在第38章“實體框架核心”中有詳細介紹。

示例應(yīng)用程序 MenuPlanner 用于維護在數(shù)據(jù)庫中的餐館菜單條目。只有經(jīng)過身份驗證的帳戶才可以執(zhí)行數(shù)據(jù)庫條目的維護。未經(jīng)身份驗證的用戶則可以瀏覽菜單。

該項目是通過使用 ASP.NET Core 1.0 Web 應(yīng)用程序模板創(chuàng)建的。身份驗證使用默認選擇的個人用戶帳戶。這個項目模板為ASP.NET MVC和控制器添加了幾個文件夾,包括HomeController和AccountController。它還添加了一些腳本庫。

定義模型

首先在 Models 目錄中定義一個模型。使用ADO.NET實體框架創(chuàng)建模型。 MenuCard類型定義了一些屬性和與菜單列表的關(guān)系(代碼文件MenuPlanner/Models/MenuCard.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public class MenuCard
{
  public int Id { get; set; }
  [MaxLength(50)]
  public string Name { get; set; }
  public bool Active { get; set; }
  public int Order { get; set; }
  public virtual List<Menu> Menus { get; set; }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

從 MenuCard 引用的菜單類型由Menu類定義(代碼文件MenuPlanner/Models/Menu.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public class Menu
{
  public int Id { get; set; }
  public string Text { get; set; }
  public decimal Price { get; set; }
  public bool Active { get; set; }
  public int Order { get; set; }
  public string Type { get; set; }
  public DateTime Day { get; set; }
  public int MenuCardId { get; set; }
  public virtual MenuCard MenuCard { get; set; }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

與數(shù)據(jù)庫的連接,以及 Menu 和 MenuCard 類型的集合都由 MenuCardsContext 管理。使用ModelBuilder,上下文指定Menu類型的Text屬性不能為null,并且它的最大長度為50(代碼文件MenuPlanner/Models/MenuCardsContext.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public class MenuCardsContext : DbContext
{
  public DbSet<Menu> Menus { get; set; }
  public DbSet<MenuCard> MenuCards { get; set; }
  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Menu>().Property(p => p.Text)
      .HasMaxLength(50).IsRequired();
    base.OnModelCreating(modelBuilder);
  }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

Web應(yīng)用程序的啟動代碼定義了用作數(shù)據(jù)上下文的MenuCardsContext,并從配置文件讀取連接字符串(代碼文件MenuPlanner/Startup.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
  // Add Entity Framework services to the services container.
  services.AddEntityFramework()
          .AddSqlServer()
          .AddDbContext<ApplicationDbContext>(options =>
             options.UseSqlServer(
               Configuration["Data:DefaultConnection:ConnectionString"]))
          .AddDbContext<MenuCardsContext>(options =>
             options.UseSqlServer(
               Configuration["Data:MenuCardConnection:ConnectionString"]));
  // etc.
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

配置文件添加 MenuCardConnection 連接字符串。 該連接字符串引用 Visual Studio 2015 附帶的SQL實例 。當然可以改變這個,也可以添加一個到SQL Azure 的連接字符串(代碼文件MenuPlanner/appsettings.json):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString":"Server=(localdb)\\mssqllocaldb;
        Database=aspnet5-MenuPlanner-4d3d9092-b53f-4162-8627-f360ef6b2aa8;
        Trusted_Connection=True;MultipleActiveResultSets=true"
    },
    "MenuCardConnection": {
      "ConnectionString":"Server=
(localdb)\\mssqllocaldb;Database=MenuCards; 
        Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  },
  // etc.
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

創(chuàng)建數(shù)據(jù)庫

可以使用Entity Framework命令來創(chuàng)建用于創(chuàng)建數(shù)據(jù)庫的代碼。命令行提示符中可以使用.NET核心命令行(CLI)和ef命令創(chuàng)建代碼以自動創(chuàng)建數(shù)據(jù)庫。要使用命令提示符,必須將當前文件夾設(shè)置為project.json文件所在的目錄:

>dotnet ef migrations add InitMenuCards --context MenuCardsContext

注意 dotnet工具在第1章“.NET應(yīng)用程序體系結(jié)構(gòu)”和第17章“Visual Studio 2015”中討論。

因為多個數(shù)據(jù)上下文( MenuCardsContext 和 ApplicationDbContext )是通過項目定義的,所以需要使用--context選項指定數(shù)據(jù)上下文。 ef命令在項目結(jié)構(gòu)創(chuàng)建一個Migrations文件夾, InitMenuCards類中使用Up方法創(chuàng)建數(shù)據(jù)庫表,使用Down方法再次刪除更改(代碼文件MenuPlanner/Migrations/[date] InitMenuCards.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

public partial class InitMenuCards : Migration
{
  public override void Up(MigrationBuilder migrationBuilder)
  {
    migrationBuilder.CreateTable(
      name:"MenuCard",
      columns: table => new
      {
        Id = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy",
            SqlServerValueGenerationStrategy.IdentityColumn),
        Active = table.Column<bool>(nullable: false),
        Name = table.Column<string>(nullable: true),
        Order = table.Column<int>(nullable: false)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_MenuCard", x => x.Id);
      });
    migrationBuilder.CreateTable(
      name:"Menu",
      columns: table => new
      {
        Id = table.Column<int>(nullable: false)
          .Annotation("SqlServer:ValueGenerationStrategy", 
            SqlServerValueGenerationStrategy.IdentityColumn),
        Active = table.Column<bool>(nullable: false),
        Day = table.Column<DateTime>(nullable: false),
        MenuCardId = table.Column<int>(nullable: false),
        Order = table.Column<int>(nullable: false),
        Price = table.Column<decimal>(nullable: false),
        Text = table.Column<string>(nullable: false),
        Type = table.Column<string>(nullable: true)
      },
      constraints: table =>
      {
        table.PrimaryKey("PK_Menu", x => x.Id);
        table.ForeignKey(
          name:"FK_Menu_MenuCard_MenuCardId",
          column: x => x.MenuCardId,
          principalTable:"MenuCard",
          principalColumn:"Id",
          onDelete: RefeerentialAction.Cascade);
      });
  }
  public override void Down(MigrationBuilder migration)
  {
    migration.DropTable("Menu");
    migration.DropTable("MenuCard");
  }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

現(xiàn)在只需要一些代碼來啟動遷移進程,用初始樣本數(shù)據(jù)填充數(shù)據(jù)庫。 MenuCardDatabaseInitializer 通過在從 Database 屬性返回的DatabaseFacade對象上調(diào)用擴展方法 MigrateAsync 來應(yīng)用遷移過程。這反過來檢查與連接字符串相關(guān)聯(lián)的數(shù)據(jù)庫是否已具有與通過遷移指定的數(shù)據(jù)庫相同的版本。如果它不具有相同的版本,則調(diào)用所需的Up方法以獲得相同的版本。除此之外,創(chuàng)建幾個MenuCard對象將它們存儲在數(shù)據(jù)庫中(代碼文件MenuPlanner/Models/MenuCardDatabaseInitializer.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace MenuPlanner.Models
{
  public class MenuCardDatabaseInitializer
  {
    private static bool _databaseChecked = false;
    public MenuCardDatabaseInitializer(MenuCardsContext context)
    {
      _context = context;
    }
    private MenuCardsContext _context;
    public async Task CreateAndSeedDatabaseAsync() 
    {
      if (!_databaseChecked)
      {
        _databaseChecked = true;
        await _context.Database.MigrateAsync();
        if (_context.MenuCards.Count() == 0)
        {
          _context.MenuCards.Add(
            new MenuCard { Name ="Breakfast", Active = true, Order = 1 });
          _context.MenuCards.Add(
            new MenuCard { Name ="Vegetarian", Active = true, Order = 2 });
          _context.MenuCards.Add(
            new MenuCard { Name ="Steaks", Active = true, Order = 3 });
        }
        await _context.SaveChangesAsync();
      }
    }
  }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

隨著數(shù)據(jù)庫和模型到位,可以創(chuàng)建一個服務(wù)。

創(chuàng)建服務(wù)

在創(chuàng)建服務(wù)之前,創(chuàng)建接口IMenuCardsService,該接口定義服務(wù)所需的所有方法(代碼文件MenuPlanner/Services/IMenuCardsService.cs):

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

using MenuPlanner.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MenuPlanner.Services
{
  public interface IMenuCardsService
  {
    Task AddMenuAsync(Menu menu);
    Task DeleteMenuAsync(int id);
    Task<Menu> GetMenuByIdAsync(int id);
    Task<IEnumerable<Menu>> GetMenusAsync();
    Task<IEnumerable<MenuCard>> GetMenuCardsAsync();
    Task UpdateMenuAsync(Menu menu);
  }
}

電腦培訓(xùn),計算機培訓(xùn),平面設(shè)計培訓(xùn),網(wǎng)頁設(shè)計培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

服務(wù)類MenuCardsService實現(xiàn)了返回菜單和菜單卡的方法,創(chuàng)建、更新和刪除菜單(代碼文件 MenuPlanner/Services/MenuCardsService.cs):

作者:沐汐 Vicky

出處:http://www.cnblogs.com/EasyInvoice

歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,否則保留追究法律責任的權(quán)利.

http://www.cnblogs.com/EasyInvoice/p/6464089.html