Autofac 依赖注入小知识

控制反转/依赖注入 IOC/DI

依赖接口而不依赖于实现,是面向对象的六大设计原则(SOLID)之一。即依赖倒置原则(Dependence Inversion Principle)

生命周期分为三种,具体如下

  • Singleton 单例(全局唯一实例)
  • Scoped 范围 (在同一个生命周期内是同一个实例)
  • Transient 瞬时(每次请求都是一个新的实例)

使用说明

创建ASP.NET Core 3.0+的项目,并安装Autofac

dotnet add package Autofac.Extensions.DependencyInjection

在Program 中Host主机指定 .UseServiceProviderFactory(new AutofacServiceProviderFactory()).

UseServiceProviderFactory调用Autofac提供程序,附加到通用宿主机制。

public class Program
{
public static void Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
+ .UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webHostBuilder => {
webHostBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
})
.Build(); host.Run();
}
}

在StartUp中配置

public class Startup
{
public Startup(IConfiguration configuration)
{
this.Configuration = configuration;
} public IConfiguration Configuration { get; private set; } + public ILifetimeScope AutofacContainer { get; private set; } public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
} // ConfigureContainer is where you can register things directly
// with Autofac. This runs after ConfigureServices so the things
// here will override registrations made in ConfigureServices.
// Don't build the container; that gets done for you by the factory.
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory
// for you.
+ builder.RegisterModule(new MyApplicationModule());
} public void Configure(
IApplicationBuilder app,
ILoggerFactory loggerFactory)
{
+ this.AutofacContainer = app.ApplicationServices.GetAutofacRoot(); loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
}
}

定义注入实现

public class MyApplicationModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
}
}
  • 注册泛型仓储
builder.RegisterGeneric(typeof(AuditBaseRepository<>)).As(typeof(IAuditBaseRepository<>)).InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(AuditBaseRepository<,>)).As(typeof(IAuditBaseRepository<,>)).InstancePerLifetimeScope();
  • 一个接口多个实现,使用Named,区分、参数为字符串即可。

注册服务

builder.RegisterType<IdentityServer4Service>().Named<ITokenService>(typeof(IdentityServer4Service).Name).InstancePerLifetimeScope();
builder.RegisterType<JwtTokenService>().Named<ITokenService>(typeof(JwtTokenService).Name).InstancePerLifetimeScope();

根据Name获取哪个服务

private readonly ITokenService _tokenService;
public AccountController(IComponentContext componentContext, IConfiguration configuration)
{
bool isIdentityServer4 = configuration.GetSection("Service:IdentityServer4").Value?.ToBoolean() ?? false;
_tokenService = componentContext.ResolveNamed<ITokenService>(isIdentityServer4 ? typeof(IdentityServer4Service).Name : typeof(JwtTokenService).Name);
}

可通过appsettings.json中配置,可决定是哪个服务

  "Service": {
"IdentityServer4": false
}
  • 基于接口的注入

AsImplementedInterfaces Specifies that a type from a scanned assembly is registered as providing all of its implemented interfaces.

指定将扫描程序集中的类型注册为提供其所有实现的接口。

根据接口ITransientDependency可以得到有哪些类继承了此接口,并判断是类,不是抽象类,不是泛型。

所有继承类接口的类,将以接口的方式自动注入实例。可直接使用接口即可。

  • InstancePerDependency 瞬时 (每次请求都是一个新的实例)
  • InstancePerLifetimeScope 范围(在同一个生命周期内是同一个实例)
  • SingleInstance 单例(全局唯一实例)
    public class DependencyModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(r => r.FullName.Contains("LinCms.")).ToArray(); //每次调用,都会重新实例化对象;每次请求都创建一个新的对象;
