zoukankan      html  css  js  c++  java
  • Asp.net MVC 中使用 Ninject 实现依赖注入

    松耦合、针对抽象编程、不针对实现编程是面向对象设计的原则。依赖注入就是,在一个类的内部,不通过创建对象的实例而能够获得实现了某个公开接口的对象引用。所谓的控制反转也是相同的意思。把依赖的创建转移到了使用这些依赖的类的外部,反转的是依赖的创建。控制反转可以是通过依赖注入和服务定位器模式来实现。依赖注入特别适用于复杂的依赖关系的程序中。

    在Asp.net MVC程序中,经常使用仓储模式来分离控制器和数据访问层。有利于进行单元测试和测试驱动开发(TDD)。

    实现依赖注入可以使控制器和使用的仓储层相互独立,使用控制器减少了对仓储层的依赖。依赖注入可以通过直接构造方法注入和属性注入、IOC容器注入三种方式。

    在Asp.net MVc中,使用NInject 实现依赖注入的步骤如下

    1、安装 Ninject

    在VS中在程序包管理控制台中输入 Install-Package Ninject -Project ApplicationName。则NuGet或自动下载和安装、引用Ninject的程序集。也可以直接使用 vs 的 工具 的管理窗口操作抽完Nuget下载。

    2、 可以有两种方式。

    第一种:

    1、:建立一个控制器工厂类,接管控制器对象的创建。在ASP.NET MVC中,一个客户端请求是在特定Controller的Action中进行处理的。 默认情况下,ASP.NET MVC使用内置的Controller工厂类 DefaultControllerFactory来创建某个请求对应的Controller实例。有时候默认的Controller工厂不能满足我们实际的需求,我们就需要对这种默认行为进行扩展,即创建一个继承自DefaultControllerFactory类的自定义Controller工厂类并重写其中的一些方法。

    public class NinjectControllerFactory: DefaultControllerFactory

    {  

        private IKernel ninjectKernel;

       protected override IController GetControllerInstance(RequestContext request requestContext,Type controllerType)

         {

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

          }

         // 添加绑定。

        private void AddBindings()

         {    

           _kernel.Bind<IStudentRepository>().To<StudentRepository>();

         }

    }

    上面代码中的 ninjectKernel.Get(controllerType) 可获取到一个Controller实例。在这里如果手动实例化Controller类是一个非常复杂的过程,我们不知道Controller类有没有带参数的构造函数,也不知道构造函数的参数是什么类型。而使用Ninject只需要使用上面的一个Get方法就可以,Ninject内部会自动处理所有的依赖关系,智能地创建我们需要的对象。

    2、需在Global.asax文件的Application_Start方法中添加下面代码:

    protected void Application_Start() {
        ......
    
        //设置Controller工厂
        ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
    }

    第二种方式:实现 System.Web.MVc 命名空间下的IDepenednctyResolver接口
    完整的代码如下:
    1、模型类:Student

    public class Student
    {
    public int ID { get; set; }

    public string LastName { get; set; }

    public string FirstName { get; set; }

    public DateTime EnrollmentDate { get; set; }


    public string FullName
    {
    get { return FirstName + LastName; }
    }
    }
    }

    2、建立仓储接口  IStudentRepository类,和实现接口StudentRepository类

    public interface IStudentRepository:IDisposable
    {
      IQueryable <Student> GetStudents();  //IQueryable<>和IEumrable<>都可以,但使用 IQueryable<>效率高一些,因为他是延迟查询,只会查出需要使用的数据。为什么用IQueryable而不用IEnumerable作为返回类型?答案是:使用IQueryable,EF会根据调用者的Linq表达式先生成相应的SQL查询语句,然后到数据库中执行查询,查询出来的数据即是用户想要的数据;而使用IEnumerable,Linq表达式的过滤、排序等操作都是在内存中发生的,即EF会先从数据库中把整个表的数据查询出来放在内存中,然后由调用者使用Linq语句进行过滤、排序等操作。

    IQueryable虽然可以很智能地根据Linq表达式生成相应的SQL语句,但毕竟有一个分析Linq表达式的过程,相对来说性能比IEnumerable要差。那么我们什么时候用IEnumerable,什么时候用IQueryable呢?我想,对于少量的数据(比如从数据库中读取应用程序相关的系统信息)和不需要对数据进行过滤操作的情况,用IEnumerable比较适合;对于数据量较大需要对数据进行过滤(比如分页查询)的情况,则用IQueryable比较合适

    Student GetStudentByID(int? studetnID);
    void InsertStduent(Student student);
    void DeleteStudent(int? studentID);
    void UpdateStudent(Student student);
    void Save();
    }

     

    //实现仓储接口。

    public class StudentRepository:IStudentRepository,IDisposable
    {
    private SchoolContext context;

    public StudentRepository(SchoolContext context)
    {
    this.context = context;
    }
    public IQueryable <Student> GetStudents()

    {
    return context.Students.ToList();
    }

    public Student GetStudentByID(int? studetnID)
    {
    return context.Students.Find(studetnID);
    }

    public void InsertStduent(Student student)
    {
    context.Students.Add(student);
    }

    public void DeleteStudent(int? studentID)
    {
    Student student = context.Students.Find(studentID);
    context.Students.Remove(student);
    }

    public void UpdateStudent(Student student)
    {
    context.Entry(student).State = EntityState.Modified;
    }

    public void Save()
    {
    context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
    if (!this.disposed)
    {
    if (disposing)
    {
    context.Dispose();
    }
    }
    }
    public void Dispose()
    {
    Dispose(true);
    GC.SuppressFinalize(this);
    }
    }

    3、实现IDendenctyResolver接口的 NinjectDependencyResolver。

    public class NinjectDependencyResolver:IDependencyResolver
    {
    private readonly IKernel _kernel;       //创建Ninject内核实例


    public NinjectDependencyResolver()
    {
    _kernel = new StandardKernel();
    AddBindings();
    }

    private void AddBindings()    //绑定接口到实现了该接口的类


    {
        _kernel.Bind<IStudentRepository>().To<StudentRepository>();
     // _kernel.Bind<IStudentRepository>().To<StudentRepositoryInMemory>();

    }

    public object GetService(Type serviceType)   //【实现IDendcyResolver 接口的两个方法
    {
    return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
    return _kernel.GetAll(serviceType);
    }
    }

    4、同样需要的 globe.asax 中注册依赖解析器

    protected void Application_Start()
    {
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    DependencyResolver.SetResolver(new NinjectDependencyResolver()); //注册依赖解析容器。
    }

    5、控制器

    public class StudentController : Controller
    {
    private IStudentRepository studentRepository;
    //如果你正使用Dependenty injection 或者DI,你不需要默认的构造方法,因为DI软件将始终保证正确的仓储对象被提供。
    public StudentController(IStudentRepository studentRepository)
    {
    this.studentRepository = studentRepository;
    }

    // GET: Student
    public ActionResult Index()
    {
    return View(studentRepository.GetStudents());
    }

    StudentController的构造函数接受了一个IStudentRepository参数,当StudentController被实例化的时候,Ninject就为其注入了StudentRepository的依赖。

    6、修改由基架自动生成的控制器方法,控制器由直接访问 数据库上下文变成访问 仓储接口。

    // GET: Student
    public ActionResult Index()
    {
    return View(studentRepository.GetStudents());
    }




    另外:还可以使用 Kernel内核对象来获取 接口的实现,比如
    Student student =ninjectKernel.Get<IStudentRepository>(); GET<>方法返回的是绑定的 StudentRepository对象。
  • 相关阅读:
    从零开始~
    SVN
    了解下几个证书~~
    重要的技术发展趋势
    求职路上英语面试试题问答大全
    C语言比java重要吗?
    开源solr搜索服务器配置
    全文索引 与 Like 的实现原理
    nginx搭建多个站点
    .Solr构建索引查询索引
  • 原文地址:https://www.cnblogs.com/liuyuanhao/p/4982359.html
Copyright © 2011-2022 走看看