首页 > 其他分享 >.NET IoC 容器(三)Autofac

.NET IoC 容器(三)Autofac

时间:2024-11-08 11:10:46浏览次数:1  
标签:Autofac RegisterType Zhy builder var NET IoC

.NET IoC 容器(三)Autofac

1 Autofac

Autofac 是一个用于 .NET 应用程序的依赖注入 (Dependency Injection, DI) 容器。它帮助开发人员管理对象的创建和生命周期,使得依赖项的注入更加灵活和可维护。以下是 Autofac 的主要功能和特性概述:

依赖注入 (Dependency Injection)

Autofac 允许你通过构造函数、属性或方法注入依赖项。这样,你可以轻松地将对象的依赖关系传递给需要它们的类,从而提高代码的可测试性和可维护性。

模块化设计 (Modular Design)

Autofac 支持模块化设计,可以将相关的依赖项注册逻辑分组到模块中。这使得大型应用程序的配置更加简洁和易于管理。

生命周期管理 (Lifecycle Management)

Autofac 提供多种对象生命周期管理方式,例如单例 (Singleton)、每次请求 (Instance Per Dependency)、每个生命周期范围 (Instance Per Lifetime Scope) 等,允许你精确控制对象的创建和销毁时机。

注册与解析 (Registration and Resolution)

Autofac 通过流畅的 API 提供了多种注册组件的方式。你可以注册类型、实例、工厂方法,甚至通过扫描程序集自动注册组件。此外,Autofac 的解析功能支持构造函数参数注入、命名参数注入等高级特性。

支持 AOP (Aspect-Oriented Programming)

Autofac 与 AOP 框架(如 Castle Windsor)集成,支持横切关注点(如日志记录、事务管理)的处理,从而使业务逻辑代码更加简洁。

集成支持

Autofac 与许多流行的 .NET 库和框架集成良好,包括 ASP.NET Core、WCF、Web API、MVC 等。通过这些集成,Autofac 可以轻松地管理 web 应用程序中的依赖项。

扩展性

Autofac 具有很高的扩展性,可以通过自定义注册源、生命周期、解析器等方式扩展其功能,以满足特定应用的需求。

2 Nuget 安装

image-20240530133535015

3 实现DI

定义接口

internal interface IComputer
{
}
internal interface IKeyboard
{
}
internal interface IMouse
{
}
internal interface IPerson
{
    IComputer Computer { get; set; }
    IKeyboard Keyboard { get; set; }
    IMouse Mouse { get; set; }
    void Work();
}

定义实现类

internal class ConstructBase
{
    public ConstructBase() 
    {
        Console.WriteLine($"{this.GetType().Name} - 被构造了");
    }
}
internal class LenovoComputer : ConstructBase, IComputer
{
    public LenovoComputer() : base() { }
}
internal class TogarKeyboard : ConstructBase, IKeyboard
{
    public TogarKeyboard() : base() { }
}
internal class LogitechMouse : ConstructBase, IMouse
{
    public LogitechMouse() : base() { }
}
internal class Programmer : ConstructBase, IPerson
{
    public IComputer Computer { get; set; }
    public IKeyboard Keyboard { get; set; }
    public IMouse Mouse { get; set; }

    public Programmer(IComputer computer, IKeyboard keyboard, IMouse mouse) : base()
    {
        Computer = computer;
        Keyboard = keyboard;
        Mouse = mouse;
    }

    public void Work()
    {
        Console.WriteLine("Programmers are building software...");
    }
}

依赖注入

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Programmer>().As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...

4 注入方式

4.1 构造函数注入 | 属性注入 | 方法注入

定义特性用来筛选属性注入

public class InjectPropertyAttribute : Attribute
{

}

定义实现类

public class Gamer : ConstructBase, IPerson
{
    public IComputer Computer { get; set; }
    [InjectProperty]
    public IKeyboard Keyboard { get; set; }
    public IMouse Mouse { get; set; }

    public Gamer(IComputer computer) : base()
    {
        Computer = computer;
    }

    public void Inject(IMouse mouse)
    {
        Mouse = mouse;
    }

    public void Work()
    {
        Console.WriteLine("The player is playing...");
    }
}

4.2 注入实现

