繁体   English   中英

如何为CQRS的通用对象注册autofac装饰器

[英]How to register an autofac decorator for a generic object for 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有可能吗?

与在ASP.NET Core中使用Autofac注册通用类型的问题有很多共同点

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

通过使用KeyedService键入处理程序的来注册处理程序时,会KeyedService 如果您想让代码正常工作,则有两种解决方案。

最好的选择是不对服务进行加密,因为没有理由-只需查看包含的代码即可对服务进行加密。 您可以注册它们而无需通过以下方式键入它们:

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

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

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

请不要将传递给ResolveKeyed方法的密钥与ResolveKeyed中使用的密钥匹配。 我不知道为什么您会选择第二个选项,但是有可能。

我认为您对装饰家有些困惑。 使用它们需要您对服务进行密钥设置,以便您可以装饰已被密钥化的服务。 请再看一下相关文档

Edwok发表评论后进行编辑

对于通用的GetEntitiesQueryHandler<TEntity>案例,我想说您必须将其注册为开放式通用组件

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM