Extending the Dependency Container example

Oct 20, 2006 at 5:49 PM
I'm working with the DependencyContainer example and have been incorporating it into a project I'm working on. This is my first venture into using Dependency Injection so what I'm about to ask/say may be way off to begin with.

The example DependencyContainer (DC) has two contstructors, one that takes no parameters and one that takes a string of XML for configuration (the first one just calling the second with a null value). This is fine for the demo and sample, but in the project I'm working on the creation of the DC is going to be everywhere in the code. I can't pass in the xml configuration all the time, so I created a class that would read the configuration out of the application config file whenever the DC was created. That way I can configure the mappings I need in the config file and not be passing the xml string around everywhere.

This brings me to the following issue: Every instance of the DC created reads the config file. Technically the config info is cached by the System.Configuration subsystem, but it does at least always look at the cache. What are people's thoughts on this? The DC is going to be used all over the place.

I just want to know if I'm using this in the wrong manner or if I should be looking at something else.
Coordinator
Oct 21, 2006 at 11:19 PM
I'm surprised that you will be creating new dependency containers frequently. Usually you would think of each container as an ever-changing context into which objects are created and removed. If you are creating lots of containers, is that because very few of your objects interact with each other?

CAB created hierarchies of containers (well, WorkItem) as a convenient disposal mechanism, but I think that behavior was somewhat driven by the use of WinForms. In other applications where I use this more traditional style of container, I've found that I tend to have a singleton container used for the entire application instance.

I would be interested to know what others are doing, of course. :)
Oct 23, 2006 at 3:57 PM
Hmm, let me give you an example of what I was trying to do and maybe you can tell me what I'm doing wrong (or using incorrectly).

My example is for a helper class I'm putting together. It has a series of methods to return some metadata from the database. I have a class named Helper (the names have been changed to protect the innocent). Helper internally will talk to a repository to get it's data, which I have abstracted into an interface named IHelperRepository. Here is some code:

The following classes are in an assembly together:

public class Helper
{
private IHelperRepository _repository;

public ServiceInfo()
{
DependencyContainer dc = new DependencyContainer();
_repository = dc.Get<IHelperRepository>();
}

public IXPathNavigable GetTaskInfoForClients(int[] clientIds)
{
return _repository.GetTaskInfoForClients(clientIds);
}
}

public interface IHelperRepository
{
IXPathNavigable GetTaskInfoForClients(Int32[] clientIds);
}

public class HelperRepository : IHelperRepository
{
public IXPathNavigable GetTaskInfoForClients(int[] clientIds)
{
//TODO: Add code to get info from the DAL/DB.
throw new Exception("The method or operation is not implemented.");
}
}

The following class is in my test harness.

public class MockHelperRepository : IHelperRepository
{
public IXPathNavigable GetTaskInfoForClients(int[] clientIds)
{
//TODO: Return stubbed data.
return new System.Xml.XmlDocument().Clone();
}
}

Note that as I stated earlier I have modified the DependencyContainer to read from the config file when it is constructed. In that config file is the following:

<Mapping FromType="SomeAssembly.IServiceInfoRepository, SomeAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
ToType="TestAssembly.MockServiceInfoRepository, TestAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

This allows me to inject the mock object instead of the actual HelperRepository object. In production code the config would have a reference to the actual HelperRepository object instead.

My test looks like this:

TestMethod
public void TaskInfoIsReturnedWhenGetTaskInfoForClientsIsCalled()
{
DependencyContainer dc = new DependencyContainer();
ServiceInfo helper = dc.Get<Helper>();
Int32[] clientIds = new int2 {101, 102};
IXPathNavigable taskInfo = helper.GetTaskInfoForClients(clientIds);
Assert.IsNotNull(taskInfo);
}

In this instance the DC is created twice. One in the test and then again inside the Helper object. In the test I could just create an instance of Helper directly, but that really doesn't answer my question. What if I have a class that has the following:

public class Processor
{

Helper _helper;
OtherHelper _otherHelper;

public Processor()
{
DependencyContainer dc = new DependencyContainer();
_helper= dc.Get<Helper>();
_otherHelper= dc.Get<OtherHelper>();
}

//Some methods that use both helpers....
}

