Autofac入门与替代ASP.NET CO re、 ABP依赖注入容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: Autofac入门与替代ASP.NET CO re、 ABP依赖注入容器

Autofac 的使用


我们在 .NET Core 控制台程序中进行测试和实践。


1,简单的实践


首先我们添加一个接口以及实现:

public interface IMyService { }
    public class MyService : IMyService { }


然后在 Main 方法中注册以及构建容器:

class Program
    {
        private static IContainer Container;
        static void Main(string[] args)
        {
            // 创建容器构建器
            var builder = new ContainerBuilder();
            // 注册组件
            builder.RegisterType<MyService>().As<IMyService>();
            // ...
            // 构建容器
            Container = builder.Build();
        }
    }


我们则可以这样使用:

public static void Test()
        {
            // 生命周期管理
            using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                // 获取实例
                IMyService myService = scope.Resolve<IMyService>();
            }
        }


.AS() 用于暴露组件的服务。

这就是 Autofac 的简单使用。

下面我们来讨论更详细的使用方法以及实践。


2,注册组件


前面我们通过 ContainerBuilder 对象来注册组件并且告诉容器有哪些组件暴露了哪些服务。


组件的注册方式有很多种,前面我们使用了反射的方法去注册,传递一个泛型参数进去:

.RegisterType<MyService>()


或者通过类型(Type)进行注入:

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


当然,通过反射注册的组件,它会自动为你注入相应的构造函数。

你也可以通过 UsingConstructor 方法,要求容器实例化组件时,使用哪一个构造函数:

builder.RegisterType<MyComponent>()
       .UsingConstructor(typeof(ILogger), typeof(IConfigReader));


我们也可以提前将实例注册进去:

MyService t = new MyService();
            builder.RegisterInstance(t).As<IMyService>();


这样就会生成一个单例应用。

不过,因为 RegisterInstance(t) 会保留对 t 的引用,也就是说将这个实例注册到容器的实例中。


当然你可以使用 Lambda 表达式树来 new :

builder.Register(c => new MyService()).As<IMyService>();


这样可以避免外部有引用。

如果你不想这样,可以使用 ExternallyOwned 方法,这样就会生成一个新的实例到容器中。如果你会 AutoMapper ,这样会很容易理解。

builder.RegisterInstance(t).As<IMyService>().ExternallyOwned();


3,Lambda 注册组件


如果一个类型的构造函数依赖于另一个接口,那么这种类型作为组件注册,就会复杂一些,我们可以使用 Lambda 表达式来注册组件。


有以下几个接口和类型:

public interface IA { }
    public class A : IA { }
    public interface IB { }
    public class B : IB
    {
        private IA _a;
        public B(IA a)
        {
            _a = a;
        }
    }


那么我们可以先注册 A 类型,再注册 B 类型:

builder.RegisterType<A>().As<IA>();
            builder.Register(c => new B(c.Resolve<IA>()));


当然,这里使用表达式来介绍方便性。你也可以这样使用:

builder.RegisterType<A>().As<IA>();
            builder.RegisterType<B>().As<IB>();

实例化 B 类型时,会自动为其注入构造函数。


4,注册泛型


如果要对泛型类型进行注册:

public interface IA { }
    public class A<T> : IA { }


则可以使用 RegisterGeneric 来注册泛型组件:

builder.RegisterGeneric(typeof(A<>)).As<IA>();


当然,如果 IA 也是泛型的话,应该使用 .As(typeof(IA))


5,属性注入


注册组件时,使用 PropertiesAutowired 方法,那么容器在生成实例时,会自动注入属性。

有以下类型:

public interface IA { }
    public class A : IA { }
    public interface IB { }
    public class B : IB
    {
        public IA A { get; set; }
    }


注册:

builder.RegisterType<A>().As<IA>();
            builder.RegisterType<B>().PropertiesAutowired().As<IB>();

那么,容器会自动给 B 类型的属性注入依赖。

当然,这样会为类型的每一个属性注入依赖。


如果我们只是想为某个属性注入的话,可以这样 使用 WithProperty 方法,例如:

builder.RegisterType<B>().WithProperty("A",new A()).As<IB>();


6,解析服务

注册组件后,调用 Build() 方法生成了容器(IContainer)。

