惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
博客园_首页
博客园 - 聂微东
V
V2EX
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
SegmentFault 最新的问题
J
Java Code Geeks
Last Week in AI
Last Week in AI
The Cloudflare Blog
月光博客
月光博客
雷峰网
雷峰网
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
博客园 - Franky
腾讯CDC
Jina AI
Jina AI
博客园 - 叶小钗
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
量子位
爱范儿
爱范儿
美团技术团队
T
Tailwind CSS Blog
博客园 - 【当耐特】
D
Docker
IT之家
IT之家
V
Visual Studio Blog
P
Proofpoint News Feed
L
LangChain Blog
Engineering at Meta
Engineering at Meta
C
Check Point Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
Recorded Future
Recorded Future

博客园 - 大西瓜3721

SVN分支/合并原理及最佳实践 Web.Config中Runtime节点-DLL版本冲突问题 工作问题 Vue资料 轻松实现WCF服务的构造函数依赖注入 WCF 依赖注入-- Attribute MVC视图分析 C#简单枚举和标志枚举的用法和区别 XDate Admin.NET框架资料 日志管理之log4net+Autofac 关于NopCommerce3.6版用户登录详解 AutoFac注册的动态实例 Named和Keyed NOP源码分析 六 NOP源码分析五---set的存储 NOP源码分析四 Nop源码分析三 NOP源码分析 二 NOP源码分析 一 NopCommerce的资料 IServiceCollection和IServiceProvider 精选10款C#/.NET开发必备类库 11个免费开源后台管理系统模板 H5连接蓝牙打印机打印小票 自定义控件 - 流式布局:TagFlowLayout MVC开源CMS nginx的安装&一个最简单的配置(windows和Centos) DNS解析
控制反转——Autofac框架
大西瓜3721 · 2026-03-07 · via 博客园 - 大西瓜3721

Autofac入门    AutoFac在MVC使用    NetFramework用Autofac依赖注入   理论基础+实战实现AutoFac注入

NopConfig-IConfigurationSectionHandler使用

一、 组件注册方式

1. RegisterType(注册类型):“需要时请new一个”

builder.RegisterType<ExposureInfoViewModel>().AsSelf().SingleInstance();
  • 作用:用于将一个具体的类注册到容器中,告知容器“当需要某个服务时,可以创建这个类的实例来提供它”
  • 原理:告诉容器一个实现类型,当有组件请求该类型(或其实现的接口/基类)时,容器会new一个新的实例(根据生命周期配置,可能是新的,也可能是共享的)
  • 使用:配合As<>来指定其暴露的服务(接口)。

2. RegisterInstance(注册实例):“给你这个现成的,一直用它”

var mySingleton = new MySingletonClass();
builder.RegisterInstance(mySingleton).As<ISingletonService>();
  • 作用:用于将一个已经存在的、特定的对象实例注册到容器中。告诉容器:“不要自己创建新的,每次有人请求这个服务时,都返回 我给你的 这个唯一的、现成的实例”。
  • 原理:你将一个已经实例化好的对象交给容器。容器不会尝试创建它、也不会管理它的销毁。每次解析该服务,返回的都是同一个对象引用。
  • 特点:提供现有对象,容器不负责创建,只负责提供引用。
  • 场景

    • 注册已经在程序启动时创建好的单例对象。
    • 注册一些在容器之外创建和配置的对象(如第三方框架的入口点)。
    • 注册常量值或配置对象。
    • 你想完全控制某个对象的创建和初始化过程,然后将其提供给 DI 容器使用。

3. RegisterModule(注册模块):“把这些相关的注册打包一起执行”

复制代码

public class DataAccessModule : Module
{
    public string ConnectionString { get; set; }

    protected override void Load(ContainerBuilder builder)
    {
        // 在这个模块内部,你可以像在外部一样使用 builder 进行注册
        builder.RegisterType<SqlUserRepository>()
               .As<IUserRepository>()
               .WithParameter(“connectionString”, ConnectionString) // 可以使用模块的属性来配置
               .InstancePerLifetimeScope();

        builder.RegisterType<SqlOrderRepository>()
               .As<IOrderRepository>()
               .WithParameter(“connectionString”, ConnectionString)
               .InstancePerLifetimeScope();

        // 也可以注册其他模块
        // builder.RegisterModule(new LoggingModule());
    }
}

