Created
January 20, 2016 23:30
-
-
Save IanYates/29180ce09c41e42b9a7e to your computer and use it in GitHub Desktop.
Proper integration between Hangfire and Windsor - does not take advantage of new HangFire 1.5 IoC features
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
To configure Hangfire | |
//Windsor integration | |
//The activator | |
var jobActivator = new WindsorScopedJobActivator(windsorContainer); | |
GlobalConfiguration.Configuration.UseActivator(jobActivator); | |
//And something to create and dispose of a child container in the activator for each job | |
var windsorJobFilter = new WindsorContainerPerJobFilterAttribute(jobActivator); | |
GlobalJobFilters.Filters.Add(windsorJobFilter); | |
public class WindsorScopedJobActivator : JobActivator | |
{ | |
private readonly IWindsorContainer parentContainer; | |
private readonly ThreadLocal<IWindsorContainer> childContainer = new ThreadLocal<IWindsorContainer>(trackAllValues:false); | |
public WindsorScopedJobActivator(IWindsorContainer parentContainer) | |
{ | |
this.parentContainer = parentContainer; | |
} | |
public override object ActivateJob(Type jobType) | |
{ | |
return childContainer.Value.Resolve(jobType); | |
} | |
private void DisposeLocalThreadContainer() | |
{ | |
if (!childContainer.IsValueCreated) return; | |
var c = childContainer.Value; | |
if (c == null) return; | |
childContainer.Value = null; | |
c.Dispose(); | |
} | |
public void StartJobLifetimeScope() | |
{ | |
//Defensive | |
DisposeLocalThreadContainer(); | |
childContainer.Value = new WindsorContainer( | |
//Specific name on container - avoids race conditions when calculating | |
//http://nguyducthuan.com/blog/2015/01/15/Race-condition-bug-of-Windsor-Castle-child-container-3-x/ | |
Guid.NewGuid().ToString(), | |
new DefaultKernel(), | |
new DefaultComponentInstaller() | |
) { Parent = parentContainer }; | |
} | |
public void EndJobLifetimeScope() | |
{ | |
DisposeLocalThreadContainer(); | |
} | |
} | |
/// <summary> | |
/// This class runs on the same thread as the job that will be performed by HangFire | |
/// So we can use it to create a Windsor container instance on the thread and then dispose of it | |
/// This lets us properly manage transient resources :) | |
/// </summary> | |
public class WindsorContainerPerJobFilterAttribute : JobFilterAttribute, IServerFilter | |
{ | |
private readonly WindsorScopedJobActivator windsorPerLifetimeScopeJobActivator; | |
public WindsorContainerPerJobFilterAttribute(WindsorScopedJobActivator windsorPerLifetimeScopeJobActivator) | |
{ | |
this.windsorPerLifetimeScopeJobActivator = windsorPerLifetimeScopeJobActivator; | |
} | |
public void OnPerforming(PerformingContext filterContext) | |
{ | |
windsorPerLifetimeScopeJobActivator.StartJobLifetimeScope(); | |
} | |
public void OnPerformed(PerformedContext filterContext) | |
{ | |
windsorPerLifetimeScopeJobActivator.EndJobLifetimeScope(); | |
} | |
} |
Why did you use use child container implementation for Windsor instead of a specialized Scope accessor. In the past when working with child containers they only seemed to work if the dependencies were installed inside the child container. If the dependencies were installed in the parent container even though the child container was the resolver they were still resolved and tracked by the parent container. This makes disposing the child container do little to nothing. I know child containers are a common use in with other containers but I've always had trouble using them with windsor. I was wondering how you get around these issues?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ended up going with @hikalkan solution for Hangfire 1.5 but wanted to say thanks @IanYates for posting this. Was stuck for a few days. Below is implementation using IWindsorContainer rather than IIocResolver for anyone else who stumbles across this.