views:

137

answers:

2

I am new to IOC in general and I'm struggling a little to understand whether what I am trying to do makes any sense. I have a web forms application in which I want to create one module to define some bindings for me. The bindings will be used to inject repositories into my business manager classes, allowing me to unit test the business managers. Also I would like to use the container to inject the Entity Framework context into my repositories that way they all share the same context per http request. So here is what I am wondering:

  1. I understand that I need to have the same kernel instance manage my object creation and their lifetime. For example if I want a one-per-httprequest type scenario I need the instance of the kernel to be available for that period of time. What if I need a singleton? Then it has to be application scoped somehow. So where exactly do I store the IKernel instance? It seems that I might want to make it a static in my Global.asax, is that the right approach and is thread safety a concern?

  2. Since I am using Bind<> to define my bindings, how do I go about making that definition in the Web/UI layer when I shouldn't be referencing my data access layer from the UI? My references look like .Web --> .Business --> DataAccess. It seems like I want to tell the kernel "hey manage my data access instances, but don't have a reference to them at compile time." A binding such as this:


    //Any object requesting an instance of AdventureWorksEntities will get an instance per request
    Bind<AdventureWorksEntities>().ToSelf().InRequestScope();

I feel like I might be approaching this incorrectly, thank you.

+1  A: 

It really depends on the complexity of your web app.

It sounds like you have a business and a data access layer; I would personally have an 'infrastructure' layer where I would store my DI repository and helper classes.

John Weldon
Thanks John, I think your suggestion is really the only way to go to avoid that coupling between the layers. I haven't used any other containers but I would have thought if the configuration was XML based this could have been avoided, meaning the container would resolve the DLLs at runtime.
e36M3
+1  A: 

Re part 1- have a look at the Ninject.Web extension - it keeps a Kernel at Application level. You can then manage other resources that have shorter lifetimes within that too.

Also, have a look around here for questions and examples on EF and L2S DataContext management wrt Ninject and DI in general (it's come up[ in the last few weeks)

UPDATE: This answer to another question from the same OP is far more concrete (There's a KernelContainer class with a .Inject( object) and a .Kernel)

Ruben Bartelink
Ruben I looked into the Ninject.Web and it does seem like it's what I've been looking for. I am guessing that this extension takes advantage of some "global" static kernel reference underneath in essence accomplishing what I was doing myself by making it a static property of the Global.asax. However going down the Ninject.Web path I don't need to worry about thread safety as I am sure they have taken care of this.
e36M3
@e36M3 Cool handle/vehicle (I'm a BH5 Blitzen :D). You have it, minus the 'static' inference - it's one per HttpApplication (there can be >1 per process and/or AppDomain), which can be slightly different. Make sure you have a look for those other articles - you need to commit your DB work at the appropriate point in the processing flow and not be expecting Ninject to just do it at the right time via IDisposable etc. - Ninject does Dispose, but async after a while - not necessarily during request processing.
Ruben Bartelink
Thanks Ruben, I will do some more digging. I know there has to be a way to get it to commit the Entity Framework context at the end of the request automatically (kind of like NHibernate), I'll do some scanning of previous posts to see if I can find something liek that. For now I have the last business manager in the "transaction" responsible for calling the SaveChanges method. Thanks again.
e36M3
@e36M3: Nothing wrong with having something like that explicitly under program control (though obv keeping it DRY in some way - some people do that by gating it through a standard invoke and/or retry strategy etc., others go to town and do AOP and other stuff to varying degrees of taste / over engineering :D)
Ruben Bartelink