Dependency Injection with Unity and Linq to SQL DataContexts
Tuesday, June 3, 2008 – 1:28 PMI’ve spent a few hours in the last couple of days playing around with ASP.NET MVC, Linq to SQL and now the Unity dependency injection (DI) container. Basically I wanted to start putting together a little N-tier application using the latest and greatest new stuff. I also got to use Moq and xUnit a bit too, but that’s another story.
Here’s a little problem I ran into trying to use Unity as part of a factory for my ASP.NET MVC controllers. I was using a simple factory pattern to inject a Linq to SQL DataContext into the controller class the factory was constructing. Linq to SQL generates the data context code which leads to a few challenges when you try and consume it with Unity.
In fact the lessons I learnt here would apply in may situations where you want to use a type you cannot modify. Or, how to tweak the container’s configuration to accommodate classes that were not designed with DI in mind.
This is what you end up with when you look at the Linq to SQl generated code.
// Generated code (pseudo code, real code looks a bit different) public partial class MyDataContext : System.Data.Linq.DataContext
{ public MyDataContext() : this("default DC") { } public MyDataContext(string connector) { // ...
} // Lots more ctors }
This class contains lots of constructors. Injecting this is going to cause Unity problems because it cannot decide which constructor to use. I have a class that takes a dependency on MyDataContext and I need Unity to inject a data connector when I ask it to resolve MyDefaultControllerClass.
public classMyDefaultControllerClass
{
publicMyDefaultControllerClass(DataContext context)
{
Context = context;
}
publicDataContext Context{ get; set; }
}
Here’s my naive container setup test. It creates a container and registers type mappings for my class and the dependent data connector. Note that Unity will construct a MyDefaultControllerClass without having to explicitly register it in the container.
[Fact] public void ContainerTest() { UnityContainer container = new UnityContainer(); container.RegisterType<System.Data.Linq.DataContext, MyDataContext>(); MyDefaultControllerClass c = container.Resolve<MyDefaultControllerClass>(); MyDataContext dc = c.Context as MyDataContext; Assert.NotNull(c); Assert.NotNull(c.Context); }
This throws when the Resolve method gets called! Unity cannot decide which DataContext constructor to use. The code is generated so I can’t add an InjectionConstructor attribute to the parameterless constructor which is the one I’d like to use. Adding an injection method to a partial class doesn’t help because the container still needs to construct the object before calling the injection method.
Turns out I was missing a magic line of code! If you’re skim reading this is the line you want.
container.Configure<InjectedMembers>(). ConfigureInjectionFor<MyDataContext>(new InjectionConstructor());
This has the same effect as adding an InjectionConstructor attribute to the parameterless constructor in the DataConnector class. Fixed! Unity can now resolve the DataContext parameter on the MyDefaultControllerClass constructor and create the DataConnector object. You can use the same trick to configure other forms of injection. This is covered in the documentation that ships with Unity, you can find it in the “Dynamically Configuring Constructor, Property, and Method Injection” section.
Interestingly Chris Tavares, one of the developers behind Unity and also closely involved in the ASP.NET MVC project ran into similar problems with classes that are not as dependency injection friendly as they might be. You can read about it here.
6 Responses to “Dependency Injection with Unity and Linq to SQL DataContexts”
This part gives me a shiver:
container.RegisterType();
MyDefaultControllerClass c = container.Resolve() as MyDefaultControllerClass;
What’s the point of the interface? Why is this not just:
MyDefaultControllerClass c = container.Resolve();
By Brad Wilson on Jun 4, 2008
Brad’s comment got a bit mangled. The comment engine removed the angle brackets. I’ve cleaned up the code a bit and learnt some more nice things about Unity in the process.
By Ade on Jun 4, 2008
Is it possible to do the same using a config file (Web/App.config)? An example would be greatly appreciated, thanks.
By Mart on Jun 20, 2008
I posted an article combining these two technologies as well. Thought it was a pretty cool way to do things but I’m sure there’s even better way to link these two technologies.
http://suite101.thefarmdigital.com.au/post/2008/07/Linq-and-Unity-Framework.aspx
http://www.codeproject.com/KB/linq/LinqAndUnity.aspx
By Shannon on Jul 15, 2008
I don’t know why it does not work. >.<
By Thoai Nguyen on Apr 11, 2009
Thoai,
What doesn’t work? I think the comment form removed whatever angle brackets you tried to use.
Ade
By Ade Miller on Apr 14, 2009