搭建大型MVC实际项目框架-利用Ninject

 如何利用Ninject搭建大型MVC实际项目

前言:

  学习MVC也有一段时间了,想抽点时间来总结、分享下,但总是被耽搁了,这几天在看一本书《Pro ASP.NET MVC 3》,网上也有中文版《精通ASP.NET MVC3》的书,里面有一个实际项目的搭建,看到后觉得挺有意思的,原来可以这么整~~,于是我自己动手搭建了整个基础框架,项目的整体架构如下图所示:(ps:有部分人看到就一个简单的项目就搞这么多接口,觉得头都大了,我还是建议您认真读完全文,说不定你会从中受益)

 如图1

整个架构分三层:

1Web层,这里主要是Controllers(控制器),Views(视图)

2Model层,这里主要是Entities(实体)和Repositories(仓储),封装对数据库的操作

3Service层(服务层),这里主要是调用Models层,实现相关业务逻辑

至于为什么这么分,可能有部分人会认为整复杂了,这个我们在后面具体代码中会进行说明

 

下面进入实战环节:

首先第一步我们先建一个解决方案,起个通俗易懂的名称(MvcTest~~,然后“右键”添加一个MVC4.0项目(MvcTest),这一步很简单,我就不贴图了。(选择空的项目)然后我们重复上面步骤,“右键”添加一个类库(MvcTest.Models),同样添加一个类库(MvcTest.Services),到此基本的项目添加完毕(如图1所示)

Models类库中,我们添加几个文件夹,EntitiesRepositoriesRepositories“右键”添加一个类ProductDbContext:

using System;

using System.Collections.Generic;

using System.Data.Entity;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using MvcTest.Models.Entities;

namespace MvcTest.Models

{

    public class ProductDbContext : DbContext

    {

        public DbSet<Product> Products { get; set; }

    }

}

然后在Entities中添加一个实体类Product:(ps:这里我不得不吐槽下我插入代码,每次都插入到顶部去了,不知道是我不会用还是怎么回事)

using System;

using System.Collections.Generic;

using System.ComponentModel.DataAnnotations;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace MvcTest.Models.Entities

{

    public class Product

    {

        [Key]

        public int ProductId { get; set; }

        public string ProductName { get; set; }

    }

}

 然后在IRepositories中添加一个泛型接口:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using MvcTest.Models.Entities;

namespace MvcTest.Models.IRepositories

{

    public interface IDataRepository<T> where T : class

    {

        T[] GetAll();

    }

}

然后我们添加一个实现该接口的类ProductRepository:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using MvcTest.Models.Entities;

using MvcTest.Models.IRepositories;

namespace MvcTest.Models.Repositories

{

    public class ProductRepository : IDataRepository<Product>

    {

        private ProductDbContext productDbContext = new ProductDbContext();

        public Product[] GetAll()

        {

            return productDbContext.Products.ToArray();

        }

    }

}

到此该类库的设计已经完成,通过上面的代码我们可以知道,这个类库主要是封装对数据库的操作,在三层中叫(DAL)数据访问层。

 

下一步我们来完成Services类库的搭建,首先我们新建2个文件夹,IServices和Services,同样和上面步骤一样,在IServices中添加一个接口IDataService:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using MvcTest.Models.IRepositories;

using MvcTest.Models.Entities;

 

namespace MvcTest.Services.IServices

{

    public interface IDataService<T> where T : class

    {

        T[] GetAll();

    }

}

然后在Services添加一个实现该接口的类ProductService:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using MvcTest.Models.Entities;

using MvcTest.Models.IRepositories;

using MvcTest.Services.IServices;

 

namespace MvcTest.Services.Services

{

    public class ProductService : IDataService<Product>

    {

        private IDataRepository<Product> productRepository;

        public ProductService(IDataRepository<Product> productRepository)

        {

            this.productRepository = productRepository;

        }

        public Product[] GetAll()

        {

            return productRepository.GetAll();

        }

    }

}

到此该类库的搭建也已经完成,在这里我有几点要说明下:

1、库直接的引用关系:

由于Services层要操作Models层,所有要在添加Models的引用

2、对于上面2个类库,有部分人认为这2个类库的代码完全一样,要实现的功能也一样,我在这里说下我的看法,Models层只是封装对数据库的基本操作(CRUD(增、删、查、改)),而Services层是业务逻辑层,在我这个示例中因为只是作为演示,所以就只是简单的设计,但实际中业务逻辑是复杂的,往往要通过调用Models层不同的方法来进行组合。

 

下面进入我们最后一个环节,Web层的搭建,这个也是整个项目的重点所在,通过图1我们可以看到Web层和新建的没什么大区别,但仔细一看的话,其中有几个重要的改变。

1、NinjectManage这个文件夹中有一个NinjectControllerFactory类,他继承自DefaultControllerFactory(表示默认情况下已注册的控制器工厂),这个基类是用来生成我们的Controller实例的,我们要做的就是重写里面的方法GetControllerInstance(通过Ninject获取Controller实例)。

2、我们的Web层中引用了Ninject这个IOC组件,简单的引用方法就是右键项目,选择管理NuGet程序包,搜索Ninject,然后在线安装这个组件。

 

图2

 

图3

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using Ninject;

using Ninject.Modules;

using MvcTest.Models.IRepositories;

using MvcTest.Models.Repositories;

using MvcTest.Services.IServices;

using MvcTest.Services.Services;

using MvcTest.Models.Entities;

namespace MvcTest.NinjectManage

{

    public class NinjectControllerFactory : DefaultControllerFactory

    {

        private IKernel ninjectKernel;

        public NinjectControllerFactory()

        {

            ninjectKernel = new StandardKernel(new MyModule());

        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)

        {

            return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);

        }

    }

    public class MyModule : NinjectModule

    {

        public override void Load()

        {

            Bind<IDataRepository<Product>>().To<ProductRepository>();

            Bind<IDataService<Product>>().To<ProductService>();

        }

    }

}

