Autofac

本文详细介绍Autofac框架的基础知识及其在.NET项目中的应用。包括Autofac的优点、安装方法、基本使用流程,以及如何在控制台程序和ASP.NET MVC项目中实现依赖注入。
原创链接

为什么使用AutoFac?

       Autofac是.NET领域最为流行的IOC框架之一,传说是速度最快的一个:

优点:

  • 它是C#语言联系很紧密,也就是说C#里的很多编程方式都可以为Autofac使用,例如可以用Lambda表达式注册组件
  • 较低的学习曲线,学习它非常的简单,只要你理解了IoC和DI的概念以及在何时需要使用它们
  • XML配置支持
  • 自动装配
  • 与Asp.Net MVC 集成
  • 微软的Orchad开源程序使用的就是Autofac,从该源码可以看出它的方便和强大

上面的优点我也是拷的别人文章里面的,上面的这个几乎所有讲Autofac博文都会出现的。这个也是首次学习,所以我们还是记录的细一点。

怎么使用Autofac

通过VS中的NuGet来加载AutoFac,引入成功后引用就会出现Autofac。

imageimage

     1、我们做一个简单的例子先用一下

就拿数据访问来做案例把,一个数据请求有两个类,一个是Oracle 一个是SQLSERVER。我们在使用的时候可以选择调用那个数据库。

1.1 我们先定义一个数据访问的接口和访问类。

复制代码
/// <summary>
    /// 数据源操作接口
    /// </summary>
    public interface IDataSource
    {
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <returns></returns>
        string GetData();
    }
复制代码

 

复制代码
/// <summary>
    /// SQLSERVER数据库
    /// </summary>
    class Sqlserver : IDataSource
    {
        public string GetData()
        {
            return "通过SQLSERVER获取数据";
        }
    }
复制代码

 

复制代码
/// <summary>
    /// ORACLE数据库
    /// </summary>
    public class Oracle : IDataSource
    {
        public string GetData()
        {
            return "通过Oracle获取数据";
        }
    }
复制代码

 

最普通的方式大家都会的吧! 如果最普通的方式调用SQLSERVER怎么写?

复制代码
static void Main(string[] args)
        {
            IDataSource ds = new Sqlserver();

            Console.WriteLine(ds.GetData());

            Console.ReadLine();
        }
调用Oracle的话new Oracle()就可以了。如果这个都不能理解的话,那学习这个你就很费劲了。
复制代码

 

改进一下代码。我们在加入一个DataSourceManager类来看一下

复制代码
/// <summary> 
/// 数据源管理类
/// </summary
public class DataSourceManager
    {

        IDataSource _ds;
        /// <summary>
        /// 根据传入的类型动态创建对象
        /// </summary>
        /// <param name="ds"></param>
        public DataSourceManager(IDataSource ds)
        {
            _ds = ds;
        }

        public string GetData()
        {
            return _ds.GetData();
        }
    }
复制代码

这样写的好处是什么,这样加入加入新的数据源,只用调用的时候传入这个对象就可以,就会自动创建一个对应的对象。那接下如果要调用SQLSERVER怎么写。看代码

DataSourceManager dsm = new DataSourceManager(new Sqlserver());
Console.WriteLine(dsm.GetData());

Console.ReadLine();

1.2 注入实现构造函数注入

    上面的DataSourceManager的动态创建的方式就是因为又有个带IDataSource的参数的构造函数,只要调用者传入实现该接口的对象,就实现了对象创建。

    那我们看看怎么使用AutoFac注入实现构造函数注入

复制代码
var builder = new ContainerBuilder();
            builder.RegisterType<DataSourceManager>();
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            using (var container = builder.Build())
            {
                var manager = container.Resolve<DataSourceManager>();
                Console.WriteLine(manager.GetData());

                Console.ReadLine();
            }
复制代码

 

     上面的就是AutoFac构造函数注入,他给IDataSource注入的是Sqlserver所以我们调用的数据,返回的就是Sqlserver数据。那下面我们具体的了解一下AutoFac的一些方法

