更新
所以,使用您的代码和Remo提出的很好的观点,需要将操作方法设置为虚拟的,并放置一个空的默认构造函数(只是为了平息动态代理,保留您的其他构造函数),我已经让操作过滤器和拦截器方法均可正常工作。
我认为,目前为止,您的代码将拦截ApiController上可能不需要的方法,因此您可能还需要编写一些代码来过滤这些方法,例如ExecuteAsync和Dispose。
我的另一个建议是性能方面。 非常重要的免责声明 这些仅是非常基本的测试(每次使用操作过滤器方法记录统计信息),我邀请您进行自己的测试!...但是使用DynamicProxy拦截器时,我得到了大约每个GET请求4毫秒的时间。
[Execution of Get took 00:00:00.0046615.]
[Execution of Get took 00:00:00.0041988.]
[Execution of Get took 00:00:00.0039383.]
将拦截代码注释掉并使用操作过滤器,我获得了亚毫秒级的性能表现:
[Execution of Get took 00:00:00.0001146.]
[Execution of Get took 00:00:00.0001116.]
[Execution of Get took 00:00:00.0001364.]
这是否是一个问题或关注点完全取决于您,但我想指出这一点。
之前的回复
您是否考虑过使用ActionFilters?这是在MVC操作上进行AOP的自然扩展点。
如果您对除控制器上的实际操作以外的方法感兴趣,那么我可以理解,但我还是想提供一个建议。
灵感来自Are ActionFilterAttributes reused across threads? How does that work?和Measure Time Invoking ASP.NET MVC Controller Actions。
更新以显示标记方法时计时器的排除。灵感来自核心WebApi框架,特别是AllowAnonymousAttribute和AuthorizeAttribute
全局注册此功能,以便所有操作都受到监视:
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter())
那么:
public class TimingActionFilter : ActionFilterAttribute
{
private const string Key = "__action_duration__";
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (SkipLogging(actionContext))
{
return;
}
var stopWatch = new Stopwatch();
actionContext.Request.Properties[Key] = stopWatch;
stopWatch.Start();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (!actionExecutedContext.Request.Properties.ContainsKey(Key))
{
return;
}
var stopWatch = actionExecutedContext.Request.Properties[Key] as Stopwatch;
if(stopWatch != null)
{
stopWatch.Stop();
var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
Debug.Print(string.Format("[Execution of {0} took {1}.]", actionName, stopWatch.Elapsed));
}
}
private static bool SkipLogging(HttpActionContext actionContext)
{
return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() ||
actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
}
}
和
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class NoLogAttribute : Attribute
{
}
现在,您可以使用以下方法排除全局过滤器:
public class ExampleController : ApiController
{
[NoLog]
public Example Get()
{
}
}