Как зарегистрировать автофакторный декоратор для универсального объекта для CQRS
Это реализации CQRS:
public interface IQuery<TResult> {}
public interface IQueryHandler<in TQuery, TResult>
where TQuery : IQuery<TResult>
{
Task<TResult> HandleAsync(TQuery query);
}
public interface IQueryDispatcher
{
Task<TResult> DispatchAsync<TQuery, TResult>(TQuery query)
where TQuery : IQuery<TResult>;
}
public class QueryDispatcher : IQueryDispatcher
{
private readonly IComponentContext resolver;
public QueryDispatcher(IComponentContext resolver)
{
if (resolver == null)
{
throw new ArgumentNullException(nameof(resolver));
}
this.resolver = resolver;
}
public async Task<TResult> DispatchAsync<TQuery, TResult>(TQuery query)
where TQuery : IQuery<TResult>
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
var handler = resolver.Resolve<IQueryHandler<TQuery, TResult>>();
return await handler.HandleAsync(query);
}
}
И я хочу создать общий запрос:
public class GetEntitiesQuery<TEntity> : IQuery<IQueryable<TEntity>>
where TEntity : Entity
{
}
public class GetEntitiesQueryHandler<TEntity> : IQueryHandler<GetEntitiesQuery<TEntity>, IQueryable<TEntity>>
where TEntity : Entity
{
// this code ...
}
Я пытаюсь зарегистрировать общий класс следующим образом:
builder.RegisterType<QueryDispatcher>().As<IQueryDispatcher>().InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(assemblies)
.As(type => type.GetInterfaces()
.Where(interfaceType => interfaceType.IsClosedTypeOf(typeof(IQueryHandler<,>)))
.Select(interfaceType => new KeyedService("QueryHandler", interfaceType)))
.InstancePerLifetimeScope();
И сгенерировать ошибку IQueryHandler не было зарегистрировано
Это возможно с Autofac?
1 ответ
Много общего с проблемой регистрации общих типов с помощью Autofac в ASP.NET Core
В показанном вами коде нет декораторов.
Полученная ошибка ожидается, когда вы регистрируете свои обработчики, набирая их - с помощью KeyedService
учебный класс. Если вы хотите, чтобы ваш код работал, у вас есть 2 решения.
Лучший вариант - не указывать свои услуги, поскольку нет никаких причин - опять же, только смотреть на код, который вы включили - чтобы обозначить свои услуги. Вы можете зарегистрировать их, не набирая их так:
builder
.RegisterAssemblyTypes(assemblies)
.AsClosedTypesOf(typeof(IQueryHandler<,>))
.InstancePerLifetimeScope();
Другой вариант - указать Autofac, что вы ищете службу с ключами, при разрешении IQueryHandler<TQuery, TResult>
так как ты их так зарегистрировал. Для этого вам придется изменить ваш QueryDispatcher
код для:
var handler = resolver.ResolveKeyed<IQueryHandler<TQuery, TResult>>("QueryHandler");
Пожалуйста, не передавайте ключ ResolveKeyed
Метод соответствует тому, который используется в регистрационном коде. Я не знаю, почему вы выбрали бы второй вариант, но это возможно.
Я полагаю, вы немного запутались с декораторами. Их использование требует от вас указания ключей ваших служб, чтобы вы могли украсить службы, которые были введены. Пожалуйста, посмотрите еще раз на соответствующую документацию.
Редактировать после комментария Эдвок
Для общего GetEntitiesQueryHandler<TEntity>
В этом случае я бы сказал, что вы должны зарегистрировать его как компонент общего назначения:
builder
.RegisterGeneric(typeof(GenericEntitiesQueryHandler<>))
.As(typeof(IQueryHandler<,>));