1

Hi I am using Unity to manage my service layers, which in turn speak to UnitOfWork which manages all the repositories.

Some of my services call other services, my question is how can i pass the same UnitOfWork between service layers?

In my case all controller actions are initiated from a GUI on each button action or event on a timer, this is why I have a factory to create UnitOfWork on demand, but it is causing issues as i dont know how to pass this UnitOfWork between services.

Especially difficult is knowing how to get this specific UnitOfWork instance injected into the service constructor. Please note that some of the services may be long running (10 minutes or so on a background thread), i don't know if that has any impact on the design or not.

Currently the service that is called from the other service is then creating its own UnitOfWork which is causing issues for both transactional design, and Entity framework entity tracking.

Suggestions very welcome!

class OtherService : IOtherService
{
    public OtherService(IUnitOfWorkFactory unitOfworkFactory, 
        ISettingsService settingsService)
    {
        UnitOfWorkFactory = unitOfworkFactory;
        SettingsService = settingsService;
    }
    IUnitOfWorkFactory UnitOfWorkFactory;
    ISettingsService SettingsService;

    function SomeSeviceCall()
    {
        // Perhaps one way is to use a factory to instantiate a 
        // SettingService, and pass in the UnitOfWork here?
        // Ideally it would be nice for Unity to handle all of 
        // the details regardless of a service being called from
        // another service or called directly from a controller
        // ISettingsService settingsService = 
        //     UnityContainer.Resolve<ISettingService>();

        using (var uow = UnitOfWorkFactory.CreateUnitOfWork())
        {
            var companies = uow.CompaniesRepository.GetAll();
            foreach(Company company in companies)
            {
                settingsService.SaveSettings(company, "value");
                company.Processed = DateTime.UtcNow();
            }
            uow.Save();
        }
    }
}

class SettingsService : ISettingsService
{
    public SettingsService(IUnitOfWorkFactory unitOfworkFactory)
    {
        UnitOfWorkFactory = unitOfworkFactory;
    }
    IUnitOfWorkFactory UnitOfWorkFactory;

    // ISettingsService.SaveSettings code in another module...
    function void ISettingsService.SaveSettings(Company company, 
        string value)
    {
        // this is causing an issue as it essentially creates a 
        // sub-transaction with the new UnitOfWork creating a new 
        // Entiy Framework context
        using (var uow = UnitOfWorkFactory.CreateUnitOfWork())
        {
            Setting setting = new Setting();
            setting.CompanyID = company.CompanyID;
            setting.SettingValue = value;
            uow.Insert(setting);
            uow.Save();
        }
    }
}
Steven
  • 166,672
  • 24
  • 332
  • 435
