我已经在我的.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:&#39;对象引用未设置为对象的实例。&#39;
我了解Hangfire没有HttpContext
。我不确定为什么它甚至会为Hangfire线程触发该行代码。我最终需要为我的IPrincipal依赖项解析服务帐户。
如何使用Hangfire和HttpContext解决我的问题?
答案 0 :(得分:2)
我现在遇到的主要问题是当我添加UseHangfireServer时,我 那么还需要解决HttpContext
在此处找到Using IoC containers
HttpContext
无法使用在实例化期间,请求信息不可用 目标类型。如果在请求范围中注册依赖项 (Autofac中的
InstancePerHttpRequest
,Ninject中的InRequestScope
等等 on),在作业激活过程中会抛出异常。所以,整个依赖图应该可用。要么注册 不使用请求范围的其他服务,或单独使用 如果您的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 :(得分:1)
为什么Hangfire会尝试解析.NET Core Startup类?
Hangfire不会在数据库中存储lambda表达式,它会存储被调用的类型和方法。然后,当计划任务运行时,它将从容器中解析该类型并调用该方法。
在您的情况下,该方法位于 public enum Existing
{
Default = 1,
None = 0,
Value1 = 1,
Value2 = 2,
Value3 = 3
}
。
如果需要,您可以使用Autofac注册Startup
,但最简单的方法是提供计划任务服务:
Startup
答案 2 :(得分:0)
我不确定作业管理员的类型,但您可以使用作用域解决容器中的依赖关系。您需要从using语句中的范围解析以防止内存泄漏。请参阅Autofac Docs
// not sure what type "jobManager" is
TYPE jobManager;
using(var scope = ApplicationContainer.BeginLifetimeScope())
{
jobManager = scope.Resolve<TYPE>();
}
RecurringJob.AddOrUpdate( ... );