然后使用 Resolve 方法在其生命周期内解析服务。


参考前面的示例如下:

using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                // 获取实例
                IMyService myService = scope.Resolve<IMyService>();
            }


要注意的是,实例是从生命周期中解析(ILifetimeScope scope),而不是从容器中(IContainer)中解析。

如果想知道一个服务是否已经被注册,我们可以使用 ResolveOptional()TryResolve() 方法。


using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                IB b;
                // 获取实例
                if (scope.TryResolve<IB>(out b))
                {
                }
            }


在解析时,可以传递参数,这样可以控制容器生成实例时,使用能够构造函数实例化类型。

Autofac提供了多种不同的参数匹配机制:

  • NamedParameter - 通过名称匹配目标参数
  • TypedParameter - 通过类型匹配目标参数 (需要匹配具体类型)
  • ResolvedParameter - 灵活的参数匹配


示例如下:

namespace AutofacTest
{
    public interface IA { }
    public class A : IA
    {
        public A(string a, string b) { Console.WriteLine($"a = {a}, b = {b}"); }
    }
    class Program
    {
        private static IContainer Container;
        static void Main(string[] args)
        {
            // 创建容器构建器
            var builder = new ContainerBuilder();
            builder.RegisterType<A>().As<IA>();
            // 构建容器
            Container = builder.Build();
            Test();
        }
        public static void Test()
        {
            // 生命周期管理
            using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                IA b = scope.Resolve<IA>(new NamedParameter("a", "测试"), new NamedParameter("b", "测试"));
            }
        }
    }


或者改成:

IA b = scope.Resolve<IA>(new TypedParameter(typeof(string), "测试"), new TypedParameter(typeof(string), "测试"));


另外,Autofac 还支持多种关系的服务解析,其种类如下:


7,生命周期


关于生命周期,你可以参考:https://autofaccn.readthedocs.io/zh/latest/lifetime/index.html

前面我们看到,要获取实例,使用了


using (ILifetimeScope scope = Container.BeginLifetimeScope())
{
}


BeginLifetimeScope 创建一个生命周期作用域,生命周期的作用域是可释放的并且可以追踪组件的释放。

你可以使用 Dispose() 或者 using{} 形式进行生命周期释放。


你也可以:

using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                using (ILifetimeScope sc = scope.BeginLifetimeScope())
                {
                }
            }


8,实例作用域

实例的作用域决定了对于暴露出来的同一个服务的实例如何在多个请求之间共享。组件的作用域是在注册组件是决定的,然后显式地调用 Resolve() 返回地示例,就会出现具体的行为(单例等)。


8.1 一个依赖一个实例

在 .NET 默认的依赖注入框架中,称为 'transientfactory ,对于每个请求,每次返回的都是不一样的实例。Autofac 默认就是这种模式。


你也可以使用 InstancePerDependency 显式声明:

builder.RegisterType<Worker>().InstancePerDependency();


8.2 单一实例

SingleInstance 方法可以注册组件为单一实例:

builder.RegisterType<Worker>().SingleInstance();


8.3 生命周期作用域实例

使用 InstancePerLifetimeScope可以设置组件在一个生命周期作用域内,获取到的实例都是同一个。


另外,层叠的生命周期作用域也是不同的,例如下面的示例中,结果是 True,False

using (ILifetimeScope scope = Container.BeginLifetimeScope())
            {
                IA b = scope.Resolve<IA>();
                IA bb = scope.Resolve<IA>();
                Console.WriteLine(b == bb);
                using (ILifetimeScope sc = scope.BeginLifetimeScope())
                {
                    IA bbb = sc.Resolve<IA>();
                    Console.WriteLine(b == bbb);
                }
            }


另外 Autofac 还有其它方法的作用域管理,请点击链接了解: https://autofaccn.readthedocs.io/zh/latest/lifetime/instance-scope.html


9,Autofac 其它需要学习的知识

Autofac 是非常厉害的框架,本文只是挑入门基础部分讲解,其它自由度高一些的复杂一些的知识点例如:

需要查看文档学习,这里不再赘述。


ASP.NET Core


ASP.NET Core 中,2.x 和 3.x 的差异比较多,这里只以 3.x 作为示例。


