Swimburger

Capturing ASP.NET Framework RawUrl with Azure Application Insights

Niels Swimberghe

Niels Swimberghe - - Azure

Follow me on Twitter, buy me a coffee

Azure Application Insights is an Application Performance Management (APM) tool providing insights into the state of your application. By default, Application Insights will capture a lot of data about your ASP.NET applications including HTTP Requests made to your website. Unfortunately, the URL captured by Application Insights doesn't always match the URL originally requested by the client.

In many ASP.NET applications, especially CMS's like DNN, the path of the HTTP request is internally rewritten by the time Application Insights records the data. This results in the rewritten URL to be captured and not the original URL. You can simulate this scenario with a simple Context.RewritePath inside of the Application_BeginRequest method of the global.asax.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace AddRawUrlToApplicationInsights
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            // This code snippet is for demo purposes only!
            // these types of rewrites can be performed by IIS Rewrite module 
            // or you can update the routing table to resolve '/' to the HomeController

            string fullOrigionalpath = Request.Url.ToString();
            if (fullOrigionalpath.Contains("/about"))
            {
                Context.RewritePath("/home/about");
            }
            else if(fullOrigionalpath.Contains("/contact"))
            {
                Context.RewritePath("/home/contact");
            }
        }
    }
}

Source at GitHub

In this sample, when /about is requested, the path is rewritten to /home/about which will resolve to the HomeController.About action. When you browse to /about and look at the recorded HTTP request inside of Application Insights, the URL will be https://domain.tld/home/about instead of https://domain.tld/about. The rewritten URL is useful information, but you may also need the original URL for proper debugging/analyzing.

Luckily, there's a property called RawUrl on the request that will always have the original path including the querystring. Application Insights provides an extensibility point for you to capture additional data using the ITelemetryInitializer interface. You can capture the original URL by implementing ITelemetryInitializer and adding the RawUrl data to the telemetry properties:

using System;
using System.Web;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;

namespace AddRawUrlToApplicationInsights
{
    public class RawUrlTelemetryInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry is RequestTelemetry requestTelemetry)
            {
                var httpContext = HttpContext.Current;
                if (httpContext?.Request == null)
                {
                    return;
                }

                var request = httpContext.Request;
                requestTelemetry.Properties["RawUrl"] = request.RawUrl;
                requestTelemetry.Properties["RawUrlFqdn"] = new Uri(request.Url, request.RawUrl).ToString();
            }
        }
    }
}

Source at GitHub

Whenever an HTTP Request telemetry is initialized, this initializer will grab the current HTTP Request and capture the RawUrl and the RawUrlFqdn. The RawUrlFqdn will include the protocol, full domain, port, path, and querystring.
For Application Insights to use the RawUrlTelemetryInitializer, you must add a reference to the class in ApplicationInsights.config:

<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
    <TelemetryInitializers>
        <Add Type="AddRawUrlToApplicationInsights.RawUrlTelemetryInitializer, AddRawUrlToApplicationInsights"/>
        ...
    </TelemetryInitializers>
    ...
</ApplicationInsights>

Full source at GitHub

This is what the resulting data looks like when sent to Application Insights:

{
  "name": "AppRequests",
  "time": "2020-09-11T16:47:04.4346673Z",
  "tags": {
    "ai.cloud.roleInstance": "YOURHOSTNAME",
    "ai.operation.id": "26d253e8979c0f4fb602fc7df4a31039",
    "ai.operation.name": "GET home/about",
    "ai.location.ip": "::1",
    "ai.internal.sdkVersion": "web:2.14.0-17971"
  },
  "data": {
    "baseType": "RequestData",
    "baseData": {
      "ver": 2,
      "id": "59b220044848c141",
      "name": "GET home/about",
      "duration": "00:00:01.6182094",
      "success": true,
      "responseCode": "200",
      "url": "https://localhost:44308/home/about",
      "properties": {
        "RawUrlFqdn": "https://localhost:44308/about",
        "RawUrl": "/about",
        "DeveloperMode": "true",
        "_MS.ProcessedByMetricExtractors": "(Name:'Requests', Ver:'1.1')"
      }
    }
  }
}

Notice how the url, properties.Rawurl, and properties.RawUrlFqdn are all capture providing a more complete picture of the request:

url https://localhost:44308/home/about
properties.RawUrlFqdn https://localhost:44308/about
properties.RawUrl /about

Summary #

Using the ITelemetryInitializer extensibility point in Application Insights, you can capture additional data. Using the RawUrl on the HttpContext.Request, you can capture the original URL in addition to the rewritten URL which is captured by default.

Related Posts

Related Posts