如何根据注入上下文自定义注入实例?
How to customize injected instance based on injection context?
我目前正在将应用程序从 Ninject
迁移到 Autofac 4
。我们有一个逻辑来设置解析的 class 实例的一些属性,然后再将其注入 *somewhere^。在 Ninject
中,我们是这样做的。
// Ninject setup example
this.Bind<IServiceContext>()
.To<DefaultServiceContext>()
.InCallScope()
.OnActivation((ctx, instance) =>
{
if (instance.Module == null) {
instance.Module = ctx.Request.Target.Member.DeclaringType.FullName;
}
});
代码中的关键是使用 ctx.Request.Target.Member
我们可以访问正在进行的注入发生的构造函数信息(当然是在构造函数注入的情况下)。因此,我们可以通过将其 Module
属性 设置为注入目标类型名称来初始化注入服务 class。
我在 Autofac
中找不到任何类似的内容。我已经尝试了 OnActivating
和 OnActivated
挂钩,但它们似乎没有提供此信息,而且与 Ninject
的挂钩相比,它们的含义似乎略有不同。
实例可以跨生命周期共享。为了避免任何副作用 Autofac 不会让我们知道哪个组件请求激活的组件。
顺便说一下,您可以创建一个自定义参数来负责注入所有 IServiceContext
。通过使用模块,您可以将此自定义参数添加到每个组件。这样你就会知道哪种类型请求了你的 IServiceContext
当请求 T
时,此模块将使您能够访问目标类型。
public class TargetPreparingCallbackModule<T> : Module
{
public TargetPreparingCallbackModule(Func<Type, Parameter> targetPreparing)
{
this._targetPreparing = targetPreparing;
}
private readonly Func<Type, Parameter> _targetPreparing;
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
registration.Preparing += this.Registration_Preparing;
}
private void Registration_Preparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, c) => p.ParameterType == typeof (T),
(p, c) => {
Parameter parameter = this._targetPreparing(t);
T instance = c.Resolve<T>(parameter);
return instance;
})
});
}
}
然后您可以像这样使用它:
builder.RegisterModule(
new TargetPreparingCallbackModule<Foo>(targetType => new NamedParameter("module", targetType.FullName)));
如果你想访问目标实例,你也可以使用目标的Activating
或Activated
事件。
我目前正在将应用程序从 Ninject
迁移到 Autofac 4
。我们有一个逻辑来设置解析的 class 实例的一些属性,然后再将其注入 *somewhere^。在 Ninject
中,我们是这样做的。
// Ninject setup example
this.Bind<IServiceContext>()
.To<DefaultServiceContext>()
.InCallScope()
.OnActivation((ctx, instance) =>
{
if (instance.Module == null) {
instance.Module = ctx.Request.Target.Member.DeclaringType.FullName;
}
});
代码中的关键是使用 ctx.Request.Target.Member
我们可以访问正在进行的注入发生的构造函数信息(当然是在构造函数注入的情况下)。因此,我们可以通过将其 Module
属性 设置为注入目标类型名称来初始化注入服务 class。
我在 Autofac
中找不到任何类似的内容。我已经尝试了 OnActivating
和 OnActivated
挂钩,但它们似乎没有提供此信息,而且与 Ninject
的挂钩相比,它们的含义似乎略有不同。
实例可以跨生命周期共享。为了避免任何副作用 Autofac 不会让我们知道哪个组件请求激活的组件。
顺便说一下,您可以创建一个自定义参数来负责注入所有 IServiceContext
。通过使用模块,您可以将此自定义参数添加到每个组件。这样你就会知道哪种类型请求了你的 IServiceContext
当请求 T
时,此模块将使您能够访问目标类型。
public class TargetPreparingCallbackModule<T> : Module
{
public TargetPreparingCallbackModule(Func<Type, Parameter> targetPreparing)
{
this._targetPreparing = targetPreparing;
}
private readonly Func<Type, Parameter> _targetPreparing;
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
registration.Preparing += this.Registration_Preparing;
}
private void Registration_Preparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, c) => p.ParameterType == typeof (T),
(p, c) => {
Parameter parameter = this._targetPreparing(t);
T instance = c.Resolve<T>(parameter);
return instance;
})
});
}
}
然后您可以像这样使用它:
builder.RegisterModule(
new TargetPreparingCallbackModule<Foo>(targetType => new NamedParameter("module", targetType.FullName)));
如果你想访问目标实例,你也可以使用目标的Activating
或Activated
事件。