1,默认依赖注入


ASP.NET Core 中,默认的依赖注入,可以使用 ConfigureServices 方法,在此方法中注册即可。

例如:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IA, A>();
        }


2,使用 Autofac


如果要在 ASP.NET Core 中使用 Autofac 作为依赖注入容器,则还需要安装名为 Microsoft.Extensions.DependencyInjection.Abstractions 的 Nuget 包。


然后在 Program 的 Host 中加上

.UseServiceProviderFactory(new AutofacServiceProviderFactory())


示例如下:

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
               .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });


然后在 Startup 类中,加上 ConfigureContainer 方法,然后在此方法中注册需要的组件:

public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterType<A>().As<IA>();
        }


最后在 ConfiguraServices 方法中添加:

services.AddOptions();


即可使用 Autofac 作为 ASP.NET Core 依赖注入容器。

完整代码:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddOptions();
            services.AddControllers();
        }
        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterType<A>().As<IA>();
        }


ABP


首先要求你添加了一个 ASP.NET Core 程序,然后配置 ABP ,引入相应的包。可以参考 https://docs.abp.io/zh-Hans/abp/latest/Getting-Started-AspNetCore-Application


ABP 中,默认也是使用 ConfigureServices 直接注入即可,使用示例:

public class AppModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddTransient<IA, A>();
        }
    }


context.Services 即为 IServiceCollection 对象。

当然,ABP 也可以使用 Autofac 作为依赖注入容器。

ABP 中要使用 Autofac,需要引用 Volo.Abp.Autofac 包。

然后在模块中加上 [DependsOn(typeof(AbpAutofacModule))] 特性。


[DependsOn(typeof(AbpAutofacModule))]
    public class AppModule : AbpModule{}


然后在 Startup 中的 ConfiguraServices 方法中,添加 ABP 模块, 并且设置使用 Autofac。

public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication<BasicAspNetCoreApplication.AppModule>(options=>
            {
                options.UseAutofac();
            });
        }
相关文章
|
25天前
|
存储 SQL 索引
Python入门:7.Pythond的内置容器
Python 提供了强大的内置容器(container)类型,用于存储和操作数据。容器是 Python 数据结构的核心部分,理解它们对于写出高效、可读的代码至关重要。在这篇博客中,我们将详细介绍 Python 的五种主要内置容器:字符串(str)、列表(list)、元组(tuple)、字典(dict)和集合(set)。
Python入门:7.Pythond的内置容器
|
25天前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
3月前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
78 1
|
3月前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
80 5
|
3月前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
71 3
|
4月前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
129 4
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
4月前
|
Kubernetes Cloud Native 开发者
云原生入门:从容器到微服务
本文将带你走进云原生的世界,从容器技术开始,逐步深入到微服务架构。我们将通过实际代码示例,展示如何利用云原生技术构建和部署应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和启示。
|
10天前
|
安全 持续交付 云计算
课时5:阿里云容器服务:最原生的集成Docker和云服务
阿里云容器服务以服务化形式构建容器基础设施,大幅提升开发效率,简化应用部署流程。通过Docker容器和DevOps工具(如Jenkins),实现自动化部署与迭代,优化企业内部复杂部署问题。该服务支持GPU调度、混合云架构无缝迁移,并与阿里云产品体系无缝集成,提供安全防护、网络负载均衡等多重功能支持。凭借微服务架构,帮助企业突破业务瓶颈,提高资源利用率,轻松应对海量流量。
课时5:阿里云容器服务:最原生的集成Docker和云服务
|
1月前
|
Ubuntu API 网络虚拟化
ubuntu22 编译安装docker,和docker容器方式安装 deepseek
本脚本适用于Ubuntu 22.04,主要功能包括编译安装Docker和安装DeepSeek模型。首先通过Apt源配置安装Docker,确保网络稳定(建议使用VPN)。接着下载并配置Docker二进制文件,创建Docker用户组并设置守护进程。随后拉取Debian 12镜像,安装系统必备工具,配置Ollama模型管理器,并最终部署和运行DeepSeek模型,提供API接口进行交互测试。
352 15
|
2月前
|
Ubuntu NoSQL Linux
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
219 6
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结