Hangfire – Multi tenant, ASP.NET Core – Resolving the correct tenant

First, you need to be able to set the TenantId in your TenantCurrentService.
Then, you can rely on filters :

client side (where you enqueue jobs)

public class ClientTenantFilter : IClientFilter
{
        public void OnCreating(CreatingContext filterContext)
        {
           if (filterContext == null) throw new ArgumentNullException(nameof(filterContext));

            filterContext.SetJobParameter("TenantId", TenantCurrentService.TenantId);
        }
}

and server side (where the job is dequeued).

public class ServerTenantFilter : IServerFilter
{
    public void OnPerforming(PerformingContext filterContext)
    {
      if (filterContext == null) throw new ArgumentNullException(nameof(filterContext));

      var tenantId = filterContext.GetJobParameter<string>("TenantId");
      TenantCurrentService.TenantId = tenantId;
    }
}

The server filter can be declared when you configure your server through an IJobFilterProvider:

        var options = new BackgroundJobServerOptions
        {
            Queues = ...,
            FilterProvider = new ServerFilterProvider()
        };
        app.UseHangfireServer(storage, options, ...);

where ServerFilterProvider is :

public class ServerFilterProvider : IJobFilterProvider
{
    public IEnumerable<JobFilter> GetFilters(Job job)
    {
        return new JobFilter[]
                   {
                       new JobFilter(new CaptureCultureAttribute(), JobFilterScope.Global, null),
                       new JobFilter(new ServerTenantFilter (), JobFilterScope.Global,  null),
                   };
    }
}

The client filter can be declared when you instantiate a BackgroundJobClient

var client = new BackgroundJobClient(storage, new BackgroundJobFactory(new ClientFilterProvider());

where ClientFilterProvider behaves as ServerFilterProvider, delivering client filter

A difficulty may be to have the TenantCurrentService available in the filters. I guess this should be achievable by injecting factories in the FilterProviders and chain it to the filters.

I hope this will help.

Leave a Comment