Unity:更改默认生命周期管理器以进行隐式注册和/或禁用它们

时间:2015-07-15 02:42:52

标签: c# .net dependency-injection unity-container

Unity容器将自动解析它可以自行解决的任何类型,而无需手动注册。这在某些方面很好,但我遇到的问题是它使用TransientLifetimeManager这种类型的分辨率,而我几乎总是想要ContainerControlledLifetimeManager。当然,我仍然可以手动将我的类型注册为单身人士,但如果我忘记了,而不是在启动时获得未处理的异常,应用程序将成功启动,一切似乎都会起作用。但是最终会出现一些错误,可能是非常微妙的,难以诊断的错误,因为有一个类型的多个实例可能是一个单例。

所以我的问题是:有没有办法可以指定不同的默认生命周期管理器或完全禁用默认的自动解析行为,并将容器限制为我自己注册的类型(直接或通过我自己的约定)?

2 个答案:

答案 0 :(得分:7)

  

有没有办法可以指定不同的默认生命周期管理器

是的,您可以使用将使用不同生命周期管理器的容器扩展。有关示例,请参阅Request for configurable default lifetimemanager

  

或完全禁用默认的自动解析行为,并将容器限制为我自己注册的类型

是的,容器扩展也可以这样做。

首先在显式注册期间记录注册的BuildKey。然后在创建对象之前检查BuildKey是否已明确注册。

public class RegistrationTrackingExtension : UnityContainerExtension
{
    private ConcurrentDictionary<NamedTypeBuildKey, bool> registrations =
        new ConcurrentDictionary<NamedTypeBuildKey, bool>();

    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<NamedTypeBuildKey, bool> registrations; 

        public ValidateRegistrationStrategy(ConcurrentDictionary<NamedTypeBuildKey, bool> 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);
            }
        }
    }
}

然后添加扩展名,注册一些类并解决。如果未明确注册该类,则会抛出异常。

IUnityContainer container = new UnityContainer();
// Add container extension
container.AddNewExtension<RegistrationTrackingExtension>();

// Register types
container.RegisterType<MyClass>();
container.RegisterType<IMyClass, MyClass>();
container.RegisterType<IMyClass, MyClass>("A");

// These succeed because they were explicitly registered
container.Resolve<IMyClass>();
container.Resolve<IMyClass>("A");
container.Resolve<MyClass>();

// MyClass2 was not registered so this will throw an exception
container.Resolve<MyClass2>();

答案 1 :(得分:2)

我尝试了DefaultLifetimeManegerExtension但不知何故它没有用。 (也许Unity已经改变了?)。无论如何,如果你不想使用扩展,你也可以使用RegsiterByConvention功能。

container.RegisterTypes(AllClasses.FromLoadedAssemblies(), WithMappings.None, WithName.Default, x => new DisposingTransientLifetimeManager());

这将使用“DisposingTransientLifetimeManager”注册所有类,我选择将其用作默认类。请注意,您应该在注册开始时执行此操作,因为所有注册都将覆盖相同类型和名称的任何先前注册。