Unity:更改隐式注册的默认生命周期管理器 and/or 禁用它们

Unity: Change default lifetime manager for implicit registrations and/or disable them

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

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

Is there a way I can either specify a different default lifetime manager

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

or disable the default auto-resolution behavior completely and limit the container to types I register myself

是的,容器扩展也可以做到这一点。

显式注册时首先记录注册的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);
            }
        }
    }
}

然后添加扩展,注册一些class然后解析。如果 class 未明确注册,则会抛出异常。

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>();

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

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

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