贰个实在的应用程序

 作者:[美]Adam Freeman
     来源:《精通ASP.NET MVC
4》

日前建立的都是粗略的MVC程序,未来到了啊全体事情综合在一齐,以创设二个简便但实在的电子商务应用程序的时候了。

在此打算建立的应用程序 — SportsStore
(体育用品商店),将规行矩步随地可知的在线集团所运用的经文格局。将创造多少个客户能够因而分类和页面举行浏览的在线产品分类,贰个客户可以加上和删除商品的购物车,和三个客户能够输入其右击地址细节的结算页面。其它,还将开创3个富含创设、读取、更新和删除效率的管理区,以便对产品分类进行保管并对该区域开始展览爱戴,以使唯有记名的指挥者才能展开修改。

此书打算建立的这几个应用程序不只是二个皮毛的演示,而是要开创二个坚固且实际的、符合当下最实用供给的应用程序。由于要树立要求的最底层结构,一开端的进程会有点慢。的确,若采用WebForm,则足以更快地建立初期的职能,只要拖放一些与数据库直接绑定的空间即可。但在
MVC
应用程序中所付出的这一个先前时代工作,会拉动可爱抚、可增加以及组织能够的代码,且那几个代码对单元测试具有独立援助。一旦妥帖地建好了那种基本的底层架构,前边的事务就会快起来了。

1.开始

1.1 创造 Visual Studio 解决方案和系列

本文打算创制八个富含四个品类的Visual Studio
消除方案,2个类型包括域模型,三个是MVC
应用程序,第几个则带有单元测试。首先用”空白解决方案”模板创造贰个名为”SportsStore”的新的Visual
Studio 解决方案。

皇冠直营现金网官方网 1

Visual Studio
消除方案是三个分包三个或多少个品类的器皿。示例应用程序须要八个类型,如下图所示:

皇冠直营现金网官方网 2

皇冠直营现金网官方网 3

 

1.2 添加引用

参考后面包车型客车博文 【MVC 4】3.MVC 基本工具(创造示范项目、使用
Ninject)
 
和 【MVC 4】4.MVC 基本工具(Visual Studio
的单元测试、使用Moq)
 
对库和花色做好科学的引用。所需的体系信赖性如下图所示:

皇冠直营现金网官方网 4

 

1.3 设置DI容器

事先的小说 【MVC 4】3.MVC 基本工具(创造示范项目、使用
Ninject)

显示过哪些行使 Ninject 创制一个自定义正视性解析器,以便 MVC
框架用它创制整个应用程序实例化对象。这里打算动用分裂的方法,即创办3个自定义的控制器工厂。用户能够在当中添加自定义代码,以转移MVC框架的(暗许)行为,或许像那里所做的一模一样,将DI
限制到应用程序的一片段。常用的方式是用依赖性解析器来处理
DI,而用自定义控制器工厂来改变查找控制器类的章程,但在此例中,只打算采取控制器工厂。

在 SportsStore.WebUI
项目中创制二个称号”Infreastructure”的文本夹,然后创设3个名为”NinjectContrillerFactory
(Ninject 控制器工厂)”的类。

using Ninject;
using System;
using System.Web.Mvc;
using System.Web.Routing;

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()
        {
            //put bindings here

        }
    }
}

 

即便如此尚未添加其它绑定,但在必要时,可以使用AddBindings 方法。必须告诉 MVC
希望选用此 NinjectControllerFactory 类来创立控制器对象,其方式是在
SportsStore.WebUI 项目中 Global.asax.cs 文件的Application_Start
方法中添加一些代码,如下粗体部分所示:

using SportsStore.WebUI.Infrastructure;using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace SportsStore.WebUI
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
    // 请访问 http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
        }
    }
}

 

1.4 运转程序

运作程序,会面到3个错误页面,那是因为所请求的 U索罗德L 是与 Ninject
尚未开始展览绑定的控制器相关联的:

皇冠直营现金网官方网 5

固然进展到这一步,表明 Visual Studio 2011 和ASP.NET MVC
开发条件的准备工作进展的卓殊胜利。

 

2.从域模型早先

