Asp.Net Core 提供了默认的依赖注入容器 IServiceCollection,它是一个轻量级的依赖注入容器,所以功能不多,只是提供了基础的一些功能,要实现AOP就有点麻烦,因此在实际工作当中,我们常常会使用第三方依赖注入容器替换掉Asp.Net Core自带的依赖注入容器。

  我们先来看下Asp.Net Core自带依赖注入容器IServiceCollection的主要用法,虽然说在工作中经常会被替换掉,但有些情况下使用该自带的就已经足够了,所以自然也就需要先了解它的使用方法。

  IServiceCollection依赖注入生命周期和其他大多数依赖注入容器一样,分为 瞬时生命周期、单例和请求单例。我们可以在Startup.cs文件中的ConfigureServices方法中直接使用它。这里我们单独把它拿出来看一下具体怎么使用,我们定义ITestService1,ITestService2,ITestService3,ITestService4以及他们的4个实现类。

IServiceCollection container = new ServiceCollection();
container.AddTransient<ITestService1, TestService1>();//瞬时生命周期
container.AddSingleton<ITestService2, TestService2>();//单例:全容器都是一个
container.AddScoped<ITestService3, TestService3>();//请求单例:一个请求作用域是一个实例
container.AddSingleton<ITestService4>(new TestService4()); var provider = container.BuildServiceProvider();
ITestService1 testService1 = provider.GetService<ITestService1>();
ITestService1 testService2 = provider.GetService<ITestService2>();
Console.WriteLine(object.ReferenceEquals(testService1, testService2));//输出 false ITestService2 testService2_1 = provider.GetService<ITestService2>();
ITestService2 testService2_2 = provider.GetService<ITestService2>();
Console.WriteLine(object.ReferenceEquals(testService2_1, testService2_2));//输出 true ITestService3 testService3_1 = provider.GetService<ITestService3>();
ITestService3 testService3_2 = provider.GetService<ITestService3>();
Console.WriteLine(object.ReferenceEquals(testService3_1, testService3_2));//输出 true var scope1 = provider.CreateScope();
var scope2 = provider.CreateScope();
ITestService3 testService3_3 = scope1.ServiceProvider.GetService<ITestService3>();
ITestService3 testService3_4 = scope2.ServiceProvider.GetService<ITestService3>();
Console.WriteLine(object.ReferenceEquals(testService3_3, testService3_4)); //输出 false ITestService4 testService4_1 = provider.GetService<ITestService4>();
ITestService4 testService4_2 = provider.GetService<ITestService4>();
Console.WriteLine(object.ReferenceEquals(testService4_1, testService4_2)); //输出 true

  上述代码已经可以很好的阐述了IServiceCollection的用法,但是这些也只是基本的功能,接下来我们就来看下使用Autofac如何替换掉IServiceCollection。

   Autofac是一个Microsoft .NET的IoC容器。 它管理类与类之间的依赖关系,使得应用程序层级之间实现了解耦,不至于在应用程序变得越来越复杂的情况下难以修改。

   那么现在就一起来看看怎么使用Autofac来替换掉Asp.Net Core自带的依赖注入容器吧,首先先来介绍最常用也是被推荐使用的构造函数注入方式。在Autofac官方文档中有例子可参考。要使用Autofac替换IServiceCollection,我们需要在Startup.cs文件中将ConfigureServices方法的返回值从void修改为 IServiceProvider。

  在开始之前,我们需要先从Nuget下载安装Autofac,可以使用如下命令进行安装

Install-Package Autofac.Extensions.DependencyInjection -Version 4.4.

  接下来随便定义两个测试接口和实现类

 public interface ITestServiceA
{
void Show();
} public interface ITestServiceB
{
void Show();
} public class TestServiceA : ITestServiceA
{
public void Show()
{
Console.WriteLine("This is TestServiceA....");
}
} public class TestServiceB : ITestServiceB
{
public void Show()
{
Console.WriteLine("This is TestServiceB....");
}
}

  接下来我们修改Startup.cs的ConfigureServices方法

// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSession();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<AutofacInitModule>();
// Populate 方法是最重要的,如果没有调用这个方法,则无法将注入到 IServiceCollection的内置对象填充到autofac中,像控制器注入,Log注入等,程序会报错。
containerBuilder.Populate(services); var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}

  AutofacInitModule类是继承了Autofac.Module类的子类,我们可以重写Load方法进行Autofac的初始化注入,当然也可以直接写在Startup文件的ConfigureServices方法中,单独抽出来会显得不那么臃肿,优雅一些。

using Autofac;

