我是Autofac和 ASP.NET Core的相对较新的用户。我最近将一个小项目从一个“经典”ASP.NET WebAPI项目移植到 ASP.NET Core。我在Autofac上遇到了问题,特别是在泛型类型的注册方面。
该项目使用命令模式,每个命令处理程序都是封闭的泛型,如
public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand>
这些命令处理程序被注入到控制器中,如下所示:
readonly private ICommandHandler<UpdateCustomerCommand> _updateCustomerCommand;
public ValuesController(ICommandHandler<UpdateCustomerCommand> updateCustomerCommand)
{
_updateCustomerCommand = updateCustomerCommand;
}
Autofac(部分)配置为:
var builder = new ContainerBuilder();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//This doesn't seem to be working as expected.
builder.RegisterAssemblyTypes(assemblies)
.As(t => t.GetInterfaces()
.Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)))
.Select(a => new KeyedService("commandHandler", a)));
上面的内容似乎没有像预期的那样注册通用。如果我用下面的方法注册,效果很好。
builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>();
当我说“它不起作用”时,我的意思是当尝试实例化控制器时,我得到“无效操作异常:在尝试激活“AutoFac_Test.Controllers.ValuesController”时无法解析类型“BusinessLogic.ICommandHandler”1[BusinessLogic.UpdateCustomerCommand]的服务。”
这在该项目的完整WebAPI版本中工作得很好,但在ASP.NET核心中重新创建之后就不行了。需要说明的是,在移植到ASP.NET核心之前,这种方法运行得非常好。
下面是我用来重现这个问题的代码的链接:https://dl.dropboxusercontent.com/u/185950/AutoFac_Test.zip
****发现解决方案后编辑****
事实上,我的Autofac配置没有任何问题,当然也不是Autofac本身。发生的事情是,我重命名了我的依赖程序集的输出,以使程序集扫描内容(替换AppDomain.CurrentDomain.GetAssemblies())
更加优雅,但是我从未修改过API项目的依赖项以引用新程序集。因此,Autofac正在扫描正确加载的程序集,这些程序集恰好是旧版本,其中不包含我期望的接口和实现...
因为即使当你试图手动注册类型时,Google也会带你到这个页面,所以我认为即使这个页面没有回答你的问题,它对未来的访问者还是有用的。因此,如果您想要手动注册一个泛型类型,可以使用以下格式:
service.AddTransient(typeof(IThing<>), typeof(GenericThing<>));
或者如果没有接口,那么只需:
service.AddTransient(typeof(GenericThing<>));
并且为了完整性,如果您有一个具有多个类型的泛型:
services.AddTransient(typeof(GenericThing<,>));
Autofac内置支持注册封闭类型的开放通用。
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
这将扫描您的程序集,查找关闭打开的泛型< code>ICommandHandler的类型
在您的示例中不起作用的是您将密钥与服务相关联。Autofac不会查找<code>ICommandHandler的键控版本
在QuietSeditionist的评论后编辑:
我将尝试详细介绍键控服务与默认服务。注册处理程序的方法是将<code>commandHandler</code>键与它们关联。
这意味着,构建容器后,只有这样一种方法可以解析此类处理程序:
// container will look for a registration for ICommandHandler<UpdateCustomerCommand> associated with the "commandHandler" key
container.ResolveKeyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
实例化 ValuesController
时,Autofac 不会查找 ICommandHandler 的键控注册
它正在执行的等效代码是 - 您可以尝试自己运行该代码以获取异常:
// BOOM!
container.Resolve<ICommandHandler<UpdateCustomerCommand>>();
您的第二次注册有效的原因是因为您没有键入服务:
// No key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.As<ICommandHandler<UpdateCustomerCommand>>();
// commandHandler key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.Keyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
但是,由于您不想一个一个地注册所有的处理程序,以下是如何注册它们而不用键入它们:
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
/Edit
我可以看到两种情况下键控服务可能很有用:
>
您有几种类型的实现相同的接口,并且您希望在不同的服务中注入不同的实现。比方说,您将
SqlConnection
和 DB2Connection
都注册为 IDbConnection
。然后,您将有 2 个服务,一个应该面向 SQL Server,另一个面向 DB2。如果它们都依赖于 IDbConnection,则需要确保在每个服务中注入正确的 IDbConnection
。
如果使用装饰器,注册的工作方式是通过键定义装饰器将应用于的服务-第一个示例是不言而喻的
我想知道如何在ASP中处理依赖注入。NET核心,用于同时具有对象和字符串作为参数的类型。由于字符串无法注册到DI框架,我目前正在使用implementationfactory并使用服务定位器模式,还有其他方法吗?是否有类似于Autofac的命名参数的.WithParameter? Asp.net核心DI使得向DI框架注册一个类型变得容易(并且干净),对于那些已经向DI框架注册了参数的类型。 给定以
会很好?或:
我正在尝试用Guice注入泛型类型。我有存储库 所以当我创建光标时
源代码 ENS中的反向解析是指从以太坊地址(比如0x1234...)到ENS域名的映射,它通过一个特定的域名空间(.addr.reverse)来实现。这个域名空间由一个专用注册中心拥有和控制,该注册中心可以接受任何人的调用,并根据调用者的地址为其分配子域名。 例如,账户 0x314159265dd8dbb310642f98f50c066173c1259b 可以通过调用声明 314159265dd8
抱歉,问题太简单了。我正在使用b2c扩展,无法找到定义的定义。有人能告诉我在哪里搜索那些文件吗。
泛型类型 除了反省函数, Swift允许你定义自己的泛型类型. 它们是可以用于任意类型的自定义类、结构体、枚举, 和Array、Dictionary方式类型. 1. 定义泛型类型 定义一个普通的结构体 struct IntStack { var items = [Int]() mutating func push(_ item: Int) { items.appen