Twitter Feed Popout byInfofru

OverrideThis.com

Adventures in .NET Software Craftsmanship!

Code and Slides on “Intro to Dependency Injection”

I hIIS Express, Razor, and WebMatrix, oh my! ad the opportunity to participate as the speaker at the Washington DC Dot Net User’s group and really enjoyed presenting an “Introduction to Dependency Injection”. I would like to thank Ganesan Muthiah, the leader of DCDNUG community, for inviting me and also for hosting and managing this fast growing new .NET developer community. 

 

The following are links to the materials used in the presentation.

 

Download Slides & Demo Code

 

Happy coding in .NET!!!

Lazy Loading Dependencies with StructureMap

Lately I have been working with an existing custom .NET Library designed to register and execute tasks triggered by events, sort of like a local Event Bus.  The Library was built in house and is used successfully in many applications but it lacks integration with Dependency Injection or Common Service Locator which makes it hard to implement in a solution where separation of concerns are enforced strictly. 

 

To highlight the issue, look at the following snippet, it is a sample of the exposed API for registering tasks associated to an event. 

 

public interface IEventTaskRegister {
    void RegisterFor<T>(ITask action) where T : IEvent;
}
// Sample use scenario.
RegisterFor<OnSomeEvent>(new SomeTask()); 

 

At first glance, there is nothing wrong with the previous code but if you look more carefully you will notice that we are passing a concrete instance of a type.  Now, my preference would be to pass just a type and have the event task library instantiate the type and its dependencies using some form of service location, but modifying the event task library is not an option for us at this time.   One possible solution is to simply use Service Location when we are registering our associated events, as you can see in the following snippet.

 

RegisterFor<OnSomeEvent>(new SomeTask(ObjectFactory.GetInstance<IRepository>()));
// Or Even Less Code.
RegisterFor<OnSomeEvent>(ObjectFactory.GetInstance<SomeTask>());

 

Luckily in the current project all tasks are registered during startup so there isn’t much wrong with muddying the registration code with service location.  But, at this point we have unknowingly created another issue, since the execution of the registration code happens once during system startup the tasks and its dependencies will be unique throughout the execution of the application.  This is a huge problem for us as our current implementation of the IRepository behaves differently depending on context information provided during instantiation, see snippet. 

 

// Repository.
public interface IRepository {
    void DoSomething();
}
public class RepositoryImpl : ITask {
    private readonly IContext context;
    public RepositoryImpl(IContext context) {
        this.context = context;
    }
    public void DoSomething() {
        // Does something that varies
        // depending on the context
        // passed in during instatiation.
    }
}
// SomeTaks
public interface ITask {
    void Execute(); 
}
public class SomeTask : ITask {
    private readonly IRepository repository;
    public SomeTask(IRepository repository) {
        this.repository = repository;
    }
    public void Execute() {
        // Do Something w/Repository.
    }
}

 

One possible solution, is to modify the way we write our implementation of ITask to allow for lazy instantiation of its dependencies but still take of advantage of Dependency Injection an Inversion Of Control.  The following snippet highlights the solution the key is to inject a Func<IRepository> not an IRepository, that way the consumer is actually the one who will be instantiating the dependency on demand.

 

// SomeTaks
public interface ITask {
    void Execute(); 
}
public class SomeTask : ITask {
    private readonly Func<IRepository> repositoryBuilder;
    public SomeTask(Func<IRepository> repositoryBuilder) {
        this.repositoryBuilder = repositoryBuilder;
    }
    public void Execute() {
        var repository = this.repositoryBuilder();
        // Do Something w/Repository.
    }
}
Now the cool part about this solution, is that we don’t need to modify the way we are currently registering our dependencies in StructureMap, all our registries work as expected.