1.3 Autofac方法说明

(1)builder.RegisterType<Object>().As<Iobject>():注册类型及其实例。例如上面就是注册接口IDataSource的实例Sqlserver
复制代码
(2)IContainer.Resolve<IDAL>():解析某个接口的实例。例如一下代码,我可以解析接口返回的就是Sqlserver实例

    var builder = new ContainerBuilder();
         //builder.RegisterType<DataSourceManager>();
         builder.RegisterType<Sqlserver>().As<IDataSource>();

         using (var container = builder.Build())
         {
             var manager = container.Resolve<IDataSource>();
             Console.WriteLine(manager.GetData());

             Console.ReadLine();
     }

复制代码
复制代码
(3)builder.RegisterType<Object>().Named<Iobject>(string name):为一个接口注册不同的实例。有时候难免会碰到多个类映射同一个接口,比如Sqlerver和Oracle都实现了IDalSource接口,为了准确获取想要的类型,就必须在注册时起名字。
复制代码
?
1
2
3
4
5
6
7
8
var builder = new ContainerBuilder();
builder.RegisterType<Sqlserver>().Named<IDataSource>( "SqlServer" ); builder.RegisterType<Oracle>().Named<IDataSource>( "Oracel" );
using ( var container = builder.Build())
{
    var manager = container.ResolveNamed<IDataSource>( "Oracel" );
    Console.WriteLine(manager.GetData());
    Console.ReadLine();
}
复制代码
image运行后的代码。
复制代码
(4)IContainer.ResolveNamed<IDAL>(string name):解析某个接口的“命名实例”。例如上面的实例最后一行代码
container.ResolveNamed<IDataSource>(”Oracel” ); 就是解析IDataSource的命名实例 Oracel。
(5)imagebuilder.RegisterType<Object>().Keyed<Iobject>(Enum enum):以枚举的方式为一个接口注册不同的实例。有时候我们会将某一个接口的不同实现用枚举来区分,而不是字符串。
    这个方法是完全可以替代builder.RegisterType<Object>().Named<Iobject>(string name),这个列子就不演示了吧!和上面的一个意思。
 
(6)IContainer.ResolveKeyed<IDAL>(Enum enum):根据枚举值解析某个接口的特定实例。这个和上面的都一样 也就不演示了。
(7)builder.RegisterType<Worker>().InstancePerDependency():用于控制对象的生命周期,每次加载实例时都是新建一个实例,默认就是这种方式。调用的话
builder.RegisterType<Sqlserver>().Keyed<IDataSource>("Sqlserver").InstancePerDependency();

(8)builder.RegisterType<Worker>().SingleInstance():用于控制对象的生命周期,每次加载实例时都是返回同一个实例
复制代码
(9)IContainer.Resolve<T>(NamedParameter namedParameter):在解析实例T时给其赋值,这个就是给你定义的方法的参数传值。
复制代码
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
IDataSource _ds;
string Name;
  /// <summary>
  /// 根据传入的类型动态创建对象
  /// </summary>
  /// <param name="ds"></param>
  public DataSourceManager( string name, IDataSource ds)
  {
      _ds = ds;
      Name = name;
  }
 
  public string GetData()
  {
      returnName + ":" + _ds.GetData();
  }
复制代码
我把DataSourceManager的构造方法加了个name参数,然后我调用的时候:
var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));

运行后的代码:

image

复制代码

 

1.4 通过配置的方式使用AutoFac

   在演示一下怎么通过配置文件来配置注册。这块就简单讲,下面的是我的web.config。

复制代码
<configuration>
  <configSections>
    <section name="autofac" type="Autofac.Configuration.SectionHandler,Autofac.Configuration"></section>
  </configSections>
  <autofac defaultAssembly="AutoFacDemo">
    <components>
      <component  type="AutoFacDemo.Model.Oracle,AutoFacDemo" service="AutoFacDemo.Model.IDataSource" />
    </components>
  </autofac>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>
复制代码

 

  后台的调用代码

