您现在的位置是:网站首页> 编程资料编程资料

一步步打造简单的MVC电商网站BooksStore(1)_实用技巧_

2023-05-24 426人已围观

简介 一步步打造简单的MVC电商网站BooksStore(1)_实用技巧_

一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

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

一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

一步步打造一个简单的 MVC 电商网站 - BooksStore(三)

一步步打造一个简单的 MVC 电商网站 - BooksStore(四)

简介

主要功能与知识点如下:

分类、产品浏览、购物车、结算、CRUD(增删改查) 管理、发邮件、分页、模型绑定、认证过滤器和单元测试等(预计四篇、周五、下周一和周二)。

【备注】项目使用 VS2015 + C#6 进行开发,有问题请发表在留言区哦,还有,页面长得比较丑,请见谅。

目录

  • 创建项目架构
  • 创建域模型实体
  • 创建单元测试
  • 创建控制器与视图
  • 创建分页
  • 加入样式

一、创建项目架构

1.新建一个解决方案“BooksStore”,并添加以下项目:

BooksStore.Domain:类库,存放域模型和逻辑,使用 EF; BooksStore.WebUI:Web MVC 应用程序,存放视图和控制器,充当显示层,使用了 Ninject 作为 DI 容器; BoosStore.UnitTest:单元测试,对上述两个项目进行测试。  

Web MVC 为一个空的 MVC 项目:

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); } ///  /// 添加绑定 ///  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()); } } 

二、创建域模型实体

1.在图中位置创建一个名为 Book 的实体类。

 public class Book { ///  /// 标识 ///  public int Id { get; set; } ///  /// 名称 ///  public string Name { get; set; } ///  /// 描述 ///  public string Description { get; set; } ///  /// 价格 ///  public decimal Price { get; set; } ///  /// 分类 ///  public string Category { get; set; } } 

有了实体之后,我们应该创建一个“库”对该实体进行操作,而这种持久化逻辑操作也应该和域模型是进行隔离的。

2.先定义一个接口 IbookRepository,在根目录创建一个名为 Abstract 的文件夹,顾名思义就是应该放置一些抽象的类,如接口。

 public interface IBookRepository { IQueryable Books { get; } }

我们通过该接口就可以得到对应类的相关信息,而不需要去管该数据如何存储,以及存储的位置,这就是存储库模式的本质。

3.接下来,我们就需要对数据库进行操作了,我们使用简单的EF(ORM 对象关系模型) 去对数据库进行操作,所以需要自己通过 Nuget 下载 EF 的类库。

4.因为之前定义了接口类,接下来就应该定义实现该接口的类了

  安装完之后,再次建立一个名为 Concrete 的文件夹,存放实例。

  在里面创建一个 EfDbContext 的类,派生于 DbContext,该类会为用户要使用的数据库中的每个表自动的定义一个属性。该属性名为 Books,指定了表名,DbSet 表示为 Book 实体的表模型,Book 对象相当于 Books 表中的行(记录)。

 public class EfDbContext : DbContext { public DbSet Books { get; set; } }

  再创建一个EfBookRepository 存储库类,它实现 IBookRepository 接口,使用了上文创建的 EfDbContext 上下文对象,包含了具体的方法定义。

 public class EfBookRepository : IBookRepository { private readonly EfDbContext _context = new EfDbContext(); public IQueryable 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) , -- 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) , -- Price - decimal N'.NET' -- Category - nvarchar(50) ) INSERT INTO dbo.Book ( Name , Description , Price , Category ) VALUES ( N'多线程从入门到精通' , -- Name - nvarchar(100) N'好书-多线程从入门到精通' , -- Description - nvarchar(max) , -- 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) , -- 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) , -- 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) , -- 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) , -- Price - decimal N'php' -- Category - nvarchar(50) ) 

测试数据

因为我希望表名为 Book,而不是 Books,所以我在之前的 Book 类上加上特性 [Table("Book")]:

三、创建单元测试

1.做完预热操作后,你可能想立即以界面的的方式进行显示,别急,先用单元测试检查一下我们对数据库的操作是否正常,通过对数据进行简单的读取,检查下连接是否成功。

2.单元测试也需要引入 ef 类库(Nuget)。

3.安装完之后会生成一个 app.config 配置文件,需要额外添加一行连接字符串(在后续的 Web UI 项目里,也需要加上这条信息,不然会提示对应的错误信息)。

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; } ///  /// 详情 ///  ///  public ActionResult Details() { return View(_bookRepository.Books); } } 

3.接下来,要创建一个视图 View 了。

4.将 Details.cshtml 的内容替换为下面的:

 @model IEnumerable @{ ViewBag.Title = "Books"; } @foreach (var item in Model) { 

@item.Name

@item.Description

@item.Price.ToString("C")



}

5.改下默认的路由机制,让他默认跳转到该页面。

6.还有一点需要注意的是,因为我们使用了 Ninject 容器,并且需要对控制器中的构造函数中的参数IBookRepository 进行解析,告诉他将使用哪个对象对该接口进行服务,也就是需要修改之前的 AddBindings 方法:

7.运行的效果大致如下(因为加了点 CSS 样式,所以显示的效果可能有些许不同),结果是一致的。

五、创建分页

1.在 Mode

-六神源码网