复制代码

//写法一:需要手动创建模块实例、可以在注册前对模块进行配置、适用于需要传递参数的模块
builder.RegisterModule(new DataAccessModule { ConnectionString = “MyConnString” });

//写法二:Autofac 会自动实例化模块、代码更简洁、要求模块有无参构造函数
builder.RegisterModule<DataAccessModule >()
  • 作用:它不是直接注册服务,而是注册一个“模块”。模块是一个包含了一组相关注册的的逻辑单元。它是一种组织和管理注册代码的方式,用于实现关注点分离和模块化设计。
  • 原理:创建一个继承自Autofac.Module的类,在其Load方法中编写一系列的注册语句。然后通过RegisterModule将这个类加入到容器构建器中,类内的所有注册都会被执行。
  • 特点
    • 组织代码:将属于同一功能块(如数据访问、日志、Web API 控制器)的注册封装在一起,让 Global.asax 或 Program.cs 中的代码更简洁。
    • 可配置性:模块可以有自己的属性,允许在注册时进行配置(如上面的连接字符串)。
    • 可重用性:封装好的模块可以在不同的项目中重用。
    • 条件注册:可以在模块的 Load 方法中编写逻辑,实现有条件的动态注册。

二、 服务暴露方式

1. AsSelf()

  • 注册方式:将类本身作为服务注册,即类直接对应注册的服务。
  • 适用场景:适用于类未继承任何接口的情况,或需要明确指定服务类型为类本身。
builder.RegisterType<ExposureInfoViewModel>().AsSelf().SingleInstance();
- builder.RegisterType<ExposureInfoViewModel>():告诉 Autofac 容器注册 ExposureInfoViewModel 类型。这样,当你需要 ExposureInfoViewModel 的实例时,Autofac 能自动创建并注入它。
- .AsSelf():指定注册时以自身类型(ExposureInfoViewModel)来解析。也就是说,只有请求 ExposureInfoViewModel 时才会返回这个实例,而不是以接口或基类的方式。
- .SingleInstance():指定该类型在整个容器生命周期内只创建一个实例(单例模式)。所有请求都会获得同一个 ExposureInfoViewModel 实例。

2. As<接口>()

  • 注册方式:将类注册为指定接口的实现,即通过接口暴露服务。
  • 适用场景:当类继承了接口时使用,可实现接口与类的关联,便于后续通过接口统一调用实现类。
builder.RegisterType<McsfLoggerFactory>().As<ILoggerFactory>().SingleInstance();

- .As<ILoggerFactory>():注册时,声明当请求 ILoggerFactory 接口时,实际提供 McsfLoggerFactory 的实例。也就是说,依赖注入时如果有类需要 ILoggerFactory,Autofac 会注入 McsfLoggerFactory。

3. 联合使用

复制代码

builder.RegisterType<MultiService>().As<IServiceA>().As<IServiceB>().SingleInstance();

 - .As<IServiceA>().As<IServiceB>():允许单个实现类同时作为多个接口的服务提供者,解析IServiceA或IServiceB时返回同一对象实例
 - 典型场景:
    - 日志服务同时实现IFileLogger和IConsoleLogger
    - 数据访问层同时支持IRepository和IQueryProvider接口

复制代码

复制代码

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

- .As<IMyService>().AsSelf():既可通过IMyService解析,也可直接解析MyService类型
- 典型场景:
  - 需要直接访问实现类特有方法(非接口声明的方法)
  - 单元测试中需Mock具体类而非接口

复制代码

三、 生命周期管理方式

1. SingleInstance(单例模式)

  • 在整个容器生命周期内只会创建一个实例,所有解析请求都返回同一个对象
  • 适用于无状态服务或全局共享资源(如配置类、日志服务)
  • 线程安全,适合多线程环境下的共享访问  