namespace WebApplication2
{
internal class AutofacInitModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterType<TestServiceB>().As<ITestServiceB>(); // builder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance(); //单例
}
}
}

  现在我们就可以在Controller中使用了

public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ITestServiceA _serviceA;
private readonly ITestServiceB _serviceB; public HomeController(ILogger<HomeController> logger, ITestServiceA serviceA, ITestServiceB serviceB)
{
this._logger = logger;
this._serviceA = serviceA;
this._serviceB = serviceB;
} public IActionResult Index()
{
this._serviceA.Show();
this._serviceB.Show();
this._logger.LogWarning("this is logger....");
return View();
}
}

  运行程序,可以看到_logger、_serviceA、_serviceB都成功的被创建了。

  那么上述是使用的autofac的构造函数注入,虽然是最被推荐的也是最常用的注入方式,但是autofac也提供了属性注入的方式,下面我们也了解一下。

  修改Startup.cs的ConfigureServices方法和AutofaceInitModule类

// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSession();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddControllersAsServices(); var containerBuilder = new ContainerBuilder(); // Populate 方法是最重要的,如果没有调用这个方法,则无法将注入到 IServiceCollection的内置对象填充到autofac中,像控制器注入,Log注入等,程序会报错。
containerBuilder.Populate(services); containerBuilder.RegisterModule<AutofacInitModule>(); var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
using Autofac;
using Microsoft.AspNetCore.Mvc;
using System.Linq; namespace WebApplication2
{
internal class AutofacInitModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//注册服务
builder.RegisterType<TestServiceA>().As<ITestServiceA>().PropertiesAutowired();
builder.RegisterType<TestServiceB>().As<ITestServiceB>().PropertiesAutowired(); //注册所有控制器
var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray(); builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); // builder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance(); //单例
}
}
}

需要注意的是 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddControllersAsServices();和

containerBuilder.Populate(services);需要写在注入服务之前,属性注入才能成功。

    public class HomeController : Controller
{
//private readonly ILogger<HomeController> _logger;
//private readonly ITestServiceA _serviceA;
//private readonly ITestServiceB _serviceB; public ILogger<HomeController> Logger { get; set; }
public ITestServiceA ServiceA { get; set; }
public ITestServiceB ServiceB { get; set; } //public HomeController(ILogger<HomeController> logger, ITestServiceA serviceA, ITestServiceB serviceB)
//{
// this._logger = logger;
// this._serviceA = serviceA;
// this._serviceB = serviceB;
//} public IActionResult Index()
{
//this._serviceA.Show();
//this._serviceB.Show();
//this._logger.LogWarning("this is logger...."); Logger.LogWarning(ServiceA.Show());
Logger.LogWarning(ServiceB.Show()); return View();
}
}

  运行可以看到成功的结果

  最后,在一开始之前,我们提到Asp.Net Core自带的依赖注入容器在实现AOP的功能很麻烦,在工作中常常会替换成第三方的依赖注入容器,那么现在我们再来看一下autofac怎么实现AOP。

  Autofac实现AOP需要引入Autofac.Extras.DynamicProxy库,通过Nuget添加该库

Install-Package Autofac.Extras.DynamicProxy -Version 4.5.

  接着为了实现AOP,我们定义如下类和接口

using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace WebApplication2
{
public class AutofacTestAop : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"invocation.Methond={invocation.Method}, invocation.Arguments={string.Join(",", invocation.Arguments)}"); invocation.Proceed(); //继续执行TestAop.Show Console.WriteLine($"Method {invocation.Method} Excuted");
}
} public interface ITestAop
{
void Show();
} [Intercept(typeof(AutofacTestAop))]
public class TestAop : ITestAop
{
private ILogger<TestAop> _logger; public TestAop(ILogger<TestAop> logger)
{
this._logger = logger;
} public void Show()
{
this._logger.LogWarning("this is TestAop .....");
}
}
}

  AutofacTestAop为实现了IInterceptor的类,它的Intercept方法就是用来做AOP的调用的。除了实现这个方法外,在需要添加AOP功能的类上需要添加特性 [Intercept(typeof(AutofacTestAop))] 。最后需要在AutofacInitModule中配置一下启用 EnableInterfaceInterceptors。

