c# - Autofac没有解析其他项目中的接口
问题描述
我正在尝试编写一个通用命令总线(类库的一部分),它在我的每个服务中使用不同的命令和处理程序。
以下代码产生以下异常:
System.Exception:命令没有任何处理程序 RegisterUserCommand
我的印象是传递我的 UserService 的 ExecutingAssemblies 将允许容器解析我的 UserService 中的处理程序,但显然不是。
难道我做错了什么?
命令总线:
public interface ICommandBus
{
void Send<T>(T Command) where T : ICommand;
}
public class CommandBus : ICommandBus
{
private IContainer Container { get; set; }
public CommandBus(Assembly assembly)
{
Container = new CommandBusContainerConfig().Configure(assembly);
}
public void Send<TCommand>(TCommand command) where TCommand : ICommand
{
var handlers = Container.Resolve<IEnumerable<ICommandHandler<TCommand>>>().ToList();
if (handlers.Count == 1)
{
handlers[0].Handle(command);
}
else if (handlers.Count == 0)
{
throw new System.Exception($"Command does not have any handler {command.GetType().Name}");
}
else
{
throw new System.Exception($"Too many registred handlers - {handlers.Count} for command {command.GetType().Name}");
}
}
}
容器构建器:
public class CommandBusContainerConfig : IContainerConfig
{
public IContainer Configure(Assembly executingAssembly)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
return builder.Build();
}
}
在我的 UserService(ASP.Net Core 3) 中,这是一个引用上述 CommandBus 的不同项目:
public class RegisterUserCommand : ICommand
{
public readonly string Name;
public readonly Address Address;
public string MobileNumber;
public string EmailAddress;
public RegisterUserCommand(Guid messageId, string name, string mobileNumber, string emailAddress, Address address)
{
Name = name;
Address = address;
MobileNumber = mobileNumber;
EmailAddress = emailAddress;
}
命令处理程序:
public class RegisterUserComnmandHandler : ICommandHandler<RegisterUserCommand>
{
public void Handle(RegisterUserCommand command)
{
Console.WriteLine($"Create user {command.Name} {command.MobileNumber} - handler");
}
}
启动:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ICommandBus>(new CommandBus(Assembly.GetExecutingAssembly()));
}
控制器:
private readonly ICommandBus _commandBus;
public UsersController(ICommandBus commandBus) {
_commandBus = commandBus;
}
// POST api/values
[HttpPost]
public async Task<IActionResult> Post([FromBody]RegisterUserCommand command)
{
if (ModelState.IsValid)
{
CommandBus commandBus = new CommandBus(Assembly.GetExecutingAssembly());
commandBus.Send(command);
_commandBus.Send(Command); //Same result as above
// return result
return Ok(command);
}
return BadRequest();
}
谢谢,
解决方案
主要错误在这里:
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
RegisterUserComnmandHandler
不是一个ICommandHandler
而是一个ICommandHandler<RegisterUserCommand>
。代替IsAssignableTo<>
方法,您可以使用IsClosedTypeOf
which 是Autofac扩展,它可以尽您所能。
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsClosedTypeOf(typeof(ICommandHandler<>)))
.AsImplementedInterfaces();
顺便说一句,在您的代码示例中,您正在使用另一个容器。大多数时候,为整个应用程序拥有一个容器总是很简单的。要使事情井井有条,您可以使用autofac 模块。您还直接从容器中解析并且不使用范围,这意味着您的实例图不会在操作结束时被释放,而是会在容器的整个生命周期内保留。
在您的控制器中,我看到您正在CommandBus
为每个请求构建一个新容器,这将创建一个新容器。构建新容器是一项繁重的操作,您应该避免经常这样做,但只在应用程序启动时进行一次。
另外我不明白这个注册的意义:
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
它看起来你不需要它,对我来说似乎没用
推荐阅读
- php - AWS RDS SESSION 与 GLOBAL sql 模式设置值
- xml - 在一行中组合/组合 xml 元素属性
- django - Django从父对象访问模板中的子数据
- gcc - Mac gcc 编译器无法识别 c11
- python - 如何持续监控 xrandr 并自动响应多显示器设置中的物理变化?
- android - 应用程序处于后台后,Android socket-io 显示传输错误(断开连接)日志
- java - 加密/解密字节数组时出错:IllegalBlockSizeException:DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
- npm - 我无法安装工作箱 cli
- javascript - 在javascript中展平数组
- python - 从 DataFrame 中获取特定列表