NET Core3.1 用 Autofac 实现IOC容器

一、IOC容器

IOC(Inversion of Control,控制反转),他不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合,更优良的程序。

DI(依赖注入)。IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

使用依赖注入,有以下优点:

  • 传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。
  • 依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。
  • 松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。

二、使用——Autofac

1、引入nuget包

在Nuget中引入两个:Autofac.Extras.DynamicProxy(Autofac的动态代理,它依赖Autofac,所以可以不用单独引入Autofac)、Autofac.Extensions.DependencyInjection(Autofac的扩展)

NET Core3.1 用 Autofac 实现IOC容器

 

 

2、在Startup类下面创建 ConfigureContainer 方法

Core 3.0以上版本写法请注意和2.2是不一样的,完整代码如下

        public void ConfigureContainer(ContainerBuilder builder)
        {
            var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
            //注册要通过反射创建的组件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();

            #region 带有接口层的服务注入

       //项目引用接口, 服务层和仓储层的bin文件直接使用,实现解耦 var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll"); var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll"); if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile))) { throw new Exception("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。"); } // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。 var cacheType = new List<Type>();// 获取 Service.dll 程序集服务,并注册 var assemblysServices = Assembly.LoadFrom(servicesDllFile); builder.RegisterAssemblyTypes(assemblysServices) .AsImplementedInterfaces() .InstancePerDependency() .EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy; .InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。 // 获取 Repository.dll 程序集服务,并注册 var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); builder.RegisterAssemblyTypes(assemblysRepository) .AsImplementedInterfaces() .InstancePerDependency(); #endregion #region 没有接口层的服务层注入 //因为没有接口层,所以不能实现解耦,只能用 Load 方法。 //注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法 //var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services"); //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces); #endregion #region 没有接口的单独类 class 注入 //只能注入该类中的虚方法 builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love))) .EnableClassInterceptors() .InterceptedBy(cacheType.ToArray()); #endregion }
没有接口的单独类 class 注入,只能注入该类中的虚方法
    /// <summary>
    /// 这是爱
    /// </summary>
    public class Love
    {
     //虚方法 public virtual string SayLoveU() { return "I ♥ U"; } }

3、在program类下面build



public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)
     .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS
     .ConfigureWebHostDefaults(webBuilder =>
     {
         webBuilder
           .UseStartup<Startup>()
           .UseUrls("http://localhost:8081")
           .ConfigureLogging((hostingContext, builder) =>
           {
               builder.ClearProviders();
               builder.SetMinimumLevel(LogLevel.Trace);
               builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
               builder.AddConsole();
               builder.AddDebug();
           });
     });

4、构造函数方式来注入

依赖注入有三种方式(构造方法注入、setter方法注入和接口方式注入),我们平时基本都是使用其中的构造函数方式实现注入,
        
     //接口
     readonly IAdvertisementServices _advertisementServices; /// <summary> /// 构造函数 /// </summary> /// <param name="advertisementServices"></param> public BlogController(IAdvertisementServices advertisementServices) { _advertisementServices = advertisementServices; }     [HttpGet("{id}", Name = "Get")] public async Task<List<Advertisement>> Get(int id) { //IAdvertisementServices advertisementServices = new AdvertisementServices(); //不依赖注入是需要引用两个命名空间IServices层和Services层        //使用 return await _advertisementServices.Query(d => d.Id == id); }

5、程序集注入 —— 实现层级引用的解耦

这是一个学习的思路,大家要多想想,可能会感觉无聊或者没用,但是对理解项目启动和加载,还是很有必要的。

1、项目最终只依赖抽象

最终的效果是这样的:工程只依赖抽象,把两个实现层删掉,引用这两个接口层。

NET Core3.1 用 Autofac 实现IOC容器

 

 

 

2、配置仓储和服务层的程序集输出

将 Blog.Repository 层和 Service 层项目生成地址改成相对路径,这样大家就不用手动拷贝这两个 dll 了,F6编译的时候就直接生成到了 api 层 bin 下了:


“..\Blog.Core\bin\Debug\”

NET Core3.1 用 Autofac 实现IOC容器

 

 

 好了,项目启动就可以运行了


常见错误:

经常会遇到一个错误:None of the constructors found with ........,

查看你的service服务,是不是用了其他的仓储repository,但是又缺少了构造函数。

 参考自:https://www.cnblogs.com/laozhang-is-phi/p/9541414.html
如果写的不明白可以看看大神原文,我是在跟着大神学习的,下节学习AOP切面
上一篇:Autofac 泛型依赖注入


下一篇:NET Core 3.0 AutoFac替换内置DI的新姿势