morleyc
  • 2,169
  • 10
  • 48
  • 108
  • 1
    Look at [this question](http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why). I think the [selected answer](http://stackoverflow.com/a/10588594/264697) addresses your question too. – Steven Jun 07 '12 at 06:50
  • @Steven thanks, I like the idea of the command/handler design, how would one go about getting the context shared across multiple services via a command decorator? If you have any code examples of the decorator being called and data returned that would be of immense value. – morleyc Jun 07 '12 at 14:44
  • I missed the fact that you are using Unity. With Unity it is extremely difficult to register generic decorators (although you might get it to work with Unity's interception support). However, in theory it is just a matter of defining a decorator (say `TransactionCommandHandlerDecorator`) that gets a unit of work injected and calls `uwo.Save` in the `Handle` method, just after calling `decorated.Handle(command)`. You register this decorator to be wrapped around your command handlers and register the unit of work with a "per web request" lifestyle. – Steven Jun 07 '12 at 14:59
  • @Steven thanks, I don't have to use Unity, any other DI container is ok, if you know of one you use to achieve the above I can use it also as I'm still riging up conceptual boiler plate code – morleyc Jun 07 '12 at 20:40
  • I use the [Simple Injector](http://simpleinjector.codeplex.com), but I like to note that I'm the main dev behind the Simple Injector, so note that I'm biased and plugging my own framework right now :-). However, Simple Injector does have great [decorator support](http://simpleinjector.codeplex.com/wikipage?title=Advanced-scenarios#Generic_Decorators). – Steven Jun 07 '12 at 20:47
  • 1
    Unity has just been replaced with Simple Injector :) I will post back how i get on, looking over your other blog posts [Commands](http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91) and [Queries](http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92) will implement some code based on that with PerRequest lifetime for the UnitOfWork and a post commit event, just need to piece the articles code together – morleyc Jun 08 '12 at 10:28
  • @Steven your container is great, well under way with it now. I am using Command/Handler's and I have moved my question here as it is going in a new direction: http://stackoverflow.com/questions/10950644/simpleinjector-calling-commands-from-within-another-command-handle-method Since I have replaced Unity, what is the best way to close this question out mentioning this new direction/question? Appreciate the help from everyone so far. – morleyc Jun 08 '12 at 14:22
  • My tip is, dont close this question; the answers might still be useful to others. Remove your own answer and mark one of the other responses as answer. – Steven Jun 08 '12 at 15:00

3 Answers3

2

Hi I've been battling with this problem this is what I've come up with...

public class UnitOfWorkFactory
{
    private static readonly Hashtable _threads = new Hashtable();
    private const string HTTPCONTEXTKEY = 
        "AboutDbContext.UnitOfWorkFactory";

    public static IUnitOfWork Create()
    {
        IUnitOfWork unitOfWork = GetUnitOfWork();

        if (unitOfWork == null || unitOfWork.IsDisposed)
        {
            unitOfWork = new UnitOfWork();
            SaveUnitOfWork(unitOfWork);
        }
        return unitOfWork;
    }

    public static IUnitOfWork GetUnitOfWork()
    {
        if (HttpContext.Current != null)
        {
            if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
            {
                return (IUnitOfWork)HttpContext
                    .Current.Items[HTTPCONTEXTKEY];
            }
            return null;
        }

        var thread = Thread.CurrentThread;

        if (string.IsNullOrEmpty(thread.Name))
        {
            thread.Name = Guid.NewGuid().ToString();
            return null;
        }

        lock (_threads.SyncRoot)
        {
            return (IUnitOfWork)_threads[Thread.CurrentThread.Name];
        }
    }

    private static void SaveUnitOfWork(IUnitOfWork unitOfWork)
    {
        if (HttpContext.Current != null)
        {
            HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork;
        }
        else
        {
            lock (_threads.SyncRoot)
            {
                _threads[Thread.CurrentThread.Name] = unitOfWork;
            }
        }
    }

    public static void DisposeUnitOfWork(IUnitOfWork unitOfWork)
    {
        if (HttpContext.Current != null)
        {
            HttpContext.Current.Items.Remove(HTTPCONTEXTKEY);
        }
        else
        {
            lock (_threads.SyncRoot)
            {
                _threads.Remove(Thread.CurrentThread.Name);
            }
        }
    }
}

public interface IUnitOfWork : IDisposable
{
    void Commit();
    bool IsDisposed { get; }
}

public class UnitOfWork : MyContext
{

}

public abstract class Repository<T>
    : IRepository<T>, IDisposable where T : class
{
    private UnitOfWork _context;

    private UnitOfWork Context
    {
        get
        {
            if (_context == null || _context.IsDisposed)
                return _context = GetCurrentUnitOfWork<UnitOfWork>();

            return _context;
        }
    }

    public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>() 
        where TUnitOfWork : IUnitOfWork
    {
        return (TUnitOfWork)UnitOfWorkFactory.GetUnitOfWork();
    }

    public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
    {
        return Context.Set<T>().Where(predicate).ToList();
    }

    public bool Exists(Expression<Func<T, bool>> predicate)
    {
        return Context.Set<T>().Any(predicate);
    }

    public T First(Expression<Func<T, bool>> predicate)
    {
        return Context.Set<T>().Where(predicate).FirstOrDefault();
    }

    public IEnumerable<T> GetAll()
    {
        return Context.Set<T>().ToList();
    }

    public IEnumerable<T> GetAllOrderBy(Func<T, object> keySelector)
    {
        return Context.Set<T>().OrderBy(keySelector).ToList();
    }

    public IEnumerable<T> GetAllOrderByDescending(Func<T, object> keySelector)
    {
        return Context.Set<T>().OrderByDescending(keySelector).ToList();
    }

    public void Commit()
    {
        Context.SaveChanges();
    }

    public void Add(T entity)
    {
        Context.Set<T>().Add(entity);
    }

    public void Update(T entity)
    {
        Context.Entry(entity).State = EntityState.Modified;
    }

    public void Delete(T entity)
    {
        Context.Set<T>().Remove(entity);
    }

    public void Dispose()
    {
        if (Context != null)
        {
            Context.Dispose();
        }
        GC.SuppressFinalize(this);
    }
}

public class MyContext : DbContext, IUnitOfWork
{
    public DbSet<Car> Cars { get; set; }

    public void Commit()
    {
        SaveChanges();
    }

    protected override void Dispose(bool disposing)
    {
        IsDisposed = true;
        UnitOfWorkFactory.DisposeUnitOfWork(this);
        base.Dispose(disposing);
    }

    public bool IsDisposed { get; private set; }
}

Then I can do:

using (var unitOfWork = UnitOfWorkFactory.Create())
{
    _carRepository.Add(new Car
    {
        Make = "Porshe", Name = "Boxter"
    });

    _carRepository.Commit();
}
Steven
  • 166,672
  • 24
  • 332
  • 435
Mantisimo
  • 4,203
  • 5
  • 37
  • 55
1

You could use some kind of "current" unit of work which is tied to current thread and explicitly resolved in service code. You need class to hold thread static instance of UoW to achieve this. However, this is not very good solution.

Gopher
  • 917
  • 6
  • 18
-1

You be the judge... I think you are double doing it.

Point 1: http://www.britannica.com/topic/Occams-razor

Point 2: From the F2 object browser description of EF main object, the DBContext...


public class DbContext Member of System.Data.Entity

Summary: A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that it can be used to query from a database and group together changes that will then be written back to the store as a unit.