Value cannot be null. Parameter name: method

First of all; great work with the Hangfire sotftware.

Only thing that annoys me, and might be related to the bug I am experiencing, is the choice of Expression compared to normal delegates like Action and Func.

In the Dashboard, although shared DLL has been synchronized, I am getting this exception from one of the methods: Value cannot be null. Parameter name: method.

As far as i can navigate in the source, it is related to loading of the Job:

                                <td class="word-break">
                                    @if (job.Job != null)
                                    {
                                        @: @Html.JobName(job.Job)
                                    }
                                    else
                                    {
                                        <em>@job.LoadException.InnerException.Message</em>
                                    }
                                </td>

Only difference from my other jobs are, that I am following the Options pattern, where my method has an Action delegate, that invokes and Options class.

Any help is appreciated.

Might be related to these:

http://hangfire.discourse.group/t/dashboard-can-not-find-the-target-method/210/5

What’s so annoying about Expressions? How would you suppose to serialize a “normal delegate”, other than embedding a disassembler into Hangfire (which is painful and really unreliable)?

Well, my ignorance might come a hand; “normal” delegates are far more flexible than the Expression variant, and it disturbs my workflow … I like to have dynamic lambda as well as reusable methods … but I did not think about serialization, which would justify the choice.

Expressions aside; here is the calling code from the Windows Service which trigger the exception in question:

public partial class HangfireService : ServiceBase
{
    public HangfireService()
    {
        // some code left out for clarity
        RecurringJob.AddOrUpdate("SBVKg3w5BQ", () => Recurring.EnlistEventlogCleanerJob(null, EventlogCleanerJobSetup), Cron.DayInterval(7));
    }

    private void EventlogCleanerJobSetup(EventlogCleanerJobOptions o)
    {
        var backInTimeThreshold = ConfigurationManager.AppSettings["EventlogCleanerJobOptions.BackInTimeThreshold"];
        TimeSpan result;
        if (TimeSpan.TryParse(backInTimeThreshold, out result))
        {
            o.BackInTimeThreshold = result;
        }
    }
}

Shared method:

    public static void EnlistEventlogCleanerJob(PerformContext context, Action<EventlogCleanerJobOptions> setup)
    {
        Job.Enlist<EventlogCleanerJob, EventlogCleanerJobOptions>(context, setup);
    }

Again, my theory is, that it’s a combination of generic and delegates that confuses Hangfire.

It just hit me; I am guessing that the dashboard cannot resolve the signature of the EventlogCleanerJobSetup method, being a delegate taking an Options object. Normally, this would have been a lambda expression, but because of the design of Hangfire, this is not possible, why I implemented and pointed to a real method.

My question is; is there a way for Hangfire to support the Options pattern?
Am i right in my theory?
Any hints or other looks are appreciated.

Okay, for test purporses, I changed the signature to object.

This made the dashboard recognize and acknowledge the method.
However, being an object, I had to make an instance of Action<EventlogCleanerJobOptions>.

This gave the following exception:

Error converting value "System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" to type 'System.Type'. Path '[1]', line 1, position 210.

Newtonsoft.Json.JsonSerializationException: Error converting value "System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" to type 'System.Type'. Path '[1]', line 1, position 210. ---> System.ArgumentException: Could not cast or convert from System.String to System.Type.
   at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
   at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Hangfire.Common.JobHelper.FromJson[T](String value)
   at Hangfire.Storage.InvocationData.Deserialize()

The log shows this serialization info:

Recurring.EnlistEventlogCleanerJob(
    null,
    "{
  "Delegate": {},
  "target0": {},
  "method0": {
    "Name": "<.ctor>b__0_0",
    "AssemblyName": "TaskScheduler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
    "ClassName": "TaskScheduler.HangfireService+<>c",
    "Signature": "Void <.ctor>b__0_0(TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions)",
    "Signature2": "System.Void <.ctor>b__0_0(TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions)",
    "MemberType": 8,
    "GenericArguments": null
  }
}");

