上一篇中,我們建立了一個基本的項目架構,如果你細心的去研究這個架構,你一定已經發現,我們實際上已經使用了一個領域模型代替了MVC中的model,為什麼要這麼做呢?只要是因為在MVC這個古老的三層架構中,M的本意是用來向Controller提供資料,封裝商務邏輯的,C在通過調用View來展示資料給使用者。反過來,使用者通過觸發View的某些事件來將自己的意圖傳遞給C,C再分發使用者的命令道M,去擷取使用者想要的結果。這是一種理想的狀態,在真正的項目中,經常會出現M繞過C,直接調用V,而View也會直接調用M的現象。這就導致了一種錯誤的、混亂的資料流的出現,是項目潛在風險遞增的根源。MVP就是為了克服這種現象而產生的,好了,我們不去管什麼MVP,MVVM了,現在就 言歸正傳,回到我們的項目中,繼續展示MVC的精彩與魅力。 我們知道,我們需要一些途徑或方式,去資料庫中取得Product entities。為了保持架構上的完美,我們要遵循持久邏輯與領域模型實體分離的原則,要做到這一點,我們使用repository 設計模式. 我們不需要擔心怎樣去實現持久層,我們從定義一個介面開始,去啟動它。 在Abstract檔案夾上右擊,選擇添加一個介面,命名為IProductsRepository,代碼如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using SportsStore.Domain.Entities;namespace SportsStore.Domain.Abstract{ public interface IProductsRepository { IQueryable<Product> Products { get; } }}
這個借口使用了IQueryable<T>介面去擷取一個Product對象,我們沒有告訴它去哪或怎麼樣去取得資料,一個使用IProductsRepository 介面的類能夠取得Product 對象,而不需要知道它們從哪來或被誰傳遞,這就是 repository設計模式的本質。接下來我們就通過添加一些特性到我們代碼中,去再次拜訪一下這個介面。 構建一個Mock Repository現在我們已經定義了一個 abstract interface, 我們能夠實現這個持久化機制並且掛接到資料庫,不過這是不是現在要做的,為了能夠啟動這個項目的其他部分,現在我們要建立一個IProductsRepository介面的Mock實現,我們需要在我們的SportsStore.WebUI工程的NinjectControllerFactory 類的AddBindings方法中去做這件事。 using System;using System.Collections.Generic;using System.Linq;using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using Moq;
using Ninject; namespace SportsStore.WebUI.Infrastructure{ public class NinjectControllerFactory: DefaultControllerFactory { private IKernel ninjectKernel; public NinjectControllerFactory() { ninjectKernel = new StandardKernel(); AddBindings(); } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType); } private void AddBindings() {
Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
mock.Setup(m => m.Products).Returns(new List<Product> {
new Product { Name = "Football", Price = 25 },
new Product { Name = "Surf board", Price = 179 },
new Product { Name = "Running shoes", Price = 95 }
}.AsQueryable());
ninjectKernel.Bind<IProductsRepository>().ToConstant(mock.Object); } } } 為了使這些添加的代碼能夠正常的運行,需要添加幾個命名空間,但是我們建立Mock repository實現的過程使用了Moq技術,AsQueryable 方法是一個 LINQ 擴充方法,它轉換IEnumerable<T>進入IQueryable<T>, 這裡我們需要去匹配我們的介面簽名。無論 IProductsRepository在哪獲得了一個請求, 我們都需要Ninject去返回同樣的mock對象,這就是 為什麼我們使用ToConstant方法的原因。...ninjectKernel.Bind<IProductRepository>().
ToConstant(mock.Object);...
展示產品列表 已經做了這麼久,我們還沒有看到任何可視化的效果,這對於有些心急的朋友來說是不公平的,看不見有任何成績出來,將會打擊我們做項目的信心,這對Team Dev是很不利的事情,現在就讓我們添加一個Controller到SportsStore.WebUI工程中,選擇添加控制器,命名為ProductController,確保模板選型為空白,如: 接下來,你要刪除VS自動為你添加的代碼,並用如下代碼代替:using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using SportsStore.Domain.Abstract;using SportsStore.Domain.Entities; namespace SportsStore.WebUI.Controllers{ public class ProductController : Controller { private IProductsRepository repository; public ProductController(IProductsRepository productRepository) { this.repository = productRepository; } public ViewResult List() { return View(repository.Products); } }} 如果你的工程中,using SportsStore.Domain.Abstract; 這條語句存在錯誤,你需要添加對SportsStore.Domain工程的引用,如: 現在要做的是添加一個View,在List方法上右擊並選擇添加View, 這裡請注意了,在模型類的下拉式清單中,你並不能找到IEnumerable<SportsStore.Domain.Entities.Product>項,你需要手工輸入它。然後,點擊添加按鈕,建立View。
渲染View資料 @model IEnumerable<SportsStore.Domain.Entities.Product> @{ ViewBag.Title =
"Products";}
@foreach (var p in Model) {
<div class="item">
<h3>@p.Name</h3>
@p.Description
<h4>@p.Price.ToString("c")</h4>
</div>
} 我們改變一下這個頁的標題,注意這裡我們不需要使用Razor text 或者@:elements去展示資料,因為每行內容都是一個HTML 元素.
設定Default Route 現在我們需要去做的,就是告訴MVC架構,當一個請求到達時,我們的網站要映射到
ProductController類的List 活動方法,這需要去修改App_Start/RouteConfig.cs檔案的
RegisterRoutes方法,代碼如下:
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Routing; namespace SportsStore.WebUI{ public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "
Product", action = "
List", id = UrlParameter.Optional } ); } }} 完成修改後,運行你的應用,你將看到如下畫面: 你可以去下載我的源碼,地址是:http://vdisk.weibo.com/s/DS1PL/1370071350 這部分我們展示了我們應用,運用了部分Moq技術和Ninject技術,但是我們現在的資料還只是Mock對象中的類比資料,還不是真正的資料庫中的資料,下一部分,我們將引入EF架構,去領略一下ORM資料操作的風采。如果你覺得我寫的辛苦,你覺得你得到了你想要的東西,那麼請推薦它給其他有需要的人吧!請繼續關注我的續篇,精彩才剛剛開始!