The process is simply using the helper classes to do it's work. This is a back end processing engine I'm writing that really doesn't have object entities it deals with. At each level in which I need an instance of an object I create the DC and get an instance. This is what I meant by creating multiple instances of the DC all over the place. One of my thoughts was that it should be a singleton when used in this manner, which you mentioned.

Am I going about this all wrong? What I would have really liked to have happen was that in the test code I could indicate I wanted to use the Mock object via configuration, but in production I wouldn't need to set anything in config, it would just use the correct one. I'm not seeing how that is possible at the moment. Again, I'm new to the dependency injection concept. The way I'm using it seems more like a factory pattern.

Oct 23, 2006 at 5:41 PM
I'm staring to wonder if what I'm really looking for will require a custom strategy for object builder.
Coordinator
Oct 23, 2006 at 5:52 PM
Here's how I deal with this kind of thing.

1. Create the object with a constructor dependency on the service:

public class Helper
{
private IHelperRepository _repository;

// The InjectionConstructor attribute on the constructor is optional here, as is the
// ServiceDependency (or Dependency) attribute on the parameter
public Helper(IHelperRepository repository)
{
_repository = repositor;
}
}

2. In the context of the application, get an instance of Helper from the container:

DependencyContainer dc = new DependencyContainer();
Helper helper = dc.Get<Helper>();

That will automatically resolve the IHelperRepository dependency.

3. In the context of the test, don't use the container at all:

public void MyTest()
{
MockRepository mockRepository = new MockRepository();
Helper helper = new Helper(mockRepository);
// ... rest of test here ...
}

An alternative that I tend to refactor to a lot is what I call the "testable class" pattern (probably not the right name):

public class TestableHelper : Helper
{
public MockRepository Repository;

private TestableHelper(MockRepository mockRepository) : base(mockRepository)
{
Repository = mockRepository;
}

public TestableHelper Create()
{
return new TestableHelper(new MockRepository());
}
}

public void MyTest()
{
TestableHelper helper = TestableHelper.Create();
// ... rest of test here ...
// helper.Repository gives access to the mock repository
}
Oct 23, 2006 at 9:16 PM
Okay, this corresponds to something another developer and I were talking about and makes more sense to me.

I assume when you say "That will automatically resolve the IHelperRepository dependency" you mean if a mapping is registered this will automatically work. When I plugged in a quick test this did not work since it couldn't create an instance of the interface without knowning what actual concrete type to create, which makes sense. When I added a registerMapping call to the test it all worked. This goes back to needing configuration to provide the mappings for my production code. I know that objectBuilder can use attributes to help build up types so (in lieu of documentation for Object Builder) do you know of any attributes off the top of your head that I could decorate the HelperRepository with to indicate it should be the object created when IHelperRepository is asked for?

As to your alternative method, this is what the other developer I was talking to had suggested in the first place. It seems okay as long as you don't have too many paramters to the constructor. For example, in my earlier post I had talked about a processor class that used both the Helper and OtherHelper. What if later we needed to add another helper, etc. That constructor could get pretty cumbersome. The other developer suggested a parameter object that represented all the helper types.

I really appreciate your thoughts and input on this BTW. I'm beginning to understand DI more through this excercise.
Oct 23, 2006 at 9:31 PM
Or maybe not decorate the HelperRepository object, but rather the constructor on Helper that gets called by the builder that may use the attribute to know which type to create by default. This I think is more of what I'm looking for. It removes the requirement for the mapping to be defined somewhere and is still flexible to use the constructor injection for testing.
Oct 24, 2006 at 9:28 PM
I wish CodePlex had an edit function for your posts

The attribute I'm refering to on the constructor would supply the type of the default object to create, but then if there were mappings registered it would allow those to override. That way you get the flexibility of the mappings in config, but also for production code you aren't having to include a lot of configuration around what objects should be created.
Coordinator
Oct 24, 2006 at 10:21 PM
I hear ya. Editing posts is on the list. :)

I'll give some thought to all of this...