2017-02-06 11 views
2

Контекст

При попытке упростить MediatR код, мы создали общий запрос/ответ/комбинацию обработчиков для GETALL, GetSingle и т.да .. функциональность. Ниже вы можете найти реализацию GETALLAutofac: Регистрация всех MediatR обработчиков как внутренние классы родовых типов

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() 
      }; 
     } 
    } 
} 

Проблему

Мы не можем показаться, чтобы зарегистрировать все наши RequestHandlers сразу используя Autofac.

Мы можем зарегистрировать один конкретный тип обработчика в нашем модуле Autofac с помощью:

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() для разрешения дополнительной зависимости. '

Что мы делаем неправильно (или забываем) здесь?

+0

Возможно, вы можете использовать мою реализацию mapmap. Это далеко не идеально, так как я должен был указать типы (команда <>, commandHandler <>, query <>, ...), но, возможно, вы можете начать с нее: https: //gist.github.com/hudo/0e9fb466c3fac5a04aa1b77cc95490e5 –

ответ

1

Вы не сможете зарегистрировать их сразу, потому что, как вы упомянули, вы должны зарегистрировать каждый из них как generics. Тем не менее, есть способ для вас, чтобы избежать ручного ведения списка таких обработчиков с небольшим количеством отражения:

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>.Handler, GetAll<string>.Handler и т. Д. Из этого
  • ли тип реализует интерфейс, который является общим типом? GetAll<T>.Handler реализует IRequestHandler<GetAll<T>.Request, GetAll<T>.Response>, который является общим типом
  • , наконец, является общим типом определения этого интерфейса IRequestHandler<,>? в нашем случае определение общего типа IRequestHandler<GetAll<T>.Request, GetAll<T>.Response> составляет IRequestHandler<,>, поэтому тип соответствует необходимым критериям.

Надеюсь, это имеет смысл.