IsInstanceRegistered ?

Mar 23, 2008 at 9:30 PM
Is there some way of checking to see if an instance of a type is registered correctly? Right now I'm calling container.Resolve<MyType>() and it's throwing an exception because a dependency isn't defined (which is why I am resolving this type, ironically). Having an IsInstanceRegistered<ObjectType() would be handy. :) I'll just wrap this in a try-catch extension method in the meantime.

Thanks you for any consideration!
Mar 24, 2008 at 12:53 AM
Edited Mar 24, 2008 at 12:53 AM
Michael,

Don't forget that Unity tries to resolve any concrete type by using the longest ctor, so concrete types not registered will still get resolved and built.

However, if you want to check whether a given type is either registered or has an instance registered for it:

Something along those lines should do it:

public class ModelExtension : UnityContainerExtension
{
    public static bool CanResolve<T>(this UnityContainer container)
    {
        return container.Configure<ModelExtension>().registeredTypes.Contains(typeof(T));
    }
 
    private List<Type> registeredTypes = new List<Type>();
 
    protected override void Initialize()
    {
        Context.RegisteringInstance += (sender, e) => registeredTypes.Add(e.RegisteredType);
        Context.Registering += (sender, e) => registeredTypes.Add(e.TypeFrom);
    }
}

and then you can use:

UnityContainer container = new UnityContainer()
  .RegisterType<IFoo, Foo>()
  .RegisterInstance<IBar>(new Bar());
 
Assert.True(container.CanResolve<IFoo>());
Assert.True(container.CanResolve<IBar>());
Assert.False(container.CanResolve<ILogger>());

Just be careful if you keep additional data in your ModelExtension (such as the registered instance) to keep references in WeakRef as it would otherwise compete with the LifetimeManager.

Makes sense?
Mar 24, 2008 at 1:43 AM
This is a very cool way of looking at this. However, if I do this, then I will have my current extension coupled with this new one. Is this an acceptible practice? I guess what I'm looking to ensure is that if I add one extension, that it gracefully adds all dependent extensions without overriding/duplicating ones that may already exist within the container.

I suppose it would be feasible to put this extension in a common assembly (which I already have :)) and then just use it from there. Ok... I think I'm getting the hang of this stuff works... Thanks!
Apr 14, 2008 at 8:55 AM
Edited Apr 14, 2008 at 9:39 AM
If we try to compile we'll get an error for method 'public static bool CanResolve<T>(this UnityContainer container)' :
Extension methods must be defined in a non-generic static class

Probably I have to change the code to:

	public static class ModelExtension 
	{
		public class UnityExtensionWithTypeTracking: UnityContainerExtension
		{
			internal readonly List<Type> registeredTypes = new List<Type>();
 
			protected override void Initialize()
			{
				Context.RegisteringInstance += (sender, e) => registeredTypes.Add(e.RegisteredType);
				Context.Registering += (sender, e) => registeredTypes.Add(e.TypeFrom);
			}
			
		}
		public static bool CanResolve<T>(this UnityContainer container)
		{
			return container.Configure<UnityExtensionWithTypeTracking>().registeredTypes.Contains(typeof(T));
		}
	}

yeah?

And it's not enough. I guess you've just skipped steps wich obvious for you. But for me as for a begginer in Unity it's a bit challeging. So have to register the extension explicitly:
IUnityContainer container = new UnityContainer()
  .RegisterType<IFoo, Foo>()
  .RegisterInstance<IBar>(new Bar());
  .AddNewExtension<ModelExtension.UnityExtensionWithTypeTracking>();
 