I have now tried with an Expression, however, no luck:

Error converting value "System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" to type 'System.Type'. Path '[1]', line 1, position 210.

Newtonsoft.Json.JsonSerializationException: Error converting value "System.Object, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" to type 'System.Type'. Path '[1]', line 1, position 210. ---> System.ArgumentException: Could not cast or convert from System.String to System.Type.
   at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
   at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Hangfire.Common.JobHelper.FromJson[T](String value)
   at Hangfire.Storage.InvocationData.Deserialize()

Log:

Recurring.EnlistEventlogCleanerJob(
    null,
    "{
  "Type": "System.Action`1[[TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions, TaskSchedulerDescriptor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  "NodeType": 18,
  "Parameters": [
    {
      "Type": "TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions, TaskSchedulerDescriptor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "NodeType": 38,
      "Name": "o",
      "IsByRef": false,
      "CanReduce": false
    }
  ],
  "Name": null,
  "Body": {
    "NodeType": 6,
    "Type": "System.Void, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "Method": {
      "Name": "EventlogCleanerJobSetup",
      "AssemblyName": "TaskScheduler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "ClassName": "TaskScheduler.HangfireService",
      "Signature": "Void EventlogCleanerJobSetup(TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions)",
      "Signature2": "System.Void EventlogCleanerJobSetup(TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions)",
      "MemberType": 8,
      "GenericArguments": null
    },
    "Object": {
      "Type": "TaskScheduler.HangfireService, TaskScheduler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "NodeType": 9,
      "Value": {
        "AutoLog": true,
        "ExitCode": 0,
        "CanHandlePowerEvent": false,
        "CanHandleSessionChangeEvent": false,
        "CanPauseAndContinue": false,
        "CanShutdown": false,
        "CanStop": true,
        "EventLog": {
          "Entries": [
            {
              "DataBuffer": "zAAAAExmTGVrNwIAMbo5WDG6OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGVsNwIAV7o5WFe6OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGVtNwIAZro5WGa6OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGVuNwIAaLo5WGi6OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGVvNwIAMr05WDK9OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGVwNwIAkL05WJC9OVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "pAAAAExmTGVxNwIAkr85WJK/OVjxAgAABAAAAAAAAAAAAAAAnAAAAAwAAACQAAAAAAAAAJwAAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBCAGEAYwBrAHUAcAAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAQEAAAAAAAUSAAAAAAAAAKQAAAA=",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "CAEAAExmTGVyNwIAC8A5WAvAOVjpAwAABAAEAAAAAAAAAAAApAAAAAwAAACYAAAAAAAAAAABAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBMAG8AYQBkAFAAZQByAGYAAABBAHIAYQBnAG8AcgBuAC4AbwBmAGkAcgBqAG8AYgAuAGQAawAAAAAAAAABAQAAAAAABRIAAABXAG0AaQBBAHAAUgBwAGwAAABXAG0AaQBBAHAAUgBwAGwAAAAxADIAAAA0AEMAOQAxADAAMAAwADAANABEADkAMQAwADAAMAAwADMANAAwADcAMAAwADAAMAAAAAAAAAAIAQAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "GAEAAExmTGVzNwIAC8A5WAvAOVjoAwAABAAEAAAAAAAAAAAApAAAAAwAAACYAAAAAAAAABABAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBMAG8AYQBkAFAAZQByAGYAAABBAHIAYQBnAG8AcgBuAC4AbwBmAGkAcgBqAG8AYgAuAGQAawAAAAAAAAABAQAAAAAABRIAAABXAG0AaQBBAHAAUgBwAGwAAABXAG0AaQBBAHAAUgBwAGwAAAAxADYAAAA0AEUAOQAxADAAMAAwADAAMQBFADkAMgAwADAAMAAwADQARgA5ADEAMAAwADAAMAAxAEYAOQAyADAAMAAwADAAAAAAAAAAGAEAAA==",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "GAEAAExmTGV0NwIAl8A5WJfAOVggIAAABAABAAAAAAAAAAAAaAAAAAAAAABoAAAAqAAAAGoAAABWAFMAUwAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAC0gQ29kZTogIENPUlNWQ0MwMDAwMDc3My0gQ2FsbDogIENPUlNWQ0MwMDAwMDc1NS0gUElEOiAgMDAwMDA1NjQtIFRJRDogIDAwMDAwNzg0LSBDTUQ6ICBDOlxXaW5kb3dzXHN5c3RlbTMyXHZzc3ZjLmV4ZSAgIC0gVXNlcjogTmFtZTogTlQgQVVUSE9SSVRZXFNZU1RFTSwgU0lEOlMtMS01LTE4IAAAGAEAAA==",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "pAAAAExmTGV1NwIA6sE5WOrBOVjyAgAABAAAAAAAAAAAAAAAnAAAAAwAAACQAAAAAAAAAJwAAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBCAGEAYwBrAHUAcAAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAQEAAAAAAAUSAAAAAAAAAKQAAAA=",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV2NwIAM8c5WDPHOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV3NwIAV8c5WFfHOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV4NwIArMc5WKzHOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV5NwIA6sg5WOrIOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV6NwIAF8k5WBfJOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV7NwIAcMk5WHDJOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV8NwIAyck5WMnJOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV9NwIATNk5WEzZOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV+NwIAZ9k5WGfZOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGV/NwIAadk5WGnZOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGWANwIA+9k5WPvZOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAbwBwAHAAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGWBNwIAGdo5WBnaOVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "GAEAAExmTGX1NwIAjLQ9WIy0PVjoAwAABAAEAAAAAAAAAAAApAAAAAwAAACYAAAAAAAAABABAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBMAG8AYQBkAFAAZQByAGYAAABBAHIAYQBnAG8AcgBuAC4AbwBmAGkAcgBqAG8AYgAuAGQAawAAAAAAAAABAQAAAAAABRIAAABXAG0AaQBBAHAAUgBwAGwAAABXAG0AaQBBAHAAUgBwAGwAAAAxADYAAAA0AEUAOQAxADAAMAAwADAAMQBFADkAMgAwADAAMAAwADQARgA5ADEAMAAwADAAMAAxAEYAOQAyADAAMAAwADAAAAAAAAAAGAEAAA==",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "GAEAAExmTGX2NwIABbU9WAW1PVggIAAABAABAAAAAAAAAAAAaAAAAAAAAABoAAAAqAAAAGoAAABWAFMAUwAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAC0gQ29kZTogIENPUlNWQ0MwMDAwMDc3My0gQ2FsbDogIENPUlNWQ0MwMDAwMDc1NS0gUElEOiAgMDAwMDM5NjgtIFRJRDogIDAwMDAzMjM2LSBDTUQ6ICBDOlxXaW5kb3dzXHN5c3RlbTMyXHZzc3ZjLmV4ZSAgIC0gVXNlcjogTmFtZTogTlQgQVVUSE9SSVRZXFNZU1RFTSwgU0lEOlMtMS01LTE4IAAAGAEAAA==",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "pAAAAExmTGX3NwIAarY9WGq2PVjyAgAABAAAAAAAAAAAAAAAnAAAAAwAAACQAAAAAAAAAJwAAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBCAGEAYwBrAHUAcAAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAQEAAAAAAAUSAAAAAAAAAKQAAAA=",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "zAAAAExmTGX4NwIAbLc9WGy3PVgAAAAABAABAAAAAAAAAAAAiAAAAAAAAACIAAAAAAAAAMQAAABPAGYAaQByAC4AVABhAHMAawBTAGMAaABlAGQAdQBsAGUAcgAAAEEAcgBhAGcAbwByAG4ALgBvAGYAaQByAGoAbwBiAC4AZABrAAAAAAAAAFMAZQByAHYAaQBjAGUAIABzAHQAYQByAHQAZQBkACAAcwB1AGMAYwBlAHMAcwBmAHUAbABsAHkALgAAAAAAAADMAAAA",
              "LogName": "Application",
              "MachineName": "."
            },
            {
              "DataBuffer": "GAEAAExmTGUPOAIApbE+WKWxPljoAwAABAAEAAAAAAAAAAAApAAAAAwAAACYAAAAAAAAABABAABNAGkAYwByAG8AcwBvAGYAdAAtAFcAaQBuAGQAbwB3AHMALQBMAG8AYQBkAFAAZQByAGYAAABBAHIAYQBnAG8AcgBuAC4AbwBmAGkAcgBqAG8AYgAuAGQAawAAAAAAAAABAQAAAAAABRIAAABXAG0AaQBBAHAAUgBwAGwAAABXAG0AaQBBAHAAUgBwAGwAAAAxADYAAAA0AEUAOQAxADAAMAAwADAAMQBFADkAMgAwADAAMAAwADQARgA5ADEAMAAwADAAMAAxAEYAOQAyADAAMAAwADAAAAAAAAAAGAEAAA==",
              "LogName": "Application",
              "MachineName": "."
            }
          ],
          "LogDisplayName": "Application",
          "Log": "Application",
          "MachineName": ".",
          "MaximumKilobytes": 20480,
          "OverflowAction": 0,
          "MinimumRetentionDays": 0,
          "EnableRaisingEvents": false,
          "SynchronizingObject": null,
          "Source": "TaskScheduler",
          "Site": null,
          "Container": null
        },
        "ServiceName": "TaskScheduler",
        "Site": null,
        "Container": null
      },
      "CanReduce": false
    },
    "Arguments": [
      {
        "Type": "TaskSchedulerDescriptor.Jobs.Diagnostics.EventlogCleanerJobOptions, TaskSchedulerDescriptor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
        "NodeType": 38,
        "Name": "o",
        "IsByRef": false,
        "CanReduce": false
      }
    ],
    "CanReduce": false
  },
  "ReturnType": "System.Void, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  "TailCall": false,
  "CanReduce": false
}");

