简体   繁体   English

ASP.Net MVC AsyncController日志请求处理时间

[英]ASP.Net MVC AsyncController log request processing time

I need to get request processing time for asp.net MVC. 我需要获得asp.net MVC的请求处理时间。 i use IHttpModule subscribing for onBeginRequest and onEndRequest events. 我使用IHttpModule订阅onBeginRequest和onEndRequest事件。 For sync controllers it works great but for async it returns wrong result(for example 20ms when real time was about 2min). 对于同步控制器,它工作得很好但是对于异步它会返回错误的结果(例如,当实时约为2分钟时为20ms)。 How could I get request processing time for AsyncController in general way(not writing aditional code in ActionAsync/ActionCompleted for each async action)? 如何以一般方式获取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; }
    }
}

That's very strange. 这很奇怪。 Normally this scenario should work. 通常这种情况应该有效。 Unfortunately you haven't shown your code so it is difficult to say what you might be doing wrong. 遗憾的是,您没有显示您的代码,因此很难说您可能做错了什么。

Besides I am unable to reproduce it. 此外,我无法重现它。 Here's the module I wrote to test: 这是我写的测试模块:

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();
            }
        };
    }
}

Which I registered in my web.config (I tested under Cassini, if you intend to use IIS 7 you will have to register the module in the respective <system.webServer> section): 我在web.config中注册了(我在Cassini下测试过,如果你打算使用IIS 7,你必须在相应的<system.webServer>部分注册模块):

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

And then wrote a sample controller to test: 然后写了一个样本控制器来测试:

[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");
    }
}

Then I fired two parallel HTTP requests to the following urls: 然后我向以下网址发出了两个并行HTTP请求:

  • /home/index
  • /home/indexsync

The 2 requests completed as expected after about 5 seconds and the log file looked perfectly normal: 2个请求在大约5秒后按预期完成,并且日志文件看起来完全正常:

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

As you can see the HTTP module measured the execution time of both the asynchronous and synchronous actions correctly. 如您所见,HTTP模块正确地测量了异步和同步操作的执行时间。

So what gives? 什么给出了什么?

By the way you might checkout MiniProfiler and ensure that there are no wheel reinventions for your scenario. 顺便说一句,您可以检查MiniProfiler并确保您的方案没有轮盘重新设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM