MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器、URL优化、导航、分页、购物车、订单、产品管理、图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离。本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能。
本篇为系列第三篇,包括:
■ 5、自定义Ninject控制器工厂
■ 6、项目的第一次运行
5、自定义Ninject控制器工厂
在MySportsStore.WebUI下添加如下引用:
● 添加对Ninject的引用
● 添加对MySportsStore.IBLL的引用
● 添加对MySportsStore.BLL的引用
● 添加对MySportsStore.Model的引用
创建NinjectControllerFactory:
using System.Web.Mvc; using MySportsStore.BLL; using MySportsStore.IBLL; using Ninject; namespace MySportsStore.WebUI.Extension { public class NinjectControllerFactory : DefaultControllerFactory { private IKernel ninjectKernel; public NinjectControllerFactory() { ninjectKernel = new StandardKernel(); AddBindings(); } protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, System.Type controllerType) { return controllerType == null ? null : (IController) ninjectKernel.Get(controllerType); } private void AddBindings() { ninjectKernel.Bind<IProductService>().To<ProductService>(); } } }
在全局中注册NinjectControllerFactory
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ...... ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } }
为什么需要NinjectControllerFactory?
Ninject这个DI容器可以帮我们很好地管理接口和实现,并且以属性或构造函数的形式注入到控制器中,从而调用接口实现类的方法。并且,Ninject提供了Get()方法,使得使用Ninject也可以创建Controller。
6、项目的第一次运行
创建BaseController,其中赋予手动垃圾回收的机制。
using System; using System.Collections.Generic; using System.Web.Mvc; namespace MySportsStore.WebUI.Controllers { public class BaseController : Controller { protected IList<IDisposable> DisposableObjects { get; private set; } public BaseController() { this.DisposableObjects = new List<IDisposable>(); } protected void AddDisposableObject(object obj) { IDisposable disposable = obj as IDisposable; if (disposable != null) { this.DisposableObjects.Add(disposable); } } protected override void Dispose(bool disposing) { if (disposing) { foreach (IDisposable obj in this.DisposableObjects) { if (null != obj) { obj.Dispose(); } } } base.Dispose(disposing); } } }
当其它的Controller派生于BaseController时,如果用到类型为IXXXService的XXXService,就通过BaseController的AddDisposableObject(object obj)把该XXXService放到BaseController中的DisposableObjects集合属性中,在使用Dispose()销毁这些XXXService。
而在BaseService中也提供了手动垃圾回收机制,可以及时回收CurrentRepository。
最后在BaseRepository中也提供了手动垃圾回收机制,可以及时回收EF上下文。
创建ProductController,使之派生于BaseController:
using System.Web.Mvc; using MySportsStore.IBLL; using Ninject; namespace MySportsStore.WebUI.Controllers { public class ProductController : BaseController { [Inject] IProductService ProductService { get; set; } public ProductController() { this.AddDisposableObject(ProductService); } public ViewResult List() { return View(ProductService.LoadEntities(p => true).AsQueryable()); } } }
对应的Prduct/List.cshtml视图为:
@model IEnumerable<MySportsStore.Model.Product> @{ ViewBag.Title = "List"; Layout = "~/Views/Shared/_Layout.cshtml"; } @foreach (var item in Model) { <div class="item"> <h3>@item.Name</h3> @item.Description <h4>@item.Price.ToString("c")</h4> </div> }
为了能够让EF在第一次运行的时候自动创建数据库并显示,我们还需要在MySportsStore.WebUI中的Web.config中配置连接字符串:
<connectionStrings> ...... <add name="conn" connectionString="Data Source=.;User=some user name;Password=some password;Initial Catalog=MySportsStore;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings>
修改默认路由为:
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional } );
运行,得到如下界面:
在数据库中也新增了MySportsStore数据库:
源码在这里。
“MVC项目实践,在三层架构下实现SportsStore”系列包括: