0

I have 3-layers architecture - asp.net web api, BLL and DAL. I use Ninject as dependency injector for injecting db context and objects between layers. As ORM i use Entity Framework . Injection of db context is processed in DAL. So every time some repository in BLL is instancied, new instance of db context is also created. Im doing it like this:

public class UserRepository : IUserRepository
{
    private IChatDbModel _chatDbModel;

    public UserRepository(IChatDbModel chatDbModel)
    {
        this._chatDbModel = chatDbModel;
    }

It´s neccesary to say that PerWebRequest, which would solve my problem is not availible in lower layers than web api. Only web api layer has info about http request lifetime, so can use Ninject.Web.Common library.

My question is, is there a way how to share db context for whole request like using of PerWebRequest in this architecture? Or is really neccesary to create new instance of db context for every new instance of repository?

Edit

I forgot to mention that in each layer I´m referencing Ninject library and I´m registering mapping for the specific layer. The method in DAL looks like this:

    public static void Register(IKernel kernel)
    {
        kernel.Bind<IChatDbModel>().To<ChatDbModel>();
    }

in BLL it looks like this:

    public static void Register(IKernel kernel)
    {
        kernel.Bind<IUserRepository>().To<UserRepository>();
        NinjectDataAccess.Register(kernel);
    }

in API it looks like this, it´s located in NinjectWebCommon.cs:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IUserLogic>().To<UserLogic>();
        NinjectLogic.Register(kernel);            
    }     

so in each layer, I´m not only mapping it´s own objects but also calling register method of the layer lying below if any and with mechanism like this, I can register dependency mapping of each layer without referencing all layers in API, where I should not reference any other layer than BLL, so in my case DAL. If I reference the DAL in API layer, then it would be possible to define the mapping and call PerWebRequest, because I would have the objects, but I´m not and I think this should be avoided by the architecture, or am I wrong?

Lukas
  • 60
  • 2
  • 12
  • Related: https://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why – Steven Nov 30 '16 at 09:32
  • Your question assumes that your BLL and DAL know anything about Ninject and how things are registered; they should not. Since objects are registered in the [Composition Root](http://blog.ploeh.dk/2011/07/28/CompositionRoot/) (which lives in your web project in your case) there should be no problem registereing your `DbContext` as `PerWebRequest`. – Steven Nov 30 '16 at 09:35
  • Thank you for your response, actually I´m defining dependency mapping in each layer so I´m referencing Ninject in each layer, to avoid referencing DAL in API - which I thought, should be avoided by the architecture. Please check my edit. – Lukas Nov 30 '16 at 10:57
  • You should not define your DI mapping in each layer. Please read [this related q/a](https://stackoverflow.com/questions/9501604/ioc-di-why-do-i-have-to-reference-all-layers-assemblies-in-entry-application). – Steven Nov 30 '16 at 11:00

1 Answers1

0

You can achieve per request instance by registering OnePerRequestHttpModule http module, which internally uses HttpContext lifecycle to track registered types and dispose them at the end of the request/response lifecycle.

After installing Ninject.Web.Common package, in NinjectWebCommon.cs you have to do (it will be added automatically once nuget package is installed)

DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule))

And for your type registrations, you can do the following

//register IChatDbModel with per request scope
kernel.Bind<IChatDbModel>().To<ChatDbModel>().InRequestScope();

//register repositories with default transient scope
kernel.Bind<IUserRepository>().To<UserRepository>();

All your repositories will be transient, so everywhere they are injected , a separate instance will be supplied, but your DBContext instance will created and disposed per request.

I am assuming you have added both BAL and DAL reference to web api project, so that web api project has access to IChatDbModel to perform type registration in Ninject kernel.

Vinod
  • 1,882
  • 2
  • 17
  • 27
  • Thank you for response, but this is not possible due to having no reference to DAL in API. So I don´t have the objects like ChatDbModel and it´s interface in API. Please check my edit. – Lukas Nov 30 '16 at 10:56
  • I was able to achieve this using Unity DI framework in one of my recent projects. Each application layer manages its own DI registrations and UI layer dictates which lifetimemanager must be used. LifetimeManager is passed as a delegate to other layers without having a need to install Unity.MVC or Unity.AspNet.WebApi in BAL or DAL. Let me know if you want to see an example. – Vinod Nov 30 '16 at 14:07
  • Also remember, the clean layering approach you are trying to achieving may not be worth it, because BAL and DAL are the run time dependencies for your Web layer. Just because you don't have an add reference in the web layer, still DAL has to be deployed to the bin folder. As the web layer is your DI container root, it should have knowledge of all the dependencies (direct or indirect). I don't think there is a clear consensus about what is the right choice. I tried clean separation using UNITY DI and it worked, but haven't made up my mind as to what is the ideal approach. – Vinod Nov 30 '16 at 16:08
  • I wanted to build totally separated n-tier application, but after a lot of reading it seems to be unnecessary and even worse - counterproductive. I ended up with referencing all objects to Composition Root as @Steven noted, which seems to be perfect solution. Thank you guys. – Lukas Dec 04 '16 at 20:15