【问题标题】:Microsoft Dependency Injection resolving generic type returns nullMicrosoft 依赖注入解析泛型类型返回 null
【发布时间】:2017-05-31 07:05:14
【问题描述】:

我正在尝试将我以前在 Autofac 中所做的事情转换为 Microsoft 依赖注入。我有一堆基于接口的 RequestHandler:

public interface IRequestHandler<TParameter, TResult>
    where TResult : IResponse
    where TParameter : IRequest
{
    TResult Handle(TParameter query);
}

我已经通过这样做注册了所有请求处理程序和我的所有 IResponse 对象和我的 IRequest 对象:

 var request handlers = ReflectionUtils.GetClosedTypes(typeof(IRequestHandler<,>), assemblies);
        foreach (var requestHandler in requestHandlers)
        {
            serviceCollection.AddScoped(requestHandler);
        }

我正在收集我的所有类型以这样注册:

 public static IEnumerable<Type> GetClosedTypes(Type openGeneric, params Assembly[] assemblies)
    {
        if (assemblies == null || assemblies.Length == 0)
        {
            return new Type[0];
        }

        var list = new List<Type>();
        foreach (var assembly in assemblies)
        {
            if (!assembly.IsDynamic)
            {
                var types = ReflectionUtils.GetExportedTypes(assembly);

                var q = from type in types
                        from i in type.GetInterfaces()
                        where i.IsGenericType && i.GetGenericTypeDefinition() == openGeneric
                        select type;

                list.AddRange(q);
            }
        }

        return list;
    }

我可以单步执行代码并查看它们是否已注册。然后,我希望能够通过 RequestDispatcher 从 ServideProvider 检索项目并调用 Handle 方法来一般地检索它们:

 public TResult Dispatch<TParameter, TResult>(TParameter query)
        where TParameter : IRequest
        where TResult : IResponse
    {
        //Get the approproprite command handler by resolving it from the autofac _serviceProvider based on the IQuery and IQueryResult
        var handler = _serviceProvider.GetService<IRequestHandler<TParameter, TResult>>();
        return handler.Handle(query);
    }

但 GetService 返回 null。我怀疑这与项目在容器中注册的方式有关。这是我过去在 Autofac 中注册东西的方式:

builder.RegisterAssemblyTypes(MyAssembly)
            .AsClosedTypesOf(typeof(IRequestHandler<,>))
            .InstancePerLifetimeScope()
            .AsImplementedInterfaces();

【问题讨论】:

  • 您可以尝试检查已注册类的列表。也许它正在以某种方式覆盖注册。例如。将它们全部注册为IRequestHandler
  • IRequestHandlerAsyncIRequestHandler 的派生类型吗?此外,我不相信注册具体类型会允许 DI 容器自动注册其基本类型(或接口)。尝试通过显式使用您要解析的接口来注册类型。
  • @Mardoxx 我刚刚解决了这个问题。 Frederico 看起来具体的类是注册的对象
  • 尝试注册... idk,使用服务描述符,然后使用接口类型作为解析类型和具体类型作为得到解析的东西来设置它?
  • 我认为这里发生的事情是您正在注册 ConcreteType 并期望其实现的 InterfaceType 能够解析它 - 它不适合您(即注册 Service 是 Service : IService,并期待IService 在不明确告诉它关系的情况下解析为 Service)

标签: c# generics reflection dependency-injection


【解决方案1】:

您应该首先更改将类型注册到 DI 容器中的方式。

我相信仅注册具体类型将不允许服务提供者解析其接口(如果未显式注册)。

尝试通过提供ServiceCollection 所需的所有类型:

public static IDictionary<Type, Type> GetClosedTypesRegistrations(Type openGeneric, params Assembly[] assemblies)
{
    if (assemblies == null || assemblies.Length == 0)
    {
        return new Dictionary<Type, Type>();
    }

    return assemblies
        .Where(a => !a.IsDynamic)
        .SelectMany(ReflectionUtils.GetExportedTypes)
        .SelectMany(t => t.GetInterfaces(), (t, i) => new { service = i, type = t } )
        .Where(r => r.service.IsGenericType && r.service.GetGenericTypeDefinition() == openGeneric)
        .ToDictionary(r => r.service, r => r.type);
}

内部ConfigureServices

var requestHandlers = ReflectionUtils.GetClosedTypesRegistrations(typeof(IRequestHandler<,>), assemblies);
foreach (var requestHandler in requestHandlers)
{
    serviceCollection.AddScoped(requestHandler.Key, requestHandler.Value);
}

【讨论】:

    猜你喜欢
    • 2019-04-13
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多