在.NET Core启动中解析Hangfire依赖项/HttpContext [英] Resolving Hangfire dependencies/HttpContext in .NET Core Startup

查看:176
本文介绍了在.NET Core启动中解析Hangfire依赖项/HttpContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在.NET Core Web应用程序的Startup类中安装并配置了Hangfire,如下所示(已删除了许多非Hangfire的代码):

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();
    }
}

如您所见,我正在将Autofac用于DI.我已经设置好了,每次执行Hangfire作业时都会注入一个新的容器.

当前,我有UseHangfireDashboard()以及添加了重复工作的调用已被注释掉,并且在引用IPrincipal的行上收到以下错误:

System.NullReferenceException:'对象引用未设置为对象的实例.'

我了解Hangfire没有HttpContext.我不太确定为什么还要为Hangfire线程触发该行代码.我最终将需要为我的IPrincipal依赖关系解析一个服务帐户.

如何解决Hangfire和HttpContext的问题?

解决方案

我现在遇到的主要问题是当我添加UseHangfireServer时, 然后也需要解析HttpContext

在此处找到使用IoC容器

HttpContext不可用

请求信息在实例化a期间不可用 目标类型.如果您在请求范围内注册依赖项 (在Autofac中为InstancePerHttpRequest,在Ninject中为InRequestScope,依此类推 on),则在作业激活过程中将引发异常.

因此,整个依赖关系图应该可用.要么注册 无需使用请求范围或单独使用其他服务 如果您的IoC容器不支持容器的实例 多个作用域的依赖项注册.

在.net core中解析

范围内的依赖项将需要一个请求,该请求在启动期间注册和激活作业时不可用.因此,请确保未使用作用域生存期来注册启动期间激活所需的服务.

 services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();

现在剩下的就是配置应用程序以使该服务与重复作业一起使用

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
}

参考

Hangfire 1.6.0

将HangFire与ASP.NET Core集成

使用IoC容器

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?

解决方案

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

这篇关于在.NET Core启动中解析Hangfire依赖项/HttpContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