APM Tips

Application Insights

Application Insights for ASP.NET MVC and Web API on .NET Framework

Updated · 6 min read · By APM Tips editorial team

ASP.NET MVC and Web API apps on .NET Framework are monitored with the Microsoft.ApplicationInsights.Web package: two HTTP modules in web.config record requests and correlation, and since Web SDK 2.6 unhandled exceptions from MVC 5 and Web API 2 controllers are collected without custom filters. The 2.x line retires on March 31, 2027; the supported way forward is SDK 3.x of the same package, which needs .NET Framework 4.6.2 or later, swaps modules and initializers for OpenTelemetry, and drops the TraceListener. The Microsoft OpenTelemetry Distro targets ASP.NET Core, not System.Web.

A large share of production .NET still runs on System.Web: MVC 5 sites, Web API 2 services, Web Forms. Application Insights has supported them from the start, and still does, but the pieces changed over the years, and SDK 3.x changes them again.

Classic SDK 2.x

What the package installs

Adding Application Insights to an ASP.NET project installs Microsoft.ApplicationInsights.Web and its dependencies (dependency collector, performance counters, the server telemetry channel, Microsoft.AspNet.TelemetryCorrelation), creates ApplicationInsights.config, adds the JavaScript snippet to _Layout.cshtml, and registers an error filter in FilterConfig.cs. Requests are recorded by two HTTP modules, and order matters: correlation first, tracking second.

The web.config registration both modules need (integrated pipeline):

<system.webServer>
  <modules>
    <add name="TelemetryCorrelationHttpModule"
         type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation"
         preCondition="integratedMode,managedHandler" />
    <add name="ApplicationInsightsHttpModule"
         type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"
         preCondition="managedHandler" />
  </modules>
</system.webServer>

Apps upgraded from SDKs older than 2.4 sometimes still have only the second module, which shows up as FileNotFoundException: Could not load file or assembly Microsoft.AspNet.TelemetryCorrelation or as telemetry that never correlates. Microsoft’s fix is the two-module registration above plus AspNetDiagnosticTelemetryModule in ApplicationInsights.config. How requests are named and which handlers are excluded (static files, bundles) is covered in how requests are named.

Exceptions in MVC and Web API

Since Web SDK 2.6, unhandled exceptions thrown in MVC 5+ and Web API 2+ controller methods are collected automatically. The custom pieces that older tutorials added, an AiHandleErrorAttribute for MVC and an IExceptionLogger for Web API, are no longer needed; Microsoft suggests removing them so each exception isn’t tracked twice. (Before 2.6, MVC’s default customErrors mode of RemoteOnly cleared the exception before the module could see it, which is why the attribute existed.)

Exception filters still miss exceptions thrown from controller constructors, message handlers, routing, response serialization, application start-up and background tasks. And a handled exception is invisible: if your code catches it and returns a 500, the request is recorded with result code 500 but no exception item. Track those yourself:

Reporting a handled exception from a Web API 2 controller with the shared client:

public class OrdersController : ApiController
{
    private static readonly TelemetryClient Telemetry = new TelemetryClient(TelemetryConfiguration.Active);

    public IHttpActionResult Get(int id)
    {
        try { return Ok(_repository.Find(id)); }
        catch (SqlException ex)
        {
            Telemetry.TrackException(ex, new Dictionary<string, string> { ["orderId"] = id.ToString() });
            return InternalServerError();
        }
    }
}

Reuse one TelemetryClient rather than creating one per request; Microsoft’s troubleshooting page lists configurations created per request as a cause of thread and memory leaks.

Web Forms and WCF in the same app

Older solutions often mix MVC with Web Forms pages or WCF services, and those parts follow different rules. For Web Forms, the HTTP module collects exceptions only when customErrors doesn’t redirect. With redirects active, report the error yourself in Global.asax.cs:

Reporting Web Forms errors when custom error redirects are on:

void Application_Error(object sender, EventArgs e)
{
    if (HttpContext.Current.IsCustomErrorEnabled && Server.GetLastError() != null)
    {
        _telemetryClient.TrackException(Server.GetLastError());
    }
}

