http://www.cnblogs.com/liqingwen/p/6640861.htmlphp
本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStorecss
主要功能與知識點以下:html
分類、產品瀏覽、購物車、結算、CRUD(增刪改查) 管理、發郵件、分頁、模型綁定、認證過濾器和單元測試等。java
【備註】項目使用 VS2015 + C#6 進行開發,有問題請發表在留言區哦,還有,頁面長得比較醜,請見諒。git
1.新建一個解決方案「BooksStore」,並添加如下項目:github
Web MVC 爲一個空的 MVC 項目:sql
2.添加項目引用(須要使用 NuGet):數據庫
這是不一樣項目須要引用的類庫和項目微信
AddBindings() 添加綁定方法,先留空。多線程
public class NinjectControllerFactory : DefaultControllerFactory { private readonly IKernel _kernel; public NinjectControllerFactory() { _kernel = new StandardKernel(); AddBindings(); } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController) _kernel.Get(controllerType); } /// <summary> /// 添加綁定 /// </summary> private void AddBindings() { } }
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } }
public class Book { /// <summary> /// 標識 /// </summary> public int Id { get; set; } /// <summary> /// 名稱 /// </summary> public string Name { get; set; } /// <summary> /// 描述 /// </summary> public string Description { get; set; } /// <summary> /// 價格 /// </summary> public decimal Price { get; set; } /// <summary> /// 分類 /// </summary> public string Category { get; set; } }
有了實體以後,咱們應該建立一個「庫」對該實體進行操做,而這種持久化邏輯操做也應該和域模型是進行隔離的。
2.先定義一個接口 IbookRepository,在根目錄建立一個名爲 Abstract 的文件夾,顧名思義就是應該放置一些抽象的類,如接口。
public interface IBookRepository { IQueryable<Book> Books { get; } }
咱們經過該接口就能夠獲得對應類的相關信息,而不須要去管該數據如何存儲,以及存儲的位置,這就是存儲庫模式的本質。
3.接下來,咱們就須要對數據庫進行操做了,咱們使用簡單的 EF(ORM 對象關係模型) 去對數據庫進行操做,因此須要本身經過 Nuget 下載 EF 的類庫。
4.由於以前定義了接口類,接下來就應該定義實現該接口的類了
安裝完以後,再次創建一個名爲 Concrete 的文件夾,存放實例。
在裏面建立一個 EfDbContext 的類,派生於 DbContext,該類會爲用戶要使用的數據庫中的每一個表自動的定義一個屬性。該屬性名爲 Books,指定了表名,DbSet<Book> 表示爲 Book 實體的表模型,Book 對象至關於 Books 表中的行(記錄)。
public class EfDbContext : DbContext { public DbSet<Book> Books { get; set; } }
再建立一個 EfBookRepository 存儲庫類,它實現 IBookRepository 接口,使用了上文建立的 EfDbContext 上下文對象,包含了具體的方法定義。
public class EfBookRepository : IBookRepository { private readonly EfDbContext _context = new EfDbContext(); public IQueryable<Book> Books => _context.Books; }
5.如今只差在數據庫新建一張表了。
CREATE TABLE Book ( Id INT IDENTITY PRIMARY KEY, Name NVARCHAR(100), Description NVARCHAR(MAX), Price DECIMAL, Category NVARCHAR(50) )
並插入測試數據:
INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'C#從入門到精通' , -- Name - nvarchar(100) N'好書-C#從入門到精通' , -- Description - nvarchar(max) 50 , -- Price - decimal N'.NET' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'ASP.NET從入門到精通' , -- Name - nvarchar(100) N'好書-ASP.NET從入門到精通' , -- Description - nvarchar(max) 60 , -- Price - decimal N'.NET' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'多線程從入門到精通' , -- Name - nvarchar(100) N'好書-多線程從入門到精通' , -- Description - nvarchar(max) 65 , -- Price - decimal N'.NET' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'java從入門到放棄' , -- Name - nvarchar(100) N'好書-java從入門到放棄' , -- Description - nvarchar(max) 65 , -- Price - decimal N'java' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'sql從入門到放棄' , -- Name - nvarchar(100) N'好書-sql從入門到放棄' , -- Description - nvarchar(max) 45 , -- Price - decimal N'sql' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'sql從入門到出家' , -- Name - nvarchar(100) N'好書-sql從入門到出家' , -- Description - nvarchar(max) 45 , -- Price - decimal N'sql' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'php從入門到出家' , -- Name - nvarchar(100) N'好書-php從入門到出家' , -- Description - nvarchar(max) 45 , -- Price - decimal N'php' -- Category - nvarchar(50) )
由於我但願表名爲 Book,而不是 Books,因此我在以前的 Book 類上加上特性 [Table("Book")] :
1.作完預熱操做後,你可能想當即以界面的的方式進行顯示,別急,先用單元測試檢查一下咱們對數據庫的操做是否正常,經過對數據進行簡單的讀取,檢查下鏈接是否成功。
2.單元測試也須要引入 ef 類庫(Nuget)。
3.安裝完以後會生成一個 app.config 配置文件,須要額外添加一行鏈接字符串(在後續的 Web UI 項目裏,也須要加上這條信息,否則會提示對應的錯誤信息)。
<connectionStrings> <add name="EfDbContext" connectionString="server=.;database=TestDb;uid=sa;pwd=123" providerName="System.Data.SqlClient"/> </connectionStrings>
4.當全部前置工做都準備好了的時候,就應該填寫測試方法了,由於我插入了 7 條數據,這裏我就判斷一下從數據庫讀取出的行數是否爲 7 :
[TestMethod] public void BooksCountTest() { var bookRepository=new EfBookRepository(); var books = bookRepository.Books; Assert.AreEqual(books.Count(),7); }
5.在該方法體的內部單擊右鍵,你能夠看到一個「運行測試」的選項,這時你能夠嘗試單擊它:
從這個符號能夠看到,是成功了!
接下來,咱們要正式從頁面顯示咱們想要的信息了。
1.先新建一個空的控制器:BookController:
2.須要咱們自定義一個 Details 方法,用於後續與界面進行交互。
public class BookController : Controller { private readonly IBookRepository _bookRepository; public BookController(IBookRepository bookRepository) { _bookRepository = bookRepository; } /// <summary> /// 詳情 /// </summary> /// <returns></returns> public ActionResult Details() { return View(_bookRepository.Books); } }
3.接下來,要建立一個視圖 View 了。
4.將 Details.cshtml 的內容替換爲下面的:
@model IEnumerable<Wen.BooksStore.Domain.Entities.Book> @{ ViewBag.Title = "Books"; } @foreach (var item in Model) { <div> <h3>@item.Name</h3> @item.Description <h4>@item.Price.ToString("C")</h4> <br /> <hr /> </div> }
5.改下默認的路由機制,讓他默認跳轉到該頁面。
6.還有一點須要注意的是,由於咱們使用了 Ninject 容器,而且須要對控制器中的構造函數中的參數 IBookRepository 進行解析,告訴他將使用哪一個對象對該接口進行服務,也就是須要修改以前的 AddBindings 方法:
7.運行的效果大體以下(由於加了點 CSS 樣式,因此顯示的效果可能有些許不一樣),結果是一致的。
1.在 Models 文件夾新增一個 PagingInfo.cs 分頁信息類。
/// <summary> /// 分頁信息 /// </summary> public class PagingInfo { /// <summary> /// 總數 /// </summary> public int TotalItems { get; set; } /// <summary> /// 頁容量 /// </summary> public int PageSize { get; set; } /// <summary> /// 當前頁 /// </summary> public int PageIndex { get; set; } /// <summary> /// 總頁數 /// </summary> public int TotalPages => (int)Math.Ceiling((decimal)TotalItems / PageSize); }
2.新增一個 HtmlHelpers 文件夾存放一個基於 Html 幫助類的擴展方法:
public static class PagingHelper { /// <summary> /// 分頁 /// </summary> /// <param name="helper"></param> /// <param name="pagingInfo"></param> /// <param name="func"></param> /// <returns></returns> public static MvcHtmlString PageLinks(this HtmlHelper helper, PagingInfo pagingInfo, Func<int, string> func) { var sb = new StringBuilder(); for (var i = 1; i <= pagingInfo.TotalPages; i++) { //建立 <a> 標籤 var tagBuilder = new TagBuilder("a"); //添加特性 tagBuilder.MergeAttribute("href", func(i)); //添加值 tagBuilder.InnerHtml = i.ToString(); if (i == pagingInfo.PageIndex) { tagBuilder.AddCssClass("selected"); } sb.Append(tagBuilder); } return MvcHtmlString.Create(sb.ToString()); } }
3.添加完畢後須要在配置文件內加入該命名空間
4.如今要從新修改 BookController.cs 控制器內的的代碼,並添加新的視圖模型類 BookDetailsViewModels.cs,讓它繼承以前的分頁類。
public class BookDetailsViewModels : PagingInfo { public IEnumerable<Book> Books { get; set; } }
修改後的控制器代碼:
public class BookController : Controller { private readonly IBookRepository _bookRepository; public int PageSize = 5; public BookController(IBookRepository bookRepository) { _bookRepository = bookRepository; } /// <summary> /// 詳情 /// </summary> /// <param name="pageIndex"></param> /// <returns></returns> public ActionResult Details(int pageIndex = 1) { var model = new BookDetailsViewModels() { Books = _bookRepository.Books.OrderBy(x => x.Id).Skip((pageIndex - 1) * PageSize).Take(PageSize), PageSize = PageSize, PageIndex = pageIndex, TotalItems = _bookRepository.Books.Count() }; return View(model); } }
5.修改視圖模型後,對應的視圖頁也須要修改
@model Wen.BooksStore.WebUI.Models.BookDetailsViewModels @{ ViewBag.Title = "Books"; } @foreach (var item in Model.Books) { <div> <h3>@item.Name</h3> @item.Description <h4>@item.Price.ToString("C")</h4> <br /> <hr /> </div> } <div class="pager"> @Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x })) </div>
1.頁面的樣式簡單的設計爲 3 大板塊,頂部爲標題,左側邊欄爲分類,主模塊將顯示具體內容。
咱們如今要在 Views 文件夾下建立一個文件 _ViewStart.cshtml,再建立一個 Shared 的文件夾和文件 _Layout.cshtml。
2._Layout.cshtml 這是佈局頁,當代碼執行到 @RenderBody() 時,就會負責將以前 Details.cshtml 的內容進行渲染:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> <link href="~/Contents/Site.css" rel="stylesheet" /> </head> <body> <div id="header"> <div class="title">圖書商城</div> </div> <div id="sideBar">分類</div> <div id="content"> @RenderBody() </div> </body> </html>
_ViewStart.cshtml 該文件表示默認的佈局頁爲該視圖文件:
@{ Layout = "~/Views/Shared/_Layout.cshtml"; }
3.網站的根目錄下也要添加一個名爲 Contents 的文件夾,用於存放 CSS。
body { } #header, #content, #sideBar { display: block; } #header { background-color: green; border-bottom: 2px solid #111; color: White; } #header, .title { font-size: 1.5em; padding: .5em; } #sideBar { float: left; width: 8em; padding: .3em; } #content { border-left: 2px solid gray; margin-left: 10em; padding: 1em; } .pager { text-align: right; padding: .5em 0 0 0; margin-top: 1em; } .pager A { font-size: 1.1em; color: #666; padding: 0 .4em 0 .4em; } .pager A:hover { background-color: Silver; } .pager A.selected { background-color: #353535; color: White; }
如今,分頁也已經有了效果,基本界面就出來了。
本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6640861.html
【參考】《精通 ASP.NT MVC ...》