代码中就是通过Ninject这个Ioc组件进行解耦的,网上也有很多Ioc组件,大家可以去尝试,至于Ninject的具体使用,根据上面代码,我来做一些解释,首先我定义一个MyModule继承自NinjectModule,然后override一下Load方法,在Load里面我们通过Bind方法来表示IDataRepository<Product>和ProductRepository的关系,然后在NinjectControllerFactory 的构造器中我们把MyModule实例化到IKernel 。我们在之前的Services层中ProductService中有这样一段代码:

        private IDataRepository<Product> productRepository;

        public ProductService(IDataRepository<Product> productRepository)

        {

            this.productRepository = productRepository;

        }

在这个构造函数中,我们和Models层进行交互的只是IDataRepository这个接口,并没有和具体的实现类(可以自由更换)进行挂钩,这种方法叫“构造器注入”(也可以通过属性注入),这样做的体现出这个架构的好处了,我们可以自由替换业务实现类和数据访问实现类。

 

最后一个步骤就是新建一个HomeController进行测试:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MvcTest.Models;

using MvcTest.Models.Entities;

using MvcTest.Services.IServices;

 

namespace MvcTest.Controllers

{

    public class HomeController : Controller

    {

        //

        // GET: /Home/

        private IDataService<Product> productService;

        public HomeController(IDataService<Product> productService)

        {

            this.productService = productService;

        }

        public ActionResult Index()

        {

            Product[] products = productService.GetAll();

            return View(products);

        }

    }

}

我们在这个控制器中,也是通过“构造器注入”来调用Services层。

 

最后一点需要注意的是,在Global.asax中:

图4

这一步的作用是我们不是使用默认的DefaultControllerFactory来进行Controller实例的获取,而是我们继承该类的子类NinjectControllerFactory

结尾:

至此,整个项目的搭建基本完成,如果大家有什么问题,可以在下方留言,如果您觉得好,请不要吝啬您右小脚轻轻一点“推荐”,您的鼓励是我前进的动力,谢谢!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。