第四十一节:再探依赖注入(coreMvc/应用启动/控制台)和多项目框架集成(原生反射、AutoFac集成新写法)

一. 再探依赖注入

其它详细用法参考之前的博客:https://www.cnblogs.com/yaopengfei/p/10754397.html  
                                               https://www.cnblogs.com/yaopengfei/p/12664400.html
官网:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0

1. coreMvc中注入

    直接在Program中注入即可, 可以以接口的形式注入,也可以直接注入类

//1. 普通注入
builder.Services.AddScoped<IUserInfo, UserInfo>();
builder.Services.AddScoped<RoleInfo>();

    使用的时候在控制器中通过构造函数注入即可,代码略。

2. 在应用启动中解析

 (即在program中要使用,这里是解析使用,注册使用的还是1中的注册)

 (1). 通过 var serviceScope = app.Services.CreateScope()

 (2). 通过GetRequiredService方法进行对象的解析

var app = builder.Build();

//2.在应用启动中解析使用(使用的还是1中的普通注入)
using (var serviceScope = app.Services.CreateScope())
{
    var services = serviceScope.ServiceProvider;
    var userInfo = services.GetRequiredService<IUserInfo>();
    var roleInfo = services.GetRequiredService<RoleInfo>();
    Console.WriteLine("------------------测试在应用启动中解析使用------------------------------");
    Console.WriteLine(userInfo.GetInfo());
    Console.WriteLine(roleInfo.GetInfo());
}

3.直接在控制台中使用

 直接注册+解析

 需要依赖【 Microsoft.Extensions.DependencyInjection】程序集,详见下面代码

             //3. 测试控制台中使用
            {
                var serviceCollection = new ServiceCollection();
                serviceCollection.AddSingleton<IUserInfo, UserInfo>();
                var serviceProvider = serviceCollection.BuildServiceProvider();
                IUserInfo userService = serviceProvider.GetRequiredService<IUserInfo>();

                //下面是使用
                var result = userService.GetInfo();
            }

 

二. 多项目框架集成

1. 需求

  有多个项目, Ypf.Service、Ypf.IService、03-CoreMvcDI三个项目, 其中CoreMvcDI添加对Ypf.IService的引用,然后把Ypf.Service项目的输出路径改为 【..\03-CoreMvcDI\bin\】

  想把Ypf.Service中所有实现ISupport接口的类注册个他的实现接口

  [FromServices] IInfo2 _info2 是注册失败的,因为没有实现ISupport接口 (需要加上以后再测试一下哦)

特别注意:这里的输出路径改为 Ypf.Service项目的输出路径改为 【..\03-CoreMvcDI\bin\】,利用合并文件夹的原则实现!!!  因为Ypf.Service项目也会生成一个Debuger文件夹

2. 原生反射写法

(和之前Core5.0中的写法基本一致)

(1). 拼接dll的路径,通过反射进行加载

(2). 获取该dll中的符合条件的类(A.去掉抽象类 B.该类要实现ISupport接口)

(3). 遍历类

   A. 拿到该类的所有接口(去掉ISupport接口)

   B. 遍历接口,把该类注册给所有实现的接口

代码分享:

{

    var dirName = "03-Ypf.Service.dll";
    Assembly asmService = Assembly.LoadFile(AppContext.BaseDirectory + dirName);
    //抽象类不进行注入,没有实现ISupport接口的类不进行注入
    var classList = asmService.GetTypes().Where(t => !t.GetTypeInfo().IsAbstract && typeof(ISupport).IsAssignableFrom(t)).ToList();
    foreach (Type serviceType in classList)
    {
        //把一个类注册给它实现的全部接口(除了ISupport接口外)
        var interfaceTypes = serviceType.GetInterfaces().Where(t => t.Name != "ISupport").ToList();
        foreach (var interfaceType in interfaceTypes)
        {
            builder.Services.AddScoped(interfaceType, serviceType);
        }
    }

}

3. AutoFac集成新写法

   和之前Core5.0的写法有区别,详见Program中的代码

封装MyAutoFacModule类
 public class MyAutoFacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            {
                //这里就是AutoFac的注入方式,下面采用常规的方式
                //详见:https://www.cnblogs.com/yaopengfei/p/9479268.html
                //官网:https://autofac.org/

                //特别注意:其中很大的一个变化在于,Autofac 原来的一个生命周期InstancePerRequest,将不再有效。正如我们前面所说的,整个request的生命周期被ASP.NET Core管理了,
                //所以Autofac的这个将不再有效。我们可以使用 InstancePerLifetimeScope ,同样是有用的,对应了我们ASP.NET Core DI 里面的Scoped。

               //在普通类中配置文件的读取麻烦,后面封装(注:appsettings.json要改为始终复制)
                var Configuration = new ConfigurationBuilder().AddJsonFile(AppContext.BaseDirectory + "appsettings.json").Build();
                var dirName = Configuration["IocDll"];
                Assembly asmService = Assembly.LoadFile(AppContext.BaseDirectory + dirName);

                builder.RegisterAssemblyTypes(asmService)
                       .Where(t => !t.IsAbstract && typeof(ISupport).IsAssignableFrom(t))  //只有实现了ISupport接口的类才进行注册
                       .AsImplementedInterfaces()    //把一个类注册给它实现的全部接口
                       .InstancePerLifetimeScope()   //作用域单例(比如Task.Run就是另外一个作用域),而非请求内单例(请求内单例用:InstancePerRequest)
                       .PropertiesAutowired();       //在core里表示在注入类中实现构造函数注入
            }
        }
    }
program中的代码(和5.0的写法有区别了) 
    builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
    // Register services directly with Autofac here. Don't call builder.Populate(), that happens in AutofacServiceProviderFactory.
    builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyAutoFacModule()));
 
 

三. 老杨的开源框架

 

   https://github.com/yangzhongke/NETBookMaterials/tree/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.Commons


   主要分析RunModuleInitializers方法和ReflectionHelper.cs

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2022-05-16 15:33  Yaopengfei  阅读(312)  评论(1编辑  收藏  举报