Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving Hangfire dependencies/HttpContext in .NET Core Startup

I've installed and configured Hangfire in my .NET Core web application's Startup class as follows (with a lot of the non-Hangfire code removed):

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseHangfireServer();
        //app.UseHangfireDashboard();
        //RecurringJob.AddOrUpdate(() => DailyJob(), Cron.Daily);
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();
        services.Configure<AppSettings>(Configuration);
        services.AddSingleton<IConfiguration>(Configuration);
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddScoped<IPrincipal>((sp) => sp.GetService<IHttpContextAccessor>().HttpContext.User);
        services.AddScoped<IScheduledTaskService, ScheduledTaskService>();

        services.AddHangfire(x => x.UseSqlServerStorage(connectionString));    
        this.ApplicationContainer = getWebAppContainer(services);
        return new AutofacServiceProvider(this.ApplicationContainer);
    }
}

public interface IScheduledTaskService
{
    void OverduePlasmidOrdersTask();
}

public class ScheduledTaskService : IScheduledTaskService
{
    public void DailyJob()
    {
        var container = getJobContainer();
        using (var scope = container.BeginLifetimeScope())
        {
            IScheduledTaskManager scheduledTaskManager = scope.Resolve<IScheduledTaskManager>();
            scheduledTaskManager.ProcessDailyJob();
        }
    }

    private IContainer getJobContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new BusinessBindingsModule());
        builder.RegisterModule(new DataAccessBindingsModule());
        return builder.Build();
    }
}

As you can see, I'm using Autofac for DI. I've set things up to inject a new container each time the Hangfire job executes.

Currently, I have UseHangfireDashboard() as well as the call to add my recurring job commented out and I'm receiving the following error on the line referencing IPrincipal:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

I understand that Hangfire does not have an HttpContext. I'm not really sure why it's even firing that line of code for the Hangfire thread. I'm ultimately going to need to resolve a service account for my IPrincipal dependency.

How can I address my issue with Hangfire and HttpContext?

like image 416
im1dermike Avatar asked May 18 '17 17:05

im1dermike


People also ask

How to resolve dependency injection in. net Core?

Resolve dependencies using IServiceProvider You can use the IServiceCollection interface to create a dependency injection container. Once the container has been created, the IServiceCollection instance is composed into an IServiceProvider instance. You can use this instance to resolve services.

What is hangfire in ASP.NET Core?

Hangfire is an open-source and well-documented task scheduler for ASP.NET and ASP.NET Core. It's multi-threaded, easily scalable, and offers a variety of job types. It's well structured, simple to use, and gives a powerful performance.

What is HttpContextAccessor in ASP.NET Core?

It stores the request and response information, such as the properties of request, request-related services, and any data to/from the request or errors, if there are any. ASP.NET Core applications access the HTTPContext through the IHttpContextAccessor interface. The HttpContextAccessor class implements it.

How do I access the hangfire dashboard?

After performing these steps, open your browser and hit the http://<your-app>/hangfire URL to see the Dashboard. By default Hangfire allows access to Dashboard pages only for local requests. In order to give appropriate rights for production use, please see the Configuring Authorization section.


1 Answers

The main problem I'm having now is when I add UseHangfireServer, I then need to resolve HttpContext too

Found here Using IoC containers

HttpContext is not available

Request information is not available during the instantiation of a target type. If you register your dependencies in a request scope (InstancePerHttpRequest in Autofac, InRequestScope in Ninject and so on), an exception will be thrown during the job activation process.

So, the entire dependency graph should be available. Either register additional services without using the request scope, or use separate instance of container if your IoC container does not support dependency registrations for multiple scopes.

resolving scoped dependencies in .net core would require a request which is not available during startup when registering and activating jobs. Therefore make sure that your service required for activation during startup are not registered using scoped lifetimes.

 services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();

All that is left now is to configure the application to use that service with the recurring job,

public class Startup {    
    public IContainer ApplicationContainer { get; private set; }

    public Startup(IHostingEnvironment env) {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public void Configuration(IApplicationBuilder app) {
        // app.AddLogger...

        //add hangfire features
        app.UseHangfireServer();
        app.UseHangfireDashboard();

        //Add the recurring job
        RecurringJob.AddOrUpdate<IScheduledTaskManager>(task => task.ProcessDailyJob(), Cron.Daily);

        //app.UseMvc...
        //...other code
    }

    public IServiceProvider ConfigureServices(IServiceCollection services) {    
        // Adding custom services
        services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();
        //add other dependencies...

        // add hangfire services
        services.AddHangfire(x => x.UseSqlServerStorage("<connection string>"));

        //configure Autofac
        this.ApplicationContainer = getWebAppContainer(services);
        //get service provider    
        return new AutofacServiceProvider(this.ApplicationContainer);
    }

    IContainer getWebAppContainer(IServiceCollection service) {
        var builder = new ContainerBuilder();        
        builder.RegisterModule(new BusinessBindingsModule());
        builder.RegisterModule(new DataAccessBindingsModule());
        builder.Populate(services);
        return builder.Build();
    }        


    //...other code
}

References

Hangfire 1.6.0

Integrate HangFire With ASP.NET Core

Using IoC containers

like image 117
Nkosi Avatar answered Sep 21 '22 18:09

Nkosi