WCF services don’t use controller filters at all. Microsoft’s pattern is an attribute that implements IErrorHandler and IServiceBehavior, adds itself to every channel dispatcher’s error handlers, and calls TrackException in HandleError. WCF calls the app makes to other services are tracked as dependencies only over HTTP-based bindings.

The JavaScript snippet that the project template added to _Layout.cshtml is a separate concern from all of this: it reports page views and browser exceptions from the user’s side and correlates them with these server requests. The JavaScript snippet guide explains what it does and when to replace it with the npm package.

Forwarding trace output

For apps that write diagnostics with System.Diagnostics.Trace (including framework tracing routed there), the Microsoft.ApplicationInsights.TraceListener package forwards each line to the traces table, correlated with the request it ran in:

<system.diagnostics>
  <trace>
    <listeners>
      <add name="myAppInsightsListener"
           type="Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener" />
    </listeners>
  </trace>
</system.diagnostics>

Leave Trace.AutoFlush off. Microsoft warns that with autoflush every trace call becomes a separate request to the ingestion service, which can exhaust the network and storage on a busy server; the server channel batches properly on its own. If you don’t already log through Trace, NLog or log4net, Microsoft suggests calling TrackTrace() directly rather than adding an adapter.

Find 500s that have no exception

Handled exceptions that were never tracked leave a trace of their own: failed requests with nothing in exceptions for the same operation. This finds them per operation, so you know which catch blocks need a TrackException:

requests
| where timestamp > ago(1d) and resultCode == "500"
| join kind=leftanti (exceptions | where timestamp > ago(1d) | distinct operation_Id) on operation_Id
| summarize silent500s = sum(itemCount) by name
| order by silent500s desc

The failed requests by result code query gives the wider picture.

Today: SDK 3.x and the Microsoft OpenTelemetry Distro

SDK 3.x for System.Web

Microsoft.ApplicationInsights.Web 3.x is Microsoft’s upgrade path for ASP.NET on .NET Framework. It targets net462, so apps on 4.5.2 must move to 4.6.2 or later first. Upgrade every Application Insights package together; don’t mix 2.x and 3.x.

What changes for an MVC or Web API app:

  • Modules. RequestTrackingTelemetryModule, ExceptionTrackingTelemetryModule and AspNetDiagnosticTelemetryModule are gone; OpenTelemetry’s ASP.NET instrumentation and exception tracking switch on automatically. Request collection can still be turned off with <EnableRequestTrackingTelemetryModule>.
  • Initializers. The <TelemetryInitializers> and <TelemetryModules> sections of ApplicationInsights.config are no longer read. Rewrite custom initializers as OpenTelemetry processors, registered through TelemetryConfiguration.ConfigureOpenTelemetryBuilder(); see telemetry initializers and processors.
  • Logging. The TraceListener and log4net appender are discontinued; use TrackTrace() or ILogger. An NLog target exists as a 3.x beta.
  • Channel. The server channel is replaced by the Azure Monitor exporter, with StorageDirectory and DisableOfflineStorage for its disk cache.
  • Connection string. <InstrumentationKey> is replaced by <ConnectionString>, and 3.x fails at startup without one.

ApplicationInsights.config in SDK 3.x, now a flat list of settings:

<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
  <ConnectionString>InstrumentationKey=...;IngestionEndpoint=https://...</ConnectionString>
  <TracesPerSecond>5</TracesPerSecond>
  <EnableQuickPulseMetricStream>true</EnableQuickPulseMetricStream>
  <EnableDependencyTrackingTelemetryModule>true</EnableDependencyTrackingTelemetryModule>
  <EnableRequestTrackingTelemetryModule>true</EnableRequestTrackingTelemetryModule>
</ApplicationInsights>

The connection string can also come from APPLICATIONINSIGHTS_CONNECTION_STRING, which the 3.x Web package reads automatically. Sampling changes from adaptive to rate-limited at five traces per second; the sampling guide explains what that does to counts. The ApplicationInsights.config guide compares the two file formats in full.