MVC
应用程序中有太多的事体都是围绕域模型而实行的,因而,域模型是起头工业作的特等地点。

鉴于那是三个电子商务应用程序,由此要求的最显然的域实体是成品(Product)。在SportsSore.Domain
项目中创设3个名为 “Entities”
的新文件夹,然后在当中创造三个名为“Product”的类。

namespace SportsStore.Domain.Entities
{
    public class Product
    {
        public int ProductID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public string Category { get; set; }
    }
}

上述清单遵从了在一块儿独立的 Visual Studio
项目中定义域模型的预定,即类必须标记为
public,即使不必然要依照这一预约,但那样做促进保持模型与控制器分离。

 

2.1 创设3个虚幻的存款和储蓄库

今昔必要某种格局来获得数据库中的Product
实体。正如前方博文所诠释的,人们期望持久化逻辑与域模型实体是分开的——此事通过利用存款和储蓄库格局来促成。此刻,不必顾虑会什么完结持久化,可是,将从概念它的接口来开首这一进度。

在 SportsStore.Domain 项目中创设一个名为 Abstract
的顶层新文件夹,并创立五个名为 IProductRepository 的新接口,代码如下:

using SportsStore.Domain.Entities;
using System.Linq;

namespace SportsStore.Domain.Abstract
{
    public interface IProductRepository
    {
        IQueryable<Product> Products { get; }
    }
}

该接口使用了 IQueryable<T> 接口,以便能够获取一体系 Product
对象,而不要表达数据怎样存款和储蓄、存款和储蓄在哪个地方,以及如何接收数据。使用这一
IProductRepository 接口的类,能够博得 Product
对象而不必知道它们来自哪个地方或怎样递交它们,那是存款和储蓄库方式的真面目。在添加特性的全套开发进程中,将再也审视这一接口。

 

2.2 创设模仿存款和储蓄库

于今,已经定义了一个抽象接口,可以兑现持久化学工业机械制,并将其挂接到二个数据库。本文打算在背后部分再做那件工作。为了能够初阶编写制定应用程序的别的部分,本文打算创立三个IProductRepository 接口的生搬硬套实现。本文打算在 SportsStore.WebUI 项目的NinjectControllerFactory 类的 AddBindings 方法中做这件事,代码如下:

using Moq;
using Ninject;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;

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()
        {
            //put bindings here
            Mock<IProductRepository> mock = new Mock<IProductRepository>();
            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<IProductRepository>().ToConstant(mock.Object);
        }
    }
}

那边必须对该问卷添加一些命名空间,但用来创制模仿存款和储蓄库完毕的历程使用的是 【MVC
4】4.MVC 基本工具(Visual Studio
的单元测试、使用Moq)

所介绍的相同的 Moq 技术。AsQueryable方法是多个 LINQ 扩大方法,它将
IEnumerable<T> 转换来IQueryable<T>,此处要求它来合作接口签名。

大千世界希望,Ninject 无论何时收到到三个 IProductRepository
接口完毕的央浼,都回到同样的模仿对象,这正是选拔 ToConstant 方法的原故

...
ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);
...

Ninject 会从来以该模仿对象来满意对 IProductRepository
接口的乞请,而不是历次都创制三个新的贯彻目的实例。

 

3.展现产品列表

本小结将创建一个控制器和2个动作方法,它能够展现存款和储蓄库中的产品细节。此刻,将只只针对模仿存款和储蓄库中的数据。

3.1 添加控制器

新建控制器”ProductController”,模板为”空 MVC 控制器”,修改代码如下

using SportsStore.Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SportsStore.WebUI.Controllers
{
    public class ProductController : Controller
    {
        private IProductRepository repository;

        public ProductController(IProductRepository productRepository)
        {
            this.repository = productRepository;
        }

        public ViewResult List()
        {
            return View(repository.Products);
        }
    }
}

 像那样调用 View
方法(未钦赐视图名称),是告诉框架为该动作方法渲染贰个暗中同意视图。通过将
Product 对象的列表传递给那一个 View
方法,那是在给框架提供数据,以便用这一个多少填充强类型视图中的 Model
对象。

 

3.2 添加视图

