アップデート
したがって、アクションメソッドを仮想にする必要があり、空のデフォルトコンストラクターを配置する必要があるというコードとRemoの優れたポイントを使用して(動的プロキシをなだめるために、他のコンストラクターを静止させておくだけです)、アクションフィルターと傍受アプローチの両方が機能しています。
現状では、コードは ApiController で望ましくない可能性のあるメソッドをインターセプトするため、ExecuteAsync や Dispose など、これらを除外するコードを配置する必要があると思います。
私の唯一の他のポイントはパフォーマンスです。免責事項として、これらは非常に基本的なテスト (毎回アクション フィルター アプローチを使用して統計を記録する) であり、独自のテストを行うことをお勧めします (!)... しかし、DynamicProxy インターセプターを使用すると、1 回あたり約 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 の自然な拡張ポイントです。
コントローラーでの実際のアクション以外の方法に興味がある場合は、理解できますが、とにかく提案を投稿すると思いました。
スレッド間で ActionFilterAttributes は再利用されますか?に触発されました。それはどのように機能しますか?およびASP.NET MVC コントローラー アクションの呼び出し時間を測定します。
メソッドがタグ付けされたときのタイマーの除外を表示するように更新されました。コア 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()
{
//
}
}