Tuesday, September 25, 2012

Func Injection in Unity

Let your container be your factory. :)

If you are using LinqToSql and dependency injection, then you have probably created a factory with which you create DataContexts. But what if you could just let your IOC Container do that work for you? You can!

If you are using Unity then you can inject a Func<T> of any registered type. Unity will automatically bind the injected Func to the container's resolve method, thus preserving the resource Lifetime Manager.

Example Code

public class FuncInjectionTests
{
    [Fact]
    public void TransientLifetimeFuncIsThreadsafe()
    {
        var container = new UnityContainer();
 
        container
            .RegisterType<IUserService, UserService>(
                new ContainerControlledLifetimeManager())
            .RegisterType<IDataContext, DataContext>(
                new TransientLifetimeManager());
 
        var parallelOptions = new ParallelOptions {MaxDegreeOfParallelism = 100};
 
        Parallel.For(0, 1000, parallelOptions, i =>
        {
            var userService = container.Resolve<IUserService>();
 
            Parallel.For(0, 1000, parallelOptions, j =>
            {
                userService.Update();
            });
        });
 
        Assert.Equal(1, UserService.Count);
        Assert.Equal(1000000, DataContext.Count);
    }
}
 
public interface IUserService
{
    void Update();
}
 
public interface IDataContext : IDisposable
{
    void UpdateUser();
}
 
public class UserService : IUserService
{
    public static int Count;
 
    private readonly Func<IDataContext> _dataContextFactory;
 
    public UserService(Func<IDataContext> dataContextFactory)
    {
        _dataContextFactory = dataContextFactory;
        Interlocked.Increment(ref Count);
    }
 
    public void Update()
    {
        using (var dataContext = _dataContextFactory())
            dataContext.UpdateUser();
    }
}
 
public class DataContext : IDataContext
{
    public static int Count;
 
    public DataContext()
    {
        Interlocked.Increment(ref Count);
    }
 
    public void UpdateUser()
    {
        Trace.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Count);
    }
 
    public void Dispose()
    {
    }
}
Shout it

Enjoy,
Tom

2 comments:

  1. Didn't knew that IOC Container can manage this so well. But still I think there will be some limitation to it. I am new to ASP.NET and it would be great help if you let me know this clearly.

    ReplyDelete
  2. This pattern has worked flawlessly for me. What limitations are you concerned about?

    ReplyDelete

Real Time Web Analytics