今天亟待为 List 动作方法添加暗中认可视图。添加对应的视图像和文字件 List.cshtml
,并渲染视图像和文字件如下:

@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>
}

 

3.3 设置暗中认可路由

近年来要做的百分之百做事是报告 MVC 框架,抵达网站根的央求应该被映射到
ProductController 类的List 动作方法上。那足以经过编写制定 Global.asax.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 }
            );
        }
    }
}

 

3.4 运营应用程序

至此,全部基础工作均已就绪。此刻早已有1个暗含二个动作方法的控制器,该动作方法在默许U卡宴L
被呼吁时被调用,它依靠于储存库接口的3个效仿落成,该存款和储蓄库接口生成了部分粗略的测试数据。那些测试数据被传送给与动作方法关联在同步的视图,而视图对种种产品创制三个简练的细节列表。运转该应用程序,效果图如下:

皇冠直营现金网官方网 6

那是ASP.NET MVC 框架典型的付出格局。

 

4.预备数据库

前方早已足以来得含有产品细节的大约视图,但其出示的文化模仿的
IProductRepository
所重回的测试数据。在能够展现真实数据的存储库以前,还亟需树立三个数据库,并用部分数量填充它。

本文打算以 SQL Server 作为数据库,并用 Entity Framework(实体框架 –
EF)来拜会数据库,EF 是 .NET 的OMuranoM(对象关联映射)框架。OXC60M
框架让开发职员能够用规则的C# 对象来使用关周密据库的表、列和行。 LINQ
能够与不一致的数据源一起干活,在那之中之一正是 Entity Framework 。

 

4.1 创立数据库

增补到 Visual Studio 2013 和 SQL Server 二零一二 中的3个很好的特征是
LocalDB。它是特地为开发者而设计的1个免管理的SQL Server
主题作用完毕。使用该天性使我们在建立项目、以及背后将数据库布置到完全版的
SQL Server 时期,能够跳过数据库的设置进度。

第⑧个步骤是在 Visual Studio
中开创数据库连接。从”View(视图)”菜单中打开”Database
Explorer(数据库能源管理器)”窗口,点击”Connect to
Database(连接到数据库)“按钮。

传闻提示,登录数据库,并新建数据库 SportsStore

皇冠直营现金网官方网 7

 

4.2 定义数据库方案

新建的数据库只需求二个数据表,用以存款和储蓄 Product
数据。右击数据库对应的”Tables(表)”条目,新增数据表。

皇冠直营现金网官方网 8

这将会显得创立新表的设计器。使用 T-SQL 窗口,输入相应的SQL语句创设数量表
Products 。

皇冠直营现金网官方网 9

点击左上角的”更新”按钮,相会到该语句的作用摘要。

皇冠直营现金网官方网 10

点击”更新数据库”,以执行该 SQL 语句,并在数据库中开创 Products 表。

皇冠直营现金网官方网 11

 

4.3 向数据库添加数据

正文打算对该数据库手工业添加一些数码。

在“数据库财富管理器”窗口中,展开 SportsStore 数据库的“表”条目,右击
Products 表,选用“展现表数据”,然后输入下图所示数据。能够用 Tab
键逐行移动光标。在一行的终极按 Tab
键,将移到下一行并创新数据库中的数据。

 皇冠直营现金网官方网 12

 

4.4 创立实体框架上下文

Entity Framework
的摩登版包蕴了3个名为“Code-first(代码先行)”的很好的风味。其构思是足以先定义模型中的类,然后再通过那些类生成数据库。

那很符合绿地(Green-田野(field))开发项目,但这一个种类并不多见。因而,本文打算演示下
Code-First 的一种变异,以此把模型类与存活的数据库关联在一起。

第②步,是将Entity Framework (此处是6.1本子)添加到 SportsStore.Domain
项目中。通过 管理NuGet 包,安装新型的 Entity Framework 包。

皇冠直营现金网官方网 13

 

下三个手续是开创1个将前方建立的简短模型与数据库关联起来的光景文类(Context
Class)。

创设1个新文件夹
“Concrete”,并在内部添加1个名为”EFDbContext”的新类。代码如下:

using SportsStore.Domain.Entities;
using System.Data.Entity;

