1

If you did this:

class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer();

            container.RegisterType<IService, DataService>();
            container.RegisterType<IService, LoggingService>("Logging");
            container.RegisterType<IService, CachingService>("Caching");

            var services = container.ResolveAll<IService>();

            foreach (var service in services)
                Console.WriteLine(service);

            Console.ReadKey();
        }
    }

    interface IService { }
    class DataService : IService { }
    class LoggingService : IService { }
    class CachingService : IService { }

The output you would get would include only the named mappings and would not include the default DataService mapping. The output of this program would be:

MoreUnityPractice.LoggingService
MoreUnityPractice.CachingService

Why did they decide not to get the default, unnamed mapping/registration with ResolveAll?

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336

1 Answers1

2

It was done this way so that you can have a Composite.

An example Composite IService

public class CompositeDataService : IService
{
    public readonly IService[] services;

    public CompositeDataService(IService[] services)
    {
        this.services = services;
    }
}

And a demonstration test

[Fact]
public void Test()
{
    var container = new UnityContainer();

    container.RegisterType<IService, CompositeDataService>();
    container.RegisterType<IService, LoggingService>("Logging");
    container.RegisterType<IService, CachingService>("Caching");

    var service = container.Resolve<IService>();

    Assert.IsType<CompositeDataService>(service);
    Assert.Equal(2, ((CompositeDataService)service).services.Count());
}

It is officially documented here

The two overloads of this method [ResolveAll] accept either an interface or a type name, and they return an instance of IEnumerable that contains references to all registered objects of that type that are not default mappings. The list returned by the ResolveAll method contains only named instance registrations. The ResolveAll method is useful if you have registered multiple object or interface types using the same type but different names


Here is some code to work around it (Note: I haven't run the code)

using System;

using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;

public class Remember : UnityContainerExtension
{
    protected override void Initialize()
    {
        this.Context.Registering += this.OnRegistering;
        this.Context.RegisteringInstance += this.OnRegisteringInstance;
    }

    private void OnRegisteringInstance(object sender, RegisterInstanceEventArgs e)
    {
        if(string.IsNullOrEmpty(e.Name))
        {
            string uniqueName = Guid.NewGuid().ToString();

            this.Context.RegisterNamedType(e.RegisteredType, uniqueName);

            this.Context.Policies.Set<IBuildKeyMappingPolicy>(
                new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.RegisteredType)), 
                new NamedTypeBuildKey(e.RegisteredType, uniqueName));
        }
    }

    private void OnRegistering(object sender, RegisterEventArgs e)
    {
        if (e.TypeFrom != null && string.IsNullOrEmpty(e.Name))
        {
            string uniqueName = Guid.NewGuid().ToString();

            this.Context.RegisterNamedType(e.TypeFrom, uniqueName);

            if (e.TypeFrom.IsGenericTypeDefinition && e.TypeTo.IsGenericTypeDefinition)
            {
                this.Context.Policies.Set<IBuildKeyMappingPolicy>(
                    new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
                    new NamedTypeBuildKey(e.TypeFrom, uniqueName));
            }
            else
            {
                this.Context.Policies.Set<IBuildKeyMappingPolicy>(
                    new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
                    new NamedTypeBuildKey(e.TypeFrom, uniqueName));
            }
        }
    }
}

With an example

[TestMethod]
public void CanResolveMultipeDefaultMappingsUsingResolveAll()
{
    var container = new UnityContainer().AddNewExtension<Remember>();

    container.RegisterType<IFoo, One>();
    container.RegisterType<IFoo, Two>();
    container.RegisterType<IFoo, Three>();

    IFoo[] foos = container.ResolveAll<IFoo>().OrderBy(f => f.GetType().Name).ToArray();

    Assert.AreEqual(3, foos.Length);
    Assert.IsInstanceOfType(foos[0], typeof(One));
    Assert.IsInstanceOfType(foos[1], typeof(Three));
    Assert.IsInstanceOfType(foos[2], typeof(Two));
}
qujck
  • 14,388
  • 4
  • 45
  • 74