Autofac.Core.Registration.ComponentNotRegisteredException

TjD*_*haw 1 c# autofac cqrs .net-core

我试图在我的应用程序中实现CQRS模式.所以我在这里找到了如何从程序集中注册所有命令处理程序:Autofac解决CQRS CommandDispatcher中的依赖关系

但它对我来说效果不佳.这是代码:

        containerBuilder.RegisterAssemblyTypes(assembly)
            .AsClosedTypesOf(typeof(ICommandHandler<>));

        containerBuilder.RegisterAssemblyTypes(assembly)
            .AsClosedTypesOf(typeof(IQueryHandler<,>));
Run Code Online (Sandbox Code Playgroud)

处理工厂

 public class CqrsHandlerFactory : ICqrsHandlerFactory
{
    private readonly IContainer container;

    public CqrsHandlerFactory(IContainer container)
    {
        this.container = container;
    }

    public ICommandHandler<TCommand> GetCommandHandler<TCommand>(TCommand command) where TCommand : class, ICommand
    {
        return container.Resolve<ICommandHandler<TCommand>>();
    }

    public IQueryHandler<TQuery, object> GetQueryHandler<TQuery>(TQuery query) where TQuery : class, IQuery
    {
        return container.Resolve<IQueryHandler<TQuery, object>>();
    }
}
Run Code Online (Sandbox Code Playgroud)

总线

 public class CqrsBus : ICqrsBus
{
    private readonly ICqrsHandlerFactory cqrsHandlerFactory;

    public CqrsBus(ICqrsHandlerFactory cqrsHandlerFactory)
    {
        this.cqrsHandlerFactory = cqrsHandlerFactory;
    }

    public void ExecuteCommand(ICommand command)
    {
        var handler = cqrsHandlerFactory.GetCommandHandler(command);
        if (handler == null)
            throw new NotImplementedHandlerException(string.Format("Cannot find handler for {0}", command.GetType()));
        handler.Handle(command);
    }

    public TResult RunQuery<TResult>(IQuery query)
    {
        var handler = cqrsHandlerFactory.GetQueryHandler(query);
        if (handler == null)
            throw new NotImplementedHandlerException(string.Format("Cannot find handler for {0}", query.GetType()));
        return (TResult)handler.Handle(query);
    }
}
Run Code Online (Sandbox Code Playgroud)

例外

Autofac.dll中出现"Autofac.Core.Registration.ComponentNotRegisteredException"类型的例外但未在用户代码中处理其他信息:请求的服务'PromocjeWsieciowkach.Messaging.Core.ICommandHandler`1 [[PromocjeWsieciowkach.Messaging.Core.ICommand ,PromocjeWsieciowkach.Messaging.Core,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'尚未注册.要避免此异常,请注册组件以提供服务,使用IsRegistered()检查服务注册,或使用ResolveOptional()方法解析可选依赖项.

堆栈跟踪

在Autocac.ResolutionExtensions.ResolveService(IComponentContext上下文,服务服务,IEnumerable 1 parameters) at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable1参数)位于C:\ Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach中的PromocjeWsieciowkach.Messaging.Factories.CqrsHandlerFactory.GetCommandHandler [TCommand](TCommand命令). Messaging\Factories\CqrsHandlersFactory.cs:第17行,位于C:\ Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach.Messaging\Bus\CqrsBus.cs:第17行的PromocjeWsieciowkach.Messaging.Bus.CqrsBus.ExecuteCommand(ICommand命令)在C:\ Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach\Controllers\PostController.cs中的PromocjeWsieciowkach.Controllers.PostController.Index():位于Microsoft.AspNetCore的lambda_method(Closure,Object,Object [])的第20行. Mvc.Internal.ControllerActionInvoker.d__28.MoveNext()

那么我做错了什么?

Ste*_*ven 6

您的代码和异常消息清楚地显示了问题.总之,您的异常消息解释了:

请求的服务'ICommandHandler <ICommand>'尚未注册.

换句话说,您要求的是ICommandHandler<ICommand>而不是ICommandHandler<TestCommand>.这可以在这里看到:

public void ExecuteCommand(ICommand command)
{
    var handler = cqrsHandlerFactory.GetCommandHandler(command);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

C#编译器对GetCommandHandler<T>调用应用了类型推断.所以以下代码是实际调用:

var handler = cqrsHandlerFactory.GetCommandHandler<ICommand>(command);
Run Code Online (Sandbox Code Playgroud)

您应该将ICrqsBus.ExecuteCommand方法更改为以下内容:

public void ExecuteCommand<TCommand>(TCommand command)
{
    // You can merge the factory and your CqrsBus. Splitting them is useless.
    var handler = cqrsHandlerFactory.GetCommandHandler<TCommand>();
    // You don't need then null check; Autofac never returns null.
    handler.Handle(command);
}
Run Code Online (Sandbox Code Playgroud)

如果您不能使该ExecuteCommand方法通用(例如,因为您在编译时不知道命令类型),您应该使用反射API构建泛型类型,如下所示:

public class CqrsBus : ICqrsBus
{
    private readonly IComponentContext context;

    public CqrsBus(IComponentContext context)
    {
        this.context = context;
    }

    public void ExecuteCommand(ICommand command)
    {
        Type handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
        dynamic handler = this.context.Resolve(handlerType);
        void handler.Execute((dynamic)command);
    }
}
Run Code Online (Sandbox Code Playgroud)