Dependency injection 在ASP.NET Core中向Autofac注册泛型类型时出现问题
我是Autofac和ASP.NET Core的新用户。我最近将一个小项目从“经典”ASP.NETWebAPI项目移植到ASP.NETCore。我在Autofac方面遇到了问题,特别是在注册泛型类型方面 这个项目使用一个命令模式,每个命令处理程序都是一个封闭的泛型Dependency injection 在ASP.NET Core中向Autofac注册泛型类型时出现问题,dependency-injection,asp.net-core,autofac,Dependency Injection,Asp.net Core,Autofac,我是Autofac和ASP.NET Core的新用户。我最近将一个小项目从“经典”ASP.NETWebAPI项目移植到ASP.NETCore。我在Autofac方面遇到了问题,特别是在注册泛型类型方面 这个项目使用一个命令模式,每个命令处理程序都是一个封闭的泛型 public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand> 公共类UpdateCustomerCommandHandl
public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand>
公共类UpdateCustomerCommandHandler:ICommandHandler
这些命令处理程序被注入控制器中,如下所示:
readonly private ICommandHandler<UpdateCustomerCommand> _updateCustomerCommand;
public ValuesController(ICommandHandler<UpdateCustomerCommand> updateCustomerCommand)
{
_updateCustomerCommand = updateCustomerCommand;
}
只读私有ICommandHandler\u updateCustomerCommand;
公共价值控制器(ICommandHandler updateCustomerCommand)
{
_updateCustomerCommand=updateCustomerCommand;
}
Autofac配置(部分)为:
var builder=newcontainerbuilder();
var assemblies=AppDomain.CurrentDomain.GetAssemblies();
//这似乎不像预期的那样有效。
builder.RegisterAssemblyTypes(程序集)
.As(t=>t.GetInterfaces()
。其中(a=>a.IsClosedTypeOf(typeof(ICommandHandler)))
.Select(a=>newkeyedservice(“commandHandler”,a));
上述情况似乎并没有像预期的那样注册泛型。如果我使用下面的注册方法,效果会很好
builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>();
builder.RegisterType().As();
当我说“它不工作”时,我的意思是,当尝试实例化控制器时,我得到“InvalidOperationException:无法解析类型'BusinessLogic.ICommandHandler`1[BusinessLogic.UpdateCustomerCommand]'的服务,同时尝试激活'AutoFac_Test.controller.ValuesController'
这在该项目的完整WebAPI版本中运行良好,但在ASP.NET Core中重新创建后效果不佳。要明确的是,在移植到ASP.NET内核之前,它工作得非常好
以下是我用来重新创建此问题的代码的链接:
****发现解决方案后编辑****
事实上,我的Autofac配置没有任何问题,当然Autofac本身也没有问题。发生的事情是,我重命名了依赖程序集的输出,以使程序集能够扫描(替换
AppDomain.CurrentDomain.GetAssemblies()
更优雅,但我从未修改API项目的依赖项以引用新程序集。因此,Autofac正在扫描正确加载的程序集,这些程序集恰好是较旧的版本,其中不包含我所期望的接口和实现…Autofac内置了注册已关闭类型的o钢笔通用
builder
.RegisterAssemblyTypes(此程序集)
.AsClosedTypesOf(typeof(ICommandHandler));
这将扫描程序集,找到关闭打开的泛型接口的类型,并根据它们实现的关闭的泛型接口注册它们中的每一个-在您的例子中是,ICommandHandler
在您的示例中,不起作用的是您将密钥与服务关联。Autofac在尝试实例化ValuesController
时,不会查找您的ICommandHandler
的密钥版本,这就是您得到异常的原因
在QuietEdition的评论后编辑:
我将尝试详细介绍键控与默认服务。您注册处理程序的方式是将commandHandler
键与它们关联
这意味着,一旦构建了容器,以下是解析此类处理程序的唯一方法:
//容器将查找与“commandHandler”键关联的ICommandHandler的注册
container.resolvedkeyed(“commandHandler”);
在实例化ValuesController
时,Autofac不会查找ICommandHandler
的键控注册,因为它没有被要求这样做
它执行的等效代码是-您可以尝试自己运行该代码以获得异常:
//轰!
container.Resolve();
第二次注册有效的原因是您没有为服务设置密钥:
//没有密钥
建设者
.RegisterType()
.As();
//commandHandler键
建设者
.RegisterType()
.Keyed(“commandHandler”);
但是,由于您不想逐个注册所有处理程序,下面介绍如何在不键入它们的情况下注册它们:
builder
.RegisterAssemblyTypes(此程序集)
.AsClosedTypesOf(typeof(ICommandHandler));
/编辑
我可以看到两种情况,其中键控服务非常有用:
- 您有几种类型实现相同的接口,并且希望在不同的服务中注入不同的实现。例如,您将
和SqlConnection
注册为DB2Connection
。然后您有两个服务,一个是针对SQL Server的,另一个是针对DB2的。如果两者都依赖于IDbConnection
,您需要确保在每个服务中注入正确的连接IDbConnection
- 如果使用,注册的工作方式就是通过一个键定义decorator将应用到的服务——第一个示例是不言自明的
builder
.RegisterAssemblyTypes(此程序集)
.AsClosedTypesOf(typeof(ICommandHandler));
这将扫描程序集,找到关闭打开的泛型接口的类型,并根据它们实现的关闭的泛型接口注册它们中的每一个-在您的例子中是,ICommandHandler
在您的示例中,不起作用的是您将密钥与服务关联。Autofac在尝试实例化ValuesController
时,不会查找您的ICommandHandler
的密钥版本,这就是您得到异常的原因
在QuietEdition的评论后编辑:
我将试着详细介绍一下键控与默认服务
builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>();
service.AddTransient(typeof(IThing<>), typeof(GenericThing<>));
service.AddTransient(typeof(GenericThing<>));
services.AddTransient(typeof(GenericThing<,>));