复制代码

using Autofac;
using System;

public interface IService { Guid Id { get; } }
public class MyService : IService 
{
    public Guid Id { get; } = Guid.NewGuid();
}

class Program
{
    static void Main()
    {
        var builder = new ContainerBuilder();
        // 关键注册:配置单例生命周期
        builder.RegisterType<MyService>().As<IService>().SingleInstance();

        using (var container = builder.Build())
        {
            // 测试单例行为
            using (var scope1 = container.BeginLifetimeScope())
            {
                var service1 = scope1.Resolve<IService>();
                var service2 = scope1.Resolve<IService>();
                Console.WriteLine($"同作用域实例比对: {service1.Id == service2.Id}"); // True
            }

            // 新建作用域测试
            using (var scope2 = container.BeginLifetimeScope())
            {
                var service3 = scope2.Resolve<IService>();
                var service4 = scope2.Resolve<IService>();
                Console.WriteLine($"跨作用域实例比对: {service3.Id == service4.Id}"); // True
            }
        }
    }
}

复制代码

2. InstancePerDependency(瞬时模式)

  • 每次解析请求都会创建一个新实例,是Autofac的默认行为
  • 适用于需要独立状态的短期对象(如请求处理器、临时计算服务)
  • 可能增加内存开销,频繁创建/销毁对象时需评估性能

复制代码

using Autofac;
using System;

public interface ILogger { void Log(string message); }
public class ConsoleLogger : ILogger 
{
    private Guid _id = Guid.NewGuid();
    public void Log(string message) => 
        Console.WriteLine($"[实例ID:{_id}] {message}");
}

class Program
{
    static void Main()
    {
        var builder = new ContainerBuilder();
        // 关键注册:配置瞬时生命周期(默认行为,显式声明更清晰)
        builder.RegisterType<ConsoleLogger>().As<ILogger>().InstancePerDependency();

        using (var container = builder.Build())
        {
            // 同一作用域内解析两次
            using (var scope = container.BeginLifetimeScope())
            {
                var logger1 = scope.Resolve<ILogger>();//每次调用Resolve()都会生成全新实例,通过Guid验证实例唯一性
                var logger2 = scope.Resolve<ILogger>();
                
                logger1.Log("第一次调用"); // 输出不同实例ID
                logger2.Log("第二次调用");
            }
        }
    }
}

复制代码

???builder.RegisterInstance(ConsoleLogger).As<ILogger>().InstancePerDependency(); 每次请求得到的是同一个实例吗

答:RegisterInstance和InstancePerDependency本身是矛盾且无效的,最终的行为将由容器决定,但通常会产生非预期的结果。

3. InstancePerLifetimeScope(作用域模式)

  • 在同一生命周期作用域内返回同一实例,不同作用域创建不同实例
  • 典型应用场景包括HTTP请求周期(如ASP.NET中每个请求一个作用域)
  • 需显式调用BeginLifetimeScope()创建作用域,避免内存泄漏

  image

复制代码

using Autofac;
using System;

public interface IService { void Execute(); }
public class MyService : IService 
{
    public void Execute() => Console.WriteLine($"实例ID: {this.GetHashCode()}");
}

class Program
{
    static void Main()
    {
        var builder = new ContainerBuilder();
        // 关键注册:配置作用域生命周期
        builder.RegisterType<MyService>().As<IService>().InstancePerLifetimeScope();

        using (var container = builder.Build())
        {
            // 场景1:同一作用域内实例共享
            using (var scope1 = container.BeginLifetimeScope())
            {
                var s1 = scope1.Resolve<IService>();
                var s2 = scope1.Resolve<IService>();
                s1.Execute(); // 输出相同哈希值
                s2.Execute();
            }

            // 场景2:不同作用域创建新实例
            using (var scope2 = container.BeginLifetimeScope())
            {
                var s3 = scope2.Resolve<IService>();
                s3.Execute(); // 输出与scope1不同的哈希值
            }
        }
    }
}

复制代码