如何为CQRS

时间:2016-12-15 21:54:19

标签: c# generics autofac cqrs autofac-configuration

是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 个答案:

答案 0 :(得分:0)

Issue registering generic types with Autofac in ASP.NET Core

有很多共同之处

您显示的代码中没有装饰器。

当您通过键入来注册处理程序时,您会得到错误 - 使用KeyedService类。如果您希望代码有效,那么您有两种解决方案。

最好的选择是不对您的服务进行密钥管理,因为没有理由 - 再次只查看您包含的代码 - 来修改您的服务。您可以通过以下方式注册键入

builder
    .RegisterAssemblyTypes(assemblies)
    .AsClosedTypesOf(typeof(IQueryHandler<,>))
    .InstancePerLifetimeScope();

另一种选择是在解析IQueryHandler<TQuery, TResult>时指示Autofac您正在寻找键控服务,因为这是您注册它们的方式。为此,您必须将QueryDispatcher代码修改为:

var handler = resolver.ResolveKeyed<IQueryHandler<TQuery, TResult>>("QueryHandler");

请不要传递给ResolveKeyed方法的密钥与注册代码中使用的密钥匹配。我不知道你为什么选择第二种选择,但这是可能的。

我认为你对decorators感到困惑。使用它们需要您键入您的服务,以便您可以装饰已经键入的服务。请再看一下the relevant documentation

Edwok评论后编辑

对于通用GetEntitiesQueryHandler<TEntity>案例,我要说你必须将其注册为open-generic component

builder
    .RegisterGeneric(typeof(GenericEntitiesQueryHandler<>))
    .As(typeof(IQueryHandler<,>));