Is it possible to have Hangfire instantiate objects with the configure JobActivator when they're scheduled to run as a RecurringJob?
The signature of the method seems to force static only usages:
public static void AddOrUpdate<T>(
string recurringJobId,
Expression<Action<T>> methodCall,
I have several ideas on how i could "abuse" statics to back channel things around, but i feel like i might be missing something. Was there a design decision that hangfire only supports statics in chron jobs?
Not sure when it was added, but I just did something similar to this in my current project and it works fine. The EmailBackgroundTask is a non-static class and that's a non-static method. The class has 4 dependencies injected via the Hangfire.Unity DI package.
RecurringJob.AddOrUpdate<EmailBackgroundTask>(x=>x.SendPeriodicEmail(),Cron.MinuteInterval(5));
Quick answer is no, the default job activator only works on parameter-less constructors or static methods. I did something (in VB.net) quick and dirty to see if I could get it working and have shown it below.
By using "AddOrUpdate", you are telling Hangfire to create an instance of T and then access the method of T, so this signature works on instance members, not statics. if you use one of the other "AddOrUpdate" method signatures without the generic parameter, it will require a static.
Now the fun part: if type T doesn't have a parameter-less default constructor then it will fail using the default jobactivator as you said.
This is where you can now use a custom jobactivator to supply dependencies to the constructors of your tasks. If you create your own class inheriting from JobActivator then you can supply dependencies to your jobs.
Here is my VB code:
Imports Hangfire
Imports System.Reflection
Public Class JobActivationContainer
Inherits JobActivator
Private Property ParameterMap As Dictionary(Of Type, [Delegate])
Private Function CompareParameterToMap(p As ParameterInfo) As Boolean
Dim result = ParameterMap.ContainsKey(p.ParameterType)
Return result
End Function
Public Overrides Function ActivateJob(jobType As Type) As Object
Dim candidateCtor As Reflection.ConstructorInfo = Nothing
'Loop through ctor's and find the most specific ctor where map has all types.
jobType.
GetConstructors.
ToList.
ForEach(
Sub(i)
If i.GetParameters.ToList.
TrueForAll(AddressOf CompareParameterToMap) Then
If candidateCtor Is Nothing Then candidateCtor = i
If i IsNot candidateCtor AndAlso i.GetParameters.Count > candidateCtor.GetParameters.Count Then candidateCtor = i
End If
End Sub
)
If candidateCtor Is Nothing Then
'If the ctor is null, use default activator.
Return MyBase.ActivateJob(jobType)
Else
'Create a list of the parameters in order and activate
Dim ctorParameters As New List(Of Object)
candidateCtor.GetParameters.ToList.ForEach(Sub(i) ctorParameters.Add(ParameterMap(i.ParameterType).DynamicInvoke()))
Return Activator.CreateInstance(jobType, ctorParameters.ToArray)
End If
End Function
Public Sub RegisterDependency(Of T)(factory As Func(Of T))
If Not ParameterMap.ContainsKey(GetType(T)) Then ParameterMap.Add(GetType(T), factory)
End Sub
Public Sub New()
ParameterMap = New Dictionary(Of Type, [Delegate])
End Sub
End Class
I know this doesn't answer the question on how to "abuse" statics, but it does show how you could roll-your-own IoC container for hangfire, or use one of the already supported IoC's as per the manual: http://hangfirechinese.readthedocs.org/en/latest/background-methods/using-ioc-containers.html
Note: I plan to use a proper IoC, my code above was purely academic and would need a lot of work!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With