Reputation: 1341
I have the following Global filter, The ISiteValidation and ICacheService are injected via the Windsor container and are setup as Transient so the container will not dispose of the dependencies automatically. This will cause a resource issue when the site goes into production. So what are folks doing to properly Dispose of resources injected into a filter? both interfaces are IDisposable but Dispose never gets called when the Action Filter goes out of scope and the container will continue to hold on to the implementation.
public class SiteValidationAttribute : ActionFilterAttribute
{
public ISiteValidation SiteValidation { get; set; }
public ICacheService CacheService { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.Url != null)
{
string host = filterContext.RequestContext.HttpContext.Request.Url.Host;
try
{
string siteId = CacheService.Get("SiteId",
() =>
SiteValidation.GetSiteId(
host));
var siteIdCookie = new HttpCookie("_site") {Value = siteId};
filterContext.RequestContext.HttpContext.Response.Cookies.Add(siteIdCookie);
}
catch (Exception)
{
throw new HttpException(404, String.Format("This site'{0}' was not found", host));
}
}
base.OnActionExecuted(filterContext);
}
}
Upvotes: 1
Views: 1415
Reputation: 32725
Attributes are created by the CLR on request:
If you want to construct an attribute object, you must call either GetCustomAttributes or GetCustomAttribute. Every time one of these methods is called, it constructs new instances of the specified attribute type and sets each of the instance’s fields and properties based on the values specified in the code.
This means they are not within the control of any IoC container. The only part of a system that could Dispose them is the one that is calling GetCustomAttribute
or GetCustomAttributes
. But nothing is explicitly doing this; as a result, Attributes shouldn't be Disposable.
Fortunately, there is another way. Don't use attributes for filters but instead implement an IActionFilter
and register a IFilterProvider
that returns a new instance of your filter (created by your IoC container) when required.
Have a look on how it is done using Ninject; the same approach should be portable to Windsor.
https://github.com/ninject/ninject.web.mvc/tree/master/mvc3/src/Ninject.Web.Mvc/Filter
Upvotes: 6