ASPNET5 依赖注入(Dependency Injection)

  依赖注入一直是asp.net web框架(Web API,SignalR and MVC)中不可或缺的一部分,但是在以前,这个框架都是各自升级,都有各自的依赖注入实现方式,即使Katana项目想通过Owin将这些项目连接起来,你还是要做统一的容器去支持它们,现在事情有所变化了。

抽象

asp.net团队决定提供依赖注入功能通过提炼最流行的IOC容器中最核心的功能,然后让不同的组件实现这些接口来实现依赖注入。

IServiceProvider

这个最主要的接口,开发都可以通过这个接口去检索Ioc容器中已经注册过的服务,这个接口只有一个方法而已:GetService(Type), 类似于Aotufact里的Container.Resolve<service>,或者Ninject里的Kernel.Get<service>.

所有的MiddleWare有两种方式可以获得所要的IserviceProvider.

  • 应用程序级别:通过HttpContext.ApplicationServices 属性提供给 MiddleWare
  • 请求级别-通过HttpContext.RequestServices属性提供给MiddleWare,这个范围的ServiceProvider通过一个隐式的MIddleWare在最开始的请求管理道中被创建,在请求最后返回响应前被释放。

全部的MiddleWare可通过这些属性去解决他们的服务,例如ASP.NET MVC MIddleWare会通过RequestServices去创建Controllers和他们的依赖

IServiceScope

 

这个接口是容器的一个包装,主要作用是在请求结束后去释放容器

  • IServiceProvider 
  • Dispose()

 

IServiceScopeFactory

很简单的一个接口,只有一个返回IServiceScope的方法CreateServiceScope()

 

所以如果你需要实现一个IOC 容器,就要自己实现以上的接口。

ServiceLifetime

  • Singleton 单个实例在整个应用程序中
  • Scoped  单个实例在范围窗口内

ServiceDescriptor

注册服务的描述信息,

  • ServiceType   用来替换具体实现类的接口,Type类型
  • ImplementationType 上面这个接口的具体实现类型,Type类型
  • Lifetime 服务的生命周期,Singleon,Scoped 或者 Transient
  • ImplementaionFactory 类型Func<IServiceProvider,Object>, 在一些场景中,开发人员希望提供一个工厂方法去创建具体实现类。他们之间是互相独立的,如果你提供了ImplementationType,那不能再提供ImpletentaionFactory.
  • ImplementationInstance 具体事例

  Registering Services

现在注册您的服务,ASPNET5希望您 的Startup类中有个叫ConfigureServices的方法名,带有一系列ServiceDescriptors包裹在IServiceCollection,并什么都不返回。你全部只要做的只是创建一系列ServiceDescriptor,并添加他们到集合,web应用程序会在稍后加载他们并注册到容器中

publicvoidConfigureServices(IServiceCollection services)
{
    var serviceDescriptor = newServiceDescriptor(typeof(IBankManager), typeof(BankManager), ServiceLifetime.Transient);
    services.Add(serviceDescriptor);

    // Add MVC services to the services container.
    services.AddMvc();
}

备注 创建serviceDescriptor有一些繁琐, 这就是你看到一些中间件用扩展方法去创建ServiceDescriptors, 像“service.AddMvc()”

 

下面的伪陈述说明服务启动和ServiceProvider是怎样创建的,相应的代码可以在HostingEngine.Start中找到

应用程序是如何启动的。

  1. Hosting engine 会创建一个IServiceCollection,是ServiceDescriptor的集合对象
  2. Hosting engine 会添加全部它所需要的服务
  3. Hosting engine 会确认在程序集中有个Startup类,并有个ConfigureServices方法
  4. Hosting engine 会去加载这个方法,并传递IServiceCollection
  5. Startup类中的ConfigureSerivces会添加应用程序需要的服务至集合中
  6. Hosting engine 接着会创建 DefaultServiceProvider(ICO容器),并注册服务集合中IServiceCollection中的服务
  7. Hosting engine 会创建一个应用程序构建器(IApplicationBuilder)并给IApplicationBuilder.ApplicationServices分配一,个新的Service Provider,并进一步的使用它
  8. Hosting engin 在Startup.Configuer执行前会创建一个RequestServicesContainerMiddleware中间件,我会在稍后介绍它
  9. Hosting engine 会执行Startup类中 Configure方法,并传递Application Builder去创建中间件。如果需要Service Provider可通过ApplicationServices属性去创建中间件。

 

运行请求

当第一个请求过来时,Httpcontext会被创建并传给第一个Middleware中的Invokde方法中,并会一直传到整个Middleware.但是在处理第一个中间件之前,Application Builder ‘s Service Provider 会被分配到HttpContext.ApplicationServices,确保整个中间件都可以通过这个属性获得需要的服务,不过,你应该记住这是一个应用程序级别的服务提供者,并且依赖于你选择的Ioc容器,如果你使用了它,你的对象可能会一直驻留在应用程序整个生活周期中.

Notein theory, 理论上,作为一个应用开发人员,你不应该直接去使用这个服务提供者,如果要用建议用Service Locator 模式

 

好吧,这是一个应用程序级别的服务提供者,那有没有每次请求范围里的的服务提供者?

在上面列出来的第8步中,我们提到了Hosting engine 会在管道开始之前会创建一个RequestServicesContainerMiddleware中间件,并会第一时间去执行它

publicasyncTask Invoke(HttpContext httpContext)

{

    using(varcontainer = RequestServicesContainer.EnsureRequestServices(httpContext, _services))

    {

        await_next.Invoke(httpContext);

    }

}