复制代码
var builder = new ContainerBuilder();
            builder.RegisterType<DataSourceManager>();
            builder.RegisterModule(
new ConfigurationSettingsReader(”autofac”
));

            using (var container = builder.Build())
            {
                var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));
                Console.WriteLine(manager.GetData());

                Console.ReadLine();
            }
复制代码

这里需要注意的是需要引用Autofac.Configuration.dll,否则没有办法使用ConfigurationSettingsReader。

还有一个需要注意的就是你的配置文件要命名空间,类名要写对。

动手尝试一下吧!

 

MVC下面使用Autofac

   引用和上面的控制台程序的原理是一模一样的。但是区别就在于要多添加一个引用

imageimage

     案例还是用上面的案例。我是把之前的接口和类拷贝到MVC项目里面作为下面演示。代码就不在写出来了,一模一样的。

1、首先在函数Application_Start() 注册自己的控制器类

MVC下怎么配置可以直接看如下代码,我把注释写的也很详细。

复制代码
protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            //创建autofac管理注册类的容器实例
            var builder = new ContainerBuilder();
            //下面就需要为这个容器注册它可以管理的类型
            //builder的Register方法可以通过多种方式注册类型,之前在控制台程序里面也演示了好几种方式了。
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            //builder.RegisterType<DefaultController>().InstancePerDependency();
            //使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            //生成具体的实例
            var container = builder.Build();
            //下面就是使用MVC的扩展 更改了MVC中的注入方式.
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        }
复制代码

需要解释的是:

1、大家看下面的这句,这句的作用就是再MVC下面你必须要注册一下Controller,否则没有办法注入。

//使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

      我们通过使用RegisterControllers就可以解决。那如果不用RegisterControllers 我就想一个个注册的话怎么弄?学技术有时候不要只管会用有的时候你也要理解人家提供的方法背后是怎么做的。看到这里你知道怎么做么?先考虑1分钟,不要记得往下看。答案其实在上面讲控制台程序使用Autofac的时候已经讲过了。好吧,我来详细讲一下,我先把之前控制台程序的代码贴出来。

复制代码
public class DataSourceManager
    {
        IDataSource _ds;
        string Name;
        /// <summary>
        /// 根据传入的类型动态创建对象
        /// </summary>
        /// <param name="ds"></param>
        
public DataSourceManager(string
 name, IDataSource ds)
        {
            _ds = ds;
            Name = name;
        }
        public string GetData()
        {
            return Name + ":" + _ds.GetData();
        }
    }
这个类还记得吗?不记得在看之前写的文章。这个类有个IDataSource 作为参数的构造方法。然后我们在看一下使用时候的代码?
复制代码
 
     
复制代码
var builder = new ContainerBuilder();
builder.RegisterType<DataSourceManager>(); 
builder.RegisterType<Sqlserver>().As<IDataSource>();
using (var container = builder.Build())
{

var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));
     Console.WriteLine(manager.GetData());
     Console.ReadLine();
 }
复制代码
 
     

 

 
     
复制代码

看到了吗?container.Resolve<DataSourceManager>()这里通过Resolve解析DataSourceManager实例,对于DataSourceManager类型,我们为Autofac提供了类型, 但是当Autofac创建DataSourceManager的实例, 调用它的构造函数的时候,它的构造函数需要提供一个IDataSource的实例作为参数的,Autofac会在自己的容器里,找注册过IDataSource的实例,并且通过AsImplementedInterfaces()方法,指明为接口IDataSource提供的实例。然后作为创建DataSourceManager时,提供给构造函数的参数。这整个原理不知道这样讲你能听懂吗?

复制代码

     大家上面提出的如果不用RegisterControllers来,需要手动添加怎么做?答案就是要写若干个这个方法。

builder.RegisterType<DefaultController>().InstancePerDependency();注: DefaultController 控制器的名称,你可要试着把RegisterControllers删除掉,用上面的这句来尝试一下。但是实际的项目中最好是用RegisterControllers。

