.NET

Use Middleware APM for .NET to collect traces, metrics and application logs from ASP.NET Core and other .NET applications, with automatic instrumentation for common libraries. The table shows which data types it collects.

TracesMetricsApp LogsCustom LogsProfiling
✅✅✖✅✅

1. Prerequisites#

  • Middleware Host Agent (for host-based mode). If your app is containerized, point it to the Host Agent using MW_AGENT_SERVICE.

    • Docker default bridge gateway: 172.17.0.1.
    • Kubernetes service DNS: mw-service.mw-agent-ns.svc.cluster.local.
  • Supported runtimes:

    • .NET 6.0+ for the Middleware .NET SDK and for auto-instrumentation on Linux, Docker and Kubernetes.
    • .NET Framework 4.6.2+ and .NET 6.0+ applications hosted in IIS on Windows, using zero-code IIS auto-instrumentation (see the Windows (PowerShell) tab).

    Check with:

    bash
    dotnet --version
    Middleware .NET: Scala APM

2. Host-based instrumentation (with Host Agent)#

1 Add the Middleware reference (Logger & helpers)#

Download the latest Middleware.dll and reference it in your project:

html
<!-- .csproj -->
<ItemGroup>
  <Reference Include="Middleware">
    <HintPath>path\to\Middleware.dll</HintPath>
  </Reference>
</ItemGroup>

The dotnet-plugin release notes confirm .NET 6+ compatibility and the Middleware.Logger.Logger API for custom logs.

2 Install the auto-instrumentation binaries#

  • Download installer
    bash
    curl -sSfL https://install.middleware.io/apm/dotnet/v1.0.0-rc.1/scripts/mw-dotnet-auto-install.sh -O
  • Install core files (adds ~/.mw-dotnet-auto/):
    bash
    sh ./mw-dotnet-auto-install.sh
    rm -f mw-dotnet-auto-install.sh
  • Allow the instrumentation script:
    bash
    chmod +x $HOME/.mw-dotnet-auto/instrument.sh
  • Run your app with instrumentation:
bash
MW_API_KEY="<MW_API_KEY>" \
. $HOME/.mw-dotnet-auto/instrument.sh && \
OTEL_SERVICE_NAME="{APM-SERVICE-NAME}" \
dotnet path/to/YourApplication.dll
  • Install and run the Middleware Windows Host Agent so OTLP is available at http://localhost:9320.
  • From an elevated PowerShell session, download and run the IIS full-instrumentation script. It installs OpenTelemetry auto-instrumentation for your .NET applications on Windows:
bash
powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://install.middleware.io/apm/dotnet/iis-full-instrumentation.ps1' -OutFile 'iis-full-instrumentation.ps1'; .\iis-full-instrumentation.ps1 -OtlpEndpoint 'http://localhost:9320' -ApiKey '<MW_API_KEY>'"
  • Restart IIS or your .NET application so the instrumentation takes effect.

IIS auto-instrumentation for .NET Framework and .NET#

The IIS script instruments your applications without any code changes or recompilation. It installs OpenTelemetry .NET Automatic Instrumentation and configures it for each IIS App Pool you select. It supports both .NET Framework App Pools and .NET (Core) / .NET 5+ App Pools ("No Managed Code").

Support for older applications: Older .NET Framework applications often pin shared libraries (such as Microsoft.Extensions.* and System.Diagnostics.DiagnosticSource) to older versions through web.config binding redirects. The script inspects each application's binding redirects and bundled assemblies, and automatically installs the newest OpenTelemetry release that is compatible with them. If no compatible release is found, the script stops without making any changes, so your applications are never left in a broken state.

Optional parameters:

ParameterDescription
-DetectOnlyDry run. Reports which App Pools would be instrumented and which OpenTelemetry release would be installed, without changing anything.
-AppPoolsOne or more App Pool names, or all. Skips the interactive prompts so the script can run unattended (for example, through AWS Systems Manager Run Command).
-OtelVersionauto (default), latest, or a specific release such as v1.12.0.

