Question

I have a WPF application with MVVM. Assuming object composition from the ViewModel down looks as follows:

MainViewModel
    OrderManager
        OrderRepository
            EFContext
        AnotherRepository
            EFContext
    UserManager
        UserRepository
            EFContext

My original approach was to inject dependencies (from the ViewModelLocator) into my View Model using .InCallScope() on the EFContext and .InTransientScope() for everything else. This results in being able to perform a "business transaction" across multiple business layer objects (Managers) that eventually underneath shared the same Entity Framework Context. I would simply Commit() said context at the end for a Unit of Work type scenario.

This worked as intended until I realized that I don't want long living Entity Framework contexts at the View Model level, data integrity issues across multiple operations described HERE. I want to do something similar to my web projects where I use .InRequestScope() for my Entity Framework context. In my desktop application I will define a unit of work which will serve as a business transaction if you will, typically it will wrap everything within a button click or similar event/command. It seems that using Ninject's ActivationBlock can do this for me.

internal static class Global
{
    public static ActivationBlock GetNinjectUoW()
    {            
        //assume that NinjectSingleton is a static reference to the kernel configured with the necessary modules/bindings
        return new ActivationBlock(NinjectSingleton.Instance.Kernel);
    }   
}

In my code I intend to use it as such:

//Inside a method that is raised by a WPF Button Command ...
using (ActivationBlock uow = Global.GetNinjectUoW())
{
    OrderManager orderManager = uow.Get<OrderManager>();
    UserManager userManager = uow.Get<UserManager>();

    Order order = orderManager.GetById(1);
    UserManager.AddOrder(order);
    ....
    UserManager.SaveChanges();
}

Questions:

  1. To me this seems to replicate the way I do business on the web, is there anything inherently wrong with this approach that I've missed?
  2. Am I understanding correctly that all .Get<> calls using the activation block will produce "singletons" local to that block? What I mean is no matter how many times I ask for an OrderManager, it'll always give me the same one within the block. If OrderManager and UserManager compose the same repository underneath (say SpecialRepository), both will point to the same instance of the repository, and obviously all repositories underneath share the same instance of the Entity Framework context.
Was it helpful?

Solution

Both questions can be answered with yes:

  1. Yes - this is service location which you shouldn't do
  2. Yes you understand it correctly

OTHER TIPS

A proper unit-of-work scope, implemented in Ninject.Extensions.UnitOfWork, solves this problem.

Setup:

_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();

Usage:

using(UnitOfWorkScope.Create()){
    // resolves, async/await, manual TPL ops, etc    
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top