I need help with this. I'm using Unity as my container and I want to inject two different instances of the same type into my constructor.
class Example
{
Example(IQueue receiveQueue, IQueue sendQueue) {}
}
....and IQueue is implemented in my MessageQueue class....
class MessageQueue : IQueue
{
MessageQueue(string path) {}
}
How can I inject two different instances of MessageQueue into my Example class? Each of the MessageQueue instances to be created with different path.
There are many ways to achieve the results you want (as evidenced by the multiple answers). Here is another way using named registrations (without attributes):
IUnityContainer container = new UnityContainer();
container.RegisterType<IQueue, MessageQueue>("ReceiveQueue",
new InjectionConstructor("receivePath"));
container.RegisterType<IQueue, MessageQueue>("SendQueue",
new InjectionConstructor("sendPath"));
container.RegisterType<Example>(
new InjectionConstructor(
new ResolvedParameter<IQueue>("ReceiveQueue"),
new ResolvedParameter<IQueue>("SendQueue")));
Example example = container.Resolve<Example>();
The downside of this approach is that if the Example constructor is changed then the registration code must also be modified to match. Also, the error would be a runtime error and not a more preferable compile time error.
You could combine the above with an InjectionFactory to invoke the constructor manually to give compile time checking:
IUnityContainer container = new UnityContainer();
container.RegisterType<IQueue, MessageQueue>("ReceiveQueue",
new InjectionConstructor("receivePath"));
container.RegisterType<IQueue, MessageQueue>("SendQueue",
new InjectionConstructor("sendPath"));
container.RegisterType<Example>(new InjectionFactory(c =>
new Example(c.Resolve<IQueue>("ReceiveQueue"),
c.Resolve<IQueue>("SendQueue"))));
Example example = container.Resolve<Example>();
If you are using a composition root then the use of the magic strings ("ReceiveQueue" and "SendQueue") would be limited to the one registration location.
Not everything has to be automatically wired by the container. You can register the Example
class like this:
container.Register<Example>(new InjectionFactory(c =>
{
var receive = new MessageQueue("receivePath");
var send = new MessageQueue("sendPath");
return new Example(receive, send);
});
You could register the two instances with names:
myContainer.RegisterInstance<IQueue>("ReceiveQueue", myReceiveMessageQueue);
myContainer.RegisterInstance<IQueue>("SendQueue", mySendMessageQueue);
and then you should be able to resolve by name, but it requires using the Dependency
attribute:
class Example
{
Example([Dependency("ReceiveQueue")] IQueue receiveQueue,
[Dependency("SendQueue")] IQueue sendQueue) {
}
}
or inject the unity container and then resolve the instances within the constructor:
class Example
{
Example(IUnityContainter container)
{
_receiveQueue = container.Resolve<IQueue>("ReceiveQueue");
_sendQueue = container.Resolve<IQueue>("SendQueue");
}
}
Well, don't
You should use the factory pattern in this case.
class Example
{
Example(IQueueFactory factory)
{
_sendQueue = factory.Create("MySend");
_receiveQueue = factory.Create("MyReceive");
}
}
It makes the intention a lot more clear and you can internally in the Example
class handle if the queues are not found or incorrectly configured.
5 years later, but I was looking for this answer too. I worked through it with my own code and then decided to create working code using (slightly altered) classes the OP provided.
This is an entire working example that you can copy into LINQPad (programmer's playground) and run.
Using Statement / Unity Libary
You'll need to add a reference to Microsoft.Practices.Unity.dll You'll also need to add a using statement of :
Microsoft.Practices.Unity
In LinqPad you press F4 to add the reference and the using statement (namespace import).
void Main()
{
// Create your unity container (one-time creation)
UnityContainer uc = new UnityContainer();
// Create simple list to hold your target objects
// (makes the sample easy to follow)
List<MessageQueue> allMQs = new List<MessageQueue>();
// I'm adding TransientLifetimeManager() in order to
// explicitly ask for new object creation each time
// uc.Resolve<MessageQueue>() is called
uc.RegisterType<IQueue, MessageQueue>(new TransientLifetimeManager());
// ### override the parameters by matching the parameter name (inPath)
var item = uc.Resolve<MessageQueue>(new ParameterOverride("inPath", "extra.txt").OnType<MessageQueue>());
allMQs.Add(item);
item = uc.Resolve<MessageQueue>(new ParameterOverride("inPath", "super.txt").OnType<MessageQueue>());
allMQs.Add(item);
foreach (MessageQueue mq in allMQs){
Console.WriteLine($"mq.Path : {mq.Path}");
}
Console.WriteLine("######################\n");
uc.RegisterType<Example>(new InjectionConstructor((allMQs[0] as IQueue),(allMQs[1] as IQueue)));
// #### Create a new Example from the UnityContainer
var example1 = uc.Resolve<Example>();
// ##### Notice that the Example object uses the default values of super.txt & extra.txt
Console.WriteLine("#### example1 obj. uses default values ###########");
Console.WriteLine($"example1.receiver.Path : {example1.receiver.Path}");
Console.WriteLine($"example1.sender.Path : {example1.sender.Path}");
// ##################################################
// Override the parameters that he Example class uses.
// ### override the parameters by matching the parameter
// names (receiveQueue, sendQueue) found in the target
// class constructor (Example class)
var example2 = uc.Resolve<Example>(
new ParameterOverrides {
{"receiveQueue", new MessageQueue("newReceiveFile")},
{ "sendQueue", new MessageQueue("newSendFile")}
}.OnType<Example>());
Console.WriteLine("######################\n");
Console.WriteLine("#### example1 obj. uses ParameterOverride values ###########");
Console.WriteLine($"example2.sender.Path : {example2.sender.Path}");
Console.WriteLine($"example2.receiver.Path : {example2.receiver.Path}");
}
class Example
{
public MessageQueue receiver {get;set;}
public MessageQueue sender {get;set;}
public Example(IQueue receiveQueue, IQueue sendQueue) {
this.receiver = receiveQueue as MessageQueue;
this.sender = sendQueue as MessageQueue;
}
}
public class MessageQueue : IQueue
{
public string Path {get;set;}
public MessageQueue(string inPath) {
Path = inPath;}
}
interface IQueue{
}
Output For Examination
If you run the script above you'll see sample output which will look like the following:
mq.Path : extra.txt
mq.Path : super.txt
######################
#### example1 obj. uses default values ###########
example1.receiver.Path : extra.txt
example1.sender.Path : super.txt
######################
#### example1 obj. uses ParameterOverride values ###########
example2.sender.Path : newSendFile
example2.receiver.Path : newReceiveFile
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With