Assert.IsTrue(container.CanResolve<IFoo>());
Assert.IsTrue(container.CanResolve<IBar>());
Assert.IsFalse(container.CanResolve<ILogger>());
Apr 1, 2009 at 1:27 PM
Hi,

 I've modified the classs so that it supports named instances:

    public static class ModelExtension
    {
        public class UnityExtensionWithTypeTracking : UnityContainerExtension
        {
            internal readonly List<RegisterInstanceEventArgs> registeredInstanceTypes = new List<RegisterInstanceEventArgs>();
            internal readonly List<RegisterEventArgs> registeredTypes = new List<RegisterEventArgs>();

            protected override void Initialize()
            {
                Context.RegisteringInstance += (sender, e) => registeredInstanceTypes.Add(e);
                Context.Registering += (sender, e) => registeredTypes.Add(e);
            }
        }

        public static bool CanResolve<T>(this IUnityContainer container)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes.Any(t => t.RegisteredType == typeof(T)) ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes.Any(t => t.TypeFrom == typeof(T)));
        }

        public static bool CanResolve<T>(this IUnityContainer container, string name)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes
                .Any(t => t.RegisteredType == typeof(T) && t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes
                .Any(t => t.TypeFrom == typeof(T) && t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)));
        }
    }

Hope this helps someone.

Regards,
Calin
Apr 15, 2009 at 3:28 PM
Hi,

There's a bug in the named instance variant that throws a null reference exception when it finds a match to the type but the name is not set.  I've modified it to include a null check on the name.

    public static class ModelExtension
    {
        public class UnityExtensionWithTypeTracking : UnityContainerExtension
        {
            internal readonly List<RegisterInstanceEventArgs> registeredInstanceTypes = new List<RegisterInstanceEventArgs>();
            internal readonly List<RegisterEventArgs> registeredTypes = new List<RegisterEventArgs>();

            protected override void Initialize()
            {
                Context.RegisteringInstance += (sender, e) => registeredInstanceTypes.Add(e);
                Context.Registering += (sender, e) => registeredTypes.Add(e);
            }
        }

        public static bool CanResolve<T>(this IUnityContainer container)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes.Any(t => t.RegisteredType == typeof(T)) ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes.Any(t => t.TypeFrom == typeof(T)));
        }

        public static bool CanResolve<T>(this IUnityContainer container, string name)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes
                .Any(t => t.RegisteredType == typeof(T) && t.Name != null && t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes
                .Any(t => t.TypeFrom == typeof(T) && t.Name != null && t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)));
        }
    }

Cheers,
John
Apr 15, 2009 at 6:04 PM
You are absolutely right John, hit that in my test's but forgot to post a new version.

Thank you,
Calin
Apr 17, 2009 at 1:35 PM
Hey,

One more change to the code, I've changed the string comparison to InvariantCulture.  This is to stop the Resolve exception  being thrown, as the container is case sensitive and won't resolve the type if the requested name and keyed name don't match exactly.

public static class ModelExtension
    {
        public class UnityExtensionWithTypeTracking : UnityContainerExtension
        {
            internal readonly List<RegisterInstanceEventArgs> registeredInstanceTypes = new List<RegisterInstanceEventArgs>();
            internal readonly List<RegisterEventArgs> registeredTypes = new List<RegisterEventArgs>();

            protected override void Initialize()
            {
                Context.RegisteringInstance += (sender, e) => registeredInstanceTypes.Add(e);
                Context.Registering += (sender, e) => registeredTypes.Add(e);
            }
        }

        public static bool CanResolve<T>(this IUnityContainer container)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes.Any(t => t.RegisteredType == typeof(T)) ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes.Any(t => t.TypeFrom == typeof(T)));
        }

        public static bool CanResolve<T>(this IUnityContainer container, string name)
        {
            return (container.Configure<UnityExtensionWithTypeTracking>().registeredInstanceTypes
                .Any(t => t.RegisteredType == typeof(T) && t.Name != null && t.Name.Equals(name, StringComparison.InvariantCulture))
                ||
                container.Configure<UnityExtensionWithTypeTracking>().registeredTypes
                .Any(t => t.TypeFrom == typeof(T) && t.Name != null && t.Name.Equals(name, StringComparison.InvariantCulture)));
        }
    }

Cheers,
John
Nov 23, 2010 at 3:47 PM
Edited Nov 23, 2010 at 5:14 PM

