25

I am trying to use Ninject and OpenAccess for the first time. Please help me with the following. Here is what my project looks like...

public class ContentController : Controller
{
    private ContentService contentSvc;

    public ContentController(ContentService contentSvc)
    {
        this.contentSvc = contentSvc;
    }
}

The following class is under a folder in my web app.

public class ContentService
{
    private IContentRepository contentRepository;

    public ContentService(IContentRepository contentRepository)
    {
        this.contentRepository = contentRepository;
    }

    public void InsertContent(Content content)
    {
         contentRepository.InsertContent(content);
    }
}

The following repository belongs to a separate assembly.

public class ContentRepository : IContentRepository
{
    DBContext db;
    public ContentRepository(DBContext _db)
    {
        db = _db;
    }

    public void InsertContent(Content content)
    {
             db.Add(content);
    }
}   

Here is what Ninject binding look like..

kernel.Bind<ContentService>().To<ContentService>().InRequestScope();
kernel.Bind<IContentRepository>().To<ContentRepository>().InRequestScope().WithConstructorArgument("_db", new DBContext());

Everything works fine if I fetch one page at a time. I am using a simple tool 'XENU' to fetch multiple pages simultaneously. This is when I get errors with DBContext by fetching multiple pages at a time.

I am not sure if Ninject is dosposing the DBContext in each REQUEST?? I get different errors, e.g. 'Object reference not set to an instance of an object.', OR 'ExecuteReader requires an open and available Connection. The connection's current state is open.'

P.S.

I have ContentService under a folder in my MVC web app. ContentRepository is a separate assembly. I will be adding business logic in ContentService and use 'ContentRepository' only for CRUD operations. Also, please let me know if this architecture is okay or is there a better way to create services and repositories.

tereško
  • 58,060
  • 25
  • 98
  • 150
eadam
  • 23,151
  • 18
  • 48
  • 71
  • 2
    I'm a big fan of seperating logical operations (your services) from data operations (your repository). Its worked really well for me in the past. I think this is a great model – undefined Aug 12 '12 at 11:50
  • Thanks, this has saved me weeks of headache trying to figure out why my dbcontext was crashing constantly. I also used the WithConstructorArgument (inject)... This should be documented more clearly somewhere! – Peter Feb 04 '15 at 09:52
  • I used kernel.Bind().To() while working with EF. – Anupam Singh Mar 26 '15 at 09:26

1 Answers1

30

Here's how I would do your Ninject bindings,

kernel.Bind<DBContext>().ToSelf().InRequestScope();
kernel.Bind<ContentService>().ToSelf().InRequestScope();
kernel.Bind<IContentRepository>().To<ContentRepository>().InRequestScope();

This pattern should work fine in the example above with EF and Ninject.

undefined
  • 33,537
  • 22
  • 129
  • 198
  • 1
    @Luke If you inject 2 repositories in the ContentService you get 2 different context where you can not commit a transaction when both repositories go to 2 different tables. Is that assumption right? – Elisabeth Feb 12 '13 at 19:20
  • @Elisa yah thats the intention – undefined Feb 12 '13 at 21:40
  • @Luke But if you have 2 different context in each repository you can not do a transaction spanning both repositories. I think this is a problem. I would recommend to the question opener to inject an IUnitOfWork into his service so a service can make a call on 2 repositories and commit that. This would be a better approach, do yu agree? – Elisabeth Feb 13 '13 at 18:35
  • 2
    @elisa the idea is that you share the DBContext between both repositories, if you have completely separate DBContexts and want to have both commit in the same transaction you will need to use transaction scope and the DTC which is pretty heavy handed. Given we are talking about a web application the request really is the unit of work so IMO you are better to just share the context between all repositories involved in the request. hence binding the context .InRequestScope() in the above – undefined Feb 13 '13 at 20:52
  • What about in a unit test? What would your bindings look like? No asp.net or mvc, but similar repo setup – Ryan Oct 15 '13 at 04:56
  • `.InRequestScope();` doesn't guarantee same instance. Here's what I had to do to get around this issue: `var ctx = new DbContext(); Bind().To().InRequestScope().WithConstructorArgument("context", ctx); Bind().To().InRequestScope().WithConstructorArgument("context", ctx);` and so on. – Mrchief Mar 05 '14 at 01:59
  • It worth to note that in the end of request DbContext will be disposed as described in http://www.davepaquette.com/archive/2013/03/27/managing-entity-framework-dbcontext-lifetime-in-asp-net-mvc.aspx – Seyed Morteza Mousavi Jan 05 '16 at 06:56