SportsStorePeta应用程序开发
步骤:
1.创建解决方案和项目(Domain、WebUI、UnitTests)
2.添加引用
3.设置ID容器
4.设计域模型
5.创建抽象存储库
6.创建模仿存储库
7.添加控制器、动作及视图
8.设置路由
9.准备数据库及数据表
10.创建实例框架上下文
11.创建产品存储库
12.添加分页
13.改进路由及URL
14.设置内容样式CSS
15.创建分部视图
一、解决方案:SportsStorePeta,该应用程序将不使用EF,而使用PetaPoco实现
项目:
二、项目引用
项目及依赖性
项目名 | VS模板 | 目的 | 工具依赖 | 项目依赖 | 微软引用 |
SportsStorePeta.Domain | 类库 | 存放域实体与逻辑,EF | None | None | System.Web.Mvc System.ComponentModel.DataAnnotations |
SportsStorePeta.WebUI | Asp.net MVC4 应用程序 Basic(基本) | 存放控制器与视图 | Ninject Moq | SportsStorePeta.Domain | None |
SportsStorePeta.UnitTests | 测试项目 | 单元测试 | Ninject Moq | SportsStorePeta.Domain SportsStorePeta.WebUI | System.Web.Mvc System.Web Microsoft.CSharp |
三、设置ID容器
1.Ninject控制器工厂:
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Routing;using Ninject;namespace SportsStorePeta.WebUI.Infrastructure{ ////// 使用Ninject修改默认控制器工厂 /// public class NinjectControllerFactory :DefaultControllerFactory { private readonly 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() { //Ninject绑定 } }}
MVC框架注册NinjectControllerFactory
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Http;using System.Web.Mvc;using System.Web.Optimization;using System.Web.Routing;using SportsStorePeta.WebUI.Infrastructure;namespace SportsStorePeta.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); //MVC框架注册NinjectControllerFactory ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } }}
四、设计域模型 和视图模型
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace SportsStorePeta.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; } }}
视图模型
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace SportsStorePeta.WebUI.Models{ public class ProductViewModel { public int ProductId { get; set; } public string Name { get; set; } public string Description { get; set; } public string Price { get; set; } public string Category { get; set; } }}
五、创建抽象存储库
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SportsStorePeta.Domain.Entities;namespace SportsStorePeta.Domain.Abstract{ public interface IProductRepository { IQueryableProducts { get; } }}
六、创建模仿存储库
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Routing;using Moq;using Ninject;using SportsStorePeta.Domain.Abstract;using SportsStorePeta.Domain.Entities;namespace SportsStorePeta.WebUI.Infrastructure{ ////// 使用Ninject修改默认控制器工厂 /// public class NinjectControllerFactory :DefaultControllerFactory { private readonly 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() { //Ninject绑定 //1.添加模拟IproductRepository实现 Mockmock=new Mock (); mock.Setup(m => m.Products).Returns( new List { new Product {Name = "Football", Price = 35}, new Product {Name = "Surf board", Price = 179}, new Product {Name = "Running shoes", Price = 87} }.AsQueryable()); //永久绑定 _ninjectKernel.Bind ().ToConstant(mock.Object); } }}
七、添加控制器、动作及视图
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using SportsStorePeta.Domain.Abstract;using SportsStorePeta.Domain.Entities;using SportsStorePeta.WebUI.Models;namespace SportsStorePeta.WebUI.Controllers{ public class ProductController : Controller { private readonly IProductRepository _repository; public ProductController(IProductRepository productRepository) { _repository = productRepository; } public ViewResult List() { ListproductViewModels = new List (); foreach (Product product in _repository.Products) { ProductViewModel productViewModel = new ProductViewModel { ProductId = product.ProductId, Name = product.Name, Description = product.Description, Price = product.Price, Category = product.Category }; productViewModels.Add(productViewModel); } return View(productViewModels); } }}
视图
@model IEnumerable@{ ViewBag.Title = "商品";}@foreach (var p in Model){ }@p.Name
@p.Description@p.Price
八、设置路由
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Web.Routing;namespace SportsStorePeta.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 } ); } }}
九、准备数据库及数据表
建表SQL语句
Create table Products( [ProductId] INT NOT NULL PRIMARY KEY IDENTITY, [Name] NVARCHAR(100) NOT NULL, [Description] NVARCHAR(500) NOT NULL, [Category] NVARCHAR(50) NOT NULL, [Price] DECIMAL(16,2) NOT NULL )
表建好后,可以插入一些数据做显示用。
INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'Lifejacket',N'Protective and fashionbale',N'Watersports',48.95);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'Soccer Ball',N'FIFA-approved size and weight',N'Soccer',19.50);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'CornerFlags',N'Give your playing field a protessional ',N'Soccer',34.50);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'蓝球',N'CornerFlagssafasdfsdf',N'Soccer',34.20);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'CornerFlags12',N'CornerFlagssafasdfsdf',N'Soccer',43.20);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'CornerFlags13',N'CornerFlagssafasdfsdf',N'Soccer',11.23);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'CornerFlags14',N'CornerFlagssafasdfsdf',N'Soccer',123.23);INSERT INTO [Products] ([Name],[Description],[Category],[Price]) VALUES (N'CornerFlagssafasdfsdf',N'CornerFlagssafasdfsdf',N'Soccer',32.23);
十、创建实例框架上下文
1.NuGet中引入PetaPoco
2.web.config添加数据库连接
3.设置PetaPoco,修改DataBase.tt模板
ConnectionStringName = "DbContext"; Namespace = "SportsStorePeta.Domain.Entities";
修改PetaPoco.Core.ttinclude
<#@ template language="C#" hostspecific="True" #>
4.新建上下文类:PpDbContext
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SportsStorePeta.Domain.Entities;namespace SportsStorePeta.Domain.Concrete{ public class PpContext : DbContextDB { public IQueryableProducts { get { var products = base.Query ("Select ProductId,Name,Description,Category,Price from Products").AsQueryable(); return products; } } }}
十一、创建产品存储库PpProductRepository
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SportsStorePeta.Domain.Abstract;using SportsStorePeta.Domain.Entities;namespace SportsStorePeta.Domain.Concrete{ public class PpProductRepository :IProductRepository { private readonly PpContext _context=new PpContext(); public IQueryableProducts { get { return _context.Products; } } }}
修改Ninject绑定:
private void AddBindings() { _ninjectKernel.Bind().To (); }
十二、添加分页
修改ProductController
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using SportsStorePeta.Domain.Abstract;using SportsStorePeta.Domain.Entities;using SportsStorePeta.WebUI.Models;namespace SportsStorePeta.WebUI.Controllers{ public class ProductController : Controller { private readonly IProductRepository _repository; public int PageSize = 4; public ProductController(IProductRepository productRepository) { _repository = productRepository; } public ViewResult List(int page=1) { ListproductViewModels = new List (); foreach (Product product in _repository.Products) { ProductViewModel productViewModel = new ProductViewModel { ProductId = product.ProductId, Name = product.Name, Description = product.Description, Price = product.Price, Category = product.Category }; productViewModels.Add(productViewModel); } return View(productViewModels.OrderBy(p => p.ProductId).Skip((page - 1)*PageSize).Take(PageSize)); } }}
1.添加分页视图模型
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace SportsStorePeta.WebUI.Models{ public class PageInfo { 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); } } }}
2.添加HTML辅助器方法
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using SportsStorePeta.WebUI.Models;namespace SportsStorePeta.WebUI.HtmlHelpers{ public static class PagingHelpers { public static MvcHtmlString PageLinks(this HtmlHelper html, PageInfo pageInfo, FuncpageUrl) { StringBuilder result = new StringBuilder(); for (int i = 1; i < pageInfo.TotalPages; i++) { TagBuilder tag=new TagBuilder("a"); tag.MergeAttribute("href",pageUrl(i)); tag.InnerHtml = i.ToString(); if (i == pageInfo.CurrentPage) { tag.AddCssClass("selected"); } result.Append(tag.ToString()); } return MvcHtmlString.Create(result.ToString()); } }}
3.修改Views/Web.config
4.添加视图模型数据 ProductsListViewModel
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace SportsStorePeta.WebUI.Models{ public class ProductsListViewModel { public IEnumerableProducts { get; set; } public PageInfo PagingInfo { get; set; } }}
5.更新List动作
添加新方法处理域模型
////// 根据Product域模型集合获得视图模型集合 /// /// ///private IEnumerable GetProductViewModelListByProducts(IQueryable products) { List productsViewModels = new List (); foreach (Product product in products) { ProductViewModel productViewModel = new ProductViewModel() { ProductId = product.ProductId, Name = product.Name, Category = product.Category, Description = product.Description, Price = product.Price.ToString("C") }; productsViewModels.Add(productViewModel); } return productsViewModels; }
public ViewResult List(int page=1) { ProductsListViewModel model = new ProductsListViewModel { Products = GetProductViewModelListByProducts( _repository.Products.OrderBy(p => p.ProductId).Skip((page - 1)*PageSize).Take(PageSize)), PagingInfo = new PageInfo { CurrentPage = page,ItemsPerPage = PageSize,TotalItems = _repository.Products.Count()} }; return View(model); }
6.更新List.cshtml视图
@model SportsStorePeta.WebUI.Models.ProductsListViewModel@{ ViewBag.Title = "商品";}@foreach (var p in Model.Products){}@p.Name
@p.Description@p.Price
@Html.PageLinks(Model.PagingInfo,x=>Url.Action("List",new{page=x}))
十三、改进路由及URL
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 } ); }
十四、设置内容样式CSS
1.定义布局模板视图_Layout.cshtml
@ViewBag.Title 体育用品商品类别@RenderBody()
2.添加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; }
十五、创建分部视图
分部视图是嵌入在另一个视图中的一个内容片段。是自包含文件,可以跨视图重用。
1.在Shared中添加分部视图ProductSummary.cshtml
@model SportsStorePeta.WebUI.Models.ProductViewModel@Model.Name
@Model.Description@Model.Price
2.修改List.cshtml
@model SportsStorePeta.WebUI.Models.ProductsListViewModel@{ ViewBag.Title = "商品";}@foreach (var p in Model.Products){ Html.RenderPartial("ProductSummary",p);}@Html.PageLinks(Model.PagingInfo,x=>Url.Action("List",new{page=x}))