回到上面的请求执行中,服务会创建Httpcontext,并分派给 Application-level Service Provider给HttpContext.ApplicationServices,接着会调用第一个中间件,就是上面的RequestServicesContainerMiddleware,它所做的事情就是创建一个范围内的服务提供者并在请求结束时销毁它

它的伪实现是:

  1. 请求正在被RequestServiceContainerMiddleware处理
  2. Invoke方法会通过application-level Service Provider创建一个IServiceScopeFactory.
  3. IServiceScopeFactory会创建一个范围容器(scoped container)
  4. scoped container会被指派给属性HttpContext.RequestServices
  5. Invoke方法调用接下来的Middleware
  6. 当全部的Middleware都被执行完后,并返回到了RequestServiceContainerMiddleware,Scoped Container会被销毁通过"Using"

NoteRequestServicesContainerMiddleware是通过这个包装/帮助类RequestServicesContainer去管理创建和销毁Scoped Service Provider.

HttpContext.RequestServices是请求生命周期的范围服务提供者,后来的所有Middle都可以访问它,例如,如果你查看MvcRouteHandler.InvokeActionAsync你会发现它就是通过这个去创建Controller的

private async Task InvokeActionAsync(RouteContext context, ActionDescriptor actionDescriptor)

{

    var services = context.HttpContext.RequestServices;

    Debug.Assert(services != null);

    var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);

    var optionsAccessor = services.GetRequiredService<IOptions<MvcOptions>>();

    actionContext.ModelState.MaxAllowedErrors = optionsAccessor.Options.MaxModelValidationErrors;

    var contextAccessor = services.GetRequiredService<IScopedInstance<ActionContext>>();

    contextAccessor.Value = actionContext;

    var invokerFactory = services.GetRequiredService<IActionInvokerFactory>();

    var invoker = invokerFactory.CreateInvoker(actionContext);

    if (invoker == null)

    {

        LogActionSelection(actionSelected: true, actionInvoked: false, handled: context.IsHandled);

        throw new InvalidOperationException(

            Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(

                actionDescriptor.DisplayName));

    }

    await invoker.InvokeAsync();

}

Note: 以一次提醒, 你不需要直接去使用Service Provider; 通过构造函数去创建服务,避免Service Locator模式。

时间: 2024-08-05 17:37:15

ASPNET5 依赖注入(Dependency Injection)的相关文章

控制反转(Inversion of Control)与依赖注入(Dependency Injection)

——摘自Rocky Ren的笔记 1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理.所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器. IoC是一个很大的概念,可以用不同的方式来实现.其主要实现方式有两种:<1>依赖查找(Dependency Look

Spring点滴七:Spring中依赖注入(Dependency Injection:DI)

Spring机制中主要有两种依赖注入:Constructor-based Dependency Injection(基于构造方法依赖注入) 和 Setter-based Dependency Injection(基于Setter方法依赖注入) 一.Contructor-based Dependency Injection(基于构造方法注入) 在bean标签中通过使用<constructor-arg />标签来实现 spring.xml <?xml version="1.0&qu

理解依赖注入(Dependency Injection)

理解依赖注入 Yii2.0 使用了依赖注入的思想.正是使用这种模式,使得Yii2异常灵活和强大.千万不要以为这是很玄乎的东西,看完下面的两个例子就懂了. class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $valu

Spring之对象依赖关系(依赖注入Dependency Injection)

承接上篇: Spring中,如何给对象的属性赋值: 1:通过构造函数,如下所示: <!-- 1:构造函数赋初始值 --><bean id="user1" class="com.bie.po.User"><constructor-arg value="10010" type="int"></constructor-arg>      <constructor-arg valu

Spring学习3—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)

一.思想理解 Spring 能有效地组织J2EE应用各层的对象.不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调.运行.Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口.当系统需要重构时,代码的改写量将大大减少. 上面所说的一切都得宜于Spring的核心机制,依赖注入.依赖注入让bean与

【SSH三大框架】Spring基础第二篇:Spring依赖注入的三种方式

控制反转(Inversion of Control)和依赖注入(Dependency Injection): 应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它.也可以说,依赖被注入到对象中.所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转. 对于依赖注入,有三种方式: 1.使用属性的setter方法注入 2.使用构造器注入 3.使用注解注入 下面我们介绍下这三种方式: 一.使用属性的setter方法注入 首先,我们写一个

Spring控制反转与依赖注入(IOC、DI)

IOC: 反转控制   Inverse Of Control DI:依赖注入 Dependency Injection 目的:完成程序的解耦合 解释:在应用系统的开发过程中,有spring负责对象的创建,对象依赖关系的组装,对象属性的初始化,程序员只需要在程序接收spring创建的对象即可. Object obj= new Object(); IOC :  Object obj;  等着接收spring容器创建好的对象,在程序中将对象的创建的权限交出,反转到spring容器中. DI:  某个对

什么是依赖注入

Spring 能有效地组织J2EE应用各层的对象.无论是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调.执行.Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的详细实现,Service对 象无须关心持久层对象的详细实现,各层对象的调用全然面向接口.当系统须要重构时,代码的改写量将大大降低. 上面所说的一切都得宜于Spring的核心机制,依赖注入.依赖注入让bean与bean之间以

控制反转(IoC)与依赖注入(DI)

1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理.所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器. IoC是一个很大的概念,可以用不同的方式来实现.其主要实现方式有两种:<1>依赖查找(Dependency Lookup):容器提供回调接口和上下文环