namespace SportsStore.Domain.Concrete
{
    public class EFDbContext:DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
}

皇冠直营现金网官方网,为了接纳 Code-First 个性,需求创设二个派生于
System.Data.Entity.DbContext
的类。那些类会为用户要动用的数据库中的每种表自动地定义八特质量。

该属性钦点了表名,并把 DbSet
结果的花色参数钦点为实体框架用来代表表行的模子。在这些事例中,该属性名是
Products(数据库中的表名)。即,希望用 Product 模型类型来代表 Products
表的相继行。

需求报告 Entity Framework 怎样连接到数据库,为了完结这一做事,只须求在
SportsStore.WebUI 项指标 Web.config
文件中上述下文类同样的名字添加一条数据库连接字符串即可,如下所示

  <connectionStrings>
    <add name="EFDbContext" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=SportsStore;Integrated Security=True" 
providerName="System.Data.SqlClient" />
  </connectionStrings>

 

4.5 创建 Product 存储库

于今,本文已经做好了真正落实 IProductRepository 类所急需的种种准备。 在
SportsStore.Domain 项指标 Concrete
文件夹中添加贰个类,取名”EFProductRepository”,代码如下:

using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using System.Linq;

namespace SportsStore.Domain.Concrete
{
    public class EFProductRepository:IProductRepository
    {
        private EFDbContext context = new EFDbContext();
        public IQueryable<Product> Products {
            get { return context.Products; }
        }
    }
}

这正是储存库类,它完毕了 IProductRepository 接口,并动用了1个EFDbContext 实例,以便用 Entity Framework
接收数据库的多寡。在对该存款和储蓄库添加特性时,便会看出那里是何许运用 Entity
Framework 的。

最终一步是吧 Ninject 对模拟存款和储蓄库的绑定替换为对实际存款和储蓄库的绑定。编辑
SportsStore.WebUI 项目中的 NinjectControllerFactory 类,使 AddBindings
方法如下所示:

using Moq;
using Ninject;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
using SportsStore.Domain.Concrete;

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()
        {
            //put bindings here
            ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
        }
    }
}

新的绑定以粗体展现,它告诉本身 Ninject ,用户期望创立 EFProductRepository
类的实例来对 IProductRepository
接口的伸手进行劳动。再一次运转应用程序,效果如下:

皇冠直营现金网官方网 14

 

只顾:记得更新 SportsStore.WebUI 项目中
Entity Framework的版本,与 SportsStore.Domain
项目中的版本保持一致。不然报错。

 

5.添加分页

从上海体育场面能够见到,数据库中的全数成品都突显在一个单一的页面上。本小结将添加对分页的支撑,以便在1个页面上显得一定数量的成品,用户能够逐页查看全数产品分类。要促成那或多或少,能够在
Product 控制器中的 List 方法上添加3个参数,如下所示:

using SportsStore.Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SportsStore.WebUI.Controllers
{
    public class ProductController : Controller
    {
        private IProductRepository repository;
        //指明用户希望每页显示4个产品
        public int PageSize = 4;

        public ProductController(IProductRepository productRepository)
        {
            this.repository = productRepository;
        }

        public ViewResult List(int page=1)
        {
            //从存储库获取 Product 对象,
            //按主键顺序排序,略过起始页之前出现的产品数,
            //然后取出由 PaeSize 字段指定的产品个数
            return View(repository.Products.OrderBy(p=>p.ProductID).Skip((page-1)*PageSize).Take(PageSize));
        }
    }
}

 

5.1 展现页面链接

借使运转这一个应用程序,将看到唯有三个条款展现在页面上。即使想查看另一页,能够把询问字符串参数加到
UKugaL 的最后,如下所示:

http://localhost:64245/?page=2

亟待修改 U帕杰罗L 的端口号,使之与正在运作的 ASP.NET
开发服务器端口号匹配。运用那种查询字符串,能够对全部产品分类实行导航。

而为了便利客户。必要在各样产品列表的底层渲染一些页面包车型的士链接,以使客户可以在不相同的页面之间导航。为了完成这一指标,本文打算落成四个可接纳的
HTML 协理器方法,它就像于事先 【MVC 4】1.首先个 MVC
应用程序
中使用的
Html.TextBoxFor 和 Html.BeginForm
方法。该帮忙器方法将为所急需的导航链接生成 HTNL 标记。

