Hangfire dependency injection with .net core

后端 未结 8 1865
孤城傲影
孤城傲影 2020-12-08 02:02

How can I use .net core\'s default dependency injection in Hangfire ?

I am new to Hangfire and searching for an example which works with asp.net core.

相关标签:
8条回答
  • 2020-12-08 02:12

    As far as I am aware, you can use .net cores dependency injection the same as you would for any other service.

    You can use a service which contains the jobs to be executed, which can be executed like so

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

    Here is an example of the Job Service class

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

    And in your projects Startup.cs you can add a dependency as normal

    services.AddTransient< IClientService, ClientService>();

    Not sure this answers your question or not

    0 讨论(0)
  • 2020-12-08 02:23

    DoritoBandito's answer is incomplete or deprecated.

    public class EmailSender {
         public EmailSender(IDbContext dbContext, IEmailService emailService)
         {
             _dbContext = dbContext;
             _emailService = emailService;
         }
    }
    

    Register services:

    services.AddTransient<IDbContext, TestDbContext>();
    services.AddTransient<IEmailService, EmailService>();
    

    Enqueue:

    BackgroundJob.Enqueue<EmailSender>(x => x.Send(13, "Hello!"));
    

    Source: http://docs.hangfire.io/en/latest/background-methods/passing-dependencies.html

    0 讨论(0)
  • 2020-12-08 02:26

    I had to start HangFire in main function. This is how I solved it:

    public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();
            using (var serviceScope = host.Services.CreateScope())
            {
                var services = serviceScope.ServiceProvider;
    
                try
                {
                    var liveDataHelper = services.GetRequiredService<ILiveDataHelper>();
                    var justInitHangfire = services.GetRequiredService<IBackgroundJobClient>();
                    //This was causing an exception (HangFire is not initialized)
                    RecurringJob.AddOrUpdate(() => liveDataHelper.RePopulateAllConfigDataAsync(), Cron.Daily());
                    // Use the context here
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "Can't start " + nameof(LiveDataHelper));
                }
            }
            host.Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
    
    0 讨论(0)
  • 2020-12-08 02:27

    All of the answers in this thread are wrong/incomplete/outdated. Here's an example with ASP.NET Core 3.1 and Hangfire.AspnetCore 1.7.

    Client:

    //...
    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));
        }
    }
    

    Server (same or different application):

    {
        //...
        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)
        {
    
        }
    }
    
    0 讨论(0)
  • 2020-12-08 02:30

    See full example on GitHub https://github.com/gonzigonz/HangfireCore-Example.
    Live site at http://hangfirecore.azurewebsites.net/

    1. Make sure you have the Core version of Hangfire:
      dotnet add package Hangfire.AspNetCore

    2. Configure your IoC by defining a JobActivator. Below is the config for use with the default asp.net core container service:

      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);
          }
      }  
      
    3. Next register hangfire as a service in the Startup.ConfigureServices method:

      services.AddHangfire(opt => 
          opt.UseSqlServerStorage("Your Hangfire Connection string"));
      
    4. Configure hangfire in the Startup.Configure method. In relationship to your question, the key is to configure hangfire to use the new HangfireActivator we just defined above. To do so you will have to provide hangfire with the IServiceProvider and this can be achieved by just adding it to the list of parameters for the Configure method. At runtime, DI will providing this service for you:

      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();
      }  
      
    5. When you enqueue a job, use the registered type which usually is your interface. Don't use a concrete type unless you registered it that way. You must use the type registered with your IoC else Hangfire won't find it. For Example say you've registered the following services:

      services.AddScoped<DbManager>();
      services.AddScoped<IMyService, MyService>();
      

    Then you could enqueue DbManager with an instantiated version of the class:

        BackgroundJob.Enqueue(() => dbManager.DoSomething());
    

    However you could not do the same with MyService. Enqueuing with an instantiated version would fail because DI would fail as only the interface is registered. In this case you would enqueue like this:

        BackgroundJob.Enqueue<IMyService>( ms => ms.DoSomething());
    
    0 讨论(0)
  • 2020-12-08 02:31

    Use the below code for Hangfire configuration

    using eForms.Core;
    using Hangfire;
    using Hangfire.SqlServer;
    using System;
    using System.ComponentModel;
    using System.Web.Hosting;
    
    namespace eForms.AdminPanel.Jobs
    {
        public class JobManager : IJobManager, IRegisteredObject
        {
            public static readonly JobManager Instance = new JobManager();
            //private static readonly TimeSpan ZeroTimespan = new TimeSpan(0, 0, 10);
            private static readonly object _lockObject = new Object();
            private bool _started;
            private BackgroundJobServer _backgroundJobServer;
            private JobManager()
            {
            }
            public int Schedule(JobInfo whatToDo)
            {
                int result = 0;
                if (!whatToDo.IsRecurring)
                {
                    if (whatToDo.Delay == TimeSpan.Zero)
                        int.TryParse(BackgroundJob.Enqueue(() => Run(whatToDo.JobId, whatToDo.JobType.AssemblyQualifiedName)), out result);
                    else
                        int.TryParse(BackgroundJob.Schedule(() => Run(whatToDo.JobId, whatToDo.JobType.AssemblyQualifiedName), whatToDo.Delay), out result);
                }
                else
                {
                    RecurringJob.AddOrUpdate(whatToDo.JobType.Name, () => RunRecurring(whatToDo.JobType.AssemblyQualifiedName), Cron.MinuteInterval(whatToDo.Delay.TotalMinutes.AsInt()));
                }
    
                return result;
            }
    
            [DisplayName("Id: {0}, Type: {1}")]
            [HangFireYearlyExpirationTime]
            public static void Run(int jobId, string jobType)
            {
                try
                {
                    Type runnerType;
                    if (!jobType.ToType(out runnerType)) throw new Exception("Provided job has undefined type");
                    var runner = runnerType.CreateInstance<JobRunner>();
                    runner.Run(jobId);
                }
                catch (Exception ex)
                {
                    throw new JobException($"Error while executing Job Id: {jobId}, Type: {jobType}", ex);
                }
            }
    
            [DisplayName("{0}")]
            [HangFireMinutelyExpirationTime]
            public static void RunRecurring(string jobType)
            {
                try
                {
                    Type runnerType;
                    if (!jobType.ToType(out runnerType)) throw new Exception("Provided job has undefined type");
                    var runner = runnerType.CreateInstance<JobRunner>();
                    runner.Run(0);
                }
                catch (Exception ex)
                {
                    throw new JobException($"Error while executing Recurring Type: {jobType}", ex);
                }
            }
    
            public void Start()
            {
                lock (_lockObject)
                {
                    if (_started) return;
                    if (!AppConfigSettings.EnableHangFire) return;
                    _started = true;
                    HostingEnvironment.RegisterObject(this);
                    GlobalConfiguration.Configuration
                        .UseSqlServerStorage("SqlDbConnection", new SqlServerStorageOptions { PrepareSchemaIfNecessary = false })
                       //.UseFilter(new HangFireLogFailureAttribute())
                       .UseLog4NetLogProvider();
                    //Add infinity Expiration job filter
                    //GlobalJobFilters.Filters.Add(new HangFireProlongExpirationTimeAttribute());
    
                    //Hangfire comes with a retry policy that is automatically set to 10 retry and backs off over several mins
                    //We in the following remove this attribute and add our own custom one which adds significant backoff time
                    //custom logic to determine how much to back off and what to to in the case of fails
    
                    // The trick here is we can't just remove the filter as you'd expect using remove
                    // we first have to find it then save the Instance then remove it 
                    try
                    {
                        object automaticRetryAttribute = null;
                        //Search hangfire automatic retry
                        foreach (var filter in GlobalJobFilters.Filters)
                        {
                            if (filter.Instance is Hangfire.AutomaticRetryAttribute)
                            {
                                // found it
                                automaticRetryAttribute = filter.Instance;
                                System.Diagnostics.Trace.TraceError("Found hangfire automatic retry");
                            }
                        }
                        //Remove default hangefire automaticRetryAttribute
                        if (automaticRetryAttribute != null)
                            GlobalJobFilters.Filters.Remove(automaticRetryAttribute);
                        //Add custom retry job filter
                        GlobalJobFilters.Filters.Add(new HangFireCustomAutoRetryJobFilterAttribute());
                    }
                    catch (Exception) { }
                    _backgroundJobServer = new BackgroundJobServer(new BackgroundJobServerOptions
                    {
                        HeartbeatInterval = new System.TimeSpan(0, 1, 0),
                        ServerCheckInterval = new System.TimeSpan(0, 1, 0),
                        SchedulePollingInterval = new System.TimeSpan(0, 1, 0)
                    });
                }
            }
            public void Stop()
            {
                lock (_lockObject)
                {
                    if (_backgroundJobServer != null)
                    {
                        _backgroundJobServer.Dispose();
                    }
                    HostingEnvironment.UnregisterObject(this);
                }
            }
            void IRegisteredObject.Stop(bool immediate)
            {
                Stop();
            }
        }
    }
    

    Admin Job Manager

        public class Global : System.Web.HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
                if (Core.AppConfigSettings.EnableHangFire)
                {
                    JobManager.Instance.Start();
    
                    new SchedulePendingSmsNotifications().Schedule(new Core.JobInfo() { JobId = 0, JobType = typeof(SchedulePendingSmsNotifications), Delay = TimeSpan.FromMinutes(1), IsRecurring = true });
    
                }
            }
            protected void Application_End(object sender, EventArgs e)
            {
                if (Core.AppConfigSettings.EnableHangFire)
                {
                    JobManager.Instance.Stop();
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题