MVC action filter and multiple threads

I currently have what I think is the problem with streams with action filters. In my application, I use ActionFilter to trace each action, this trace will provide statistical information such as call duration, and also record the parameters sent to the action.

The actual trace implementation (which was executed by another command) works with the IDisposable object, basically, when the instance is created, the start time is initialized, and when the object is deleted, it sets the end date, both calls create an entry in the custom log, the code below (delete some code for simplicity):

public class TraceActionAttribute : ActionFilterAttribute { private IDisposable logManagerBeginTrace; /// <summary> /// Called by the ASP.NET MVC framework before the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); List<object> parameters = new List<object>(); string actionName = filterContext.ActionDescriptor.ActionName; Type controllerType = filterContext.Controller.GetType(); foreach (KeyValuePair<string, object> currentParameter in filterContext.ActionParameters) { parameters.Add(currentParameter.Value); } this.logManagerBeginTrace = LogManager.BeginMethodTrace(ApplicationConstants.ApplicationName, controllerType, actionName, Guid.NewGuid(), parameters.ToArray()); } /// <summary> /// Called by the ASP.NET MVC framework after the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); this.logManagerBeginTrace.Dispose(); } } 

The exception doesn’t tell me much, basically that he is trying to dispose of the elements while the others are still active, I still need to examine the code of the tracer ... but I found this post which says the following:

In previous versions of ASP.NET MVC, action filters were created for each request, except in a few cases. Such behavior was never guaranteed behavior, but merely a detailed implementation, and the filter contract was to consider them stateless. In ASP.NET MVC 3, filters are cached more aggressively. Therefore, any custom action filters that incorrectly maintain the state of an instance can be corrupted.

Which looks very strange to me, since the action filters should be equal, so we post public properties on it and configure its behavior for certain actions, right?

I appreciate any help with this, Regards.

+4
source share
2 answers

One possible workaround for the solution is to save an instance of the object in HttpContext.Items instead of the private variable in the ActionFilter class.

HttpContext.Items - A storage engine for each request that sounds the way you need it.

This is what your modified code will look something like:

  public class TraceActionAttribute : ActionFilterAttribute { private IDisposable logManagerBeginTrace; /// <summary> /// Called by the ASP.NET MVC framework before the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); List<object> parameters = new List<object>(); string actionName = filterContext.ActionDescriptor.ActionName; Type controllerType = filterContext.Controller.GetType(); foreach (KeyValuePair<string, object> currentParameter in filterContext.ActionParameters) { parameters.Add(currentParameter.Value); } filterContext.HttpContext.Items["TraceActionKey"] = LogManager.BeginMethodTrace(ApplicationConstants.ApplicationName, controllerType, actionName, Guid.NewGuid(), parameters.ToArray()); } /// <summary> /// Called by the ASP.NET MVC framework after the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); ((IDisposable)filterContext.HttpContext.Items["TraceActionKey"]).Dispose(); } } 
+7
source

In MVC 5, at least the same behavior is true, action attributes are cached and reused. BUT not only this, be careful, because the same instance can be used simultaneously in several threads.

+1
source

Source: https://habr.com/ru/post/1388539/


All Articles