11

I'm attempting to use HangFire to schedule any class that implements a certain interface I have called IScheduledService. These services run as expected, but HangFire UI always shows the same name for each service in the HangFire dashboard PerformService(). I know this is by design because I'm passing the same function name into each job, but users don't really know what specific job is running.

I created the interface with ServiceName because I thought may be able to pass that into HangFire to override the visible job name instead of the name of the function being called, but don't see the ability to modify the job name. Is there a way to provide a custom job name so that the HangFire UI will show the title of each job based on the value of ServiceName property?

public interface IScheduledService
{
    string ServiceId { get; }
    string ServiceName { get; }
    void PerformService();
}

public class Service1 : IScheduledService
{
    public string ServiceId { get => "e56643b1-f0cf-44b2-81ef-bf7a085de760"; }
    public string ServiceName { get => this.GetType().Name; }

    public void PerformService()
    {
        Console.WriteLine($"Hello world from {ServiceName}");
    }
}
Geekn
  • 2,650
  • 5
  • 40
  • 80

2 Answers2

12

You can display multiple arguments. In my implementation, I have DisplayName instead of JobDisplayName (Hangfire ver 1.7.5)

public static class Func 
{
   [DisplayName("JobID: {0} => [{1}:{2}]")]
   public static void Execute(long requestID, string stepName, string stepLocation)
   {
      // do work here
   }
}

// above method is called by the background.enqueue call
BackgroundJob.Enqueue(() => Func.Execute(longId, stepName, stepLocation);

That seems to provide the information relevant to the job that is executed.

Pang
  • 9,564
  • 146
  • 81
  • 122
Jawad
  • 11,028
  • 3
  • 24
  • 37
  • Note: You have to set this attribute on the abstraction layer (i.e. your interface). – L01NL Dec 11 '19 at 14:57
  • Dont believe it has to be on the interface... I have it on the actual public method that is Enqueued and the job name comes up correctly. (like the example above) – Jawad Dec 11 '19 at 15:01
  • My implementation is more generic, setting it on the class itself did not work. – L01NL Dec 11 '19 at 15:05
  • in your class, the method that is enqueued, thats the one that gets the DisplayName. ```[DisplayName("Running PerformService")] public void PerformService()``` – Jawad Dec 11 '19 at 19:34
  • @Jawad This does not seem to be working anymore Hangifre 1.7.9 I have tried [JobDisplayName("Test")] and [DisplayName("Test")] I want to override the 'Can not find target method' without having to add assemblies to my Dashboard Project that contains Hangfire. Is this possible at all ? – Jeffrey Holmes Oct 20 '22 at 10:53
  • If you have not updated or included the assemblies on server thats serving the dashboard, you won't see the details – Jawad Oct 20 '22 at 13:41
8

Try using JobDisplayNameAttribute.

I see a couple spots in the code where it might be rendered...

In the RecurringJobsPage and the JobDetailsPage you can see it calling HtmlHelper.JobName

HtmlHelper has some code looking for JobDisplayNameAttribute

https://github.com/HangfireIO/Hangfire/blob/a07ad0b9926923db75747d92796c5a9db39c1a87/src/Hangfire.Core/Dashboard/HtmlHelper.cs

You can see reference to it in an issue that was closed to Release 1.7.0. If you are on that version.

https://github.com/HangfireIO/Hangfire/issues/1136

Also there are some references in old Issues to using DisplayNameAttribute on the method.

Try decorating the method with either JobDisplayName or DisplayName like this

[JobDisplayName("RunJobNumberOne")]
public void RunSomeJob(string arg){

TheMikeInNYC
  • 423
  • 3
  • 4
  • I tried your suggestion but it didn't seem to work. The closest thing I can come up with is using the recurringJobId but that would only work for recurringJobs and may not be the correct usage of that parameter. – Geekn Nov 12 '19 at 14:07
  • In your question " Is there a way to provide a custom job name so that the HangFire UI will show the title of each job based on the value of ServiceName property?" where exactly are you looking for it to show the title? – TheMikeInNYC Nov 12 '19 at 17:58
  • Under the column named "Job" where ever that is listed on the HangFire dashboard. It's used in several places which always indicates the name of the interface method. If it's not supported then that's fine. I was trying to have a generic way to register all my jobs with HangFire (any class that implements the IScheduledService interface. On the surface it would seem like it would be fairly easy to provide an overload that can accept a custom title for that (similar to how they allow you to provide a custom ID). I updated question to specifically say I'm looking for it from the dashboard. – Geekn Nov 12 '19 at 18:41
  • 1
    the code i linked to appeared to support it. I also found some posts about DisplayNameAttribute that might be helpful. I'll update the answer. – TheMikeInNYC Nov 13 '19 at 20:22
  • Thanks for the update. That attribute only works on the interface method which will be different for each implementation of that interface. So yea it does work, but it would only allow me to provide a custom name of the interface method which would still be the same for every scheduled service. Appreciate all the help and will certainly up vote your suggestion. I'm actually a bit surprised you can't just pass in a friendly name when you envoke a job. – Geekn Nov 14 '19 at 00:29
  • Thank you! This works in .NET Core (6), the other answers suggesting ```DisplayName``` do not work (attribute does not exist) in Hangfire for .NET Core. – Randy Gamage Dec 10 '21 at 23:51
  • This does not work in ASP.NET 4.6 / HF 1.7.9 using the DisplayName or JobDisplayName attribute. Are there any work arounds, in order to customize the message so i can change it in a project that the Dashboard does not have a reference to - so i don't get the 'Could not find target method' message ? – Jeffrey Holmes Oct 20 '22 at 10:59