Skip to content

Instantly share code, notes, and snippets.

@IanYates
Created January 20, 2016 23:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save IanYates/29180ce09c41e42b9a7e to your computer and use it in GitHub Desktop.
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
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();
}
}
@skyrawrcode
Copy link

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