第五话 Asp.Net MVC 3.0【MVC实战项目の一】
前面几话都讲的一些有关MVC相关东西,从这话开始应用实战的项目开始。
实战一个简单的购物流程的项目吧!
首先创建一个空白的解决方案,如下图1.
图1.我们预计创建3个模块,一个模块包含我们的域模型(DoMain),一个模块包含我的MVC Web应用程序,还有一个单元测试的模块。
我们的域模型(DoMain)是一个类库项目,然后是一个Asp.Net MVC3 的Web应用程序(Razor引擎)项目,然后添加一个测试项目进来,添加测试项目如下图2.
图2.当我们创建好我们的域模型(DoMain)类库项目和测试项目(类库项目),VS会自动创建一个Class1.cs的文件和UnitTest1.cs的文件,这个对我们来说没有多大的用处,可以直接干掉。之后我们的行么如下图3.
图3.下一步就是添加项目引用,可项目需要用到包(扩展工具/第三方插件),我们项目具体要用到的第三方插件如下:
具体项目 | 第三插件名称 |
SportsStore.Domain | Ninject |
SportsStore.UI | Ninject |
SportsStore.Domain | Moq |
SportsStore.UI | Moq |
可以在VS里面的"程序包控制管理"用下面的命令导入第三方插件包,命令如下:
Install-Package Ninject -Project SportsStore.WebUI
Install-Package Ninject -Project SportsStore.Domain
Install-Package Moq -Project SportsStore.WebUI
Install-Package Moq -Project SportsStore.Domain
也可以在相关项目上右键,使用NuGet程序包管理一个一个导入,方法根据自己所好,不在啰嗦!
然后就是我们项目的依赖关系,如下表所示:
具体项目 | 依赖项目 |
SportsStore.Domain | 无 |
SportsStore.UI | SportsStore.Domain |
SportsStore.UnitTests |
SportsStore.Domain SportsStore.UI |
因为我们将使用Ninject创建我们的MVC应用程序控制器和处理DI,所以我们需要创建一个新的类更改配置。在SportsStore.UI应用程序里创建一个文件夹(命名"Infrastructure")然后在改文件里创建一个类叫NinjectControllerFactory,它的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Ninject; using System.Web.Routing; using Moq; using SportsStore.Domain.Abstract; using SportsStore.Domain.Entities; namespace SportsStore.WebUI.Infrastructure { public class NinjectControllerFactory : DefaultControllerFactory { private IKernel ninjectKernel; public NinjectControllerFactory() { this.ninjectKernel = new StandardKernel(); AddBindings(); } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType); } private void AddBindings() { //绑定额外数据 } } }
我们需要注册NinjectControllerFactory到MVC框架,所以我们也需要在Global.asax.cs里给它注册进去,具体代码如下:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); //注册路由 ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); }
我们可以试着启动跑下我的MVC Web项目,结果如下图4.
图4.如果真出现这个错误页面也是预计必然的结果,接下来的任务就是让这个页面消失吧!
从我们的域模型(DoMain)开始吧!既然我们搞的是一个购物流程的项目,那我们肯定需要商品才能购物,那就在域模型(Domain)里创建一个文件夹(命名"Entities")放相应的模型在该文件夹来创建一个Product类吧!Product类的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SportsStore.Domain.Entities { public class Product : Object { 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; } } }
接下来创建一个抽象存储库,我们知道我们用一些方法可以是Prodcut和数据交互,这里我们使用存储库模式,我们不需要担心他是如何去实现,所以在域模型(DoMain)项目里建立一个文件夹(命名"Abstract")在该文件里创建一个接口"IProductRepository",它的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SportsStore.Domain.Entities; namespace SportsStore.Domain.Abstract { public interface IProductRepository { IQueryable<Product> Products { get; } } }
这个接口使用这个IQueryable < T >可以获取Product对象,它没有说任何关于如何或数据存储在哪里或者它将如何被检索。一个类,它使用IProductRepository接口就可以获得Product对象,但是不需要知道任何关于它们来自于哪儿,或者他们如何将被交付到那儿,这是最基本的存储库的模式。
然后我们使用模拟库,因为我们一定定义了一个接口那么我接着就实现它,让他跟数据交互,我们模拟一下实现IProductRepository接口,代码如下:
private void AddBindings() { //绑定额外数据 //模拟IProductRepository实现 Mock<IProductRepository> mock = new Mock<IProductRepository>(); mock.Setup(h => h.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()); this.ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object); }
准备工作的差不多了我们需要要能展现的东西出来才不算前功尽弃,我们要展示出我们的商品,首先要来创建相应的控制器(命名"ProductController"),代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using SportsStore.Domain.Abstract; namespace SportsStore.WebUI.Controllers { public class ProductController : Controller { private IProductRepository repository; public ProductController(IProductRepository productReposittory) { this.repository = productReposittory; } } }
这个只不过是一个的空的控制器,我们创建了一个构造函数,该函数接收IProductRepository来的参数,这里也就方便Ninject在Product对象实例化的时候的注入(构造注入)。然后我需要返回一个视图展示出来,所以修改ProductController控制器如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using SportsStore.Domain.Abstract; namespace SportsStore.WebUI.Controllers { public class ProductController : Controller { private IProductRepository repository; public ProductController(IProductRepository productReposittory) { this.repository = productReposittory; } //返回一个视图 public ViewResult List() { return this.View(this.repository.Products); } } }
接下来,需要添加一个视图(View),我们需要创建一个强类型视图,如下图5.
图5.当然在我们选择模型类的时候,下拉框并不能找到IEnumerable<SportsStore.Domain.Entities.Product>,因为他不会包含枚举的域模型(DoMain)对象,所以需要我们手动输入。
IEnumerable<Product>意味着我们可以创建一个列表,现在就用犀利Razor引擎来搞这个页面,List.cshtml页面代码如下:
@model IEnumerable<SportsStore.Domain.Entities.Product> @{ ViewBag.Title = "Product List"; } @foreach (var Product in Model) { <div class="item"> <h3>@Product.Name</h3> @Product.Description <h4>@Product.Price.ToString("C")</h4> </div> }
说明:@Product.Price.ToString("C"),ToString("C")根据你的服务器将数字转换为相应的货币。
然后我们需要修改一下默认的路由,具体的修改如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using SportsStore.WebUI.Infrastructure; namespace SportsStore.WebUI { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // 路由名称 "{controller}/{action}/{id}", // 带有参数的 URL new { controller = "Product", action = "List", id = UrlParameter.Optional } // 参数默认值 ); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); //注册路由 ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } } }
注明:修改就是上面代码红色部分里标识为蓝色的控制器名称和相应方法(Action)名称。
接下来,在跑下我们的MVC Web应用程序,运行结果如下图6所示.
图6.可以看到我们已经消灭之前的黄页了,项目开始就先搞怎么些东西,后续继续完善。要是那里描述有误还请路过的前辈牛人给点指点,这样才能更好的进步,谢谢!