0

是 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 has not been registered

Autofac可以做到这一点吗?

4

1 回答 1

0

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

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

当您通过键入处理程序来注册处理程序时,您会得到预期的错误- 使用KeyedService类。如果您希望您的代码工作,您有 2 个解决方案。

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

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

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

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

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

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

在 Edwok 的评论后编辑

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

builder
    .RegisterGeneric(typeof(GenericEntitiesQueryHandler<>))
    .As(typeof(IQueryHandler<,>));
于 2016-12-15T23:02:43.250 回答