首先,我强烈建议将您的ActionFilter 重命名为更具体的名称,例如LogActionFilterAttribute(注意——动作过滤器是一个属性)。现在不要使用options.Filters.Add(...) 全局应用它,而是仅将它应用到您要记录的操作:
// an action that must be logged -- apply LogActionFilter attribute
[HttpGet]
[Route("api/....")]
[LogActionFilter]
public JsonResult FirstAction(...)
{
//...
}
// an action that should not be logged -- don't apply LogActionFilter
[HttpGet]
[Route("api/....")]
public JsonResult SecondAction(...)
{
//...
}
更新版本
如果您对“Ignore”属性有明确要求,您可以按如下方式实现。
按照您的方式保留全局配置:
services.AddMvc(options => {
options.Filters.Add(typeof(LoggingActionFilter));
});
LoggingActionFilter 的实现应该改变:
// this filter is applied globally during configuration of web application pipeline
public class LoggingActionFilter : IActionFilter
{
// we use private class types as keys for HttpContext.Items dictionary
// this is better than using strings as the keys, because
// it avoids accidental collisions with other code that uses HttpContext.Items
private class StopwatchItemKey { }
private class SuppressItemKey { }
public void OnActionExecuting(ActionExecutingContext context)
{
// here we save timestamp at the beginning of the request
// I use Stopwatch because it's handy in this case
context.HttpContext.Items[typeof(StopwatchItemKey)] = Stopwatch.StartNew();
}
public void OnActionExecuted(ActionExecutedContext context)
{
// check whether SuppressLoggingAttribute was applied to current request
// we check it here in the end of the request because we don't want to depend
// on the order in which filters are configured in the pipeline
if (!context.HttpContext.Items.ContainsKey(typeof(SuppressItemKey)))
{
// since SuppressItemKey was not set for the current request,
// we can do the logging stuff
var clock = (Stopwatch) context.HttpContext.Items[typeof(StopwatchItemKey)];
var elapsedMilliseconds = clock.ElapsedMilliseconds;
DoMyLoggingStuff(context.HttpContext, elapsedMilliseconds);
}
}
// SuppressLoggingAttribute calls this method to set SuppressItemKey indicator
// on the current request. In this way SuppressItemKey remains totally private
// inside LoggingActionFilter, and no one else can use it against our intention
public static void Suppress(HttpContext context)
{
context.Items[typeof(SuppressItemKey)] = null;
}
}
“忽略”属性(我将其命名为SuppressLoggingAttribute)将如下所示:
// this filter attribute is selectively applied to controllers or actions
// in order to suppress LoggingActionFilter from logging the request
public class SuppressLoggingAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// this will put "suppress" indicator on HttpContext of the current request
LoggingActionFilter.Suppress(context.HttpContext);
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
现在您只需在必要时应用“忽略”属性:
[HttpGet("{id}")]
[SuppressLogging]
public string Get(int id)
{
return "value";
}
性能考虑
与@junnas 的回答相比,我的代码不使用反射 (MethodInfo.CustomAttributes),因此它的运行速度更快。
如果有人质疑Stopwatch 的使用:是的,Stopwatch.StartNew() 会在每个请求的堆上分配一个新的Stopwatch 对象。但是将DateTime 分配给HttpContext.Items 字典的作用相同,因为它意味着装箱。 DateTime 和 Stopwatch 对象都是 64 位大小,因此在分配方面,DateTime 和 Stopwatch 选项是相等的。