Search code examples
asp.netasp.net-mvcstructuremapunit-of-workaction-filter

asp.net MVC : use unitOfWork inside custom AuthenticationAttribute when ActionFilters are not per-request?


I have implemented IAuthenticationFilter to create a custom one. in the constructor I use structureMap to get instance of my IUnitOfWork. this authentication logic is to check user status in the database and ....

IUnitOfWork uow;

public CustomAuthenticatationAttribute()
{
    this.uow = ObjectFactory.GetInstance<IUnitOfWork>();
}

I have configured structureMap to serve IUnitOfWork HttpContextScoped.

x.For<IUnitOfWork>().HttpContextScoped().Use(() => new MyDbContext());

but then something strange happened. I deleted the user in one action, but when the AuthenticationFilter is executed on another action, the instance of unitOfWork still returns the user ! I searched the web for hours and I come to this :

Are ActionFilterAttributes reused across threads? How does that work?

in short , it says that Filters are cached and used across requests !

Now I'm confused . how to deal with this ? shall I give up using unitOfWork and get back to using(var context = ....) ? or there is a correct way of using unitOfWork inside Filters .

I found a solution here

https://gist.github.com/ivanra/9019273

It replaces the DefaultFilterProvider and I prefer to avoid that if possible.


Solution

  • The solution you found with suppressing caching in the FilterProvider is actually the same solution that the MVC integration libraries for both Autofac and Simple Injector use.

    But the caching behavior of attributes is just one of the many reasons why doing dependency injection in attributes is actually a bad idea.

    The best solution is IMO to move to passive attributes if you can, or at least encapsulate the attributes logic and its dependencies into a component and don't do anything more than resolving and executing that component in the OnActionExecuting method. For instance:

    public class CustomAuthenticatationAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var action =
                ObjectFactory.GetInstance<IActionFilter<CustomAuthenticatationAttribute>>();
    
            action.OnActionExecuting(this, context);
        }
    }