12

我已经在我的 .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 的问题?

4

3 回答 3

5

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

在这里找到使用 IoC 容器

HttpContext不可用

在目标类型的实例化期间,请求信息不可用。如果您在请求范围内注册您的依赖项(InstancePerHttpRequest在 Autofac、InRequestScopeNinject 等中),则在作业激活过程中将引发异常。

所以,整个依赖图应该是可用的。如果您的 IoC 容器不支持多个范围的依赖项注册,则可以在不使用请求范围的情况下注册其他服务,或者使用单独的容器实例。

解决 .net 核心中的作用域依赖项将需要在注册和激活作业时启动期间不可用的请求。因此,请确保您在启动期间激活所需的服务未使用作用域生命周期进行注册。

 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
}

参考

挂火1.6.0

将 HangFire 与 ASP.NET Core 集成

使用 IoC 容器

于 2017-05-29T11:50:41.460 回答
1

为什么 Hangfire 试图解析 .NET Core Startup 类?

Hangfire 不会在数据库中存储 lambda 表达式,它会存储被调用的类型和方法。然后,当计划任务即将运行时,它会从容器中解析类型并调用该方法。

在您的情况下,该方法是 on Startup

您可以Startup根据需要在 Autofac 注册,但拥有计划任务服务可能是最简单的:

AddOrUpdate<IScheduledTaskService>(x => x.DailyTask(), Cron.Daily);
于 2017-05-24T13:28:20.180 回答
0

我不确定 jobmanager 的类型,但您可以使用范围解决容器的依赖关系。您需要从 using 语句中的范围解析,以防止内存泄漏。请参阅Autofac 文档

// not sure what type "jobManager" is
TYPE jobManager;

using(var scope = ApplicationContainer.BeginLifetimeScope())
{
    jobManager = scope.Resolve<TYPE>();
}

RecurringJob.AddOrUpdate( ... );
于 2017-05-18T23:00:04.873 回答