Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

The Unity container will automatically resolve any type that it can figure out on its own without the need for manual registration. That's good in some ways, but the problem I have is that it uses a TransientLifetimeManager for this type of resolution, while I almost always want a ContainerControlledLifetimeManager. I can still register my types as singletons manually, of course, but if I forget, instead of getting an unhandled exception at startup, the app will launch successfully and everything will appear to work. But there will eventually be bugs, possibly very subtle, hard-to-diagnose ones, due to the fact that there are multiple instances of a type that's meant to be a singleton.

So my question is: Is there a way I can either specify a different default lifetime manager or disable the default auto-resolution behavior completely and limit the container to types I register myself (directly or by my own conventions)?

like image 775
dlf Avatar asked Jul 15 '15 02:07

dlf


People also ask

When should I use ContainerControlledLifetimeManager?

Use the ContainerControlledLifetimeManager when you want to create a singleton instance. In the above example, we specified ContainerControlledLifetimeManager in the RegisterType() method. So, Unity container will create a single instance of the BMW class and inject it in all the instances of Driver .

What is Hierarchicallifetimemanager?

A special lifetime manager which works like ContainerControlledLifetimeManager, except that in the presence of child containers, each child gets it's own instance of the object, instead of sharing one in the common parent.

What is RegisterType?

RegisterType a type mapping with the container, where the created instances will use the given LifetimeManager. Namespace: Microsoft.Practices.Unity.

What is Unity IoC?

Unity container is an open source IoC container for . NET applications supported by Microsoft. It is a lightweight and extensible IoC container. The source code for Unity container is available at https://github.com/unitycontainer/unity.


1 Answers

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

Yes, you can use a container extension that will use a different lifetime manager. See Request for configurable default lifetimemanager for an example.

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

Yes, a container extension can do this as well.

First during explicit registration record the BuildKey of the registration. Then before creating the object check if the BuildKey was explicitly registered.

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

Then add the extension, register some classes and resolve. If the class was not explicitly registered then an exception will be thrown.

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>();
like image 127
Randy supports Monica Avatar answered Oct 14 '22 03:10

Randy supports Monica