views:

286

answers:

3

I've recently started using an IoC container for the first time, but I'm not educated on the best practices for using it. More specificaly I'm using Unity in a C# .NET project, and I started using it because it came with Prism.

I use the container to resolve the "top level" objects, and they get the correct objects injected based on the container. However, I can't see the best practice clearly when I have an object with children and children's children, and I need some data from the IoC container all the way down, but not in between. How you'd typically organize the use of IoC container?

Initially I'd think that you'd pass the container everywhere it is needed instead of extracting the needed data from the container on top-level and passing this data on. But then again I get problems when I reach objects which take other specific data in addition to the injected interfaces, and I'd prefer not to inject these through properties or init-methods after resolving the object.

I hope this was clear enough, but let's look at a fictional (and slightly stupid..) example.

class Employee
{
    private ICommands _commands; 
    priate List<Customer> _customers = new List<Customer>(); 
    public Employee(ICommands commands)
    {
        _commands = commands; 
    }
    public void AddCustomer(string customerName)
    {
        var customer = new Customer(customerName, _commands); 
        _customers.Add(customer); 
    }
}

class Customer 
{
    private string _name; 
    private ICommands _commands; 
    priate List<Case> _cases = new List<Case>(); 
    public Customer(string, name, ICommands commands)
    {
        _name = name; 
        _commands = commands; 
    }
    public void AddCase()
    {
        var case = new Case(_commands); 
        _cases.Add(case); 
    }
}

class Case    {
    private ICommands _commands; 
    public Customer(ICommands commands)
    {
        _commands = commands; 
    }
    public void TriggerCommands()
    {
        _command.TriggerSomething(); 
    }
}

So, this example doesn't really make much sense, but the essence is the same of what I need to do. I have some application commands I pass down the line through my ViewModel classes, because some of them need to be able to trigger commands to display something. I also have common storage, etc. which may be needed for some classes but currently are passed through and stored in middle classes. With only commands it's no big deal if you store commands or container, but would one in a typical IoC-usage pass the IoC container instead, and use this for resolving objects down the line? And what about specific data like the customer name? You can't just pass this in on the Resolve(), so you need to inject that afterwards?

Sorry - this was as short as I was able to make it. Won't require answers of the same length ;-) .. Just; what's the best practice of doing stuff like this with IoC containers?

+2  A: 

I'm not quite sure that I understand your question. But I don't think you should be passing the container around at all. It's much easier to just create a wrapper class for the container. For example:

public class IoCContainer
{
  private static ContainerType = null;

  public static ContainerType Instance 
  {
    get 
    {
      if (_container == null)
      {
        string configFileName = ConfigurationManager.AppSettings[ConfigFileAppSettingName];
        _container = new WindsorContainer(new XmlInterpreter(configFileName));
      }

      return _container;
    }
  }
}

Now you call this everywhere in your code.

IoCContainer.Instance.Resolve<IAwesomeService>(); 

Does this help you?

Carl Bergquist
Thanks. I believe this helps. Is this to be considered best practice? This would mean that I wouldn't have to pass anything through the classes which won't be using it anyway - which is a good thing..!
stiank81
Will attempt a static class solution like this one. Thanks for your help!
stiank81
Glad to help =)
Carl Bergquist
+2  A: 

I'm not sure if this answers your question, but I would say that a good way to act on an application using the Unity container (also applicable to other IoC engines I think) is:

  • Design your classes so that all the required dependencies are specified in the constructor. This way you don't need to explicitly deal with Unity unless you need to create new objects.
  • If you need to create new objects within your classes, pass the Unity container itself in the constructor as well (as a reference to IUnityContainer), and create all new object instances by using the Resolve method. Even for objects that are not registered and have not dependencies, the container will give you a proper instance, and later you can decide to register types that were not previously registered, without changing the client code.
  • As for passing explicit values to resolved objects, you can specify concrete injection members when you register types (see the InjectionMembers parameter in the RegisterType class).
Konamiman
This was what I was trying to achieve until I met the problem of how to pass explicit values to the constructor if I use Resolve to create the objects. But will look into the InjectionMembers parameter you mention. I have however read advices some places against passing the IoC container around whereever needed, but you're saying this is okay then?
stiank81
My point of view is: if you base your overall application design on obtaining all objects via IoC container, what's more coherent than obtaining the IoC container itself the same way?
Konamiman
+1  A: 

I'd define a static class IoC, that can be initialized with a particular container and implement methods like Resolve, Resolve(...), which in turn delegate the actual work to the container instance (you'll store this instance in a field or property). This way you don't have to pass anything around, just use

IoC.Resolve<SomeType>();

anywhere in your code.

Regarding the specific data: some containers will take a parameter and resolve depending on this parameter (Autofac has this kind of feature). Or you can always create a factory class that will have a method that accepts a set of parameters (like customer name) and returns a corresponding object instance.

liggett78
Thx. Seems like using a static IoC class is a popular choice. Sounds reasonable.
stiank81