【问题标题】:Activating classes with hangfire in ASP Net Core在 ASP Net Core 中使用 hangfire 激活类
【发布时间】:2021-02-14 07:33:46
【问题描述】:

我在配置 HangFire 时遇到问题。我试图在 ASP Net Core 中触发并忘记一个令人震惊的调用。

报警服务:

public void FireAndForgetAlarm(int statusCode, string message, string subject = null, IList<string> attachmentFilePaths = null)
{
    BackgroundJob.Enqueue(() => Alarm(statusCode, message, subject, 
    attachmentFilePaths));
}

*Alarm 方法是公开的。

错误描述:

警告:Hangfire.AutomaticRetryAttribute[0] 无法处理作业“eb7f76ea-7522-49e2-b7b9-3ed3ed091a0c”:发生异常。 10 次重试第 2 次将在 00:01:02 执行。 System.InvalidOperationException:尝试激活“Wms.Alarming.AlarmingService”时无法解析“Wms.Alarming.AlarmingConfig”类型的服务。 在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider 提供程序) 在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider 提供程序,类型 instanceType,Object[] 参数) 在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider 提供程序,类型类型) 在 Hangfire.AspNetCore.AspNetCoreJobActivatorScope.Resolve(类型类型) 在 Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext 上下文) 在 Hangfire.Server.BackgroundJobPerformer.c__DisplayClass9_0.b__0() 在 Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter 过滤器,PerformingContext preContext,Func1 continuation) at Hangfire.Server.BackgroundJobPerformer.&lt;&gt;c__DisplayClass9_1.&lt;PerformJobWithFilters&gt;b__2() at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable1 过滤器) 在 Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext 上下文) 在 Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId)

我的启动类包含:

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureAlarmingServices(new AlarmingConfig()
    {
        Port = int.Parse(ConfigurationManager.AppSettings["mailPort"]), // for SSL 465
        Sender = ConfigurationManager.AppSettings["mailSender"],
        SmtpServer = ConfigurationManager.AppSettings["smtpServer"],
        Recipients = ConfigurationManager.AppSettings["mailRecipients"],
        SenderPassword = ConfigurationManager.AppSettings["mailPassword"]
    });
    services.AddHangfire(c => {
            c.UseMemoryStorage();
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
{
     app.UseHangfireServer(new BackgroundJobServerOptions(){Activator = new AspNetCoreJobActivator(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>())});
}

注意事项:

  • 我已经为启动类尝试了多个版本,包括将激活器放在 AddHangire 方法中。没有任何尝试真正奏效,我也正确地遵循了文档。
  • 报警服务配置正确,无需 HangFire 即可工作。
  • 在警报配置中传递文字不起作用
  • 唯一的解决方案是使方法静态化,但这不允许好的 DI
  • 我在他们的文档中看到了一个解决方案,他们总是有一个默认构造函数并使用参数调用构造函数。但是,这对我来说是不可能的,因为我也在注入记录器。

在 cmets 中请求的扩展方法的内容:

public static void ConfigureAlarmingServices(this IServiceCollection collection, AlarmingConfig config)
{
    collection.AddSingleton<IAlarmingService>(x=> new 
    AlarmingService(x.GetService<ILogger<IAlarmingService>>(), config));
}

【问题讨论】:

  • 实际抛出错误的代码在哪里?您似乎缺少FileStorageService 的配置。
  • 你是对的@Xerillio 我展示了警报服务,因为我也遇到了警报服务的问题(相同)。让我更新。
  • @Xerillio 我更新了错误消息,filestorageservice 错误消息是我的第一个错误消息,我可以通过将其设为静态来解决。然而,这种令人担忧的服务无法以这种方式解决。
  • ConfigureAlarmingServices 是自定义方法吗?这种方法发生了什么?您似乎缺少services.AddScoped&lt;AlarmingService&gt;(...) 或类似的东西。
  • 是的,这是一种扩展方法,我将警报服务注册为单例@Xerillio

标签: c# hangfire


【解决方案1】:

首先,您看到的异常的重要部分是:

在尝试激活“Wms.Alarming.AlarmingService”时无法解析“Wms.Alarming.AlarmingConfig”类型的服务

这表明在您的代码中的某处(您尚未显示的部分)您正在尝试注入 AlarmingService 的实例。

您已经配置了如何为接口IAlarmingService 解析单例服务,这意味着您应该能够拥有一个依赖于IAlarmingService 的类。但是,如果您的类具体依赖于AlarmingService(而不是接口),您将收到此错误,因为您尚未定义如何解决AlarmingService 类型的依赖关系。

要么...

  • 您没有显示的代码应该只依赖于IAlarmingService 而不是具体类本身 (AlarmingService) 或..
  • 您还需要配置 DI 容器来处理特定于 AlarmingService 类型的依赖项,例如:
public static void ConfigureAlarmingServices(this IServiceCollection collection, AlarmingConfig config)
{
    collection.AddSingleton<AlarmingService>(
        x => new AlarmingService(x.GetService<ILogger<AlarmingService>>(), config));
    collection.AddSingleton<IAlarmingService>(x => x.GetService<AlarmingService>());
}

我认为第一点是你需要解决的问题。

【讨论】:

  • 没有什么取决于具体的类,我使用适当的 DI。第二个语句与第一个语句没有什么不同,加号在您获取 IAlarmingService 并尝试将其注册为 AlarmingService 时无效。不过,您给了我一个新想法,分别注册配置。成功了!
  • @wutBruh 你是对的,服务注册应该已经被交换了。现在已经解决了。我仍然想知道为什么您需要单独注册配置。当您为IAlarmingService 定义工厂时,这不是必需的。如果你不注册配置并使用我的固定代码,那还不行吗?
  • 啊,它确实有效,我现在才明白你的意思。该库想要实际的实现,因为尽管传递了接口,但它就是在执行它的地方。有道理。
  • 还有一个问题。将运行单个异步方法的作业排入队列是否有意义?我应该等待还是不等待?
  • @wutBruh 当然,为什么不呢?您调用的方法数量无关紧要。是否等待我认为没有区别。据我所知,Hangfire 还不支持真正的“异步”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
  • 2016-10-21
  • 2017-06-09
  • 2018-12-04
  • 2018-11-04
  • 2018-08-14
相关资源
最近更新 更多