我目前正在使用动作过滤器我认为是线程问题,在我的应用程序上我使用ActionFilter来执行每个动作的跟踪,此跟踪将提供统计信息,例如呼叫的持续时间以及记录发送给操作的参数。
实际跟踪实现(由其他团队完成)与IDisposable对象一起使用,基本上在创建实例时初始化开始时间,并且当处置对象设置结束日期时,两个调用都在自定义日志中创建一个条目,代码如下(为简单起见,删除一些代码):
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();
}
}
异常并没有告诉我多少,基本上是它试图处理元素而其他人仍处于活动状态,我仍然需要查看跟踪器代码......但我发现this post其中说明如下:
在以前的ASP.NET MVC版本中,除少数情况外,每个请求都会创建操作过滤器。这种行为从来都不是保证行为,而只是一个实现细节,而过滤器的合同是将它们视为无状态。在ASP.NET MVC 3中,过滤器被更积极地缓存。因此,任何不正确地存储实例状态的自定义操作过滤器都可能会被破坏。
对我来说这看起来非常奇怪,因为动作过滤器应该是对等请求,这就是我们在其上放置公共属性,并为特定动作配置其行为的原因,不是吗?
我很感激任何帮助,问候。
答案 0 :(得分:7)
一种可能的解决方法是将对象实例存储在HttpContext.Items
而不是ActionFilter
类的私有变量中。
HttpContext.Items
是一种按请求存储的机制,听起来就像你需要的那样。
这是您修改后的代码大致如下所示:
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();
}
}
答案 1 :(得分:1)
在MVC 5中,至少相同的行为是正确的,动作属性被缓存和重用。但不仅如此,要小心,因为同一个实例可以同时在多个线程中使用。