How to determine if object is held by the container?

Apr 13, 2011 at 10:00 PM

I'm trying to determine how to write an extension method for unity that would allow me to determine if an object is held by a container (ideally, regardless of which lifetime manager was used, but if the implementation had to be specific to a certain type of lifetime manager such as ContainerControlledLifetimeManager that would be OK).

The reason I need this is I need to conditionally perform some operations on objects that are more expensive to create, but only if they were created (below is an example).

Thanks, Todd

            var container = new UnityContainer();
            container.RegisterType<UserSession>(
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c => c.Resolve<ISessionManager>().StartUserSession() ));

            ... Later ... 

            if( container.IsHeldByContainer<UserSession>() )
            {
                 container.Resolve<ISessionManager>().EndUserSession(container.Resolve<UserSession>());
            }
Apr 14, 2011 at 1:10 AM

You would need to subscribe to the Registering events so you can keep track of the types that are getting registered.  A sample code was posted in this thread.

If you upgrade to Unity 2.0, this can be easily accomplished using the IsRegistered method of the UnityContainer class. 

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 14, 2011 at 1:52 AM

I am using unity 2.0, but what I'm trying to check here is if an object of the specified type is held by the container.  IsRegistered() only tells you if there is a type registration.

Apr 14, 2011 at 2:14 AM

I'm confused, what do you exactly mean "held by the container"?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 14, 2011 at 2:25 AM

An object instance instance is held by the container (meaning the underlying lifetime manager for the type registered).  As in, the following unit test passes:

            var container = new UnityContainer();
            container.RegisterType<UserSession>(
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c => c.Resolve<ISessionManager>().StartUserSession() ));

            Assert.IsFalse( container.IsHeldByContainer<UserSession>() );
            container.Resolve<UserSession>();
            Assert.IsTrue( container.IsHeldByContainer<UserSession>() );

Apr 14, 2011 at 2:42 AM

I see, you mean the instance is already created by the container?  In your first assert, the UserSession isn't held by the container yet since there's no existing instance yet of the UserSession since it's the first time that that type will be resolved.  And then in the second assert, it says the UserSession is held by the container since it was previously resolved and that instance was kept by the container due to the use of ContainerControlledLifetimeManager.  Am I right?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 14, 2011 at 2:45 AM

Right, so if the default TransientLifetimeManager was used, such a method would always return false:

var container = new UnityContainer();
container.RegisterType<UserSession>();
Assert.IsFalse( container.IsHeldByContainer<UserSession>() );
container.Resolve<UserSession>();
Assert.IsFalse( container.IsHeldByContainer<UserSession>() );

Apr 14, 2011 at 2:57 AM

Ok.  I'll investigate how you can implement this functionality and get back to you.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 15, 2011 at 12:05 AM
Edited Apr 15, 2011 at 1:23 AM

So the key is to get the ILifetimePolicy of the object and call the GetValue method:

public static class CustomExtensionContainerExtension
    {
        public static bool? IsHeldByContainer<T>(this IUnityContainer container)
        {
            return IsHeldByContainer<T>(container, null);
        }
 
        public static bool? IsHeldByContainer<T>(this IUnityContainer container, string name)
        {
            var extension = container.Configure<CustomExtension>();
 
           if (extension == null) return null; //consider to either return null or throw an exception 
return extension.InstanceExists(typeof(T), name);
        }     
}       
public class CustomExtension : UnityContainerExtension     
{         
        protected override void Initialize() { }           
        
        public bool InstanceExists(Type typeToCheck, string name)         
        {             
		var key = new NamedTypeBuildKey(typeToCheck, name);             
		var policy = Context.Policies.Get<ILifetimePolicy>(key);             
		if (policy == null) return false;             
		var value = policy.GetValue();             
		return value != null;  
	}     
}

This is how  you can use it then:

var container = new UnityContainer();
container.AddNewExtension<CustomExtension>();
 
container.RegisterType<UserSession>(new ContainerControlledLifetimeManager());
 
Console.WriteLine(container.IsHeldByContainer<UserSession>());
 
container.Resolve<UserSession>();
 
Console.WriteLine(container.IsHeldByContainer<UserSession>());

Hope this helps.

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 15, 2011 at 5:09 PM

This doesn't seem to work for interface registrations... how would I get this to work?

var container = new UnityContainer();
container.RegisterType<IUserSession, UserSession>(new ContainerControlledLifetimeManager());
Assert.IsFalse( container.IsHeldByContainer<IUserSession>() );
container.Resolve<IUserSession>();
Assert.IsTrue( container.IsHeldByContainer<IUserSession>() );

Apr 18, 2011 at 12:28 AM

I didn't check for interfaces, sorry about that.  You can modify the InstanceExists method to:

public bool InstanceExists(Type typeToIntercept, string name)
{
            var key = new NamedTypeBuildKey(typeToIntercept, name);
            ILifetimePolicy policy = Context.Policies.Get<ILifetimePolicy>(key);
            if (policy == null)
            {
                var buildKeyMapping = Context.Policies.Get<IBuildKeyMappingPolicy>(key);
                var actualKey = buildKeyMapping.Map(key, null);
                policy = Context.Policies.Get<ILifetimePolicy>(actualKey);
            }
            if (policy == null)
            {
                return false;
            }
            object value = policy.GetValue();
            return value != null;
}

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 18, 2011 at 4:11 PM

So far so good - thanks for the help!