net core Autofac

一、Autofac+原生

Autofac:貌似目前net下用的最多吧

Ninject:目前好像没多少人用了

Unity:也是较为常见

微软 core 自带的 DI

 

其实.Net Core 有自己的轻量级的IoC框架,

ASP.NET Core本身已经集成了一个轻量级的IOC容器,开发者只需要定义好接口后,在Startup.cs的ConfigureServices方法里使用对应生

 

命周期的绑定方法即可,常见方法如下

 

services.AddTransient<IApplicationService,ApplicationService>//服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我们的Repository和ApplicationService服务)

 

services.AddScoped<IApplicationService,ApplicationService>//服务在每次请求时被创建,生命周期横贯整次请求

 

services.AddSingleton<IApplicationService,ApplicationService>//Singleton(单例) 服务在第一次请求时被创建(或者当我们在ConfigureServices中指定创建某一实例并运行方法),其后的每次请求将沿用已创建服务。如果开发者的应用需要单例服务情景,请设计成允许服务容器来对服务生命周期进行操作,而不是手动实现单例设计模式然后由开发者在自定义类中进行操作。

 

二、三种注入的生命周期 

权重:

AddSingleton→AddTransient→AddScoped

AddSingleton的生命周期:

项目启动-项目关闭   相当于静态类  只会有一个  

AddScoped的生命周期:

请求开始-请求结束  在这次请求中获取的对象都是同一个 

AddTransient的生命周期:

请求获取-(GC回收-主动释放) 每一次获取的对象都不是同一个

 

 

注意:

由于AddScoped对象是在请求的时候创建的

所以不能在AddSingleton对象中使用

甚至也不能在AddTransient对象中使用

 

 

三、Autofac使用

 

1.引入nuget

 

在Nuget中引入两个Autofac.Extras.DynamicProxy(Autofac的动态代理,它依赖Autofac,所以可以不用单独引入Autofac)Autofac.Extensions.DependencyInjection(Autofac的扩展),注意是最新版本的。

 

2.配置容器,注入服务

 

startup.cs 文件中,增加一个方法,用来配置Autofac 服务容器

首先我们创建一个接口和对应的实现类:

 

 public interface IAdvertisementServices

 {

     int Test();

 }

 

 public class AdvertisementServices : IAdvertisementServices

 {

     public int Test()

     {

         return 1;

     }

 }

 

 

然后将这个服务,注入到Autofac 容器里:

 

 public void ConfigureContainer(ContainerBuilder builder)

 {

     var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;

     //直接注册某一个类和接口

     //左边的是实现类,右边的As是接口

     builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();

 

     //注册要通过反射创建的组件

     var servicesDllFile = Path.Combine(basePath"Blog.Core.Services.dll");

     var assemblysServices = Assembly.LoadFrom(servicesDllFile);

     builder.RegisterAssemblyTypes(assemblysServices)

               .AsImplementedInterfaces()

               .InstancePerLifetimeScope()

               .EnableInterfaceInterceptors();

 }

 

 

net core Autofac

 

 

3.使用服务工厂,将Autofac容器添加到Host

 

为什么要这么做呢,从上边你也应该看到了,我们现在仅仅是配置了服务和容器,还没有添加到我们的项目宿主里,那我们的controller就拿不到相应的服务。

我们需要在 Program.cs 文件中,配置 UseServiceProviderFactory

 

public static IHostBuilder CreateHostBuilder(string[] args) =>

    Host.CreateDefaultBuilder(args)

    .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS

        .ConfigureWebHostDefaults(webBuilder =>

        {

            webBuilder.UseStartup<Startup>();

        });

 

4.使用构造函数方式来注入

依赖注入有三种方式(构造函数注入、属性注入和方式注入),我们平时基本都是使用其中的构造函数方式实现注入,

大家还记得默认控制器 WeatherForecastController 么,当时我们说到了,已经有了一个依赖注入的用法,就是 ILogger,那现在我们继续注入,

 private readonly ILogger<WeatherForecastController_logger;

 private readonly IAdvertisementServices advertisementServices;

 public WeatherForecastController(ILogger<WeatherForecastControllerloggerIAdvertisementServices advertisementServices)

 {

     _logger = logger;

     this.advertisementServices = advertisementServices;

 }

 /// <summary>

 /// 获取接口数据

 /// </summary>

 /// <returns></returns>

 [HttpGet]

 public string[] Get()

 {

     var ads = advertisementServices.Test();

     return Summaries;

 }

 

 

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

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

NetCore 自带的注入实现效果

// 注入 service services.AddScoped<IAdvertisementServices, AdvertisementServices>();

 

四、整个dl程序集注入

1、服务程序集注入方式 —— 未解耦

通过反射将 Blog.Core.Services 和 Blog.Core.Repository 两个程序集的全部方法注入

修改如下代码,注意这个时候需要在项目依赖中,右键,添加引用 Blog.Core.Services 层和 Repository 层 到项目中,如下图,这个时候我们的程序依赖了具体的服务

net core Autofac

 

 

核心代码如***意这里是 Load 模式(程序集名),还是在startup.cs 文件中,配置Autofac容器。

 

 public void ConfigureContainer(ContainerBuilder builder)

 {

     var assemblysServices = Assembly.Load("Blog.Core.Services");

   

     builder.RegisterAssemblyTypes(assemblysServices)

               .AsImplementedInterfaces()

               .InstancePerLifetimeScope()

               .EnableInterfaceInterceptors();

 }

 

 

2、程序集注入 —— 实现层级解耦

1、项目最终只依赖抽象

 

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

net core Autofac

 

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

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

 

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

 

net core Autofac

 

3、使用 LoadFile 加载服务层的程序集

var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;//获取项目路径

var servicesDllFile = Path.Combine(basePath"Blog.Core.Services.dll");//获取注入项目绝对路径

var assemblysServices = Assembly.LoadFile(servicesDllFile);//直接采用加载文件的方法

 

 

4、解除Service层和Repository层之间的耦合

还记得Blog.Core.Services中的BaseServices.cs么,它还是通过new 实例化的方式在创建,仿照contrller,修改BaseServices并在全部子类的构造函数中注入:

 

public class BaseServices<TEntity> : IBaseServices<TEntitywhere TEntity : classnew()

    {

        //public IBaseRepository<TEntity> baseDal = new BaseRepository<TEntity>();

        public IBaseRepository<TEntitybaseDal;//通过在子类的构造函数中注入,这里是基类,不用构造函数

  //...

 }

 

    public class AdvertisementServices : BaseServices<Advertisement>, IAdvertisementServices

    {

        IAdvertisementRepository dal;

        public AdvertisementServices(IAdvertisementRepository dal)

        {

            this.dal = dal;

            base.baseDal = dal;

        }

    }