2、如果没有写builder.RegisterControllers<> ,而且控制器也没有通过builder.RegisterType<>注册, 你会看到如下的错误

image

     整个MVC 使用autofac配置的工作就完成了。那接下来直接来看代码里面怎么使用。

2、   添加控制器,并注入依赖代码

复制代码
public class DefaultController : Controller
    {

        IDataSource ds;
        // 接口定义  构造函数注入
        public DefaultController(IDataSource _ds)
        {
            ds = _ds;
        }

        // GET: Default
        public ActionResult Index()
        {
            //调用具体类的具体方法返回结果 赋值给ViewBag.Message
            ViewBag.Message = "STONE刘先生:" + ds.GetData();
            return View();
        }
    }
复制代码

整个功能请求的数据添加到ViewBag然后在页面上面显示出来,也比较简单的。

运行后的效果:

image

成功了!

补充一下:

上面的列子演示的是构造函数注入,那看看能否改成属性注入。

看如下代码,IDataSource 加上get;set就变成属性了:

 

复制代码
public class DefaultController : Controller
    {

        public IDataSource ds { get; set; }
        // 接口定义  构造函数注入
        //public DefaultController(IDataSource _ds)
        //{
        //    ds = _ds;
        //}

        // GET: Default
        public ActionResult Index()
        {
            //调用具体类的具体方法返回结果 赋值给ViewBag.Message
            ViewBag.Message = "STONE刘先生:" + ds.GetData();
            return View();
        }
    }
复制代码

 

如果现在任何地方都不改的情况下,你看看会报什么错,是不是提醒ds为null,那怎么支持属性注入呢! 我看了好久

  
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();

 

把Global.asax里面的这句改成如上这句 就好了!

 

补充,自动注入

 

    Autofac提供一个RegisterAssemblyTypes方法。它会去扫描所有的dll并把每个类注册为它所实现的接口。既然能够自动注入,那么接口和类的定义一定要有一定的规律。我们可以定义IDependency接口的类型,其他任何的接口都需要继承这个接口。比如

   

    public interface IDependency
    {
    }

 

 

?
1
2
3
4
5
6
7
8
/// <summary>
/// 业务逻辑实现——岗位管理
/// </summary>
public class PostService : IDependency
{
   public IPostService postService { get ; set ; }
   ........
  }

  

自动注入原理说明:

首先我们去找到所有Dll,再去找到实现了IDependency接口的类,然后使用RegisterAssemblyTypes进行注入。

复制代码
Assembly[] assemblies = Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray();
 //注册所有实现了 IDependency 接口的类型
 Type baseType = typeof(IDependency);
 builder.RegisterAssemblyTypes(assemblies)
        .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
        .AsSelf().AsImplementedInterfaces()
        .PropertiesAutowired().InstancePerLifetimeScope();


//注册MVC类型
builder.RegisterControllers(assemblies).PropertiesAutowired();
builder.RegisterFilterProvider();

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
复制代码

 