To remove the instrumentation, run the IIS uninstrumentation script from an elevated PowerShell session.

  • Install deps and Middleware auto-installer:
    bash
    RUN apt-get update && apt-get install -y curl unzip
    RUN curl -sSfL https://install.middleware.io/apm/dotnet/v1.0.0-rc.1/scripts/mw-dotnet-auto-install.sh -O 
    RUN bash mw-dotnet-auto-install.sh 
    RUN rm -rf mw-dotnet-auto-install.sh
    RUN chmod +x $HOME/.mw-dotnet-auto/instrument.sh
    
    # ... your app build/publish here ...
  • Start with instrumentation:
    bash
    CMD . $HOME/.mw-dotnet-auto/instrument.sh && dotnet Mw-WebApplication.dll
  • If using ASP.NET, expose ports/URLs explicitly:
    bash
    ENV ASPNETCORE_HTTP_PORTS=5000
    ENV ASPNETCORE_URLS=http://0.0.0.0:5000
  • Add connectivity/env:
    bash
    ENV MW_AGENT_SERVICE=172.17.0.1
    ENV MW_API_KEY=<MW_API_KEY>
  • Install deps and Middleware auto-installer:
    bash
    RUN apt-get update && apt-get install -y curl unzip
    RUN curl -sSfL https://install.middleware.io/apm/dotnet/v1.0.0-rc.1/scripts/mw-dotnet-auto-install.sh -O 
    RUN bash mw-dotnet-auto-install.sh 
    RUN rm -rf mw-dotnet-auto-install.sh
    RUN chmod +x $HOME/.mw-dotnet-auto/instrument.sh
    
    # ... your app build/publish here ...
  • Start with instrumentation:
    bash
    CMD . $HOME/.mw-dotnet-auto/instrument.sh && dotnet Mw-WebApplication.dll
  • If using ASP.NET, expose ports/URLs explicitly:
    bash
    ENV ASPNETCORE_HTTP_PORTS=5000
    ENV ASPNETCORE_URLS=http://0.0.0.0:5000
  • Add the following environment variables to your container:
bash
MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local
MW_API_KEY="<MW_API_KEY>"

The default namespace for running the Middleware agent is mw-service.mw-agent-ns.svc.cluster.local.

3. Sending custom data (optional)#

Custom logs (Middleware logger)#

bash
using Middleware.Logger;

Logger.Info("This is info log");
Logger.Warning("This is info log");
Logger.Debug("This is info log");
Logger.Error(new Exception("oops"));

Application logs (OpenTelemetry console exporter)#

Add packages to your .csproj:

html
<Project Sdk="Microsoft.NET.Sdk.Web">
  <ItemGroup>
    <PackageReference Include="OpenTelemetry" Version="1.5.1" />
    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.5.1" />
  </ItemGroup>
</Project>

Wire up logging:

bash
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;

var builder = WebApplication.CreateBuilder(args);

builder.Logging.AddOpenTelemetry(options =>
{
    options.AddConsoleExporter();
});

var app = builder.Build();
app.Run();

4. View your data#

After deployment, give it 3–5 minutes and check APM → Traces, Logs, and Continuous Profiling in Middleware.

5. Serverless / Direct (no Host Agent)#

Use the NuGet package and configure via appsettings.json.

1 Install package#

bash
dotnet add package MW.APM

(Available for .NET 6.0 / .NET Framework 4.8 as of v1.2.0.)

2 Program configuration#

bash
// Program.cs
var builder = WebApplication.CreateBuilder(args);

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();

builder.Services.ConfigureMWInstrumentation(configuration);

// optional: additional logging sinks
builder.Logging.AddConfiguration(configuration.GetSection("Logging"));
builder.Logging.AddConsole();
builder.Logging.SetMinimumLevel(LogLevel.Debug);

// After var app = builder.Build();
Logger.Init(app.Services.GetRequiredService<ILoggerFactory>());

3 Account & routing (appsettings.json)#

bash
{
  "MW": {
    "ApiKey": "<MW_API_KEY>",
    "TargetURL": "https://<MW_UID>.middleware.io:443",
    "ServiceName": "<service-name>",
  }
}

6. Environment variables — quick reference#

VariableWherePurposeExample
MW_AGENT_SERVICEHost (containers)Address/DNS of Host Agent172.17.0.1 (Docker), mw-service.mw-agent-ns.svc.cluster.local (K8s)
MW_API_KEYHost & DockerAuth token used by installer/runtimexxxx...
OTEL_SERVICE_NAMEHostAPM service name (auto-exporter uses this)orders-api
ASPNETCORE_HTTP_PORTS, ASPNETCORE_URLSDocker (ASP.NET)Bind HTTP ports / URLs inside container5000, http://0.0.0.0:5000

Serverless/direct uses appsettings.json keys under MW (ApiKey, TargetURL, ServiceName, etc.) rather than these env vars.

7. Troubleshooting#

  • No data (Host mode):
    • Verify the Host Agent is running and reachable. In containers, set MW_AGENT_SERVICE to your bridge gateway or K8s service DNS.
    • Ensure you prepended the instrumentation script before dotnet ....
  • Windows apps not instrumented:
  • Docker ASP.NET not listening:
    • Set ASPNETCORE_HTTP_PORTS and ASPNETCORE_URLS as shown above and map the port in your runtime.
  • Prefer direct ingest / serverless:
    • Use the MW.APM package and appsettings.json config with TargetURL to bypass a local agent. (NuGet package & config shown above.
  • Need cluster-wide auto-instrumentation:
    • Middleware supports OTel Kubernetes auto-instrumentation (including .NET) if you’d rather manage it at the platform layer.

Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us or join our Slack channel.

What did you think of this content?