(1) 添加视图模型

为了补助 HTML
帮忙器方法,本文打算把可用页面数、当前页、已经储存库中产品总数等地点的音信传递给视图。做那种事最简单的章程是开创三个视图模型,在
SportsStore.WebUI 文件夹 Models 中新建类文件 PagingInfo.cs ,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SportsStore.WebUI.Models
{
    public class PagingInfo
    {
        public int TotalItems { get; set; }
        public int ItemsPerPage { get; set; }
        public int CurrentPage { get; set; }

        public int TotalPages
        {
            get { return (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); }
        }
    }
}

视图模型并不是域模型的一片段,它只是一种便利在控制器与视图之间传递数据的类。为了强调那或多或少,将以此类位居
SportsStore.WebUI 项目中,以使它与域模型的类分离开(将视图模型放在 MVC
框架项目标 Models
文件夹,而不是身处类库项目中,那种做法可以证明视图模型不是域模型,显明了概念,也使应用程序的结构更清楚)。

 

(2)添加 HTML 协理器方法

今日有了那些视图模型,便能够实现这一个 HTML
协助器方法了,该办法称为“PageLinks”。在 SportsStore.WebUI
项目中开创1个新文件夹“HtmlHelpers”,并丰富二个新的静态类“PagingHelpers(分页协理器)”。类公事的剧情如下所示:

using SportsStore.WebUI.Models;
using System;
using System.Text;
using System.Web.Mvc;

namespace SportsStore.WebUI.HtmlHelpers
{
    public static class PagingHelpers
    {
        public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl)
        {
            StringBuilder result = new StringBuilder();
            for (int i = 1; i <= pagingInfo.TotalPages; i++)
            {
                TagBuilder tag = new TagBuilder("a"); // 构造一个<a>标签
                tag.MergeAttribute("href", pageUrl(i));
                tag.InnerHtml = i.ToString();
                if (i == pagingInfo.CurrentPage)
                    tag.AddCssClass("selected");
                result.Append(tag.ToString());
            }
            return MvcHtmlString.Create(result.ToString());
        }
    }
}

那几个 PageLinks 扩展方法运用 PagingInfo
对象中提供的音信生成一组页面链接的 HTML 。Func
参数提供了在里头传递委托的力量,该信托用于转移查看其余页面包车型地铁链接。

 

唯有隐含扩大方法的命名空间在界定内时,当中的恢宏方法才是可用的。在二个代码文件中,那是用
using 语句来成功的;但对于四个 Razor 视图,必须把1个安插条目添加到
Web.config 文件中,或在那一个视图上添加一条 @using 语句
。不难混淆的是,在三个 Razor 的 MVC 项目中有三个 Web.config
文件:主配置文件位于应用程序的根目录,而视图专用的配置文件位于 Views
文件夹。供给修改的是 Views/Web.config 文件,如下所示:

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="SportsStore.WebUI.HtmlHelpers"/>
      </namespaces>
    </pages>
  </system.web.webPages.razor>

在二个 Razor
视图中须要引用的每三个命名空间,都急需以那种艺术开始展览宣示,或在视图中用
@using 语句举行宣示。

 

(3)添加视图模型视图

眼前还没做好利用 HTML 协助器方法的预备,还亟需把那一个 PagingInfo
视图模型类的一个实例提须要视图。能够用 View Bag
(视图包)脾性来做那件事,可是二个更好的不二法门是把控制器发送给视图全部数据封装成一个单一的视图模型类。为此,须求把2个新的名为“ProductsListViewModel”
的类添加到 SportsStore.WebUI 的 Models 文件夹。

using SportsStore.Domain.Entities;
using System.Collections.Generic;

namespace SportsStore.WebUI.Models
{
    public class ProductsListViewModel
    {
        public IEnumerable<Product> Products { get; set; }
        public PagingInfo PagingInfo { get; set; }
    }
}

