Autofac:将所有MediatR处理程序注册为泛型类型的内部类

时间:2017-02-06 10:51:14

标签: c# generics inversion-of-control autofac mediatr

上下文

在尝试简化MediatR代码时,我们为GetAll,GetSingle等功能创建了通用的请求/响应/处理程序组合。您可以在下面找到GetAll实现

public class GetAll<T> where T : class
{
    public class Request : IRequest<Response>
    {
    }

    public class Response
    {
        public IQueryable<T> All { get; set; }
    }

    public class Handler : IRequestHandler<Request, Response>
    {
        private readonly IRepository<T> repository;

        public Handler(IRepository<T> repository)
        {
            this.repository = repository;
        }

        public Response Handle(Request message)
        {
            return new Response
            {
                All = repository.GetAll()
            };
        }
    }
}

问题

我们似乎无法使用Autofac立即注册所有RequestHandler。

我们可以使用以下方法在我们的Autofac模块中注册一个特定类型的Handler:

builder.RegisterGeneric(typeof(GetAll<>.Handler)).AsImplementedInterfaces();

但我们希望为IRequestHandler<,>所有实现执行此操作(而不仅仅是GetAll实现)。我们已经使用文档中建议的AsClosedTypesOf函数尝试了这个:

builder.RegisterAssemblyTypes(typeof(GetAll<>.Request).Assembly)
              .AsClosedTypesOf(typeof(IRequestHandler<,>));

builder.RegisterAssemblyTypes(typeof(GetAll<>.Request).Assembly)
              .AsClosedTypesOf(typeof(IRequestHandler<,>))
              .AsImplementedInterfaces();

但是这会产生以下异常:

  

Autofac.Core.Registration.ComponentNotRegisteredException:'请求的服务'MediatR.IRequestHandler<GetAll<T>.Request,GetAll<T>.Response>'尚未注册。要避免此异常,请注册组件以提供服务,使用IsRegistered()检查服务注册,或使用ResolveOptional()方法解析可选的依赖项。'

我们在这里做错了什么(或遗忘)?

1 个答案:

答案 0 :(得分:1)

您无法立即注册,因为正如您所提到的,您必须将每个注册为泛型。但是,您可以通过一些反思来避免手动保留此类处理程序的列表:

var genericRequestHandlers = typeof(GetAll<>).Assembly
    .ExportedTypes
    .Where(x => IsGenericRequestHandler(x))
    .ToArray();

foreach (var genericRequestHandler in genericRequestHandlers)
{
    builder
        .RegisterGeneric(genericRequestHandler)
        .AsImplementedInterfaces();
}

private static bool IsGenericRequestHandler(Type t)
{
    return
        t.IsGenericTypeDefinition &&
        t.GetInterfaces.Any(i =>
        {
            return
                i.IsGenericType &&
                i.GetGenericTypeDefinition == typeof(IRequestHandler<,>);
        });
}

以下是IsGenericRequestHandler中所做检查的解释:

  • 是泛型类型定义的类型?换句话说,我们可以用这种类型定义构造泛型类型吗? GetAll<T>.Handler因为您可以构建GetAll<int>.HandlerGetAll<string>.Handler等等......
  • 类型是否实现了泛型类型的接口? GetAll<T>.Handler实现IRequestHandler<GetAll<T>.Request, GetAll<T>.Response>,这是一种通用类型
  • 最后,是这个接口IRequestHandler<,>的泛型类型定义?在我们的例子中,IRequestHandler<GetAll<T>.Request, GetAll<T>.Response>的泛型类型定义是IRequestHandler<,>,因此类型符合必要的标准。

我希望这是有道理的。

相关问题