The Distro and System.Web

The Microsoft OpenTelemetry Distro for .NET (Microsoft.OpenTelemetry) targets net8.0 and netstandard2.0, and its always-on instrumentation lists ASP.NET Core requests, HttpClient, SqlClient and Azure SDK calls, not the System.Web pipeline that MVC 5 and Web API 2 run on. Microsoft’s Live Metrics page also lists ASP.NET as not supported with OpenTelemetry. For an MVC or Web API app that stays on .NET Framework, SDK 3.x is the documented route; the Distro becomes the natural choice when the app moves to ASP.NET Core. The SDK vs Distro guide weighs the two.

Troubleshooting

SymptomLikely causeFix
Could not load ... Microsoft.AspNet.TelemetryCorrelationUpgrade from a pre-2.4 SDK left web.config incompleteRegister both modules, in order
Each exception appears twiceOld AiHandleErrorAttribute or IExceptionLogger plus automatic collectionRemove the custom handler
500 responses with no exceptionException handled in codeCall TrackException in the catch block
Trace lines missing (2.x)No listener, or autoflush flooding the channelAdd the listener; turn autoflush off
Initializers ignored after upgrading to 3.x<TelemetryInitializers> no longer readRewrite as OpenTelemetry processors
3.x package won’t installApp targets .NET Framework 4.5.2Retarget to 4.6.2 or later

Queries for this topic

From the KQL library: explained queries for the Application Insights tables, ready to copy.

  • Returns: One row per problem ID, operation and result code among failed requests, with the sampling-adjusted exception count, how many failed operations it appeared in, and an example exception type and message.

  • Unhandled vs handled exceptions

    exceptionsrequests exceptions

    Returns: One row per handledAt value and request outcome, with the sampling-adjusted exception count, the number of distinct exception types and one example type.

  • Exceptions by type and operation

    exceptions exceptions

    Returns: Up to 50 rows, one per exception type and operation, with the sampling-adjusted count, the number of distinct problem IDs, one outer message and one innermost exception type.

Frequently asked questions

Do I still need AiHandleErrorAttribute or a custom IExceptionLogger?

Not with Web SDK 2.6 or later: unhandled exceptions from MVC 5+ and Web API 2+ controllers are collected automatically, and Microsoft suggests removing older custom handlers to avoid tracking each exception twice. Exceptions thrown outside controllers, or ones you catch, still need TrackException.

Can I use the Microsoft OpenTelemetry Distro in an ASP.NET MVC app?

The Distro targets net8.0 and netstandard2.0, and its built-in request instrumentation is for ASP.NET Core. For System.Web apps, Microsoft's documented path is SDK 3.x of Microsoft.ApplicationInsights.Web, which uses OpenTelemetry internally. Live Metrics isn't supported for ASP.NET with OpenTelemetry.

What replaces the Application Insights TraceListener in 3.x?

Nothing directly. Microsoft discontinued the TraceListener and Log4Net appender packages because System.Diagnostics.Trace and log4net are legacy APIs, and points to TrackTrace or ILogger instead. An NLog target exists for 3.x as a beta.

Sources, checked

  1. Monitor .NET and Node.js applications with Application Insights (Classic API 2.x, ASP.NET)learn.microsoft.com · checked
  2. Migrate Application Insights Classic API SDKs to OpenTelemetry (SDK 3.x packages)learn.microsoft.com · checked
  3. Breaking changes: Application Insights 2.x to 3.x (Microsoft.ApplicationInsights.Web)github.com · checked
  4. Migration guidance from 2.x to 3.x (unsupported packages and replacements)github.com · checked
  5. Troubleshoot no data in Application Insights for .NET (TelemetryCorrelation module)learn.microsoft.com · checked
  6. Live Metrics, monitor and diagnose with 1-second latencylearn.microsoft.com · checked
  7. Microsoft.OpenTelemetry (Microsoft OpenTelemetry Distro for .NET, README)github.com · checked