Type transientDependency = typeof(ITransientDependency);
builder.RegisterAssemblyTypes(currentAssemblies)
.Where(t => transientDependency.GetTypeInfo().IsAssignableFrom(t) && t.IsClass && !t.IsAbstract && !t.IsGenericType)
.AsImplementedInterfaces().InstancePerDependency(); //同一个Lifetime生成的对象是同一个实例
Type scopeDependency = typeof(IScopedDependency);
builder.RegisterAssemblyTypes(currentAssemblies)
.Where(t => scopeDependency.GetTypeInfo().IsAssignableFrom(t) && t.IsClass && !t.IsAbstract && !t.IsGenericType)
.AsImplementedInterfaces().InstancePerLifetimeScope(); //单例模式,每次调用,都会使用同一个实例化的对象;每次都用同一个对象;
Type singletonDependency = typeof(ISingletonDependency);
builder.RegisterAssemblyTypes(currentAssemblies)
.Where(t => singletonDependency.GetTypeInfo().IsAssignableFrom(t) && t.IsClass && !t.IsAbstract &&!t.IsGenericType)
.AsImplementedInterfaces().SingleInstance(); }
}

如果不写继承,如何批量注入呢。

1.类名有规则

2.基于特殊标签

3.继承接口。

  • 类名有规则

    比如仓储后缀,全是Repository,其中Assembly为仓储的实现所在程序集。将自动注入所有的仓储,仓储必须有接口。
    Assembly assemblysRepository = Assembly.Load("LinCms.Infrastructure");
