20

当社では、ASP.NET WebApi コントローラーのアクション メソッドの 1 つが呼び出されるたびに、特定のものをログに記録する必要があります。現在DIにNinjectを使っているので、これも使っていきたいです。これは私がこれまでに試したことです。

Ninject、Ninject.Extensions.Interception、および Ninject.Extensions.Interception.DynamicProxy を NuGet 経由でインストールしました。次のモジュールがあります。

public class InterceptAllModule : InterceptionModule
{
    public override void Load()
    {
        Kernel.Intercept(p => p.Request.Service.Name.EndsWith("Controller")).With(new TimingInterceptor());
    }
}

TimingInterceptor の場所

public class TimingInterceptor : SimpleInterceptor
{
    readonly Stopwatch _stopwatch = new Stopwatch();
    protected override void BeforeInvoke(IInvocation invocation)
    {
        _stopwatch.Start();
    }

    protected override void AfterInvoke(IInvocation invocation)
    {
        _stopwatch.Stop();
        string message = string.Format("[Execution of {0} took {1}.]",invocation.Request.Method,_stopwatch.Elapsed);
        Log.Info(message + "\n");
        _stopwatch.Reset();
    }
}

さて、モジュールをninjectカーネルに接続してサイトを実行しようとすると

var kernel = new StandardKernel(new InterceptAllModule());

ただし、アクション メソッドの 1 つに呼び出しが入るたびに、次のエラーがスローされます。

Cannot instantiate proxy of class: MyApiController.

経験のある人は、私が間違っていることを指摘してもらえますか? ありがとう。

4

2 に答える 2

30

アップデート

したがって、アクションメソッドを仮想にする必要があり、空のデフォルトコンストラクターを配置する必要があるというコードと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 フレームワーク、特にAllowAnonymousAttributeAuthorizeAttributeからのインスピレーション

これをグローバルに登録して、すべてのアクションがこれによって監視されるようにします。

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()
    {
       //
    }
}
于 2012-12-28T20:28:53.023 に答える