04-01
<think>好的,我需要回答用户关于Autofac在.NET框架中的依赖注入库的使用方法的问题。首先,我需要回忆Autofac的基本概念和核心功能。Autofac是一个流行的IoC容器,用于.NET应用程序中的依赖注入,帮助管理对象的创建和生命周期。 接下来,我要确保覆盖用户可能关心的主要方面,比如基本使用步骤、注册组件的方法、生命周期管理以及与ASP.NET Core的集成。同时,用户提到了引用内容,其中提到了作用域和依赖释放,我需要将这些点整合到回答中,确保引用标识正确。 首先,介绍Autofac是什么,它的作用以及为什么使用它。然后分步骤讲解安装、容器构建、组件注册和解析。这里需要给出代码示例,比如如何创建ContainerBuilder,注册服务,并解析使用。 然后是注册组件的方法,包括类型注册、实例注册和Lambda表达式注册。这部分需要具体例子,比如注册MyService,或者使用Lambda处理复杂初始化。 生命周期管理是关键部分,用户提供的引用[1]提到作用域和依赖释放,我需要详细说明Autofac的InstancePerLifetimeScope,并举例在ASP.NET Core中如何使用,确保依赖项在作用域结束时自动释放。同时,要提醒用户注意长时间存活类中的依赖解析问题,避免内存泄漏,如引用[1]中的警告。 集成ASP.NET Core的部分,需要提到Autofac的扩展库,如何替换默认容器,并在Program.cs中进行配置。给出代码示例,展示AddAutofac()的使用,以及控制器中构造函数注入的例子。 最后,生成相关问题,涵盖高级功能、生命周期比较、与原生容器的区别以及解决循环依赖的方法,这些都能帮助用户进一步学习。 检查是否所有数学公式和独立公式使用正确格式,但看起来这里没有数学内容,可能不需要。然后确保引用正确,引用[1]和引用[2]的相关内容要自然融入回答中,比如作用域释放和构造器注入。 最后通读一遍,确保结构清晰,步骤明确,代码正确,并且引用的位置合适,没有格式错误。这样用户就能系统地了解Autofac的使用方法,并解决可能的疑问。</think>### Autofac依赖注入库在.NET框架中的使用 Autofac是.NET生态中广泛使用的轻量级**控制反转(IoC)容器**,专注于依赖注入(DI),帮助开发者解耦组件并管理对象生命周期。以下是其核心使用方法: --- #### 1. **基础使用步骤** 1. **安装NuGet包** 通过NuGet安装`Autofac`和`Autofac.Extensions.DependencyInjection`(ASP.NET Core集成需此包): ```bash Install-Package Autofac Install-Package Autofac.Extensions.DependencyInjection ``` 2. **创建容器并注册组件** 使用`ContainerBuilder`注册服务与实现: ```csharp var builder = new ContainerBuilder(); builder.RegisterType<MyService>().As<IMyService>(); // 注册接口与实现 builder.RegisterInstance(new Logger()).As<ILogger>(); // 注册单例实例 var container = builder.Build(); ``` 3. **解析依赖** 通过容器解析服务: ```csharp using var scope = container.BeginLifetimeScope(); var service = scope.Resolve<IMyService>(); // 解析服务实例 ``` --- #### 2. **组件注册方式** - **类型注册** ```csharp builder.RegisterType<EmailService>().As<INotificationService>(); ``` - **实例注册**(单例) ```csharp var cache = new MemoryCache(); builder.RegisterInstance(cache).As<ICache>(); ``` - **Lambda注册**(复杂初始化) ```csharp builder.Register(c => new ConfigReader(c.Resolve<IConfig>())) .As<IConfigReader>(); ``` --- #### 3. **生命周期管理** Autofac通过生命周期作用域(Lifetime Scope)控制对象释放,避免内存泄漏[^1]: - **瞬时实例**(每次解析新对象) ```csharp builder.RegisterType<TransientService>().InstancePerDependency(); ``` - **作用域实例**(同一作用域内单例) ```csharp builder.RegisterType<ScopedService>().InstancePerLifetimeScope(); ``` - **单例实例**(全局唯一) ```csharp builder.RegisterType<SingletonService>().SingleInstance(); ``` --- #### 4. **与ASP.NET Core集成** 在ASP.NET Core中替换默认DI容器为Autofac: ```csharp var builder = WebApplication.CreateBuilder(args); builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureContainer<ContainerBuilder>(container => { container.RegisterModule<MyApplicationModule>(); // 模块化注册 }); ``` **控制器依赖注入示例**: ```csharp public class HomeController : Controller { private readonly IMyService _service; public HomeController(IMyService service) { _service = service; // 通过构造函数自动注入 } } ``` --- #### 5. **注意事项** - **作用域释放**:通过`BeginLifetimeScope()`创建的作用域结束时,其解析的所有瞬时/作用域实例会自动释放[^1]。 - **单例陷阱**:若单例服务依赖作用域服务,需使用`ILifetimeScope`参数或`InstancePerMatchingLifetimeScope`限定作用域[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值