0

I hit a little road block trying to set up DI.

So given that I have this controller:

public UsersController(IUnitOfWork unitOfWork)
{
   // Stuff
}

I previously had this UnitOfWork implementation that accessed my repositories directly.

public class UnitOfWork : IUnitOfWork, IDisposable
{
  private readonly DbContext _context = new DbContext();

  public IRepository<User> Users { get { return new UserRepository(_context); } }
}

Ninject UnitOfWork code: Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();

Now this actually works fine. However I want to change it so that instead of UnitOfWork containing the repositories, it contains services which take in multiple repositories.

public class UserService : IUserService
{
  private readonly IUserRepository _userRepository;
  public UserService(IUserRepository userRepository, /* Other repositories */)
  {
    _userRepository = userRepository;
  }
}

Right now the only solution I can come up with is

public class UnitOfWork : IUnitOfWork, IDisposable
{
  private readonly DbContext _context = new DbContext();

  public IUserService UserService
  {
    get
    {
      return new UserService(new UserRepository(_context), /* etc. */);
    }
  }
}

This doesn't seem right. Now I'm creating all of the service dependencies myself.

I've seen posts on StackOverflow mentioning that it's better to have services access the multiple repositories and handle the business logic rather than having the controller (MVC application) worry about it.

Can't find any specifics on how to actually do this properly though. So how could I use Ninject to do what I'm after?

Brandon
  • 68,708
  • 30
  • 194
  • 223

1 Answers1

2

Sorry, this is really an overgrown comment but hey...

A DbContext is a Unit Of Work, and creating a monster unit of work that straddles two DbContexts is definitely not a general pattern (hence your question sez you)

The comments on this answer here to a related question stray into the same territory.

Questions to ask yourself before you try to solve it this way:

  • What are you attempting to accomplish with this Unit of Work of mine beyond having a DbContext?
  • Does this need to be transactional?
  • Is there actually a missing service in the middle which should have its own data that references the two other ones?
  • Does this need to straddle two Bounded Contexts? What if you need to pull them part again later?
  • If I had 3 cases of this in my app would I keep merging them into one BC? 4?

For me the crux is that creating your own UoW to wrap a UoW:

  1. doesn't buy you much
  2. makes it harder to reason about your core problem

If you are still going to shoehorn this stuff in with Ninject in the way, the technical approach is to use the Context Preservation and Factory Extensions together - go read the examples in their wikis. If you decide to strip things back, they probably still have parts to play too.

UPDATE: I catch your drift now - it's important to link to stuff like that which is guiding your thinking up front. First, go read this. Next, decide if you're going to have a Unit of Work. If so, who and where is going to Commit and Dispose it?

If the Repositories and/or Services are going to share either a UoW or a DBContext and something is going to centrally Commit stuff, then you bind the things to be Shared/Disposed InRequestScope to have it a) get a single shared instance b) get Disposal

My main concern remains whether all these abstractions are all actually benefiting things - are you really writing tests that use the abstractions (and not just for the first few)? Are you really going to switch repositories. I personally would go read the DDD book a few times as a better time investment.

I realise a lot of this is highly patronising and this is just a simplified question representing part of a larger problem, but I've just seen too many questions recently prompted by the intersection of wrapping layers and DI container trickery hence my rant. Rant complete, thanks!

Community
  • 1
  • 1
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • Thanks for the answer. The code I have is built off the sample they have on the MVC site: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application If it's a bad idea, then I will consider alternate solutions. Really the only thing I want to avoid is having all my business logic in the controller, and since it doesn't belong in a repository I figured it'd be suitable for a service layer instead. That would mean I should share the DbContext, which is what I thought the UnitOfWork class was for. – Brandon Apr 05 '13 at 22:20
  • Also, could you clarify what you mean by two bounded contexts? I don't quite follow. I'm passing the same instance of the context into multiple repositories, so why would there be two contexts? – Brandon Apr 05 '13 at 22:22
  • @Brandon Def keep a Service Layer and push stuff out of Actions. It its the same instance of the DbContext most of my comments don't apply. You can Bind the `DbContext` `InRequestScope` and stuff that needs it asks for a `Func` and wraps it in a `using`. – Ruben Bartelink Apr 05 '13 at 22:26
  • @Brandon re 2 bounded contexts, it's pretty clear I misinterpreted your question. But it makes me feel stronger about the central thing that you're about to wrap a thing that wraps wrappers for N tables in a thing that will offer accessors for slightly less than N tables. I'd instead make Services that do something useful and deal with whatever number of Repositories that involves - if that's just 1, all the better. And the Repositories can be the DbTable or similar that the DbContext can give you. – Ruben Bartelink Apr 05 '13 at 22:31