While piloting Application Insights to monitor our homegrown applications, one thing that was asked was to capture the operation names of WebMethod that were invoked in ASMX web services. While Application Insights will capture the call to the web services asmx resource, the actual name of the method getting invoked doesn’t get captured out of the box.

In order to achieve this, I had to write a custom Application Insights Telemetry Initializer library to capture that information. A special shout out goes to Sergey Kanzhelev for pointing me in the right direction for this. I highly recommend checking out his blog here: http://www.apmtips.com and follow him on Twitter using the handle @SergeyKanzhelev.

At a high level, it boils down to capturing two high level scenarios. Depending on how the call to the method is done, can capture the name of the method in a few ways. The most important one to address in my particular case was being able to capture SOAP requests over HTTP. In order to get the method name in that scenario, you have to inspect the HTTP headers of the POST request being made in order to grab the SOAPAction property. With some simple string manipulation, you can extract the name of the method invoked.

For more information about the ITelemetryInitializer interface from the Application Insights SDK, consult the following page from Microsoft: Add properties: ITelemetryInitializer

As I’m only an amateur developer, please forgive me if the code is not the prettiest! If you think I should change some things in the code below, feel free to comment. I’ll gladly improve it and update this post!

To build this extension, I built a simple C# class library project in Visual Studio.

I then added the Application Insights Nuget packages to my solution in order to add the references needed for this new extension.

<packages> <package id="Microsoft.ApplicationInsights" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.4.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.4.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.Web" version="2.4.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.WindowsServer" version="2.4.1" targetFramework="net461" /> <package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.AspNet.TelemetryCorrelation" version="1.0.0" targetFramework="net461" /> <package id="System.Diagnostics.DiagnosticSource" version="4.4.0" targetFramework="net461" /> </packages>

I then proceeded by writing the code below in a new class file named WebMethodInitializer.cs .

using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; using Microsoft.ApplicationInsights.Extensibility; using System.Linq; /// <summary> /// Summary description for WebMethodInitializer /// </summary> namespace GEM.ApplicationInsights.Web { public class WebMethodInitializer : ITelemetryInitializer { public WebMethodInitializer() { // // TODO: Add constructor logic here // } public void Initialize(ITelemetry telemetry) { var requestTelemetry = telemetry as RequestTelemetry; string soapActionMethod = null; string requestMethodName = null; string webServiceMethod = null; // Is this a TrackRequest() ? if (requestTelemetry == null) return; requestMethodName = System.Web.HttpContext.Current.Request.Params["op"]; // Item("HTTP_SOAPACTION"); if (requestMethodName == "" || requestMethodName == null) { if (System.Web.HttpContext.Current.Request.PathInfo != null) { requestMethodName = System.Web.HttpContext.Current.Request.PathInfo; } if (requestMethodName != "" && requestMethodName != null) { requestMethodName = requestMethodName.Replace("/", ""); // If we set the Success property, the SDK won't change it: requestTelemetry.Success = true; // Allow us to filter these requests in the portal: requestTelemetry.Properties["WebMethodName"] = requestMethodName; webServiceMethod = requestMethodName; } } string soapAction = System.Web.HttpContext.Current.Request.Headers["SOAPAction"]; if (soapAction != null) { soapAction = soapAction.Replace("\"", ""); soapActionMethod = soapAction.Split('/').Last(); requestTelemetry.Properties["SOAPAction"] = soapAction; webServiceMethod = soapActionMethod; } if (webServiceMethod != null) { requestTelemetry.Context.Operation.Name = requestTelemetry.Context.Operation.Name.Replace("/" + webServiceMethod, "") + "/" + webServiceMethod; } } } }

The above code captures the mtehod name in both SOAP and regular HTTP POST requests. It will also append the method name to the operation name (out of the box, it’s only the name of the asmx getting called.). That way you will see trends for each method of a web service in the Application Insights Azure portal.

Once the solution and DLL is compiled, you can take the resulting DLL and drop it in the bin directory of the ASP .NET site where your ASMX are located. Once that’s done, you’ll need to add a line like the following to the ApplicationInsights.config file for that particular web application:

<TelemetryInitializers> <!--other initializers above--> <Add Type="GEM.ApplicationInsights.Web.WebMethodInitializer, GEM.ApplicationInsights"/> </TelemetryInitializers>

With that in place, your new extension should be capturing the method name of the web services during HTTP SOAP requests.

You can see what it looks like ultimately in the following screeenshot:

Should you have questions about this post, don’t hesitate to reach out using the comments below!