3

asp.net MVC の要求処理時間を取得する必要があります。onBeginRequest および onEndRequest イベントのサブスクライブ IHttpModule を使用します。同期コントローラーの場合はうまく機能しますが、非同期の場合は間違った結果を返します (たとえば、リアルタイムが約 2 分の場合に 20 ミリ秒)。一般的な方法で AsyncController のリクエスト処理時間を取得するにはどうすればよいですか (非同期アクションごとに ActionAsync/ActionCompleted に追加のコードを記述しないでください)。

public class TrackRequestModule : RequestProcessingModuleBase, IHttpModule
{
    public const string BeginRequestTimeKey = "beginRequestTime";

    public void Init(HttpApplication context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        context.BeginRequest += onBeginRequest;
        context.EndRequest += onEndRequest;
    }

    private void onEndRequest(object sender, EventArgs e)
    {
        InvokeHandler(sender, OnEndRequest);
    }

    private void onBeginRequest(object sender, EventArgs e)
    {
        InvokeHandler(sender, OnBeginRequest);
    }

    public void OnBeginRequest(HttpContextBase context)
    {
        context.Items[BeginRequestTimeKey] = DateTime.Now.ToLocalTime();
    }

    public void OnEndRequest(HttpContextBase context)
    {
        var beginRequestTime = (DateTime)context.Items[BeginRequestTimeKey];
        TimeSpan elapsedTime = DateTime.Now.ToLocalTime() - beginRequestTime;

        var info = new RequestData
                    {
                        BeginTime = beginRequestTime,
                        ElapsedTimeMilliseconds = elapsedTime.Milliseconds,
                        Url = context.Request.Url.AbsoluteUri,
                        Data = GetRequestData(context.Request)
                    };
        ThreadPool.QueueUserWorkItem(logRequestInfo, info);
    }

    public void Dispose() { }

    private void logRequestInfo(object state)
    {
        var info = (RequestData)state;
        var queryStore = ObjectBuilder.Instance.Resolve<IRequestTrackingDataQueryStore>();
        queryStore.SaveRequestTrackingData(info.BeginTime, info.ElapsedTimeMilliseconds, info.Url, info.Data);
    }

    private sealed class RequestData
    {
        public DateTime BeginTime { get; set; }
        public int ElapsedTimeMilliseconds { get; set; }
        public string Url { get; set; }
        public string Data { get; set; }
    }
}
4

1 に答える 1

5

それは非常に奇妙です。通常、このシナリオは機能するはずです。残念ながら、コードを表示していないため、何が間違っているのかを判断するのは困難です。

その上、私はそれを再現することができません。テスト用に書いたモジュールは次のとおりです。

public class MeasureModule : IHttpModule
{
    private static readonly ReaderWriterLockSlim _gateway = new ReaderWriterLockSlim();

    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, e) =>
        {
            var app = (sender as HttpApplication);
            var watch = Stopwatch.StartNew();
            app.Context.Items["watch"] = watch;
        };

        context.EndRequest += (sender, e) =>
        {
            var app = (sender as HttpApplication);
            var watch = app.Context.Items["watch"] as Stopwatch;
            watch.Stop();
            var url = app.Context.Request.Url.AbsoluteUri;
            var message = string.Format("url: {0}, time: {1}ms", url, watch.ElapsedMilliseconds);
            var log = HostingEnvironment.MapPath("~/log.txt");
            _gateway.EnterWriteLock();
            try
            {
                File.AppendAllLines(log, new[] { message });
            }
            finally
            {
                _gateway.ExitWriteLock();
            }
        };
    }
}

web.config に登録したもの (Cassini でテストしました。IIS 7 を使用する場合は、それぞれの<system.webServer>セクションでモジュールを登録する必要があります):

<httpModules>
  <add name="measure" type="MvcApplication.Modules.MeasureModule, MvcApplication" />
</httpModules>

次に、テストするサンプル コントローラーを作成します。

[SessionState(SessionStateBehavior.Disabled)]
public class HomeController : AsyncController
{
    public ActionResult IndexSync()
    {
        Thread.Sleep(5000);
        return Content("completed", "text/plain"); 
    }

    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(() =>
        {
            Thread.Sleep(5000);
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ActionResult IndexCompleted()
    {
        return Content("completed", "text/plain");
    }
}

次に、次の URL に対して 2 つの並列 HTTP リクエストを発行しました。

  • /home/index
  • /home/indexsync

2 つの要求は約 5 秒後に期待どおりに完了し、ログ ファイルは完全に正常に見えました。

url: http://localhost:14953/home/index, time: 5047ms
url: http://localhost:14953/home/indexsync, time: 5005ms

ご覧のとおり、HTTP モジュールは非同期アクションと同期アクションの両方の実行時間を正しく測定しました。

それで、何が得られますか?

ところで、MiniProfilerをチェックアウトして、シナリオに車輪の再発明がないことを確認してください。

于 2012-06-22T12:09:06.070 に答える