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. UVaLive 3905 Meteor (扫描线)

    题意:给定上一个矩形照相机和 n 个流星,问你照相机最多能拍到多少个流星. 析:直接看,似乎很难解决,我们换一个思路,我们认为流星的轨迹就没有用的,我们可以记录每个流星每个流星在照相机中出现的时间段, ...

  2. FileWriter 写文件

    FileWriter fw = new FileWriter("C://Users//pc//Desktop//aaa.txt",true); fw.write("201 ...

  3. 在 beforeSend中设置ajax请求的Content-type

    $.ajaxSetup({        beforeSend: function (xhr, settings) {            if (settings.type == "PO ...

  4. CvvImage在高级别的Opencv2.4.11下的配置以及错误解决办法。

    由于高版本的OpenCV2.4.11里取消了CImage(CvvImage),在此我们可以用老的版本替代. 在需要的地方引入 #include "CvvImage.h" 就可以用了 ...

  5. Codeforces 174B【模拟构造】

    题意: 给你一个串只有小写字母和点,让你构造前缀是1-8,后缀是1-3长度的文件名: 思路: 那么以"."作为分割点,把字符串都拿出来,然后 首段长度<=8 OK; 中间&l ...

  6. CodeForces691C 【模拟】

    这一题的模拟只要注意前后导零就好了... 感受就是... 如果是比赛中模拟题打好..要盯着注意点,测试不同的情况下的注意点..起码要针对性测试10分钟.. 还是蛮简单的,但是自己打烦了,应该,队友代码 ...

  7. 选择Go语言的12个理由

    编者按:多核化和集群化是互联网时代的典型特征,那语言需要哪些特性来应对这些特征呢?多数语言在语法层面并不直接支持协程,而通过库的方式支持的协程的功能也并不完整,比如仅仅提供协程的创建.销毁与切换等能力 ...

  8. Codevs 1140 Jam的计数法

    1140 Jam的计数法 题目描述 Description Jam是个喜欢标新立异的科学怪人.他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩.在他的计数法中,每个 ...

  9. 五粮液【线段树】By cellur925

    题目传送门 考场上感觉的确是线段树,还要维护区间最值...最值怎么维护?还要区间修改?\(update\)的时候加一下就好了吧...之后怎么搞啊?\(qwqwq\)之后好像不太会了...果断删除几乎快 ...

  10. File upload in ASP.NET Core web API

    参考1:File upload in ASP.NET Core web API https://www.janaks.com.np/file-upload-asp-net-core-web-api/ ...