This thread was very helpful.  Our implementation of TryResolve<T> was very slow:

        public static T TryResolve<T>(this IUnityContainer container)
            where T : class
        {
            if (!typeof(T).IsInterface)
                throw new InvalidOperationException("Only interface types may be used with TryResolve.");

            try
            {
                return container.Resolve<T>();
            }
            catch (ResolutionFailedException e)
            {
                if (!e.Message.Contains("is an interface and cannot be constructed. Are you missing a type mapping?"))
                    throw;
                return null;
            }
        }

I've adapted the example to work with child containers, use dictionaries for the type lookups and to unregister event handlers when the extension is removed.

namespace Microsoft.Practices.Unity
{
    /// <summary>
    /// Extensions for Microsoft Unity
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Extension that tracks types registered in the container.
        /// </summary>
        public class UnityExtensionWithTypeTracking : UnityContainerExtension
        {
            private readonly Dictionary<TypeType> types = new Dictionary<TypeType>();
            private readonly Dictionary<stringType> namedTypes = new Dictionary<stringType>();
            private const string NamedTypeFormatString = "{0}, {1}";

            /// <summary>
            /// Returns whether a type is registered.
            /// </summary>
            /// <param name="type">The type.</param>
            public bool IsRegistered(Type type)
            {
                return this.types.ContainsKey(type)
                    || (this.Container.Parent != null && this.Container.Parent.IsRegistered(type));
            }

            /// <summary>
            /// Returns whether a type is registered.
            /// </summary>
            /// <param name="type">The type.</param>
            /// <param name="name">The name the type is registered with.</param>
            public bool IsRegistered(Type type, string name)
            {
                var namedTypeKey = UnityExtensionWithTypeTracking.GetNamedTypeKey(type, name);

                return this.namedTypes.ContainsKey(namedTypeKey)
                    || (this.Container.Parent != null && this.Container.Parent.IsRegistered(type, name));
            }

            protected override void Initialize()
            {
                this.Context.RegisteringInstance += (sender, e) => this.AddRegistrationToDictionaries(e.RegisteredType, e.Name);
                this.Context.Registering += (sender, e) => this.AddRegistrationToDictionaries(e.TypeFrom, e.Name);
            }

            public override void Remove()
            {
                this.Context.RegisteringInstance -= (sender, e) => this.AddRegistrationToDictionaries(e.RegisteredType, e.Name);
                this.Context.Registering -= (sender, e) => this.AddRegistrationToDictionaries(e.TypeFrom, e.Name);

                base.Remove();
            }

            /// <summary>
            /// Returns a key for use in the namedTypes dictionary.
            /// </summary>
            /// <param name="type">The registered type.</param>
            /// <param name="name">The name of the registration.</param>
            private static string GetNamedTypeKey(Type type, string name)
            {
                return string.Format(NamedTypeFormatString, type.AssemblyQualifiedName, name);
            }

            /// <summary>
            /// Adds a registration to the dictionaries.
            /// </summary>
            /// <param name="type">The from type.</param>
            /// <param name="name">The name of the registration.</param>
            private void AddRegistrationToDictionaries(Type type, string name)
            {
                if (!types.ContainsKey(type))
                    types.Add(type, type);

                if (name == nullreturn;
                var key = GetNamedTypeKey(type, name);
                if (!namedTypes.ContainsKey(key))
                    namedTypes.Add(key, type);
            }
        }

        /// <summary>
        /// Returns whether a type is registered.
        /// </summary>
        /// <typeparam name="T">The type.</typeparam>
        /// <param name="container">The container.</param>
        public static bool IsRegistered<T>(this IUnityContainer container)
        {
            return container.IsRegistered(typeof(T));
        }

        /// <summary>
        /// Returns whether a type is registered.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="type">The type.</param>
        public static bool IsRegistered(this IUnityContainer container, Type type)
        {
            return container.Configure<UnityExtensionWithTypeTracking>().IsRegistered(type);
        }

        /// <summary>
        /// Returns whether a type is registered.
        /// </summary>
        /// <typeparam name="T">The type.</typeparam>
        /// <param name="container">The container.</param>
        /// <param name="name">The name the type is registered with.</param>
        public static bool IsRegistered<T>(this IUnityContainer container, string name)
        {
            return container.IsRegistered(typeof(T), name);
        }

