8

The projects in my solution are set up like this:

  • App.Data
  • App.Models
  • App.Web

In App.Data, I'm using Entity Framework to access my data with a bunch of Repositories to abstract interaction with it. For obvious reasons, I would like my App.Web to reference only the App.Data project and not Entity Framework.

I'm using Constructor Injection to give my Controllers a reference to a Repository container that looks like this:

public interface IDataRepository
{
    IUserRepository User { get; set; }
    IProductRepository Product { get; set; }

    // ...
}

public class DataRepository : IDataRepository
{
    private readonly AppContext _context;

    public DataRepository(AppContext context)
    {
        _context = context;
    }

    // ...
}

DataRepository will have a AppContext object (which inherits from Entity Framework's DbContext) that all the child Repositories will use to access the database.

So finally we come to my problem: how do I use Constructor Injection on DataRepository considering it's a code library and has no entry-point? I can't bootstrap AppContext in App.Web because then I have to reference Entity Framework from that project.

Or am I just doing something stupid?

ajbeaven
  • 9,265
  • 13
  • 76
  • 121
  • Not an answer to your question, but instead of defining a lot of repository interfaces, try defining a single `IRepository` interface, as explained [here](http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92). This allows much more flexibility. – Steven May 10 '13 at 08:48
  • 6
    @Steven Thanks for your comment. I prefer specific repositories for this reason: "a repository is a part of the domain being modeled, and that domain is not generic. Not every entity can be deleted, not every entity can be added, not every entity has a repository". http://stackoverflow.com/questions/1230571/advantage-of-creating-a-generic-repository-vs-specific-repository-for-each-obje – ajbeaven May 10 '13 at 08:53

1 Answers1

12

You can define a RepositoryConnection class in App.Data that acts as a wrapper to the Context and removes the need to reference EF in App.Web. If you are using an IoC Container you can control the lifetime of the RepositoryConnection class to ensure that all instances of Repository get the same Context. This is a simplified example ...

public class RepositoryConnection
{
    private readonly AppContext _context;

    public RepositoryConnection()
    {
        _context = new AppContext();
    }

    public AppContext AppContext { get { return _context; } }
}

public class DataRepository : IDataRepository
{
    private readonly AppContext _context;

    public DataRepository(RepositoryConnection connection)
    {
        _context = connection.AppContext;
    }

// ...
}
qujck
  • 14,388
  • 4
  • 45
  • 74
  • If all classes are getting the same context, no one is disposing of the EF context, which is bad, very bad. EF contexts are designed with the idea that you instantiate, use, and dispose. – Bruno Brant Jun 21 '13 at 15:23
  • @BrunoBrant you are absolutely correct - a `Context` should be as short lived as possible and this answer fully supports that. The fact that we have a `RepositoryConnection` to act as a `bridge` between assemblies doesn't change anything. The `RepositoryConnection` and therefore the `Context` are registered **Per Web Request**. Each `RepositoryConnection` (and therefore `Context`) will exists within the scope of a single web request and therefore will be alive for a matter of seconds. As soon as the Web request has finished the DI managed classes will go out of scope and be `Disposed()`. – qujck Jun 21 '13 at 17:59
  • @qujck, I may be missing something, but, who guarantees the immediate `Dispose()`? AFAIK, ASP.Net gives no such guarantees. – Bruno Brant Jun 28 '13 at 22:01
  • @BrunoBrant `Disposing` is the responsibility of the `Container`. See here for example http://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement#PerWebRequest – qujck Jun 28 '13 at 23:37
  • 3
    So in your example above, `RepositoryConnection` should be `IDisposable` and the `Dispose` method simply calls `_context.Dispose()`? – ajbeaven Jan 04 '14 at 22:20
  • @ajbeaven yes, you are entirely correct - an object that instantiates other objects is wholly responsible for disposing of the objects it instantiates. If an IoC Container instantiates an object then it must dispose of it. If my class directly instantiates disposable objects then it should ensure they are disposed of at the right time. As this fact relates to a question in the comments and does not directly relate to the actual question I will not update my answer. – qujck Jan 06 '14 at 15:46
  • What about opaques dependencies like _context = new AppContext(); ? – Luis Teijon Sep 23 '16 at 20:48