使用 RegisterAssemblyTypes 时通过短 class 名称解析服务
Resolve service by short class name while using RegisterAssemblyTypes
我想通过 class 短名称获取组件。
示例:
public interface ITransactionDef{}
public class Transaction1 : ITransactionDef {}
我将有数百笔交易 classes。所以我用它来注册所有 ITransactionDef-s:
builder.RegisterAssemblyTypes(typeof(MyType).Assembly)
.AssignableTo<ITransactionDef>().As<ITransactionDef>()
.AsSelf().InstancePerLifetimeScope();
但是在我的控制器中我有这个:
public IActionResult GetTransaction([FromQuery]GetTransactionRequestDto actionRequestDto)
{
ITransactionDef trx = (ITransactionDef)serviceProvider
.GetServices(typeof(ITransactionDef))
.FirstOrDefault(s => s.GetType().Name == actionRequestDto.TransactionId);
...
}
我不想要这个,因为它会根据每个请求构建所有交易。我想了三个解决方案:
- 在
actionRequestDto.TransactionId
中接收完整的 class 名称,获取类型并使用该类型代替 typeof(ITransactionDef)
。我想跳过这个。在前端某处使用完整的 class 名称似乎有点奇怪。
- 使用命名组件,但是我没有找到通过其短 class 名称注册组件的方法。此外,我需要在
RegisterAssemblyTypes
. 中执行此操作
- 使用
TransactionDefRepository
并用它注册组件:
builder.Register(c => new TransactionDefRepository());
builder.RegisterAssemblyTypes(typeof(MyType).Assembly).AssignableTo<ITransactionDef>().
OnActivating(e => {
TransactionDefRepository repository =
e.Context.Resolve<TransactionDefRepository>();
ITransactionDef transactionDef = ((ITransactionDef)e.Instance);
repository.Register(transactionDef);
})
.AsSelf().InstancePerLifetimeScope();
然后在控制器方法中使用它:
Type trxType = trxRepository.GetTransactionType(actionRequestDto.TransactionId);
ITransactionDef trx = (ITransactionDef)serviceProvider.GetServices(trxType)
这将不起作用,因为在请求组件时会调用 OnActivating,因此 TransactionDefRepository 为空。
我该如何实施?最好不用解1.
当您说“短 class 名称”时,我假设您的意思是 Type.Name
(SomeTransaction
) 而不是 Type.FullName
(MyNamespace.SomeTransaction
)。
在这里您不会看到任何特定于 Autofac 的内容来帮助您,因为类型确实需要限定。如果您考虑一下,您可能有 FirstNamespace.SomeType
和 SecondNamespace.SomeType
,所以 Type.Name
将是同一件事。 (实际上,从技术上讲,您可以在 中同时加载两个不同的程序集 中的相同 Type.FullName
,这样您就可以在那个时候进入 Type.AssemblyQualifiedName
,但我们不要在那里的杂草中。)
因此,如果你想解决它,可能你必须自己写一些东西。
但是,有一种方法我可以 可以 仅使用 Autofac 来完成,但是 IServiceProvider
无法使用它,您必须使用 Autofac:元数据
注册类型时,您可以注册元数据。在注册时添加 SimpleName
元数据值。
builder
.RegisterAssemblyTypes(typeof(MyType).Assembly)
.AssignableTo<ITransactionDef>()
.WithMetadata("SimpleName", t => t.Name)
.As<ITransactionDef>()
.InstancePerLifetimeScope();
请注意,我将其切换为将它们注册为 ITransactionDef
这会派上用场,因为您可以将类型注入控制器 而无需使用 [=27= 解析它们 ].它们是可组合的,因此:
public class MyController
{
private readonly IEnumerable<Meta<Lazy<ITransactionDef>>> _transactionDefs;
public MyController(IEnumerable<Meta<Lazy<ITransactionDef>>> transactionDefs)
{
this._transactionDefs = transactionDefs;
}
public string SomeAction(RequestObject request)
{
var simpleName = request.GetTheSimpleName();
// Find the right Meta<T> from the list
var meta = this._transactionDefs.First(m => m.Metadata["SimpleName"].Equals(simpleName));
// Get the Lazy<T> out of the Meta<T>
var lazy = meta.Value;
// Get the T out of the Lazy<T>
var transactionDef = lazy.Value;
// Now you have the right thing resolved
transactionDef.DoWork(request);
}
}
您可以将其压缩为 one-liner LINQ 查询,但我将其分解,以便您了解发生了什么。
无论如何,这是一种方法。如果需要,您可以在技术上将其包装在工厂中,然后注入工厂。
public class DefFactory
{
private readonly IEnumerable<Meta<Lazy<ITransactionDef>>> _transactionDefs;
public DefFactory(IEnumerable<Meta<Lazy<ITransactionDef>>> transactionDefs)
{
this._transactionDefs = transactionDefs;
}
public ITransactionDef GetDef(string simpleName)
{
return this._transactionDefs
.First(m => m.Metadata["SimpleName"].Equals(simpleName))
.Value
.Value;
}
}
您可以根据需要扩展概念。但是,无论如何,这可能是获得所需内容的最简单方法。
我想通过 class 短名称获取组件。 示例:
public interface ITransactionDef{}
public class Transaction1 : ITransactionDef {}
我将有数百笔交易 classes。所以我用它来注册所有 ITransactionDef-s:
builder.RegisterAssemblyTypes(typeof(MyType).Assembly)
.AssignableTo<ITransactionDef>().As<ITransactionDef>()
.AsSelf().InstancePerLifetimeScope();
但是在我的控制器中我有这个:
public IActionResult GetTransaction([FromQuery]GetTransactionRequestDto actionRequestDto)
{
ITransactionDef trx = (ITransactionDef)serviceProvider
.GetServices(typeof(ITransactionDef))
.FirstOrDefault(s => s.GetType().Name == actionRequestDto.TransactionId);
...
}
我不想要这个,因为它会根据每个请求构建所有交易。我想了三个解决方案:
- 在
actionRequestDto.TransactionId
中接收完整的 class 名称,获取类型并使用该类型代替typeof(ITransactionDef)
。我想跳过这个。在前端某处使用完整的 class 名称似乎有点奇怪。 - 使用命名组件,但是我没有找到通过其短 class 名称注册组件的方法。此外,我需要在
RegisterAssemblyTypes
. 中执行此操作
- 使用
TransactionDefRepository
并用它注册组件:
builder.Register(c => new TransactionDefRepository());
builder.RegisterAssemblyTypes(typeof(MyType).Assembly).AssignableTo<ITransactionDef>().
OnActivating(e => {
TransactionDefRepository repository =
e.Context.Resolve<TransactionDefRepository>();
ITransactionDef transactionDef = ((ITransactionDef)e.Instance);
repository.Register(transactionDef);
})
.AsSelf().InstancePerLifetimeScope();
然后在控制器方法中使用它:
Type trxType = trxRepository.GetTransactionType(actionRequestDto.TransactionId);
ITransactionDef trx = (ITransactionDef)serviceProvider.GetServices(trxType)
这将不起作用,因为在请求组件时会调用 OnActivating,因此 TransactionDefRepository 为空。
我该如何实施?最好不用解1.
当您说“短 class 名称”时,我假设您的意思是 Type.Name
(SomeTransaction
) 而不是 Type.FullName
(MyNamespace.SomeTransaction
)。
在这里您不会看到任何特定于 Autofac 的内容来帮助您,因为类型确实需要限定。如果您考虑一下,您可能有 FirstNamespace.SomeType
和 SecondNamespace.SomeType
,所以 Type.Name
将是同一件事。 (实际上,从技术上讲,您可以在 中同时加载两个不同的程序集 中的相同 Type.FullName
,这样您就可以在那个时候进入 Type.AssemblyQualifiedName
,但我们不要在那里的杂草中。)
因此,如果你想解决它,可能你必须自己写一些东西。
但是,有一种方法我可以 可以 仅使用 Autofac 来完成,但是 IServiceProvider
无法使用它,您必须使用 Autofac:元数据
注册类型时,您可以注册元数据。在注册时添加 SimpleName
元数据值。
builder
.RegisterAssemblyTypes(typeof(MyType).Assembly)
.AssignableTo<ITransactionDef>()
.WithMetadata("SimpleName", t => t.Name)
.As<ITransactionDef>()
.InstancePerLifetimeScope();
请注意,我将其切换为将它们注册为 ITransactionDef
这会派上用场,因为您可以将类型注入控制器 而无需使用 [=27= 解析它们 ].它们是可组合的,因此:
public class MyController
{
private readonly IEnumerable<Meta<Lazy<ITransactionDef>>> _transactionDefs;
public MyController(IEnumerable<Meta<Lazy<ITransactionDef>>> transactionDefs)
{
this._transactionDefs = transactionDefs;
}
public string SomeAction(RequestObject request)
{
var simpleName = request.GetTheSimpleName();
// Find the right Meta<T> from the list
var meta = this._transactionDefs.First(m => m.Metadata["SimpleName"].Equals(simpleName));
// Get the Lazy<T> out of the Meta<T>
var lazy = meta.Value;
// Get the T out of the Lazy<T>
var transactionDef = lazy.Value;
// Now you have the right thing resolved
transactionDef.DoWork(request);
}
}
您可以将其压缩为 one-liner LINQ 查询,但我将其分解,以便您了解发生了什么。
无论如何,这是一种方法。如果需要,您可以在技术上将其包装在工厂中,然后注入工厂。
public class DefFactory
{
private readonly IEnumerable<Meta<Lazy<ITransactionDef>>> _transactionDefs;
public DefFactory(IEnumerable<Meta<Lazy<ITransactionDef>>> transactionDefs)
{
this._transactionDefs = transactionDefs;
}
public ITransactionDef GetDef(string simpleName)
{
return this._transactionDefs
.First(m => m.Metadata["SimpleName"].Equals(simpleName))
.Value
.Value;
}
}
您可以根据需要扩展概念。但是,无论如何,这可能是获得所需内容的最简单方法。