From 9586176baa04dd4b9f02fa91659bef6eb8a8c204 Mon Sep 17 00:00:00 2001 From: Patrick van der Linden Date: Wed, 12 Feb 2025 01:13:54 +0100 Subject: [PATCH 1/2] Add support for a formatted display name for dynamic jobs --- .../Startup.cs | 3 ++- src/Hangfire.DynamicJobs/DynamicJob.cs | 8 +++++++- .../DynamicJobDisplayNameAttribute.cs | 14 ++++++++++++++ .../DynamicJobRecurringJobManagerExtensions.cs | 7 ++++--- .../DynamicRecurringJobOptions.cs | 3 +++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/samples/Hangfire.Microservices.OrdersService/Startup.cs b/samples/Hangfire.Microservices.OrdersService/Startup.cs index 4b85c3e..ab79426 100644 --- a/samples/Hangfire.Microservices.OrdersService/Startup.cs +++ b/samples/Hangfire.Microservices.OrdersService/Startup.cs @@ -26,7 +26,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IRecurri "* * * * *", new DynamicRecurringJobOptions { - Filters = new [] { new QueueAttribute("newsletter") } + Filters = new [] { new QueueAttribute("newsletter") }, + DisplayName = "Process newsletter '{0}'" }); if (env.IsDevelopment()) diff --git a/src/Hangfire.DynamicJobs/DynamicJob.cs b/src/Hangfire.DynamicJobs/DynamicJob.cs index 11c4aab..bd1e386 100644 --- a/src/Hangfire.DynamicJobs/DynamicJob.cs +++ b/src/Hangfire.DynamicJobs/DynamicJob.cs @@ -18,13 +18,15 @@ public DynamicJob( [NotNull] string method, [CanBeNull] string parameterTypes, [CanBeNull] string args, - [CanBeNull] JobFilterAttribute[] filters) + [CanBeNull] JobFilterAttribute[] filters, + [CanBeNull] string displayName) { Type = type ?? throw new ArgumentNullException(nameof(type)); Method = method ?? throw new ArgumentNullException(nameof(method)); ParameterTypes = parameterTypes; Args = args; Filters = filters; + DisplayName = displayName; } [NotNull] @@ -49,6 +51,10 @@ public DynamicJob( [SuppressMessage("Security", "CA2326:Do not use TypeNameHandling values other than None")] public JobFilterAttribute[] Filters { get; } + [CanBeNull] + [JsonProperty("d", NullValueHandling = NullValueHandling.Ignore)] + public string DisplayName { get; } + [PublicAPI] [DynamicJobDisplayName] public static object Execute(DynamicJob dynamicJob, PerformContext context) diff --git a/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs b/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs index 7087eb4..3eda6e6 100644 --- a/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs +++ b/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs @@ -2,6 +2,7 @@ // Please see the LICENSE file for the licensing details. using System; +using System.Globalization; using Hangfire.Annotations; using Hangfire.Common; using Hangfire.Dashboard; @@ -23,6 +24,11 @@ public override string Format([NotNull] DashboardContext context, [NotNull] Job { if (arg is DynamicJob dynamicJob) { + if (dynamicJob.DisplayName != null) + { + return FormatDynamicDisplayName(dynamicJob); + } + return $"Dynamic: {ExtractTypeName(dynamicJob.Type, out _, out _)}.{dynamicJob.Method}"; } } @@ -60,5 +66,13 @@ internal static string ExtractTypeName(string type, out string @namespace, out s return type; } + + private static string FormatDynamicDisplayName([NotNull] DynamicJob dynamicJob) + { + var format = dynamicJob.DisplayName; + var args = SerializationHelper.Deserialize(dynamicJob.Args); + + return string.Format(CultureInfo.CurrentCulture, format, args); + } } } \ No newline at end of file diff --git a/src/Hangfire.DynamicJobs/DynamicJobRecurringJobManagerExtensions.cs b/src/Hangfire.DynamicJobs/DynamicJobRecurringJobManagerExtensions.cs index a94aae0..ce061b0 100644 --- a/src/Hangfire.DynamicJobs/DynamicJobRecurringJobManagerExtensions.cs +++ b/src/Hangfire.DynamicJobs/DynamicJobRecurringJobManagerExtensions.cs @@ -28,7 +28,7 @@ public static void AddOrUpdateDynamic( manager.AddOrUpdate( recurringJobId, - ToDynamicJob(job, options?.Filters), + ToDynamicJob(job, options?.Filters, options?.DisplayName), cronExpression, options ?? new RecurringJobOptions()); } @@ -133,7 +133,7 @@ public static void AddOrUpdateDynamic( AddOrUpdateDynamic(manager, recurringJobId, job, cronExpression, options); } - private static Job ToDynamicJob([NotNull] Job job, [CanBeNull] IEnumerable filters) + private static Job ToDynamicJob([NotNull] Job job, [CanBeNull] IEnumerable filters, [CanBeNull] string displayName) { if (job == null) throw new ArgumentNullException(nameof(job)); @@ -142,7 +142,8 @@ private static Job ToDynamicJob([NotNull] Job job, [CanBeNull] IEnumerable DynamicJob.Execute(dynamicJob, default)); } diff --git a/src/Hangfire.DynamicJobs/DynamicRecurringJobOptions.cs b/src/Hangfire.DynamicJobs/DynamicRecurringJobOptions.cs index 42c29d3..ae08b07 100644 --- a/src/Hangfire.DynamicJobs/DynamicRecurringJobOptions.cs +++ b/src/Hangfire.DynamicJobs/DynamicRecurringJobOptions.cs @@ -11,5 +11,8 @@ public class DynamicRecurringJobOptions : RecurringJobOptions { [CanBeNull] public IEnumerable Filters { get; set; } + + [CanBeNull] + public string DisplayName { get; set; } } } \ No newline at end of file From 3c7477117f971d2ec69127991396142e9b2dd641 Mon Sep 17 00:00:00 2001 From: Patrick van der Linden Date: Wed, 12 Feb 2025 12:35:10 +0100 Subject: [PATCH 2/2] Remove the serialization part for dynamic display name --- .../Hangfire.Microservices.OrdersService/Startup.cs | 7 +++++-- .../DynamicJobDisplayNameAttribute.cs | 11 +---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/samples/Hangfire.Microservices.OrdersService/Startup.cs b/samples/Hangfire.Microservices.OrdersService/Startup.cs index ab79426..ac9e711 100644 --- a/samples/Hangfire.Microservices.OrdersService/Startup.cs +++ b/samples/Hangfire.Microservices.OrdersService/Startup.cs @@ -1,3 +1,4 @@ +using System; using Hangfire.Microservices.NewsletterService; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -20,14 +21,16 @@ public void ConfigureServices(IServiceCollection services) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IRecurringJobManager manager) { + var campaignId = 1111; + manager.AddOrUpdateDynamic( "periodic-newsletter", - () => NewsletterSender.Execute(1111), + () => NewsletterSender.Execute(campaignId), "* * * * *", new DynamicRecurringJobOptions { Filters = new [] { new QueueAttribute("newsletter") }, - DisplayName = "Process newsletter '{0}'" + DisplayName = $"Process newsletter '{campaignId}'" }); if (env.IsDevelopment()) diff --git a/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs b/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs index 3eda6e6..8b69b96 100644 --- a/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs +++ b/src/Hangfire.DynamicJobs/DynamicJobDisplayNameAttribute.cs @@ -2,7 +2,6 @@ // Please see the LICENSE file for the licensing details. using System; -using System.Globalization; using Hangfire.Annotations; using Hangfire.Common; using Hangfire.Dashboard; @@ -26,7 +25,7 @@ public override string Format([NotNull] DashboardContext context, [NotNull] Job { if (dynamicJob.DisplayName != null) { - return FormatDynamicDisplayName(dynamicJob); + return dynamicJob.DisplayName; } return $"Dynamic: {ExtractTypeName(dynamicJob.Type, out _, out _)}.{dynamicJob.Method}"; @@ -66,13 +65,5 @@ internal static string ExtractTypeName(string type, out string @namespace, out s return type; } - - private static string FormatDynamicDisplayName([NotNull] DynamicJob dynamicJob) - { - var format = dynamicJob.DisplayName; - var args = SerializationHelper.Deserialize(dynamicJob.Args); - - return string.Format(CultureInfo.CurrentCulture, format, args); - } } } \ No newline at end of file