I am not satisfied, but I resolved the issue at hand by not using the options pattern.
Instead i simply transfer the EventlogCleanerJobOptions object directly to the shared assembly.

I believe, however, that it would be a nice addition if Hangfire supported action and func delegates in the signature; aside the problems with serializing as pieceofsummer referred to.

Keep up the good work :slight_smile:

Nice try, @gimlichael, good investigation! :slight_smile: Thanks for pointing this out, delegates and expressions are definitely not supported in Hangfire. I’m not sure their support will add much benefits, because of serialization issues and different problems that appear after you rename delegate methods.

However, Hangfire really should throw an exception whose message clearly says that delegates and expressions aren’t supported to not to confuse anyone. You could make a PR to implement this protection, if you like. I believe you know better what message you need :wink:

1 Like

Just a thought; have you considered using a BinaryFormatter, store the result as a Base64 encapsulated in JSON with some meta information for your core-program (or something similar)? Again, once you go lambda, its hard to go back :smiley:

[http://stackoverflow.com/questions/1132702/could-we-save-delegates-in-a-file-c] (i am not allowed to make a link)

Anyway, I understand and appreciate your concerns; thank you for enlightening the area of serialization for me.

Reliable implementation of delegates would require preservation of the entire method/lambda body (IL), not just a reference to it, otherwise it would be impossible to pass a lambda between processes, and could easily break after the slightest code changes. That is not something the BinaryFormatter can do.
And even if you manage to save and restore it somehow (which is not possible on all platforms), it would still requre quite a bit of analisys and post-processing to patch up all the dependencies required by that method.

It can still be done by passing an Expression to the job method and compiling it into lambda inside the method itself, but it still might be a bit troublesome,

Rather than working out all those quirks, it is much easier to add a few wrapper methods, each passing a dedicated lambda to the main method, and use those when enqueuing jobs.