前天,能够立异 ProductController 类中的 List 方法,以便利用那几个ProductsListViewModel
类,给视图提供在页面上出示的制品细节和分页细节,修改后代码如下:

using SportsStore.Domain.Abstract;
using SportsStore.WebUI.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SportsStore.WebUI.Controllers
{
    public class ProductController : Controller
    {
        private IProductRepository repository;
        public int PageSize = 4;

        public ProductController(IProductRepository productRepository)
        {
            this.repository = productRepository;
        }

        public ViewResult List(int page = 1)
        {
            ProductsListViewModel model = new ProductsListViewModel
            {
                Products = repository.Products.OrderBy(p => p.ProductID).Skip((page - 1) * PageSize).Take(PageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = page,
                    ItemsPerPage = PageSize,
                    TotalItems = repository.Products.Count()
                }
            };
            return View(model);
        }
    }
}

那一个改动将3个 ProductsListViewModel 对象作为模型数据传递给了视图。

 

此时,视图期望的是一个 Product 对象的行列,因而供给更新 List.cshtml
,以拍卖那几个新视图模型类型,修改后代码如下:

@model SportsStore.WebUI.Models.ProductsListViewModel

@{
    ViewBag.Title = "Products";
}

@foreach (var p in Model.Products) { 
<div class="item">
    <h3>@p.Name</h3>
    @p.Description
    <h4>@p.Price.ToString("c")</h4>
</div>
}

 

这么些例子修改了 @model 提示符,以报告
Razor,现在正在利用多个不相同的数据类型。也急需立异 foreach
循环,以使数据源是模型数据的 Products 属性。

 

(4)展现页面链接

现明儿早上已实现好了再 List
视图上添加页面链接的持有准备。前边早已创办了含蓄分页消息的视图模型,更新了控制器以使那么些音讯可见传递给视图,并修改了
@model 提醒符以匹配新的视图模型类。剩下的事是在视图中调用那些 HTML
援救器方法,修改视图像和文字件如下:

@model SportsStore.WebUI.Models.ProductsListViewModel

@{
    ViewBag.Title = "Products";
}

@foreach (var p in Model.Products)
{ 
    <div class="item">
        <h3>@p.Name</h3>
        @p.Description
        <h4>@p.Price.ToString("c")</h4>
    </div>
}

<div class="pager">
    @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x }));
</div>

运转该应用程序,能够看看曾经添加了页面链接,如下图所示。那么些链接的体裁如故是很基本。主要的是其一链接能把客户从三个页面带到另二个页面,并浏览正在销售的出品。

皇冠直营现金网官方网 15

5.2 改进 URL

页面链接即便能够其成效,但它们采纳的仍然是询问字符串,以便将分页新闻服务器,代码如下:

http://localhost/?page=2

三个更好的不二法门是特地创立一种遵从可组合 UEscortL 方式的方案。“可构成 U本田CR-VL
”是一种对用户有含义的法子,其方式如下:

http://localhost/Page2

有幸的是,MVC 很简单修改 UKoleosL 方案,因为它选拔了 ASP.NET
的路由性子。所要做的学识吧一条新路由添加到 Global.asax.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: null,
                url: "Page{page}",
                defaults: new { controller = "Product", action = "List" }
                );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
            );

        }
    }
}

重要的是吧那条路由加在 Default
路由此前。路由是按它们列出的依次举办拍卖的,那里须要那条新路由事先于已经存在的这条。

那是唯一须要对成品分页的 U宝马X3L 方案展开改动的地点。MVC
框架与路由成效是精心集成的。因而那样的改动将自行反映在 Url.Action
方法的处理结果中。即使运维那几个应用程序,并导航到贰个页面,将会看出那么些新的
UPRADOL 方案在其作用。

皇冠直营现金网官方网 16

 

6.装置剧情样式

眼下早已建立了大批量的根底结构,而且应用程序也起首真正地集合在协同了,但未曾把注意力放到其外观上。就算那本书不是一本关于
Web 设计或 CSS 的书,但SportsStore
应用程序设计也会因为太不佳的格式而损坏它的技术强度。本节将有个别健康的作业。

本文打算完毕三个富含底部的经典式两列布局。

 

6.1 定义布局中的公用内容

