Unity IOC container: inject named instances or types

84 views
Skip to first unread message

David Mäder

unread,
Nov 19, 2015, 2:03:14 PM11/19/15
to Particular Software
Helpful information to include
Product name: NServiceBus
Version:4.7.8
Stacktrace:
Description:
In Unity framework there's this concept of named instances or named types, where it's possible to have more than object of the same type, distinguished by a unique name. How can I inject such a named instance in a message handler? Or is there a way to inject the Unity container itself, in order to access any items from the container directly? I'm glad for any documentation or example, explaining how to get a firmer grip on the Unity container. Many thanks - David

simon.cropp

unread,
Nov 19, 2015, 4:17:43 PM11/19/15
to Particular Software
David


Both the registration and resolution of handlers of Handlers in an internal concern of NSB. So you cannot, for example, change how a Handler is registered in the container to use a delegated or named-parameter constructor.

However you can use Unitys callback functionality to take full control of customizing the instance as it is resolved from the container.


and then add this 


static class Program
{
    static void Main()
    {
        #region ContainerConfiguration
        BusConfiguration busConfiguration = new BusConfiguration();
        busConfiguration.EndpointName("Samples.Unity");

        UnityContainer container = new UnityContainer();
        container.AddExtension(new MyExtension());
        container.RegisterInstance(new MyService());
        busConfiguration.UseContainer<UnityBuilder>(c => c.UseExistingContainer(container));
        #endregion
        busConfiguration.UseSerialization<JsonSerializer>();
        busConfiguration.UsePersistence<InMemoryPersistence>();
        busConfiguration.EnableInstallers();

        using (IBus bus = Bus.Create(busConfiguration).Start())
        {
            bus.SendLocal(new MyMessage());
            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }
}

internal class MyExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        var strategy = new CustomFactoryBuildStrategy(Context);
        //note there are a variety of options available through UnityBuildStage
        //you should pick the one that best matches your specific use case
        Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
    }
}
public class CustomFactoryBuildStrategy : BuilderStrategy
{
    private ExtensionContext baseContext;

    public CustomFactoryBuildStrategy(ExtensionContext baseContext)
    {
        this.baseContext = baseContext;
    }

    public override void PostBuildUp(IBuilderContext context)
    {
        base.PostBuildUp(context);

        //here you can do any kind of reflection or type logic to 
        //control what is injected into the instance
        //eg perhaps check if the instance inherits form IHandleMessages
        
        MyHandler handler = context.Existing as MyHandler;
        
        if (handler != null)
        {
            handler.InjectedProperty = "Foo";
        }
    }
}

Does this allow you to move forward?

simon.cropp

unread,
Nov 19, 2015, 4:25:22 PM11/19/15
to Particular Software
And now i just discover it is possible

Take this registration


        UnityContainer container = new UnityContainer();
        container.RegisterInstance<IMyService>("MyService1",new MyService1());
        container.RegisterInstance<IMyService>("MyService2",new MyService2());
        busConfiguration.UseContainer<UnityBuilder>(c => c.UseExistingContainer(container));

and these services


    public class MyService1:IMyService
    {
        static ILog logger = LogManager.GetLogger<MyService1>();
    
        public void WriteHello()
        {
            logger.Info("Hello from MyService1.");
        }
    }

    public class MyService2 : IMyService
    {
        static ILog logger = LogManager.GetLogger<MyService2>();

        public void WriteHello()
        {
            logger.Info("Hello from MyService2.");
        }
    }

    public interface IMyService
    {
        void WriteHello();
    }

you can use an attribute to inject the names instance into your handler as such

    public class MyHandler : IHandleMessages<MyMessage>
    {
        IMyService myService;

        public MyHandler([Dependency("MyService2")]  IMyService myService)
        {
            this.myService = myService;
        }

        public void Handle(MyMessage message)
        {
            myService.WriteHello();
        }
    }

David Mäder

unread,
Nov 20, 2015, 4:08:13 AM11/20/15
to Particular Software
Hi Simon, that's exactly the solution to my problem, thanks very much for that! It's great to arrive at the office in the morning, finding my issues resolved over night; for once time-zones are working in my favour :)
Reply all
Reply to author
Forward
0 new messages