// 注入顺序(与编码顺序无关):构造函数注入 > 属性注入 > 方法注入
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()
    // 方法注入
    .OnActivating(e =>
    {
        IMouse mouse = e.Context.Resolve<IMouse>();
        e.Instance.Inject(mouse);
    })
    // 属性注入
    .PropertiesAutowired((g, o) => g.Name == "Keyboard")
    // 构造函数注入
    .UsingConstructor(typeof(IComputer))
    .As<IPerson>();
var container = builder.Build();
IPerson gamer = container.Resolve<IPerson>();
gamer.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
The player is playing...

结果

注入顺序:构造函数注入 > 属性注入 > 方法注入

5 接口注册

5.1 重复注册

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Programmer>().As<IPerson>();
builder.RegisterType<Gamer>()
    // 方法注入
    .OnActivating(e =>
    {
        IMouse mouse = e.Context.Resolve<IMouse>();
        e.Instance.Inject(mouse);
    })
    // 属性注入
    .PropertiesAutowired((g, o) => g.Name == "Keyboard")
    // 构造函数注入
    .UsingConstructor(typeof(IComputer))
    .As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
The player is playing...

调换Gamer和Programmer的注册顺序:

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()
    // 方法注入
    .OnActivating(e =>
    {
        IMouse mouse = e.Context.Resolve<IMouse>();
        e.Instance.Inject(mouse);
    })
    // 属性注入
    .PropertiesAutowired((g, o) => g.Name == "Keyboard")
    // 构造函数注入
    .UsingConstructor(typeof(IComputer))
    .As<IPerson>();
builder.RegisterType<Programmer>().As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...

结论

同一接口多次注册时,后注册的会覆盖前面注册的,若需要实现多重注册,需要指定名称

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()
    // 方法注入
    .OnActivating(e =>
    {
        IMouse mouse = e.Context.Resolve<IMouse>();
        e.Instance.Inject(mouse);
    })
    // 属性注入
    .PropertiesAutowired((g, o) => g.Name == "Keyboard")
    // 构造函数注入
    .UsingConstructor(typeof(IComputer))
    .Named<IPerson>("person");
builder.RegisterType<Programmer>().Named<IPerson>("programmer");
var container = builder.Build();
IPerson programmer = container.ResolveNamed<IPerson>("programmer");
IPerson person = container.ResolveNamed<IPerson>("person");
programmer.Work();
person.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Programmers are building software...
The player is playing...

5.2 指定参数注册

修改接口

internal interface IMouse
{
    string Type { get; set; }
}

修改实现类

internal class LogitechMouse : ConstructBase, IMouse
{
    public LogitechMouse() : base() { }

    public LogitechMouse(string type) : base()
    {
        Type = type;
    }

    public string Type { get; set; }
}

注入

var builder = new ContainerBuilder();
builder.RegisterType<LogitechMouse>().WithParameter("type","502").As<IMouse>();
var container = builder.Build();
IMouse mouse = container.Resolve<IMouse>();
Console.WriteLine("mouse type: " + mouse.Type);

输出

Zhy.IoC.Autofac.LogitechMouse - 被构造了
mouse type: 502

6 生命周期

Instance Per Dependency(默认) 每次请求组件时都会创建一个新的实例。这是默认的生命周期管理模式。

builder.RegisterType<MyService>().As<IMyService>();

Singleton 在整个容器生命周期内,只有一个实例。

builder.RegisterType<MyService>().As<IMyService>().SingleInstance();

Instance Per Lifetime Scope 在每个生命周期范围内,共享一个实例。每个生命周期范围都会创建一个新的实例,但在该范围内共享该实例。

builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();

Instance Per Matching Lifetime Scope 在特定的生命周期范围内共享实例,需要指定标记。

builder.RegisterType<MyService>().As<IMyService>().InstancePerMatchingLifetimeScope("my-scope");

Instance Per Request 通常用于 web 应用程序,在每个 HTTP 请求期间共享一个实例。

builder.RegisterType<MyService>().As<IMyService>().InstancePerRequest();

Externally Owned 组件由外部代码管理生命周期,Autofac 不会在容器释放时释放该实例。

builder.RegisterType<MyService>().As<IMyService>().ExternallyOwned();

Instance Per Dependency 每次依赖请求时都会创建一个新实例。

