ArgumentException OptionsManager 无法转换为服务类型 IOptions

ArgumentException OptionsManager can't be converted to service type IOptions

我正在尝试测试是否可以使用以下代码解决我 IServiceCollection 中的所有服务:

static void TestServiceResolve(IServiceCollection services)
{
    var provider = services.BuildServiceProvider();
    foreach (var item in services)
    {
        var serviceToResolve = item.ServiceType;
        var implemantationService = provider.GetService(serviceToResolve);
    }
}

抛出异常:

System.ArgumentException: Implementation type 'Microsoft.Extensions.Options.OptionsManager`1[TOptions]' can't be converted to service type 'Microsoft.Extensions.Options.IOptions`1[TOptions]'

我已经添加了 services.AddOptions(); 和我认为必要的所有可能的包。 任何人都可以帮助解释异常,也许知道它来自哪里?

请注意,应用程序代码运行良好,当我调试代码时,所有必要的依赖项都得到解决,例如IOptions<somesetting> 得到很好的解决。只是测试失败了,我不知道它来自哪里。

如果我过滤掉名称以 IOptions 开头的所有服务,它也会在 ILogger

上失败

System.ArgumentException: Implementation type 'Microsoft.Extensions.Logging.Logger`1[T]' can't be converted to service type 'Microsoft.Extensions.Logging.ILogger`1[TCategoryName]'

同样,日志记录在应用程序中工作正常。

服务注册列表包含非通用(例如HomeController)、封闭通用(例如ILogger<HomeController>)和开放通用(例如ILogger<T>)注册,而 GetService 只能提供非泛型和封闭泛型类型。

也就是说,在遍历列表的时候,遇到注册了ILogger<T>ServiceType,但是调用provider.GetService(typeof(ILogger<>))会失败,因为:whichILogger<T>你真的想要吗?

我认为您的问题的根源是 MS.DI 抛出的令人困惑的异常消息。抛出如下异常会更好:

The request for type ILogger<T> is invalid because it is an open-generic type: it is only possible to instantiate instances of closed-generic types. A generic type is closed if all of its type parameters have been substituted with types that are recognized by the compiler.

以上消息是直接来自另一个开源 DI Container 的异常。

此处的解决方案是在验证您的 DI 注册时排除所有开放通用注册。例如:

static void TestServiceResolve(IServiceCollection services)
{
    var provider = services.BuildServiceProvider();
    foreach (var item in services)
    {
        if (!item.ServiceType.ContainsGenericParameters)
        {
            provider.GetService(item.ServiceType);
        }
    }
}