Ответ 1
Обновление
Таким образом, используя ваш код и Remo превосходный момент в том, что нужно, чтобы методы действий были виртуальными и помещались в пустой конструктор по умолчанию (просто чтобы успокоить динамический прокси, сохранить еще один конструктор), у меня есть оба фильтр действия и подход к перехвату.
Я бы сказал, что, поскольку он стоит, ваш код будет перехватывать потенциально нежелательные методы на ApiController, поэтому вам, вероятно, также потребуется поместить некоторый код в место, чтобы отфильтровать их, например. ExecuteAsync и Dispose.
Мой единственный момент - это производительность. Огромный отказ от ответственности - это всего лишь очень простые тесты (каждый раз при использовании подхода фильтра действий каждый раз, чтобы регистрировать статистику), я предлагаю вам сделать свой (!)... но используя перехватчик DynamicProxy, я получал время около 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.
Если бы вас интересовали методы, отличные от фактического действия на контроллере, я бы понял, но я думал, что все равно опубликую предложение.
Вдохновленный Повторяются ли ActionFilterAttributes по потокам? Как это работает? и Измерять время, вызывая действия ASP.NET MVC Controller.
Обновлен, чтобы показать исключение таймера при пометке метода. Вдохновение из основной структуры 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
{
// GET api/example
[NoLog]
public Example Get()
{
//
}
}