Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它
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替换它的更多相关文章
- ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法
在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...
- [ASP.NET Core 3框架揭秘] 依赖注入[5]: 利用容器提供服务
毫不夸张地说,整个ASP.NET Core框架是建立在依赖注入框架之上的.ASP.NET Core应用在启动时构建管道以及利用该管道处理每个请求过程中使用到的服务对象均来源于依赖注入容器.该依赖注入容 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[10]:与第三方依赖注入框架的适配
.NET Core具有一个承载(Hosting)系统,承载需要在后台长时间运行的服务,一个ASP.NET Core应用仅仅是该系统承载的一种服务而已.承载系统总是采用依赖注入的方式来消费它在服务承载过 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[9]:实现概述
<服务注册>.<服务消费>和<生命周期>主要从实现原理的角度对.NET Core的依赖注入框架进行了介绍,接下来更进一步,看看该框架的总体设计和实现.在过去的多个版 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[7]:服务消费
包含服务注册信息的IServiceCollection集合最终被用来创建作为依赖注入容器的IServiceProvider对象.当需要消费某个服务实例的时候,我们只需要指定服务类型调用IService ...
- [ASP.NET Core 3框架揭秘] 依赖注入[6]:服务注册
通过<利用容器提供服务>我们知道作为依赖注入容器的IServiceProvider对象是通过调用IServiceCollection接口的扩展方法BuildServiceProvider创 ...
- ASP.NET Core技术研究-探秘依赖注入框架
ASP.NET Core在底层内置了一个依赖注入框架,通过依赖注入的方式注册服务.提供服务.依赖注入不仅服务于ASP.NET Core自身,同时也是应用程序的服务提供者. 毫不夸张的说,ASP.NET ...
- [ASP.NET Core 3框架揭秘] 依赖注入:控制反转
ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期
生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...
随机推荐
- QDUOJ 一道简单的数据结构题 栈的使用(括号配对)
一道简单的数据结构题 发布时间: 2017年6月3日 18:46 最后更新: 2017年6月3日 18:51 时间限制: 1000ms 内存限制: 128M 描述 如果插入“+”和“1”到 ...
- 渲染路径-u3d渲染路径比较
Unity支持不同的渲染路径.应具体取决于你的游戏内容和目标平台/硬件来选择使用哪一个.不同的渲染路径有不同的特点和性能特点,主要影响灯光和阴影. 项目所使用的渲染路径在Player S ...
- 基于 Laravel 开发 ThinkSNS+ 中前端的抉择(webpack/Vue)踩坑日记
在上一篇文章< ThinkSNS+基于Laravel master分支,从1到 0,再到0.1>,简单的介绍了 ThinkSNS+ ,这里分享在开发过程中,前端选择的心理活动. Larav ...
- Poj2299 Ultra-QuickSort(另附本质不同逆序对)
Description 给定一个长度为 n(n≤5*10^5) 的序列 a,如果只允许进行比较和交换相邻两个数的操作求至少需要多少次交换才能把 a 从小到大排序. Input The input co ...
- Hexo - Template render error unexpected token
问题与分析 今天发现在使用hexo g时报错如下: FATAL Something's wrong. Maybe you can find the solution here: http://hexo ...
- mysql 安装和修改编码(utf8mb4)
安装mysql(linux 我的环境centos 7) 安装MySQL官方的Yum Repository wget -i -c http://dev.mysql.com/get/mysql57-com ...
- SpringBoot | Hibernate @Transient 注解
在默认情况下,持久化类的所有属性会自动映射到数据表的数据列.如果在实际应用中,不想持久保存某些属性,则可以考虑使用@Transient来修饰它们. 如果一个属性并非数据库表的字段映射,就务必将其标示为 ...
- 最新Centos7安装python3并与python2共存
1.查看是否已经安装Python CentOS 7.2 默认安装了python2.7.5 因为一些命令要用它比如yum 它使用的是python2.7.5. 使用 python -V 命令查看一下是否安 ...
- NOIP前计划
距离NOIp还有13天 距离继续学/退役还有13天 是时候列一波计划了 1. 要学的东西 cdq分治(突然发现cdq分治不太行,而且说不定可以用来代替想不出来的数据结构题) 主席树(写的太少啦,不熟练 ...
- [JSOI2009]密码
Description Input Output Sample Input 10 2 hello world Sample Output 2 helloworld worldhello HINT 一看 ...