tRuEsAtM
tRuEsAtM

Reputation: 3678

ASP.NET Website Server Timing API does not display time info

I have an ASP.NET Website. I am using the following code in Global.Asax.cs

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            Context.Response.SetServerTiming(
    new ServerTimingMetric("cache", 300, "Cache"),
    new ServerTimingMetric("sql", 900, "Sql Server"),
    new ServerTimingMetric("fs", 600, "FileSystem"),
    new ServerTimingMetric("cpu", 1230, "Total CPU")
);

        }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for HttpResponseHeadersExtensions
/// </summary>
public static class HttpResponseHeadersExtensions
{
    public static void SetServerTiming(this HttpResponse response, params ServerTimingMetric[] metrics)
    {
        ServerTimingHeaderValue serverTiming = new ServerTimingHeaderValue();

        foreach (ServerTimingMetric metric in metrics)
        {
            serverTiming.Metrics.Add(metric);
            response.Headers.Add("Server-Timing", serverTiming.ToString());
        }


        //response.Headers.Append("Server-Timing", serverTiming.ToString());
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for IServerTiming
/// </summary>
public interface IServerTiming
{
    ICollection<ServerTimingMetric> Metrics { get; }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

internal class ServerTiming : IServerTiming
{
    public ICollection<ServerTimingMetric> Metrics { get; }

    public ServerTiming()
    {
        Metrics = new List<ServerTimingMetric>();
    }
}
using System;
using System.Collections.Generic;

public class ServerTimingHeaderValue
{
    public ICollection<ServerTimingMetric> Metrics { get; }

    public ServerTimingHeaderValue()
    {
        Metrics = new List<ServerTimingMetric>();
    }

    public override string ToString()
    {
        return String.Join(",", Metrics);
    }
}
using System.Globalization;
using System;

public struct ServerTimingMetric
{
    private string _serverTimingMetric;

    public string Name { get; }

    public decimal? Value { get; }

    public string Description { get; }

    public ServerTimingMetric(string name, decimal? value, string description)
    {
        if (String.IsNullOrEmpty(name))
            throw new ArgumentNullException(nameof(name));

        Name = name;
        Value = value;
        Description = description;

        _serverTimingMetric = null;
    }

    public override string ToString()
    {
        if (_serverTimingMetric == null)
        {
            _serverTimingMetric = Name;

            if (Value.HasValue)
                _serverTimingMetric = _serverTimingMetric + "=" + Value.Value.ToString(CultureInfo.InvariantCulture);

            if (!String.IsNullOrEmpty(Description))
                _serverTimingMetric = _serverTimingMetric + ";\"" + Description + "\"";
        }
        return _serverTimingMetric;
    }
}

I am getting the following output, enter image description here

Has anyone configured the Server Timing API for the old ASP.NET Website?

Upvotes: 1

Views: 579

Answers (1)

pfx
pfx

Reputation: 23334

Your code sends out more than 1 Server-Timing HTTP header while there should only be 1.
The image you included shows 4 cache items in the lower left.

Also, the HTTP header value being sent out is not according to the specifications.
That is the reason why you only see cache (4 times) in your image; the other parts are not being recognized.

In order to get the result you are looking for, that single Server-Timing HTTP header must look like below.

Server-Timing: cache;desc="Cache";dur=300, sql;desc="Sql Server";dur=900, fs;desc="FileSystem";dur=600, cpu;desc="Total CPU";dur=1230

Each timing item has a name, e.g. cache, optionally followed by key value pairs separated by a semicolon, with desc for the description and dur for the duration. When a description (desc) is present and when it contains a space then it must be enclosed by double quotes.

An example: sql;desc="Sql Server";dur=900


With the correct header in place, my web browser (Chrome) shows below.

enter image description here


I made these changes.

  1. In class HttpResponseHeadersExtensions, add only a single Server-Timing HTTP header.
public static class HttpResponseHeadersExtensions
{
    public static void SetServerTiming(this HttpResponse response, params ServerTimingMetric[] metrics)
    {
        ServerTimingHeaderValue serverTiming = new ServerTimingHeaderValue();

        foreach (ServerTimingMetric metric in metrics)
        {
            serverTiming.Metrics.Add(metric);
        }

        response.Headers.Add("Server-Timing", serverTiming.ToString());
    }
}
  1. In struct ServerTimingMetric, format the string representation differently.
public struct ServerTimingMetric
{
    // Existing code left out for brevity.

    public override string ToString()
    {
        if (_serverTimingMetric == null)
        {
            var builder = new StringBuilder(Name);

            if (!string.IsNullOrEmpty(Description))
                builder.AppendFormat(@";desc=""{0}""", Description);

            if (Value != null)
                builder.AppendFormat(@";dur=""{0}""", Value);

            _serverTimingMetric = builder.ToString();
        }

        return _serverTimingMetric;
    }
}
  1. In class ServerTimingHeaderValue, join the metrics by a comma and space instead of only by a comma.
public class ServerTimingHeaderValue
{
    // Other code left out for brevity.

    public override string ToString()
    {
        return String.Join(", ", Metrics);
    }
}

Upvotes: 1

Related Questions