using Autofac;
using Autofac.Extras.DynamicProxy;
using Microsoft.AspNetCore.Mvc;
using System.Linq; namespace WebApplication2
{
internal class AutofacInitModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//注册服务
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterType<TestServiceB>().As<ITestServiceB>(); builder.Register(c => new AutofacTestAop());
builder.RegisterType<TestAop>().As<ITestAop>().EnableInterfaceInterceptors(); // builder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance(); //单例
}
}
}

  最后在HomeController中调用ITestAop的Show方法就会先执行AutofacTestAop里的Intercept方法了。

Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它的更多相关文章

  1. ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法

    在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...

  2. [ASP.NET Core 3框架揭秘] 依赖注入[5]: 利用容器提供服务

    毫不夸张地说,整个ASP.NET Core框架是建立在依赖注入框架之上的.ASP.NET Core应用在启动时构建管道以及利用该管道处理每个请求过程中使用到的服务对象均来源于依赖注入容器.该依赖注入容 ...

  3. [ASP.NET Core 3框架揭秘] 依赖注入[10]:与第三方依赖注入框架的适配

    .NET Core具有一个承载(Hosting)系统,承载需要在后台长时间运行的服务,一个ASP.NET Core应用仅仅是该系统承载的一种服务而已.承载系统总是采用依赖注入的方式来消费它在服务承载过 ...

  4. [ASP.NET Core 3框架揭秘] 依赖注入[9]:实现概述

    <服务注册>.<服务消费>和<生命周期>主要从实现原理的角度对.NET Core的依赖注入框架进行了介绍,接下来更进一步,看看该框架的总体设计和实现.在过去的多个版 ...

  5. [ASP.NET Core 3框架揭秘] 依赖注入[7]:服务消费

    包含服务注册信息的IServiceCollection集合最终被用来创建作为依赖注入容器的IServiceProvider对象.当需要消费某个服务实例的时候,我们只需要指定服务类型调用IService ...

  6. [ASP.NET Core 3框架揭秘] 依赖注入[6]:服务注册

    通过<利用容器提供服务>我们知道作为依赖注入容器的IServiceProvider对象是通过调用IServiceCollection接口的扩展方法BuildServiceProvider创 ...

  7. ASP.NET Core技术研究-探秘依赖注入框架

    ASP.NET Core在底层内置了一个依赖注入框架,通过依赖注入的方式注册服务.提供服务.依赖注入不仅服务于ASP.NET Core自身,同时也是应用程序的服务提供者. 毫不夸张的说,ASP.NET ...

  8. [ASP.NET Core 3框架揭秘] 依赖注入:控制反转

    ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样 ...

  9. [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期

    生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...

随机推荐

  1. 精通BitmapData

    一.构造方法: var bmd:BitmapData=new BitmapData(200,100,true,0xffff0000); 参数说明: 1.宽 2.高 3.是否使用32位填充位图(包括al ...

  2. C++里的强制类型转换符reinterpret_cast、static_cast 、dynamic_cast、const_cast 区别

    C 风格(C-style)强制转型如下: (T) exdivssion // cast exdivssion to be of type T 函数风格(Function-style)强制转型使用这样的 ...

  3. AtCoder Regular Contest 061 E - すぬけ君の地下鉄旅行【最短路】

    具体题解又要搬大哥的了,嘿嘿~ 请点击:G点我 这道题目的难点就是同一家公司的路直接走不需要再花费,然后多了一个公司这个东西,这个不像是边的副权值(瞎说的)之类的东西,这是对于路来说的,路的属性... ...

  4. P4463 [国家集训队] calc(拉格朗日插值)

    传送门 设\(dp[i][j]\)为考虑\(i\)个数,其中最大值不超过\(j\)的答案,那么转移为\[dp[i][j]=dp[i-1][j-1]\times i\times j+dp[i][j-1] ...

  5. Sublime Text 报“Pylinter could not automatically determined the path to lint.py

    Pylinter could not automatically determined the path to lint.py. please provide one in the settings ...

  6. python 基础(十四) 正则表达式

    正则表达式 概念: 正则匹配就是一个模糊的匹配 只要符合我的匹配规则 就会认为是正确的数据(精确的匹配) 1.[] #代表原子表把想要匹配的内容写入原子表中   匹配包含的任意一位字符 [a]     ...

  7. Codeforces 1119D(贡献计算)

    题目传送 排序看一看. 关键点在于发现性质: 算一个点的贡献时: 1.与后一个有重叠.\[当 a[i] + r >= a[i + 1] + l, 即 r - l >= a[i + 1] - ...

  8. Hive_Hive的数据类型

    Hive Basic Data Type: Basic Types: tinyint/samllint/int/bigint float/double boolean string Complex T ...

  9. hdu 3686 Traffic Real Time Query System 点双两通分量 + LCA。这题有重边!!!

    http://acm.hdu.edu.cn/showproblem.php?pid=3686 我要把这题记录下来. 一直wa. 自己生成数据都是AC的.现在还是wa.留坑. 我感觉我现在倒下去床上就能 ...

  10. Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果

    建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...