Core: Background services which require HTTP Context

Created on 1 Jul 2018  路  6Comments  路  Source: dotnet/core

EDIT Summary

I have a background service, which requires a DBContext, my DbContext is dependent on the HTTPContext, which is out of scope when requested from the Background Service. How can I capture and moq the HTTPContext, so my user claims will carry over to the background service?

I'm writing a hosted service to queue pushing messages from my Hubs in Signalr. My Background.

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem);
    Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>> _workItems = new ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>>();
    private SemaphoreSlim _signal = new SemaphoreSlim(0);

    public void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem)
    {
        if (workItem == null)
        {
            throw new ArgumentNullException(nameof(workItem));
        }

        this._workItems.Enqueue(workItem);
        this._signal.Release();
    }

    public async Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken)
    {
        await this._signal.WaitAsync(cancellationToken);
        this._workItems.TryDequeue(out var workItem);

        return workItem;
    }
}

I'm queue work items that require my DbContext, My Db Context automatically filters data based off the logged in user, So it requires access to the HTTPContextAccessor.

When I Queue up an Item that requires my DbContext, I get an error the the HTTPContext is null, which makes sense because, I'm running in a background process.

var backgroundTask = sp.GetRequiredService<IBackgroundTaskQueue>();

backgroundTask.QueueBackgroundWorkItem((isp, ct) => {
    //When this line is executed on the background task it throws
    var context = sp.GetService<CustomDbContext>(); 
    //... Do work with context
});

My DBContext uses the HTTPContextAccessor to filter data:

public CustomDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor)
{
}

Is there a way I can capture the HTTPContext with each Task, or perhaps Moq one and capture the UserClaims, and replace them in the scope for the BackgroundService?

How can I use services dependent on HTTPContext from my background services.

area-aspnet

Most helpful comment

Don鈥檛 write services that depend on the http context that need to be used in background threads. That won鈥檛 work. If you need state then you鈥檒l need to copy it from the request and pass it to the background thread.

All 6 comments

@danmosemsft to help route.

To clarify. I鈥檓 going to start to shy away from depending on httpcontextaccessor. In my other dependencies, and start abstracting the pieces that I need,

e.g my DbContext in the future will only depend on a new dependency which contains my claims, and I鈥檒l pass the user based dependency into my backgroundtaskqueue.

However, this is not a viable option at all times. In my case it can be done, but it would be nice if there was an easy built in way to replace the HttpContextAccessor so it can pass in a moq HttpContext with user claims etc

Don鈥檛 write services that depend on the http context that need to be used in background threads. That won鈥檛 work. If you need state then you鈥檒l need to copy it from the request and pass it to the background thread.

@davidfowl, I鈥檓 aware of that now and am changing my architecture. But it would be nice if there was a built in way to mock the httpcontext, not everyone will be aware of this when designing their application, and it could cause a large rewrite for systems bigger than mine.

Maybe we can also update the documentation to mention, to not be dependent on httpcontext

@davidfowl is the best place to open up a request like that in the aspnet/home repo?

aspnet/Docs

Was this page helpful?
0 / 5 - 0 ratings