使用.net核心进行Hangfire依赖注入

ead*_*dam 52 c# hangfire asp.net-core

如何在Hangfire中使用.net core的默认依赖注入?

我是Hangfire的新手,正在寻找一个与asp.net核心兼容的例子.

Gon*_*ero 55

请参阅GitHub上的完整示例https://github.com/gonzigonz/HangfireCore-Example.
现场网站http://hangfirecore.azurewebsites.net/

  1. 确保您拥有Hangfire的核心版本:
    dotnet add package Hangfire.AspNetCore

  2. 通过定义a来配置IoC JobActivator.以下是与默认的asp.net核心容器服务一起使用的配置:

    public class HangfireActivator : Hangfire.JobActivator
    {
        private readonly IServiceProvider _serviceProvider;
    
        public HangfireActivator(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public override object ActivateJob(Type type)
        {
            return _serviceProvider.GetService(type);
        }
    }  
    
    Run Code Online (Sandbox Code Playgroud)
  3. 接下来在Startup.ConfigureServices方法中注册hangfire作为服务:

    services.AddHangfire(opt => 
        opt.UseSqlServerStorage("Your Hangfire Connection string"));
    
    Run Code Online (Sandbox Code Playgroud)
  4. Startup.Configure方法中配置hangfire .与您的问题相关,关键是配置hangfire以使用HangfireActivator我们刚才定义的新内容.为此,您必须提供hangfire,IServiceProvider这可以通过将其添加到Configure方法的参数列表来实现.在运行时,DI将为您提供此服务:

    public void Configure(
        IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory,
        IServiceProvider serviceProvider)
    {
        ...
    
        // Configure hangfire to use the new JobActivator we defined.
        GlobalConfiguration.Configuration
            .UseActivator(new HangfireActivator(serviceProvider));
    
        // The rest of the hangfire config as usual.
        app.UseHangfireServer();
        app.UseHangfireDashboard();
    }  
    
    Run Code Online (Sandbox Code Playgroud)
  5. 将作业排入队列时,请使用通常是您的界面的注册类型.除非您以这种方式注册,否则请勿使用具体类型.您必须使用在IoC注册的类型,否则Hang​​fire将无法找到它. 例如,您已经注册了以下服务:

    services.AddScoped<DbManager>();
    services.AddScoped<IMyService, MyService>();
    
    Run Code Online (Sandbox Code Playgroud)

然后你可以DbManager使用该类的实例化版本入队:

    BackgroundJob.Enqueue(() => dbManager.DoSomething());
Run Code Online (Sandbox Code Playgroud)

但是你不能这样做MyService.使用实例化版本进行入队将失败,因为DI将失败,因为只有接口已注册.在这种情况下,你会像这样入队:

    BackgroundJob.Enqueue<IMyService>( ms => ms.DoSomething());
Run Code Online (Sandbox Code Playgroud)

  • 当前的Hangfire版本(1.6.19)自动注册AspNetCoreJobActivator.https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.AspNetCore/HangfireServiceCollectionExtensions.cs#L107 (16认同)
  • **这是实现错误,不应使用**。作业激活器具有这些`BeginScope`函数是有原因的。在这里使用此实现的唯一方法是将其传递给根服务提供者。这意味着它永远不会被丢弃,这意味着每次创建作业时,您都会泄漏所创建的所有依赖项。 (3认同)
  • @Voo - 提到“这个实现是错误的”,但你还没有提供什么是“正确的”实现。很有帮助。谢谢 (2认同)

小智 12

据我所知,您可以像使用任何其他服务一样使用.net核心依赖注入.

您可以使用包含要执行的作业的服务,这样可以执行

var jobId = BackgroundJob.Enqueue(x => x.SomeTask(passParamIfYouWish));

以下是Job Service类的示例

public class JobService : IJobService
{
    private IClientService _clientService;
    private INodeServices _nodeServices;

    //Constructor
    public JobService(IClientService clientService, INodeServices nodeServices)
    {
        _clientService = clientService;
        _nodeServices = nodeServices;
    }

    //Some task to execute
    public async Task SomeTask(Guid subject)
    {
        // Do some job here
        Client client = _clientService.FindUserBySubject(subject);
    }      
}
Run Code Online (Sandbox Code Playgroud)

在您的项目Startup.cs中,您可以正常添加依赖项

services.AddTransient< IClientService, ClientService>();

不确定这是否回答了你的问题

  • 这个解决方案开箱即用.谢谢 (4认同)
  • 这是如何开箱即用的?所以ClientService就是你自己的API.BackgroundJob如何知道调用JobService的实例?IJobService是一个hangfire接口吗?如果是这样我就找不到了.非常困惑! (4认同)

SO *_*ood 11

该线程中的所有答案都是错误的/不完整的/过时的。这是 ASP.NET Core 3.1 和 Hangfire.AspnetCore 1.7 的示例。

客户:

//...
using Hangfire;
// ...

public class Startup
{
    // ...

    public void ConfigureServices(IServiceCollection services)
    {
        //...
        services.AddHangfire(config =>
        {
            // configure hangfire per your requirements
        });
    }
}

public class SomeController : ControllerBase
{
    private readonly IBackgroundJobClient _backgroundJobClient;

    public SomeController(IBackgroundJobClient backgroundJobClient)
    {
        _backgroundJobClient = backgroundJobClient;
    }
    
    [HttpPost("some-route")]
    public IActionResult Schedule([FromBody] SomeModel model)
    {
        _backgroundJobClient.Schedule<SomeClass>(s => s.Execute(model));
    }
}
Run Code Online (Sandbox Code Playgroud)

服务器(相同或不同的应用程序):

{
    //...
    services.AddScoped<ISomeDependency, SomeDependency>();

    services.AddHangfire(hangfireConfiguration =>
    {
        // configure hangfire with the same backing storage as your client
    });
    services.AddHangfireServer();
}

public interface ISomeDependency { }
public class SomeDependency : ISomeDependency { }

public class SomeClass
{
    private readonly ISomeDependency _someDependency;

    public SomeClass(ISomeDependency someDependency)
    {
        _someDependency = someDependency;
    }

    // the function scheduled in SomeController
    public void Execute(SomeModel someModel)
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我在与客户端相同的应用程序上运行服务器,并且我已经注册了如下依赖项:`services.AddScoped&lt;ISomeDependency , SomeDependency &gt;();`,那么该依赖项的范围是什么? (6认同)

Dan*_*ini 8

DoritoBandito的答案不完整或已弃用。

public class EmailSender {
     public EmailSender(IDbContext dbContext, IEmailService emailService)
     {
         _dbContext = dbContext;
         _emailService = emailService;
     }
}
Run Code Online (Sandbox Code Playgroud)

注册服务:

services.AddTransient<IDbContext, TestDbContext>();
services.AddTransient<IEmailService, EmailService>();
Run Code Online (Sandbox Code Playgroud)

入队:

BackgroundJob.Enqueue<EmailSender>(x => x.Send(13, "Hello!"));
Run Code Online (Sandbox Code Playgroud)

资料来源:http : //docs.hangfire.io/en/latest/background-methods/passing-dependencies.html

  • 这是实现OP要求的正确方法。 (2认同)