builder.RegisterType<MyService>().As<IMyService>().InstancePerDependency();

默认生命周期

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
IComputer computer1 = container.Resolve<IComputer>();
Console.WriteLine("computer0: " + computer0.GetHashCode());
Console.WriteLine("computer1: " + computer1.GetHashCode());
Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 22687807
computer0 == computer1: False

单例生命周期

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>().SingleInstance();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
IComputer computer1 = container.Resolve<IComputer>();
Console.WriteLine("computer0: " + computer0.GetHashCode());
Console.WriteLine("computer1: " + computer1.GetHashCode());
Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 32347029
computer0 == computer1: True

每个周期范围一个生命周期

var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>().InstancePerLifetimeScope();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
using (var scope = container.BeginLifetimeScope())
{
    IComputer computer1 = scope.Resolve<IComputer>();
    IComputer computer2 = scope.Resolve<IComputer>();
    Console.WriteLine("computer0: " + computer0.GetHashCode());
    Console.WriteLine("computer1: " + computer1.GetHashCode());
    Console.WriteLine("computer2: " + computer2.GetHashCode());
    Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");
    Console.WriteLine($"computer1 == computer2: {computer1 == computer2}");
}

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 22687807
computer2: 22687807
computer0 == computer1: False
computer1 == computer2: True

7 依赖配置

7.1 Nuget

image-20240530145634223

7.2 配置文件

Json

{
  "components": [
    {
      "type": "Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac",
      "services": [
        {
          "type": "Zhy.IoC.Core.IComputer,Zhy.IoC.Core"
        }
      ],
      "autoActivate": true,
      "instanceScope": "singleinstance"
    },
    {
      "type": "Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac",
      "services": [
        {
          "type": "Zhy.IoC.Core.IKeyboard,Zhy.IoC.Core"
        }
      ],
      "autoActivate": true,
      "instanceScope": "singleinstance"
    },
    {
      "type": "Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac",
      "services": [
        {
          "type": "Zhy.IoC.Core.IMouse,Zhy.IoC.Core"
        }
      ],
      "parameters": {
        "places": 4
      },
      "autoActivate": true,
      "instanceScope": "singleinstance"
    },
    {
      "type": "Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac",
      "services": [
        {
          "type": "Zhy.IoC.Core.IPerson,Zhy.IoC.Core"
        }
      ],
      "autoActivate": true,
      "instanceScope": "singleinstance"
    }
  ]
}

XML

<?xml version="1.0" encoding="utf-8" ?>
<autofac>
	<components name="0">
		<type>Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac</type>
		<services name="0" type="Zhy.IoC.Core.IComputer,Zhy.IoC.Core" />
	</components>
	<components name="1">
		<type>Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac</type>
		<services name="0" type="Zhy.IoC.Core.IKeyboard,Zhy.IoC.Core" />
	</components>
	<components name="2">
		<type>Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac</type>
		<services name="0" type="Zhy.IoC.Core.IMouse,Zhy.IoC.Core" />
	</components>
	<components name="3">
		<type>Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac</type>
		<services name="0" type="Zhy.IoC.Core.IPerson,Zhy.IoC.Core" />
	</components>
</autofac>

调用

var config = new ConfigurationBuilder();
config.AddJsonFile("DI-Autofac.json");
// config.AddXmlFile("DI-Autofac.xml");
var module = new ConfigurationModule(config.Build());
var builder = new ContainerBuilder();
builder.RegisterModule(module);
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();

输出

Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...

8 AOP

8.1 Nuget安装

image-20240530165433656

8.2 定义接口、实现类

public interface IMyService
{
    void DoWork();
}
public void DoWork()
{
    Console.WriteLine("Doing work...");
}

8.3 定义切面

using Castle.DynamicProxy;

public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"Invoking method {invocation.Method.Name} at {DateTime.Now}");
        invocation.Proceed();
        Console.WriteLine($"Method {invocation.Method.Name} has completed at {DateTime.Now}");
    }
}

8.4 容器配置

var builder = new ContainerBuilder();
builder.Register(c => new LoggingInterceptor());
builder.RegisterType<MyService>()
       .As<IMyService>()
       .EnableInterfaceInterceptors()
       .InterceptedBy(typeof(LoggingInterceptor));
var container = builder.Build();
var service = container.Resolve<IMyService>();
service.DoWork();

