[.NET] 一步步打造一個簡單的 MVC 電商網站 - BooksStore(一) (轉)

http://www.cnblogs.com/liqingwen/p/6640861.htmlphp

一步步打造一個簡單的 MVC 電商網站 - BooksStore(一)

  本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStorecss

簡介

  主要功能與知識點以下:html

    分類、產品瀏覽、購物車、結算、CRUD(增刪改查) 管理、發郵件、分頁、模型綁定、認證過濾器和單元測試等。java

     【備註】項目使用 VS2015 + C#6 進行開發,有問題請發表在留言區哦,還有,頁面長得比較醜,請見諒。git

 

目錄

  • 建立項目架構
  • 建立域模型實體
  • 建立單元測試
  • 建立控制器與視圖
  • 建立分頁
  • 加入樣式

 

1、建立項目架構

  1.新建一個解決方案「BooksStore」,並添加如下項目:github

  

     BooksStore.Domain:類庫,存放域模型和邏輯,使用 EF;
     BooksStore.WebUI:Web MVC 應用程序,存放視圖和控制器,充當顯示層,使用了 Ninject 做爲 DI 容器;
     BoosStore.UnitTest:單元測試,對上述兩個項目進行測試。

  

  Web MVC 爲一個空的 MVC 項目:sql

 

  2.添加項目引用(須要使用 NuGet):數據庫

    

  這是不一樣項目須要引用的類庫和項目微信

 

  3.設置 DI 容器
     咱們經過 Ninject ,建立一個自定義的工廠,一個名爲 NinjectControllerFactory 的類繼承 DefaultControllerFactory(默認的控制器工廠)。你也能夠在裏面添加自定義的代碼,改變 MVC 框架的默認行爲。
 

   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()
        {
            
        }
    }
複製代碼

 

  4.而且在 Global.asax 中加入一行代碼,告訴 MVC 用新建的類來建立控制器對象。
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());
        }
    }
Global.asax

 

2、建立域模型實體

     1.在圖中位置建立一個名爲 Book 的實體類。
複製代碼
    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")] : 

 

3、建立單元測試

  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.在該方法體的內部單擊右鍵,你能夠看到一個「運行測試」的選項,這時你能夠嘗試單擊它:

  從這個符號能夠看到,是成功了!

  接下來,咱們要正式從頁面顯示咱們想要的信息了。

 

4、建立控制器與視圖 

  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 樣式,因此顯示的效果可能有些許不一樣),結果是一致的。

 

5、建立分頁

  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>
複製代碼

 

6、加入樣式

  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;
        }
Site.css

 

  如今,分頁也已經有了效果,基本界面就出來了。

 

  本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore


【博主】反骨仔

【原文】http://www.cnblogs.com/liqingwen/p/6640861.html

【參考】《精通 ASP.NT MVC ...》

 
  • 感謝您的閱讀。喜歡的、有用的就請大哥大嫂們賞幾個小錢花花,沒錢的就請高擡貴手「推薦一下」吧!你的物質和精神支持是博主強大的寫做動力。歡迎轉載!
  • 博主的文章沒有高度、深度和廣度,只是湊字數。因爲博主的水平不高(實際上是個菜B),不足和錯誤之處在所不免,但願你們可以批評指出。
  • 個人博客:http://www.cnblogs.com/liqingwen/
  • 博主是利用讀書、參考、引用、抄襲、複製和粘貼等多種方式打形成本身的純鍍 24k 文章,請原諒博主成爲一個無恥的文檔搬運工!
 
 
好文要頂 關注我 收藏該文
12
0
 
 
 
« 上一篇: [SQL] SQL 基礎知識梳理(七)- 集合運算
相關文章
相關標籤/搜索