-->

UnitOfWork in Action Filter seems to be caching

2020-08-12 18:51发布

问题:

I have an MVC 3 site that uses IoC (Unity), and my model is generated w/ EF4 and POCOs. I am using an action filter to commit my UnitOfWork:

public class UseUnitOfWorkAttribute : ActionFilterAttribute, IActionFilter
{
    private readonly IUnitOfWork _unitOfWork;

    public UseUnitOfWorkAttribute()
    {
        _unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>();
    }

    void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
    {
        _unitOfWork.Commit();
    }

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
    }
}

However, even though the Commit() seems to be getting fired, it somehow seems to be caching what it thinks is "dirty".

For example, in my controller, the following gets executed from a service class:

var user = _userRepository.Single(u => u.Id == 2);
user.DateAdded = DateTime.Now;

Whenever I do a fresh build of the solution and hit this controller action, the change is actually committed. However, successive hits to the controller doesn't do anything.

On the other hand, if I put a UnitOfWork in my controller and commit it following the service method call, it works as expected (every time I request the controller action):

public AccountController()
{
    _unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>();
}

public ActionResult Test()
{
    var user = _userRepository.Single(u => u.Id == 2);
    user.DateAdded = DateTime.Now;
    _unitOfWork.Commit();
}

So it definitely seems like some sort of caching is going on, but I can't figure it out what is getting cached -- the UnitOfWork, the ActionFilter, or the repository.

Any ideas what could be going on? And if not, any ideas what else I could do to troubleshoot?

Thanks in advance.

回答1:

You are initializing your unit of work in the constructor of the action filter which means that it will be injected when the action filter is instantiated. Quote from the ASP.NET MVC 3 release notes:

In previous versions of ASP.NET MVC, action filters were created per request except in a few cases. This behavior was never a guaranteed behavior but merely an implementation detail and the contract for filters was to consider them stateless. In ASP.NET MVC 3, filters are cached more aggressively. Therefore, any custom action filters which improperly store instance state might be broken.



回答2:

Make sure the dependency container returns the same instance in all places and rewrite the filter to avoid state caching:

public class UseUnitOfWorkAttribute : ActionFilterAttribute, IActionFilter
{
    void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
    {
        var unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>();
        unitOfWork.Commit();
    }

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
    }
}


回答3:

I would check the lifetime on your repository. That was certainly the culprit in our implementation.