Unity:更改默认生命周期管理器以进行隐式注册和/或禁用它们
Unity容器将自动解析它可以自己解决的任何类型,而无需手动注册。 这在某些方面很好,但我遇到的问题是它使用TransientLifetimeManager
进行这种类型的分辨率,而我几乎总是想要一个ContainerControlledLifetimeManager
。 当然,我仍然可以手动将我的类型注册为单身人士,但如果我忘了,而不是在启动时获得未处理的exception,应用程序将成功启动,一切似乎都会起作用。 但是最终会出现一些错误,可能是非常微妙的,难以诊断的错误,因为有一个类型的多个实例是一个单例。
所以我的问题是:有没有办法可以指定不同的默认生命周期管理器或完全禁用默认的自动解析行为,并将容器限制为我自己注册的类型(直接或通过我自己的约定)?
有没有办法可以指定不同的默认生命周期管理器
是的,您可以使用将使用不同生命周期管理器的容器扩展。 有关示例,请参阅请求可配置的默认生命周期管理器。
或者完全禁用默认的自动解析行为,并将容器限制为我自己注册的类型
是的,容器扩展也可以这样做。
首先在显式注册期间记录注册的BuildKey。 然后在创建对象之前检查BuildKey是否已显式注册。
public class RegistrationTrackingExtension : UnityContainerExtension { private ConcurrentDictionary registrations = new ConcurrentDictionary(); protected override void Initialize() { base.Context.Registering += Context_Registering; base.Context.Strategies.Add( new ValidateRegistrationStrategy(this.registrations), UnityBuildStage.PreCreation); } private void Context_Registering(object sender, RegisterEventArgs e) { var buildKey = new NamedTypeBuildKey(e.TypeTo, e.Name); this.registrations.AddOrUpdate(buildKey, true, (key, oldValue) => true); } public class ValidateRegistrationStrategy : BuilderStrategy { private ConcurrentDictionary registrations; public ValidateRegistrationStrategy(ConcurrentDictionary registrations) { this.registrations = registrations; } public override void PreBuildUp(IBuilderContext context) { if (!this.registrations.ContainsKey(context.BuildKey)) { Exception e = new Exception("Type was not explicitly registered in the container."); throw new ResolutionFailedException(context.BuildKey.Type, context.BuildKey.Name, e, context); } } } }
然后添加扩展,注册一些类并解决。 如果未明确注册该类,则会抛出exception。
IUnityContainer container = new UnityContainer(); // Add container extension container.AddNewExtension(); // Register types container.RegisterType(); container.RegisterType(); container.RegisterType("A"); // These succeed because they were explicitly registered container.Resolve(); container.Resolve ("A"); container.Resolve(); // MyClass2 was not registered so this will throw an exception container.Resolve();
我尝试了DefaultLifetimeManegerExtension但不知何故它没有用。 (也许Unity已经改变了?)。 无论如何,如果您不想使用扩展,您还可以使用RegsiterByConventionfunction。
container.RegisterTypes(AllClasses.FromLoadedAssemblies(), WithMappings.None, WithName.Default, x => new DisposingTransientLifetimeManager());
这将使用“DisposingTransientLifetimeManager”注册所有类,我选择将其用作默认类。 请注意,您应该在注册开始时执行此操作,因为所有注册都将覆盖相同类型和名称的任何先前注册。