builder.RegisterAssemblyTypes(assemblysRepository)
.Where(a => a.Name.EndsWith("Repository"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
  • 注入服务后就执行一段逻辑
builder.RegisterType<MigrationStartupTask>().SingleInstance();
builder.RegisterBuildCallback(async (c) => await c.Resolve<MigrationStartupTask>().StartAsync());

动态代理

dotnet add package Autofac.Extras.DynamicProxy
dotnet add package Castle.Core.AsyncInterceptor
  • 服务注册

AOP+属性注入+以后缀为Service的服务实现,注入Scope 范围的生命周期+启用接口的拦截器。

  • 使用EnableInterfaceInterceptors创建执行拦截的接口代理,
  • 使用EnableClassInterceptors() 动态对子类进行重写, 执行virtual方法的拦截
builder.RegisterType<UnitOfWorkInterceptor>();
builder.RegisterType<UnitOfWorkAsyncInterceptor>(); List<Type> interceptorServiceTypes = new List<Type>()
{
typeof(UnitOfWorkInterceptor),
}; Assembly servicesDllFile = Assembly.Load("LinCms.Application");
builder.RegisterAssemblyTypes(servicesDllFile)
.Where(a => a.Name.EndsWith("Service") && !a.IsAbstract && !a.IsInterface && a.IsPublic)
.AsImplementedInterfaces()//接口注入
.InstancePerLifetimeScope()//生命周期:范围
.PropertiesAutowired()// 属性注入
.InterceptedBy(interceptorServiceTypes.ToArray())//声明拦截器
.EnableInterfaceInterceptors();//启用接口的拦截器。

这二个类,请参考如下代码

Autofac.Extras.DynamicProxy依赖Castle.Core,即只支持同步方法的拦截。

异步方法的拦截需要安装包:Castle.Core.AsyncInterceptor

  • 异步方法,分为有/无返回值:async Task RunAsync(),asyn Task<Result> RunAsync()
  • 同步方法:void Run(),Result Run()

同步拦截

1.定义拦截器

public class CallLogger : IInterceptor
{
TextWriter _output; public CallLogger(TextWriter output)
{
_output = output;
} public void Intercept(IInvocation invocation)
{
_output.Write("Calling method {0} with parameters {1}... ",
invocation.Method.Name,
string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())); invocation.Proceed(); _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
}
}

2.注册拦截器。

// Named registration
builder.Register(c => new CallLogger(Console.Out))
.Named<IInterceptor>("log-calls"); // Typed registration
builder.Register(c => new CallLogger(Console.Out));

将拦截器与要拦截的类型 关联

[Intercept(typeof(CallLogger))]
public class First
{
public virtual int GetValue()
{
// Do some calculation and return a value
}
} // This attribute will look for a NAMED
// interceptor registration:
[Intercept("log-calls")]
public class Second
{
public virtual int GetValue()
{
// Do some calculation and return a value
}
}

链接

Autofac 依赖注入小知识的更多相关文章

  1. 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入

    一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...

  2. 【干货】利用MVC5+EF6搭建博客系统(二)测试添加数据、集成Autofac依赖注入

    PS:如果图片模糊,鼠标右击复制图片网址,然后在浏览器中打开即可. 一.测试仓储层.业务层是否能实现对数据库表的操作 1.在52MVCBlog.IRepository程序集下创建IsysUserInf ...

  3. asp.net mvc4 简单使用Autofac依赖注入小结

    1,首先使用 NuGet下载适当的Autofac版本 文件一,Autofac.3.5.2 文件二,Autofac.Mvc4.3.1.0 1,接口类 public interface IReposito ...

  4. ASP.NETCore使用AutoFac依赖注入

    原文:ASP.NETCore使用AutoFac依赖注入 实现代码 1.新建接口类:IRepository.cs,规范各个操作类的都有那些方法,方便管理. using System; using Sys ...

  5. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  6. Autofac依赖注入

    简介 Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改 .它的实现方式是将常规的.net类当做 组件 处理. ...

  7. Autofac依赖注入容器

    依赖注入容器-- Autofac https://github.com/danielpalme/IocPerformance Unity 更新频率高,微软的项目Grace 综合性能更高 目录: 一.简 ...

  8. Quartz使用AutoFac依赖注入问题小结

    theme: channing-cyan highlight: a11y-dark 背景 最近在做一个需求,就是在Job中捕捉异常,然后通过邮件或者消息的方式推送给指定人员,在需求实现的过程中遇到的一 ...

  9. Autofac 依赖注入

    介绍 Autofac是一款IOC框架,很轻量级性能非常高,自动注入很给力. NuGet Autofac:Autofac控制反转容器核心 Autofac.MVC5:提供IDependencyResolv ...

随机推荐

  1. 学习java 7.6

    学习内容: 方法重写注意事项:子类不能重写父类的私有方法 子类的访问权限不比父类的低(父类默认,子类可以是默认也可以是public) java中继承的注意事项:java中类只支持单继承,java中类支 ...

  2. python生成器浅析

    A 'generator' is a function which returns a generator iterator. It looks like a normal function exce ...

  3. day09搭建均衡负载和搭建BBS博客系统

    day09搭建均衡负载和搭建BBS博客系统 搭建BBS博客系统 本次搭建bbs用到的技术 需要用到的: 1.Nginx+Django 2.Django+MySQL 环境准备 主机 IP 身份 db01 ...

  4. Git的使用-一个分支完全替换另一个分支

    之前公司git分支混乱,今天花时间整理了一下,在合并分支的时候遇到一个问题: 一个很久没有拉取远程代码的分支与master分支合并时,出现冲突之外,还会丢失文件,很头疼,然后找到了下面的方法,可以直接 ...

  5. Can static functions be virtual in C++?

    In C++, a static member function of a class cannot be virtual. For example, below program gives comp ...

  6. canal整合springboot实现mysql数据实时同步到redis

    业务场景: 项目里需要频繁的查询mysql导致mysql的压力太大,此时考虑从内存型数据库redis里查询,但是管理平台里会较为频繁的修改增加mysql里的数据 问题来了: 如何才能保证mysql的数 ...

  7. SpringAOP简单例子

    这个只是个简单AOP例子,包括前置通知,后置通知,环绕通知,和目标对象.写这个例子的主要目标只是想让想学AOP的能更快地入门,了解一下如何去配置AOP里面的东东.目标对象的接口:IStudent.ja ...

  8. Servlet(4):一个简单的注册页面

    一. 注册要求 1. 一个注册页面 username (文本框) password:密码 (密码框) passwordYes :再次输入密码(密码框) hobby (多选框) sex (单选框) in ...

  9. Spring Cloud集成RabbitMQ的使用

    同步 or 异步 前言:我们现在有一个用微服务架构模式开发的系统,系统里有一个商品服务和订单服务,且它们都是同步通信的. 目前我们商品服务和订单服务之间的通信方式是同步的,当业务扩大之后,如果还继续使 ...

  10. shell脚本采集系统cpu、内存、磁盘、网络信息

    有不少朋友不知道如何用shell脚本采集linux系统相关信息,包括cpu.内存.磁盘.网络等信息,这里脚本小编做下讲解,大家一起来看看吧. 一.cpu信息采集 1),采集cpu使用率采集算法:通过/ ...