【MVC 4】2.使用
Razor
中曾演说了
Razor 布局是何许做事和采纳的。 当为 Product 控制器创立 List.cshtml
视图时,曾必要用户选中 “使用1个搭架子”
复选框,但该文本框保留为空。那便利用了暗许布局 _Layout.cshtml,能够在
SportsStore.WebUI 项指标 Views/Shared
文件夹中找到它。打开那些文件并修改如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="~/Content/Site.css" type="text/css" rel="stylesheet" />
</head>
<body>
    <div id="header">
        <div class="title">SPORTS STORE</div>
    </div>
    <div id="categories">
        We will put something useful here later
    </div>
    <div id="content">
        @RenderBody()
    </div>
</body>
</html>

 

6.2 添加CSS样式

修改引用的 CSS 样式文件 Site.css 如下:

...
body { font-family: Cambria, Georgia, "Times New Roman"; margin: 0; }
div#header div.title, div.item h3, div.item h4, div.pager a { font: bold 1em "Arial Narrow", "Franklin Gothic Medium", Arial; }
div#header { background-color: #444; border-bottom: 2px solid #111; color: white; }
div#header div.title { font-size: 2em; padding: .6em; }
div#content { border-left: 2px solid gray; margin-left: 9em; padding: 1em; }
div#categories { float: left; width: 8em; padding: .3em; }
div.item { border-top: 1px dotted gray; padding-top: .7em; margin-bottom: .7em; }
div.item:first-child { border-top: none; padding-top: 0; }
div.item h3 { font-size: 1.3em; margin: 0 0 .25em 0; }
div.item h4 { font-size: 1.1em; margin: .4em 0 0 0; }
div.pager { text-align: right; border-top: 2px solid silver; padding: .5em 0 0 0; margin-top: 1em; }
div.pager a { font-size: 1.1em; color: #666; text-decoration: none; padding: 0 .4em 0 .4em; }
div.pager a:hover { background-color: silver; }
div.pager a.selected { background-color: #353535; color: white; }
...

若是运营程序,会看到其外观已经赢得革新,效果图如下:

皇冠直营现金网官方网 17

 

6.3 创制分部视图

正文的最后贰个技能是重构应用程序,以简化 List.cshtml
视图。本节打算创建二个分部视图(Partial
View)
,那种分部视图是放置在另一个视图中的二个剧情片断。分部视图是自包涵文件,且能够跨视图重用,那促进裁减重复,越发是急需在应用程序的多少个地点渲染同样的多寡时。

为了抬高分部视图,右击 SportsStore.WebUI 项目中的 /Views/Shared
文件夹,添加新的视图像和文字件 ProductSummary.cshtml 。

皇冠直营现金网官方网 18

修改视图文件如下:

@model SportsStore.Domain.Entities.Product

<div class="item">
    <h3>@Model.Name</h3>
    @Model.Description
    <h4>@Model.Price.ToString("c")</h4>
</div>

接着更新 Views/Product/List.cshtml ,以使它亦可利用那几个分部视图。

@model SportsStore.WebUI.Models.ProductsListViewModel

@{
    ViewBag.Title = "Products";
}

@foreach (var p in Model.Products)
{
    Html.RenderPartial("ProductSummary",p);
}

<div class="pager">
    @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x }))
</div>

其一例子已经去掉了事先的 List.cshtml 视图中的 foreach
循环中的标记,并把它改成了那些新的分部视图中。用 Html.RenderPartial
帮忙器方法来调用那几个分部视图,参数是视图的称呼和视图模型对象。

提示:RenderPartial 方法并不像大部分其它支持器方法那样再次回到 HTML
标记。相反,它把内容一向写入到响应流,因而必须用二个支行,像多少个完完全全的
C# 程序行一样来调用它。那比缓存已渲染的分部视图的 HTML
更有效一些,因为它将被写到响应流。假使喜欢用一种更平等的语法,能够使用
Html.partial 方法,它成功与 RenderPartial 方法一致的效果,但回来的是一个HTML 片段,并且能够像 @Html.Partial(“ProductSummary”,p) 一样采取它。

运作应用程序,效果不变。

相关文章