Search code examples
c#asp.net.netasp.net-coreminiprofiler

MiniProfiler dynamic response handling in .NET 6


Recently I have integrated MiniProfiler into a .NET 6 API and all works well, can see the SQL queries via EFCore and all on the dashboard. What I would like to achieve now is that the profiler still profiles all HTTP requests like it does now, but when an error happens anywhere in the application (Status code != 200) I would want to do some custom stuff with the profiler data, for example save the profiler trace (same stuff that's shown on the dashboard) to a DB or logger.

What I had in mind initially was to make a custom middleware, and then after await _next(context); fetch the data (duration time, steps, types, queries) from the profiler from MiniProfiler.Current but I can't seem to make it work. Any solutions?


Solution

  • Found some help over here enter link description here. To summarize, I've managed to write a custom middleware, that fetches all data from the MiniProfiler before the response is returning to the client, enabling to catch the stack timings, saving logs to DB and later analyzing them. The full solution also contains saving of the exact request and response data, which enables to see the full scope of a HTTP request, but for simplicity, I'll add just the MiniProfiler code:

    public async Task InvokeAsync(HttpContext context)
    {
        // Call the next delegate/middleware in the pipeline.
        await _next(context);
        try
        {
            if (context.Response.StatusCode != StatusCodes.Status200OK)
            {
                var profiler = MiniProfiler.Current;
                if (profiler == null)
                {
                    return;
                }
                profiler.Stop();
                
                var time = timing.DurationMilliseconds != null ? decimal.Round(timing.DurationMilliseconds.Value, 2) : 0;
                //Write to Console or Logger
                Console.WriteLine($"{new string('>', timing.Depth)} {timing.Name} {time}ms");
                
                if (timing.HasCustomTimings)
                {
                    foreach (var timingType in timing.CustomTimings)
                    {
                        foreach (var queryTiming in timingType.Value)
                        {
                            var message = $"{new string('>', timing.Depth + 1)} ({timingType.Key},{queryTiming.DurationMilliseconds}ms) {queryTiming.CommandString.Replace("\r\n", " ")}";
                            //Write to Console or Logger
                            Console.WriteLine(message);
                        }
                    }
                }
            }
        }
        catch (Exception)
        {
            //Do something
        }
    }