• 轻量级IoC框架Ninject.NET搭建


    说在之前的话

    IOC的概念相信大家比较熟悉了,习惯性称之为依赖注入或控制反转,园子里对基于MVC平台IOC设计模式已经相当多了,但大家都只知道应该怎么应用一个IOC模式,比如Ninject, Unity等常用框架,并不清楚为什么要用它,它们之间有什么区别,换句话说在实际应用中的横向对比的文章比较少,本文旨在抛砖引玉,欢迎大家讨论

    Ninject模式实现

    VS工具提供了很方便的ninject模式引入,新建一个asp.net mvc项目后,执行几行命令就即可

     1.添加Ninject。工具-->Nuget程序包管理器-->程序包管理器控制台,输入下面的命令:

    Install-Package Ninject -version 3.0.1.10
    Install-Package Ninject.Web.Common -version 3.0.0.7
    Install-Package Ninject.MVC3 -Version 3.0.0.6

    分别引用了

    Minject

    Ninject.Web.Common

    Ninject.Web.MVC

    Ninject模式下,有两种常用的方式实现,一种是通过Activitor激活Controller的方式,另一种方式MVC5推荐的DependencyResolver方式

    首先做好准备工作,假设有一个Employee实体类

    public class Employee
        {
            [Display(Name="ID")]
            public string Id { get; private set; }
            [Display(Name = "姓名")]
            public string Name { get; private set; }
            [Display(Name = "性别")]
            public string Gender { get; private set; }
            [Display(Name = "出生日期")]
            [DataType(DataType.Date)]
            public DateTime BirthDate { get; private set; }
            [Display(Name = "部门")]
            public string Department { get; private set; }
    
            public Employee(string id, string name, string gender, DateTime birthDate, string department)
            {
                this.Id = id;
                this.Name = name;
                this.Gender = gender;
                this.BirthDate = birthDate;
                this.Department = department;
            }
        }

    对实现类提供的操作服务

    public interface IEmployeeRepository
        {
            IEnumerable<Employee> GetEmployees(string id = "");
        }

    添加对服务的实现

    public class EmployeeRepository: IEmployeeRepository
        {
            private static IList<Employee> employees;
            static EmployeeRepository()
            {
                employees = new List<Employee>();
                employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee1", "", new DateTime(1987, 8, 24), "销售部"));
                employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee2", "", new DateTime(1991, 7, 10), "人事部"));
                employees.Add(new Employee(Guid.NewGuid().ToString(), "Employee3", "", new DateTime(1993, 9, 21), "财务部"));
            }
            public IEnumerable<Employee> GetEmployees(string id = "")
            {
                return employees.Where(e => e.Id == id || string.IsNullOrEmpty(id) || id == "*");
            }
        }

    1.看看最新的DependencyResolver方式的实现,新建类 NinjectDependencyResolver 来实现IDependencyResolver的GetService和GetSerivices两个接口,

    注意这里的Bind的方法,这里是为Controller注册Service的核心代码,所有Controller中以来的Ninject接口服务都在这里注册(接口与实现分离,Ninject托管)

    public class NinjectDependencyResolver : IDependencyResolver
        {
            private IKernel kernel;
    
            public NinjectDependencyResolver()
            {
                kernel = new StandardKernel();
                Bind();
            }
    
            public NinjectDependencyResolver(IKernel kernelParam)
            {
                kernel = kernelParam;
                Bind();
            }
    
            public object GetService(Type serviceType)
            {
                return kernel.TryGet(serviceType);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                return kernel.GetAll(serviceType);
            }
    
            private void Bind()
            {
                this.kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
            }

    上面已经注册了服务,现在需要把注册信息告诉Controller的Builder工厂;MVC5把这个工作已经自动化了,当最上面引入Ninject.Web.Common的时候,已经在App_Start文件夹下自动生成了NinjectWebCommon,注意RegisterServices方法需要我们主动将上面已经写好的注册类NinjectDependencyResolver初始化给Mvc.DependencyResolver对象,大家不难发现这里是对当前程序的全局设置,事实上NinjectWebCommon的Start方法比Global中Application_Start方法更早的执行,已便对整个应用程序做好初始化

    public static class NinjectWebCommon 
        {
            private static readonly Bootstrapper bootstrapper = new Bootstrapper();
    
            /// <summary>
            /// Starts the application
            /// </summary>
            public static void Start() 
            {
                DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
                DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
                bootstrapper.Initialize(CreateKernel);
            }
            
            /// <summary>
            /// Stops the application.
            /// </summary>
            public static void Stop()
            {
                bootstrapper.ShutDown();
            }
            
            /// <summary>
            /// Creates the kernel that will manage your application.
            /// </summary>
            /// <returns>The created kernel.</returns>
            private static IKernel CreateKernel()
            {
                var kernel = new StandardKernel();
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
                
                RegisterServices(kernel);
                return kernel;
            }
    
            /// <summary>
            /// Load your modules or register your services here!
            /// </summary>
            /// <param name="kernel">The kernel.</param>
            private static void RegisterServices(IKernel kernel)
            {
                System.Web.Mvc.DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
            }        
        }

    到此Ninject已经引入完成了,怎么使用呢

    下面添加一个对Employee操作的Controller, 声明一个IEmployeeRepository服务,注意这里是接口,在上面打上[Inject]标记后,在Action方法中就可以随意使用Employee服务了。可能有人疑惑这里的IEmployeeRepository没实例化如何就能使用,其实上面实现的RegisterServices方法中,已经对ControllerBuilder的初始化了注册信息,所有实现Controller的子类在实例化时根据[Inject]标记查找注册信息中的实现类进行初始化服务,在Action中引用的已经是实例化好的服务实体了

    public class EmployeeController : Controller
        {
            [Inject]
            public IEmployeeRepository Repository { get; set; }
    
            public ActionResult Index()
            {
                var employees = this.Repository.GetEmployees();
                return View(employees);
            }
    
            public ActionResult Detail(string id)
            {
                Employee employee = this.Repository.GetEmployees(id).FirstOrDefault();
                if (null == employee)
                {
                    throw new HttpException(404, string.Format("ID为{0}的员工不存在", id));
                }
                return View(employee);
            }
        }

    读到这算是知其然了,感觉很麻烦,为什么不直接在controller里new一个EmployeeRepository,接口都省了,想到这点说明你很勤于思考,回答这点需要说下为什么要引入Ninject,或者说IOC有什么好处,多做了那么多复杂的动作,好处呢

    1. 这里托管给Jinject的服务实例会根据访问量最大限度的节约实例创建,如果省了这些,我们不得不在每个controller中保留要依赖的服务对象占用资源

    2.controller中并没有直接对服务的实现类依赖,而是引用的接口,也就是说,controller开发者不需要关心服务是否已经现实,只在接口已经声明就可以开发,这即是实现当下最流行的敏捷开发的基础,后端服务的实现和前端的交互可同时进行(注意这里的接口集应该独立在新建的程序集中而不是放在MVC应用程序集,后面基于IOC框架设计再扩展)

    3.MVC应用程序使用的所有服务都托管在Ninject而不是散落在controller(甚至到页面上), 对于安全策略,日志记录,错误处理可以集中处理,相当于对前端有了一个总阀

    4.对于后端的扩展和模块化设计提供了便捷,这点比较宽泛

    附言:

    MVC5中的NinjectWebCommon类的CreateKernel方法中提供了IHttpModule的Bind,这里为喜欢玩管道的打开了一扇窗,让这版MVC成了一个新的过渡


    2.Activitor激活实现

    这里也是在ControllerBuilder初始化时做文章

    public class NinjectControllerActivator : IControllerActivator
        {
            public IKernel Kernel { get; private set; }
            public NinjectControllerActivator()
            {
                this.Kernel = new StandardKernel();
                AddBindings();
            }
            public IController Create(RequestContext requestContext, Type controllerType)
            {
                return (IController)this.Kernel.TryGet(controllerType) as IController;
            }
            private void AddBindings()
            {
                this.Kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
            }
        }

    对应在Global的Application_Start方法中是这样告诉Builder的,这里通过初始化CountrollerFactory对象实现服务注册信息的注入

    NinjectControllerActivator controllerActivator = new NinjectControllerActivator();
    DefaultControllerFactory controllerFactory = new DefaultControllerFactory(controllerActivator);
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);

    看到ControllerFactory可能有人会想起Unity的方式,后面将Ninject比对下Unity

    参考文章:

    http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-032.html

    http://www.cnblogs.com/stoneniqiu/p/4594642.html

  • 相关阅读:
    paip.代码生成器数据源格式最佳实践
    paip.hibernate list 返回位null的解决
    paip.hibernate save 失败的解决
    paip.提升效率---提升绑定层次--form绑定取代field绑定
    paip.python NameError name 'xxx' is not defined
    paip.sqlite 管理最好的工具 SQLite Expert 最佳实践总结
    paip.输入法英文词库的处理 python 代码 o4
    paip.判断文件是否存在uapi python php java c#
    paip.截取字符串byLastDot方法总结uapi python java php c# 总结
    paip.python连接mysql最佳实践o4
  • 原文地址:https://www.cnblogs.com/johnx/p/6806168.html
Copyright © 2020-2023  润新知