        /// <summary>
        /// Returns whether a type is registered.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="type">The type.</param>
        /// <param name="name">The name the type is registered with.</param>
        public static bool IsRegistered(this IUnityContainer container, Type type, string name)
        {
            return container.Configure<UnityExtensionWithTypeTracking>().IsRegistered(type, name);
        }

        /// <summary>
        /// Attempts to resolve a type, returning null when the type isn't registered.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="type">The type to resolve.</param>
        public static object TryResolve(this IUnityContainer container, Type type)
        {
            if (!type.IsInterface)
                throw new ArgumentException("The type must be an interface.""type");

            if (container.IsRegistered(type))
                return container.Resolve(type);
            return null;
        }

        /// <summary>
        /// Attempts to resolve a type, returning null when the type isn't registered.
        /// </summary>
        /// <typeparam name="T">The type to resolve.</typeparam>
        /// <param name="container">The container.</param>
        public static T TryResolve<T>(this IUnityContainer container)
            where T : class
        {
            return (T)container.TryResolve(typeof(T));
        }

        /// <summary>
        /// Attempts to resolve a type, returning null when the type isn't registered.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="type">The type to resolve.</param>
        /// <param name="name">The name the type is registered with.</param>
        public static object TryResolve(this IUnityContainer container, Type type, string name)
        {
            if (!type.IsInterface)
                throw new ArgumentException("The type must be an interface.""type");

            if (container.IsRegistered(type, name))
                return container.Resolve(type, name);
            return null;
        }

        /// <summary>
        /// Attempts to resolve a type, returning null when the type isn't registered.
        /// </summary>
        /// <typeparam name="T">The type to resolve.</typeparam>
        /// <param name="container">The container.</param>
        /// <param name="name">The name the type is registered with.</param>
        public static T TryResolve<T>(this IUnityContainer container, string name)
            where T : class
        {
            return (T)container.TryResolve(typeof(T), name);
        }

        /// <summary>
        /// Attempts to resolve a type, resolving the substitute type if the type isn't registered.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="type">The type to resolve.</param>
        /// <param name="substitute">The type to resolve if the first type isn't registered.</param>
        public static object TryResolve(this IUnityContainer container, Type type, Type substitute)
        {
            return container.TryResolve(type) ?? container.Resolve(substitute);
        }

        /// <summary>
        /// Attempts to resolve a type, resolving the substitute type if the type isn't registered.
        /// </summary>
        /// <typeparam name="T">The type to resolve.</typeparam>
        /// <typeparam name="TSubstitute">The type to resolve if the first type isn't registered.</typeparam>
        /// <param name="container">The container.</param>
        public static T TryResolve<T, TSubstitute>(this IUnityContainer container)
            where T : class
            where TSubstitute : T
        {
            return (T)container.TryResolve(typeof(T), typeof(TSubstitute));
        }

        /// <summary>
        /// Retrieves the child container registered with the specified name.  If one doesn't exist
        /// then a new child container is created, registered and returned.
        /// </summary>        
        /// The name the child container instance was registered with
        /// </param>
        public static IUnityContainer GetChildContainer(this IUnityContainer container, string name)
        {
            if (container.IsRegistered<IUnityContainer>(name))
                return container.Resolve<IUnityContainer>(name);

            var childContainer = container.CreateChildContainer();
            childContainer.AddNewExtension<Extensions.UnityExtensionWithTypeTracking>();
            container.RegisterInstance<IUnityContainer>(name, childContainer);

            return childContainer;
        }

        /// <summary>
        /// Resolves a list of types.
        /// </summary>
        /// <typeparam name="T">The base type or common interface of each item in the list.</typeparam>
        /// <param name="types">A list of types to resolve.</param>
        public static IEnumerable<T> Resolve<T>(this IUnityContainer container, IEnumerable<Type> types)
        {
            var items = new List<T>(types.Count());
            foreach (var type in types)
            {
                if (typeof(T).IsAssignableFrom(type))
                    items.Add((T)container.Resolve(type));
                else
                    throw new ArgumentException(string.Format("Each element must be a {0}."typeof(T).FullName), "types");
            }
            return items;
        }
    }
}