我有一个用于System.Web.Http.Filters.ActionFilterAttribute
的自定义属性扩展名,用于通过Web API控制器进行日志记录。我遇到一个问题,表明该属性对象正在被重用。初始呼叫中我的公共属性中的数据将显示在后续呼叫的记录信息中,依此类推。
我在此post中读到,我“永远不要将实例状态存储在将在不同方法之间重用的动作过滤器中。” 他接着说, “这基本上意味着动作过滤器的相同实例可以重复用于不同的动作,如果您在其中存储了实例状态,它可能会损坏。”
我的自定义属性显然是“ break” 。因此,我开始寻找答案...
如何在System.Web.Http.Filters.ActionFilterAttribute的方法之间传递线程安全数据?
我在上面引用的帖子中给出了一个示例,说明如何使用HttpContext.Items
字典将数据传递给方法。太好了,我可以看到有什么用,但我没有使用ASP.net MVC的System.Web.Http.Mvc.ActionFilterAttribute
,这是发布者在他的回答中使用的。我正在做Web API,并且传递到OnActionExecuting
方法中的上下文对象是HttpActionContext
类型的,而不是ActionExecutingContext
类型的。我无法通过传递的上下文访问HttpContext.Items
字典,但是,我相信这样访问HttpContext
是安全的:
HttpContext.Current.Items[key]
这样安全吗?
但是,我无法在构造函数中访问该字典,并且由于那是我在其中接收到作为位置参数的参数化消息字符串的地方,因此我似乎依赖于存储实例状态。
那该怎么办?
在此post中-也依赖于ASP.net MVC的System.Web.Http.Mvc.ActionFilterAttribute
及其ActionExecutingContext
-发布者使用该上下文对象的ActionParameters
属性来获取参数传递给该属性,但在Web API的HttpActionContext
中找不到任何等效项。如果可以的话,这似乎是答案!但是a ...
如何安全地获取传递到构造函数中的位置参数值和通过OnActionExecuting
方法中的公共属性传递的命名参数值?
我研究过的帖子:
背景:在构造函数中,我传递了一个参数化的消息字符串,其中包括占位符,该占位符表示传递给应用该属性的方法的参数值。我还有一个可选的LogAllResponses属性,该属性通过命名参数设置为用于确定要记录多少信息的属性。接收这些值的公共属性是通过构造函数和属性调用设置的,如下所示:
[LogAction("Retrieve information for all ad week items with storeId: {storeId}.", LogAllResponses = false)]
操作过滤器实现的重要部分如下所示:
public class LogActionAttribute : ActionFilterAttribute
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public string ParameterizedMessage { get; set; }
public bool LogAllResponses { get; set; } = true;
public LogActionAttribute(string parameterizedMessage)
{
ParameterizedMessage = parameterizedMessage;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
HttpContext.Current.Items["__Parameterized_Message__"] = ParameterizedMessage;
HttpContext.Current.Items["__Log_All_Responses__"] = LogAllResponses.ToString();
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var contextualizedMessage = HttpContext.Current.Items["__Parameterized_Message__"] as string ?? "";
var logAllResponsesAsString = HttpContext.Current.Items["__Log_All_Responses__"] as string ?? "";
var logAllResponses = logAllResponsesAsString.CompareIgnoreCase("true") == 0;
// convert argument values with ID suffixes to identifiable names
var arguments = actionExecutedContext.ActionContext.ActionArguments;
//foreach (var arg in arguments)
// ...
// replace the placeholders in the parameterized message string with actual values
// log the contextualized message
//Log.Debug(...
base.OnActionExecuted(actionExecutedContext);
}
}