Unit of work with hangfire?

Hi,

In our web app, we have a fairly logic scope for ‘unit of work’ - that is, a web request.

With a web request, our IoC container is able to determine the current user (injecting our domain ‘User’ object per web request), create an NHibernate session etc.

I’m implementing some background-job framework code in our project that sets up some ‘context’ before the job is executed and I was just wondering how best to ‘scope’ the IoC container. For example, ideally, I’d have an NHibernate session created just before the job is executed and disposed once execution is complete.

I hope it’s clear enough about what I’m trying to do but if not, let me know and i’ll provide more details.

cheers,
PD

This is a very good question. As I understand, you are asking about this because of IDisposable objects. Without them you can simply set thread-scoped resolution, and all things would be fine. However, as I think, you also want to release shared disposable objects after background job was performed.

Currently IoC container support does not allow you to register dependencies in a single background job performance scope. You should use abstract factories now or resolve service locator and create nested scope manually. Here is an example for Autofac:

public class MyType : IDisposable
{
    private readonly ILifetimeScope _lifetimeScope;

    public MyType(ILifetimeScope parentLifetimeScope)
    {
        _lifetimeScope = parentLifetimeScope.BeginLifetimeScope();
        _lifetimeScope.Tag = MyContextHierarchy.BackgroundJob;
    }

    public void MyMethod()
    {
        var dbContext = _lifetimeScope.Resolve<DbContext>();
    }

    public void Dispose()
    {
        _lifetimeScope.Dispose();
    }
}

Here is the registration:

builder.RegisterType<DbContext>().InstancePerMatchingLifetimeScope(MyContextHierarchy.BackgroundJob);

I’m having an issue with something similar. I have setup a generic repository and UoW using AutoFac…

builder.RegisterModule(new RepositoryModule());
builder.RegisterType(typeof(MyContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerLifetimeScope();

I have a scheduled task that runs my service object just fine, but entity framework complains when I try to save to the database…

“New transaction is not allowed because there are other threads running in the session.”

After researching, I know this is because the Hangfire process is being executing in a background thread but I am kind of lost on how to resolve that from here. Any help would be greatly appreciated.

I seem to have got it working. Corrected an issue in my Unit of Work class and updated my AutoFac init to this…

builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerLifetimeScope();
builder.RegisterType<MyContext>().AsSelf();