输出

Invoking method DoWork at 2024/5/30 16:49:34
Doing work...
Method DoWork has completed at 2024/5/30 16:49:34

9 参考资料

IOC容器之Unity与AutoFac_unity autofac-CSDN博客

Autofac/src/Autofac at develop · autofac/Autofac (github.com)

控制容器的反转和依赖关系注入模式 (martinfowler.com)

标签:Autofac,RegisterType,Zhy,builder,var,NET,IoC
From: https://www.cnblogs.com/winemonk/p/18534712

相关文章

  • 分布式事物传递 NetMQ测试
    usingNetMQ;usingNetMQ.Sockets;usingSystem;usingSystem.Threading;namespace消息传递库_NetMQ服务端{internalclassProgram{publicstaticvoidMain(){using(varpublisher=newPublisherSocket()){......
  • DevExpress JS & ASP.NET Core v24.1亮点 - 支持DateOnly/TimeOnly类型
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac,到ASP.NETCore或Vue,DevExtreme包含全面的高性能和响应式UI小部件集合,可在传统Web和下一代移动应用程序中......
  • 【K8S问题系列】Kubernetes Pod节点CrashLoopBackOff 状态【已解决】
    在Kubernetes中,Pod的状态为CrashLoopBackOff表示某个容器在启动后崩溃,Kubernetes尝试重启该容器,但由于持续崩溃,重启的间隔时间逐渐增加。下面将详细介绍CrashLoopBackOff状态的原因、解决方案及相关命令的输出解释。一、CrashLoopBackOff状态的详细介绍描述C......
  • dotnet cli publish 命令行发布脚本 bat shell
    dotnetcli发布脚本publish_remote.bat该脚本实现一键主要发布到远程的共享文件夹中@echooff::定义变量SHARE_PATH:共享文件夹,SOURCE_DIR:代码发布的文件夹,TARGET_DIR:目标文件夹(共享文件夹的映射)setPRO_PATH=.\WebAppsetSHARE_PATH=\\pcmesone\Reportset......
  • chrome浏览器network控制台使用和功能介绍
    chrome浏览器network的控制面板主要分为7大板块1、功能区2、筛选区(功能区漏斗需要开启)3、快照区(功能区需要打开屏幕捕获)4、时间轴区(功能区需要开启overview)5、主显示区6、信息汇总区 一、功能区1、红色圆点代表是否开启network的日志功能,如果灰色的,就代......
  • Acunetix v24.9 发布下载,新增功能概览
    Acunetixv24.9(Linux,Windows)-Web应用程序安全测试Acunetix|WebApplicationSecurityScanner请访问原文链接:https://sysin.org/blog/acunetix/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org重要提示AcunetixPremium现在使用日历化版本命名。请......
  • .net网页验证码、登录验证码
    来源:https://blog.csdn.net/Yuhang_Zhou/article/details/140614304验证码辅助类usingSystem.Drawing;usingSystem.Drawing.Imaging;namespaceXCGApp{///<summary>///验证码辅助类///</summary>publicclassValidateCodeUtil{/......
  • dotnet core微服务框架Jimu ~ 会员注册微服务
     提供会员注册服务,用户必须注册成会员才能享受应用提供的服务,如浏览和发布新闻,但有些服务又需要指定角色的会员才能操作,如所有会员都可以浏览新闻,只有管理员(admin)角色的会员才可以发布新闻。有2个公开的api:CheckName:判断用户名是否可用;Register:根据用户名注册......
  • 使用AMD GPU进行图像分类的ResNet模型
    ResNetforimageclassificationusingAMDGPUs—ROCmBlogs2024年4月9日,作者:LoganGrado。在这篇博客中,我们演示了如何使用ROCm在AMDGPU上训练一个简单的ResNet模型来进行CIFAR10数据集的图像分类。在AMDGPU上训练ResNet模型非常简单,仅需安装ROCm和适当的PyTorch库,无......
  • Acunetix v24.9 发布下载,新增功能概览
    Acunetixv24.9(Linux,Windows)-Web应用程序安全测试Acunetix|WebApplicationSecurityScanner请访问原文链接:https://sysin.org/blog/acunetix/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org重要提示AcunetixPremium现在使用日历化版本命名。请注意,从......