首页 新闻 会员 周边

反射程序集使用services.AddScoped()和services.AddScoped<T>()注入DI的问题

0
悬赏园豆:20 [已解决问题] 解决于 2022-07-15 16:14

1、使用Assembly.Load加载程序集

        //反射注入DI
        var path = AppDomain.CurrentDomain.BaseDirectory;
        var asses = new List<Assembly>();
        var files = Directory.GetFiles(path, "*.dll");
        for (int i = 0; i < files.Length; i++)
        {
            asses.Add(Assembly.Load(File.ReadAllBytes(files[i])));
        }

2、循环遍历类,发现符合条件的类使用AddScoped方法注入DI,举例类名为LoginContext

        for (int i = 0; i < asses.Count; i++)
        {
            var modules = asses[i].GetModules();
            for (int j = 0; j < modules.Length; j++)
            {
                var types = modules[j].GetTypes();
                for (int m = 0; m < types.Length; m++)
                {
                    var service = types[m];
                    if (可注入条件)
                    {
                        services.AddScoped(service);//项目不可正常启动
                        services.AddScoped(typeof(LoginContext));//项目正常启动
                        services.AddScoped<LoginContext>();//项目正常启动
                    }
                }
            }
        }

3、services内容

4、使用构造函数注入的方式
5、错误信息
只保留services.AddScoped(service);启动项目时会报错:
Unable to resolve service for type

不知道错误原因是什么,services.AddScoped()和services.AddScoped<T>()的注入效果不应该是一样的吗?

问题补充:

补充问题:
错误:Unable to resolve service for type 'Adam.Application.IService.System.IDemoClass'
1、准备一个测试接口类:IDemoClass和测试实现类:DemoClass
2、IDemoClass与DemoClass在同一个项目中(编译后则在同一个程序集dll),无论其命名空间是否相同
//第一种写法报错
var inj = service.GetInterface("I" + service.Name);
services.AddScoped(inj, service);
//第二种写法不报错
services.AddScoped(typeof(IDemoClass), typeof(DemoClass));
//第三种写法不报错
services.AddScoped<IDemoClass, DemoClass>();
3、IDemoClass与DemoClass不在同一个的项目中(编译后则不在同一个程序集dll),无论其命名空间是否相同
//第一种写法不会报错
var inj = service.GetInterface("I" + service.Name);
services.AddScoped(inj, service);
//第二种写法不报错
services.AddScoped(typeof(IDemoClass), typeof(DemoClass));
//第三种写法不报错
services.AddScoped<IDemoClass, DemoClass>();

疑惑点:
现在疑惑点转移到第一种写法与第二种写法的问题,为什么会造成这种限制,是我电脑环境(core5.0)的问题,还是代码本身带的这种限制,还是说写法错误

需要第一种写法的原因:
1、我在代码设计中有些注册到DI的类没有接口类
2、我是通过反射的方式将想要注册的类注册到DI中,不想写太多的注册代码

愉悦的绅士的主页 愉悦的绅士 | 初学一级 | 园豆:184
提问于:2021-02-21 16:05
< >
分享
最佳答案
1

LoginContext 是啥呢

我们通常实现类似这样:

参考:

收获园豆:20
智客工坊 | 小虾三级 |园豆:1855 | 2021-02-21 19:02

大神:
LoginContext是我自己定义的类,在设计上没打算给它设计接口类
后面我自己测试了下,使用services.AddScoped(接口类类型,实现类类型);这种注入有些限制,我不知道是不是我开发环境的问题
1、只要接口类和实现类在同一个项目(同一个dll)中,同样会报Unable to resolve service for type这个错误
2、接口类和实现类不在同一个项目中,则能正常使用
3、services.AddScoped(typeof(接口类),typeof(实现类));services.AddScoped<接口类,实现类>();这两种写法则能忽视这个限制
我想知道造成这个限制的根源,我反编译5.0版本的程序集Microsoft.Extensions.DependencyInjection.Abstractions.dll,没发现什么问题,是dotnet自己限制、还是我没能发现问题

愉悦的绅士 | 园豆:184 (初学一级) | 2021-02-21 22:21

用这个是可以的,不可以反射程序集

愉悦的绅士 | 园豆:184 (初学一级) | 2022-07-15 16:16
其他回答(1)
1
  1. services.AddScoped(service);//项目不可正常启动 这样注入是成功的,你放心.
  2. 使用的方法不对, 试试看这样: serviceProvider.getservice(service)// 这里的service和你在注入DI的是同一个type对象, 就是这个 var service = types[m];.

你先硬编码测试一下.

czd890 | 园豆:14412 (专家六级) | 2021-02-22 09:54

我测试了下,我准备了一个类DemoClass
你的意思是在controller中使用HttpContext.RequestServices获取这个serviceProvider,然后手动获取吗
1、使用services.AddScoped(service);注册到DI
var serviceProvider = HttpContext.RequestServices;
var demo = serviceProvider.GetService(typeof(DemoClass));
var demo1 = serviceProvider.GetService<DemoClass>();
demo和demo1这两个变量为null
2、使用services.AddScoped(typeof(DemoClass));注册到DI
var serviceProvider = HttpContext.RequestServices;
var demo = serviceProvider.GetService(typeof(DemoClass));
var demo1 = serviceProvider.GetService<DemoClass>();
demo和demo1这两个变量则能成功获取

是否是我因为使用Assembly.Load加载程序集的原因吗?

支持(0) 反对(0) 愉悦的绅士 | 园豆:184 (初学一级) | 2021-02-22 12:26

@愉悦的绅士:
使用的方法不对, 试试看这样: serviceProvider.getservice(service)// 这里的service和你在注入DI的是同一个type对象, 就是这个 var service = types[m];.

你分析的对

支持(0) 反对(0) czd890 | 园豆:14412 (专家六级) | 2021-02-22 12:45

@czd890:
没怎么看明白
serviceProvider.getservice(service)
这就话是让我在项目启动注册DI容器的时候使用,还是说,在要使用该 类实例 的时候用此方法从DI容器中获取该实例?

支持(0) 反对(0) 愉悦的绅士 | 园豆:184 (初学一级) | 2021-02-22 13:57

@愉悦的绅士:

//伪代码
var serviceTypeForLoadAss = types.firstdefault(t=>t.name=="LoginContext"); //types assembly.load 来的.
var servieeType=typeof(LoginContext);
console.writeline(servieeType==serviceTypeForLoadAss) // output false. 

这样子懂了不

支持(0) 反对(0) czd890 | 园豆:14412 (专家六级) | 2021-02-22 15:06

@czd890:
懂了
比较结果为false

支持(0) 反对(0) 愉悦的绅士 | 园豆:184 (初学一级) | 2021-02-22 15:30
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册