添加 Autofac 扩展以在未正确注入已批准的类型时抛出异常
add Autofac extension to throw exception if not appropriately injected into approved type
我正在尝试创建一个 Autofac 扩展方法,当为不是批准的对象类型的对象创建注册类型时,该方法将抛出异常。
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> OnlyForInheritorsOf<TLimit, TReflectionActivatorData, TStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> registration, Type baseType)
where TReflectionActivatorData : ReflectionActivatorData
{
return registration.OnActivated(e =>
{
if (!baseType.IsInstanceOfType(??? instance of target/receiver ???))
throw new InvalidOperationException("Expected to implement");
});
}
e.Instance
指向刚好 created/activated 的对象。但是,我需要有关我们要将其提供给的对象的信息。我怎样才能得到这些信息?
如果您需要指定某些注册需要特定类型而其他注册需要另一种类型,您应该查看 Named and Keyed Services
例如,如果您有两个 IFoo
的实现,您可以像这样注册它们。
builder.RegisterType<Foo1>().Named<IFoo>("foo1");
builder.RegisterType<Foo2>().Named<IFoo>("foo2");
如果 Bar
需要 Foo1
你可以这样注册 Bar
:
builder.RegisterType<Bar>()
.As<Bar>()
.WithParameter((pi, c) => pi.ParameterType == typeof(IFoo),
(pi, c) => c.ResolveNamed<IFoo>("foo1"));
或者通过使用 Bar
构造函数上的属性指定键:
public class Bar
{
public Bar([WithKey("foo1")]IFoo foo)
{ }
}
我不知道您的确切场景,它可能需要一些代码重构,但这些更改可能比使用更复杂的场景更好。
顺便说一下,如果你真的想做你解释的事情。我写了一些使用自定义 Parameter
和 Module
的代码,如果调用者不是注册所需的类型,它们将抛出异常。
public static class RegistrationExtensions
{
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> OnlyForInheritorsOf<TLimit, TReflectionActivatorData, TStyle>(this IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> registration, Type baseType)
where TReflectionActivatorData : ReflectionActivatorData
{
registration.RegistrationData.Metadata.Add(RestrictingRegistrationModule.MetadataKey, baseType);
return registration;
}
}
public class RestrictingRegistrationModule : Autofac.Module
{
internal const String MetadataKey = "RestrictedType";
internal class RestrictedAutowiringParameter : Parameter
{
public RestrictedAutowiringParameter(RestrictingRegistrationModule restrictingRegistrationModule)
{
this._restrictingRegistrationModule = restrictingRegistrationModule;
}
private readonly RestrictingRegistrationModule _restrictingRegistrationModule;
public override Boolean CanSupplyValue(ParameterInfo pi, IComponentContext context, out Func<Object> valueProvider)
{
if (pi == null)
{
throw new ArgumentNullException("pi");
}
if (context == null)
{
throw new ArgumentNullException("context");
}
IInstanceLookup lookup = context as IInstanceLookup;
if (lookup != null)
{
IComponentRegistration registration;
if (context.ComponentRegistry.TryGetRegistration(new TypedService(pi.ParameterType), out registration))
{
Type restrictedType;
if (this._restrictingRegistrationModule.RestrictedRegistrations.TryGetValue(registration, out restrictedType))
{
Type callerType = lookup.ComponentRegistration.Activator.LimitType;
if (!(callerType == restrictedType || callerType.IsSubclassOf(restrictedType)))
{
throw new Exception(String.Format("Registration {0} is not compatible for type {1}", registration, callerType));
}
}
valueProvider = (() => context.ResolveComponent(registration, Enumerable.Empty<Parameter>()));
return true;
}
}
valueProvider = null;
return false;
}
}
public RestrictingRegistrationModule()
{
this._restrictedRegistrations = new Dictionary<IComponentRegistration, Type>();
}
private readonly Dictionary<IComponentRegistration, Type> _restrictedRegistrations;
public Dictionary<IComponentRegistration, Type> RestrictedRegistrations
{
get
{
return this._restrictedRegistrations;
}
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
Object value;
if (registration.Metadata.TryGetValue(RestrictingRegistrationModule.MetadataKey, out value))
{
this._restrictedRegistrations.Add(registration, (Type)value);
}
registration.Preparing += (sender, e) =>
{
e.Parameters = e.Parameters.Concat(new Parameter[] { new RestrictedAutowiringParameter(this) });
};
}
}
您可以像这样使用此代码:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new RestrictingRegistrationModule());
builder.RegisterType<Bar>().As<Bar>();
builder.RegisterType<Bar2>().As<Bar2>();
builder.RegisterType<Foo>().As<IFoo>().OnlyForInheritorsOf(typeof(Bar));
IContainer container = builder.Build();
Bar bar = container.Resolve<Bar>();
Bar2 bar2 = container.Resolve<Bar2>(); // will throw
这段代码我没有深入测试过,仅供娱乐和学习,谨慎使用!
我正在尝试创建一个 Autofac 扩展方法,当为不是批准的对象类型的对象创建注册类型时,该方法将抛出异常。
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> OnlyForInheritorsOf<TLimit, TReflectionActivatorData, TStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> registration, Type baseType)
where TReflectionActivatorData : ReflectionActivatorData
{
return registration.OnActivated(e =>
{
if (!baseType.IsInstanceOfType(??? instance of target/receiver ???))
throw new InvalidOperationException("Expected to implement");
});
}
e.Instance
指向刚好 created/activated 的对象。但是,我需要有关我们要将其提供给的对象的信息。我怎样才能得到这些信息?
如果您需要指定某些注册需要特定类型而其他注册需要另一种类型,您应该查看 Named and Keyed Services
例如,如果您有两个 IFoo
的实现,您可以像这样注册它们。
builder.RegisterType<Foo1>().Named<IFoo>("foo1");
builder.RegisterType<Foo2>().Named<IFoo>("foo2");
如果 Bar
需要 Foo1
你可以这样注册 Bar
:
builder.RegisterType<Bar>()
.As<Bar>()
.WithParameter((pi, c) => pi.ParameterType == typeof(IFoo),
(pi, c) => c.ResolveNamed<IFoo>("foo1"));
或者通过使用 Bar
构造函数上的属性指定键:
public class Bar
{
public Bar([WithKey("foo1")]IFoo foo)
{ }
}
我不知道您的确切场景,它可能需要一些代码重构,但这些更改可能比使用更复杂的场景更好。
顺便说一下,如果你真的想做你解释的事情。我写了一些使用自定义 Parameter
和 Module
的代码,如果调用者不是注册所需的类型,它们将抛出异常。
public static class RegistrationExtensions
{
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> OnlyForInheritorsOf<TLimit, TReflectionActivatorData, TStyle>(this IRegistrationBuilder<TLimit, TReflectionActivatorData, TStyle> registration, Type baseType)
where TReflectionActivatorData : ReflectionActivatorData
{
registration.RegistrationData.Metadata.Add(RestrictingRegistrationModule.MetadataKey, baseType);
return registration;
}
}
public class RestrictingRegistrationModule : Autofac.Module
{
internal const String MetadataKey = "RestrictedType";
internal class RestrictedAutowiringParameter : Parameter
{
public RestrictedAutowiringParameter(RestrictingRegistrationModule restrictingRegistrationModule)
{
this._restrictingRegistrationModule = restrictingRegistrationModule;
}
private readonly RestrictingRegistrationModule _restrictingRegistrationModule;
public override Boolean CanSupplyValue(ParameterInfo pi, IComponentContext context, out Func<Object> valueProvider)
{
if (pi == null)
{
throw new ArgumentNullException("pi");
}
if (context == null)
{
throw new ArgumentNullException("context");
}
IInstanceLookup lookup = context as IInstanceLookup;
if (lookup != null)
{
IComponentRegistration registration;
if (context.ComponentRegistry.TryGetRegistration(new TypedService(pi.ParameterType), out registration))
{
Type restrictedType;
if (this._restrictingRegistrationModule.RestrictedRegistrations.TryGetValue(registration, out restrictedType))
{
Type callerType = lookup.ComponentRegistration.Activator.LimitType;
if (!(callerType == restrictedType || callerType.IsSubclassOf(restrictedType)))
{
throw new Exception(String.Format("Registration {0} is not compatible for type {1}", registration, callerType));
}
}
valueProvider = (() => context.ResolveComponent(registration, Enumerable.Empty<Parameter>()));
return true;
}
}
valueProvider = null;
return false;
}
}
public RestrictingRegistrationModule()
{
this._restrictedRegistrations = new Dictionary<IComponentRegistration, Type>();
}
private readonly Dictionary<IComponentRegistration, Type> _restrictedRegistrations;
public Dictionary<IComponentRegistration, Type> RestrictedRegistrations
{
get
{
return this._restrictedRegistrations;
}
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
Object value;
if (registration.Metadata.TryGetValue(RestrictingRegistrationModule.MetadataKey, out value))
{
this._restrictedRegistrations.Add(registration, (Type)value);
}
registration.Preparing += (sender, e) =>
{
e.Parameters = e.Parameters.Concat(new Parameter[] { new RestrictedAutowiringParameter(this) });
};
}
}
您可以像这样使用此代码:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new RestrictingRegistrationModule());
builder.RegisterType<Bar>().As<Bar>();
builder.RegisterType<Bar2>().As<Bar2>();
builder.RegisterType<Foo>().As<IFoo>().OnlyForInheritorsOf(typeof(Bar));
IContainer container = builder.Build();
Bar bar = container.Resolve<Bar>();
Bar2 bar2 = container.Resolve<Bar2>(); // will throw
这段代码我没有深入测试过,仅供娱乐和学习,谨慎使用!