DiagnosticExplorer.Hosting 5.3.0

dotnet add package DiagnosticExplorer.Hosting --version 5.3.0
                    
NuGet\Install-Package DiagnosticExplorer.Hosting -Version 5.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DiagnosticExplorer.Hosting" Version="5.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DiagnosticExplorer.Hosting" Version="5.3.0" />
                    
Directory.Packages.props
<PackageReference Include="DiagnosticExplorer.Hosting" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DiagnosticExplorer.Hosting --version 5.3.0
                    
#r "nuget: DiagnosticExplorer.Hosting, 5.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DiagnosticExplorer.Hosting@5.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DiagnosticExplorer.Hosting&version=5.3.0
                    
Install as a Cake Addin
#tool nuget:?package=DiagnosticExplorer.Hosting&version=5.3.0
                    
Install as a Cake Tool

DiagnosticExplorer

Add live diagnostic data to a .NET application, then inspect it in a browser.

Dashboard

Diagnostic Explorer dashboard showing registered gadgets and live gadget events

Inspect registered objects, their properties, and live diagnostic events from one browser view.

Quick Start

This package adds configuration-based Diagnostic Explorer hosting:

<PackageReference Include="DiagnosticExplorer.Hosting" Version="5.0.0" />

This appsettings.json section enables a local viewer and a remote-service connection. Use either host or both, and tune retention without changing code:

{
  "DiagnosticExplorer": {
    "Enabled": true,
    "Hosts": [
      { "Type": "SelfHost", "Url": "http://127.0.0.1:50101" },
      { "Type": "Remote", "Url": "http://localhost:50000/diagnostics" }
    ],
    "EventRetention": {
      "MaxEventsPerSink": 1000,
      "MaxAgeMinutes": 30
    },
    "LogEventRetention": {
      "MaxEvents": 5000,
      "MaxAgeMinutes": 5
    }
  }
}

This generic-host setup reads the host configuration, starts the selected hosts, registers diagnostic objects, and configures their presentation:

using DiagnosticExplorer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddSingleton<WidgetService>();
builder.Services.ConfigureDiagnosticExplorer(
    builder.Configuration,
    diagnostics =>
    {
        diagnostics.RegisterObjects(RegisterObjects);
        ConfigureClasses(diagnostics);
        ConfigureEventRoutes(diagnostics);
    }
);

await builder.Build().RunAsync();

RegisterObjects runs when diagnostics are collected. Resolve an application service, then register the dynamic objects it owns:

private static void RegisterObjects(IDiagRegistrar registrar)
{
    WidgetService widgetService = registrar.GetRequiredService<WidgetService>();

    registrar.RegisterService<WidgetService>("Application", "Widget service");
    foreach (Widget widget in widgetService.Widgets)
        registrar.Register(widget, "Widgets", widget.Name);
}

RegisterService<T> resolves T from the application service provider before registering it. Use it for long-lived services, typically singletons. Register remains available for objects created at runtime.

Without a type profile, Diagnostic Explorer displays public scalar properties, collection counts, and complex values as drilldown icons. A type profile lets you start small and make the display intentional. This is a good first profile:

private static void ConfigureClasses(IDiagConfigurator diagnostics)
{
    diagnostics.Configure<Widget>(options =>
    {
        options.ExcludeAll();

        options.Property(widget => widget.Name)
            .WithLabel("Widget name")
            .AllowSet();
        options.Property(widget => widget.Status);
    });
}

ExcludeAll() starts with an empty display, then each Property(...) adds one row. Use IncludeAll() when the default public-property view is closer to what you need. WithLabel(...) changes only the text users see; it does not change which property is read. AllowSet() makes a writable property editable in the viewer.

Organize properties

Add Category(...) when a group makes the display easier to scan. Properties without a category appear at the top of the view, so there is no need to create a catch-all category such as General.

diagnostics.Configure<Widget>(options =>
{
    options.ExcludeAll();

    options.Property(widget => widget.Name).WithLabel("Widget name");
    options.Property(widget => widget.Status).WithCategory("Health");
    options.Property(widget => widget.LastUpdated)
        .WithLabel("Last updated")
        .WithCategory("Health")
        .ShowElapsed();
});

Show nested details

Use Expand() to place an object's properties directly in the current view. First-level expanded sections start open by default. Pass false when the details should start collapsed.

diagnostics.Configure<Widget>(options =>
{
    options.Property(widget => widget.Connection)
        .WithLabel("Connection")
        .Expand(initiallyExpanded: false)
        .WithExpandedHover();
});

WithExpandedHover() opens the same nested details on hover. It is useful when you want the main display compact but still need quick inspection.

Configure collections

For supported collection properties, Property(...) shows a count by default. Choose one of the collection outputs to show the items instead:

diagnostics.Configure<Widget>(options =>
{
    options.Property(widget => widget.Components)
        .WithLabel("Components")
        .WithCategory("Inventory")
        .ListItems(items => items
            .WithName(component => component.Name)
            .WithValue(component => component.Status))
        .WithMaxItems(50)
        .WithDrillDown();

    options.Property(widget => widget.Tags)
        .WithCategory("Inventory")
        .ConcatItems(", ")
        .WithTextWrap();
});

ListItems(...) gives each item its own row. ConcatItems(...) creates one compact text value. ExpandItems(items => items.WithName(item => item.Id)) creates an expanded section for the collection, then an item section for each value with that item's diagnostic properties. Without WithName(...), item names default to the collection name and a zero-based index. A configured name must be distinct for every item; include an identifier when a readable name alone is not unique. Pass WithInitiallyCollapsed() when the collection should start collapsed:

options.Property(widget => widget.Gadgets)
    .ExpandItems(items => items.WithName(gadget => gadget.FullName).WithInitiallyCollapsed());

Chain WithPrimaryPropertiesOnly() after ExpandItems(...) or Expand() to show only direct, uncategorized properties. Nested Expand() and Custom() sections are omitted, keeping the expanded section focused on primary values.

WithMaxItems(...) limits list, category, and concatenated outputs; the viewer shows how many items were omitted. WithTextWrap() lets a concatenated value wrap instead of cutting it off.

Arrays, the common collection interfaces, List<T>, HashSet<T>, ObservableCollection<T>, and BindingList<T> are supported. Dictionaries are also supported and display key/value pairs.

Group derived diagnostics

Use Custom(...).Expand() to group derived properties in an expandable main view section. The projection may include a collection output:

options.Custom("Gadgets", projection =>
{
    projection.Property("All gadgets", form => form.Gadgets)
    .ExpandItems(items => items.WithName(gadget => gadget.FullName));
}).Expand();

The Gadgets section contains the generated item sections directly; an ExpandItems(...) member does not add another collection section inside an expanded custom projection. This is useful when the group is diagnostic-only rather than a property on the application type.

Drill into a value

WithDrillDown() makes a complex value, collection item, or custom property interactive while keeping its rendered value. Use WithDrillDownOnly() to show only a [show more] text value, or pass a custom string instead.

diagnostics.Configure<Widget>(options =>
{
    options.Property(widget => widget.Configuration)
        .WithDrillDown(maxItems: 50);

    options.Property("Connection snapshot", widget => new
        {
            widget.Connection.Endpoint,
            widget.Connection.IsConnected,
        })
        .WithDrillDownOnly("View connection");
});

diagnostics.ConfigureDrillDown<WidgetConfiguration>(options =>
{
    options.ExcludeAll();
    options.Property(instance => instance.Status);
    options.Property(instance => instance.Owner).WithDrillDown();
});

ConfigureDrillDown<T>(...) controls what appears in that overlay. If you do not add a drilldown profile, Diagnostic Explorer reuses the normal type profile. Drilldowns are not shown for null values or empty collections.

Use Property("name", value) for a named or computed property. AsJson() with WithJsonHover() fetches JSON only when users hover over the value.

Private fields and anonymous objects

Use a named delegate property to expose computed or private state. Write the configuration inside the declaring type when it needs private-field access:

private static void ConfigureDiagnostics(IDiagConfigurator diagnostics)
{
    diagnostics.Configure<Widget>(options =>
    {
        options.Property("Retry count", widget => widget._retryCount).WithCategory("Internal");
        options.Property("Last error", widget => widget._lastError?.Message).WithCategory("Internal");
    });
}

For DateTime and DateTimeOffset values, date display options are available directly from Property:

options.Property(widget => widget._lastUpdated).ShowElapsed();
options.Property("Last updated", widget => widget._lastUpdated).ShowDate(false).ShowElapsed();

For RateCounter values, configure rate and total displays the same way:

options.Property(widget => widget._requests).ShowRate(false).ShowTotal();
options.Property("Background requests", widget => widget._backgroundRequests).ShowTotal();

Return an anonymous object for a small, read-only diagnostic snapshot. Its generated public properties render in the drilldown view:

options.Property(
        "Connection snapshot",
        widget => new
        {
            widget.Connection.Endpoint,
            widget.Connection.IsConnected,
        }
    )
    .WithDrillDownOnly("View connection");

The widget sample configuration has more examples of custom properties, collection outputs, warnings, and errors. For an agent-focused, end-to-end integration guide, see configuring Diagnostic Explorer in an application.

This helper routes events from named loggers to separate event sinks. Each integration below uses these same routes:

private static void ConfigureEventRoutes(IDiagConfigurator diagnostics)
{
    diagnostics.ConfigureEventRouting(routes =>
        routes
            .UseMatchMode(EventSinkRouteMatchMode.AllMatches)
            .Route("Widgets", route => route.AtLeast(LogLevel.Information).To("Widgets", "Widget Events"))
            .Route("Gadgets", route => route.AtLeast(LogLevel.Warning).To("Gadgets", "Gadget Warnings"))
            .Route("*", route => route.AtLeast(LogLevel.Error).To("System", "Errors")));
}

For an application without a generic host, create the configuration, register objects directly, and start the configured hosts yourself:

using DiagnosticExplorer;

DiagnosticConfiguration diagnostics = DiagnosticManager.Configure(config =>
{
    config.ConfigureHosting(applicationConfiguration);
    config.RegisterObjects(registrar => registrar.Register(widget, "Widgets", "Widget 42"));
    ConfigureClasses(config);
    ConfigureEventRoutes(config);
});

await DiagnosticHostingService.StartAsync(diagnostics);
try
{
    RunApplication();
}
finally
{
    await DiagnosticHostingService.Stop();
}

Run the application and open the configured SelfHost URL in a browser. For a Remote host, run DiagnosticService, open its configured URL, and select your registered application.

Download

Download the latest DiagnosticService Windows Service installer.

Microsoft.Extensions.Logging

This optional package forwards Microsoft.Extensions.Logging events to Diagnostic Explorer:

<PackageReference Include="DiagnosticExplorer.Extensions.Logging" Version="5.0.0" />

This registers the logging provider after ConfigureDiagnosticExplorer:

using DiagnosticExplorer;
using DiagnosticExplorer.Extensions.Logging;
using Microsoft.Extensions.Logging;

services.AddLogging(logging => logging.AddDiagnosticExplorer());

The provider sends matching Microsoft.Extensions.Logging events to Diagnostic Explorer, including structured properties:

logger.LogInformation("Processed {WidgetCount} widgets", widgetCount);

NLog

This package adds a Diagnostic Explorer target to NLog:

<PackageReference Include="DiagnosticExplorer.NLog" Version="5.0.0" />

This configuration sends NLog events through the routes configured above:

using DiagnosticExplorer.NLog;
using NLog;
using NLog.Config;

LoggingConfiguration logging = new();
logging.AddDiagnosticExplorer();
LogManager.Configuration = logging;

NLog templates retain their event properties:

logger.Info("Processed {WidgetCount} widgets", widgetCount);

Serilog

This package adds a Diagnostic Explorer sink to Serilog:

<PackageReference Include="DiagnosticExplorer.Serilog" Version="5.0.0" />

This configuration sends Serilog events through the routes configured above:

using DiagnosticExplorer.Serilog;
using Serilog;

using ILogger logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .WriteTo.DiagnosticExplorer()
    .CreateLogger();

Serilog properties are forwarded with the event:

logger.Information("Processed {WidgetCount} widgets", widgetCount);
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.3.0 286 9/2/2026
5.2.0 85 9/2/2026
5.1.0 93 9/1/2026
5.0.31 91 8/31/2026
5.0.30 102 8/30/2026
5.0.29 95 8/30/2026
5.0.28 90 8/29/2026
5.0.27 95 8/29/2026
5.0.26 102 8/28/2026
5.0.25 96 8/28/2026
5.0.24 88 8/28/2026
5.0.23 89 8/28/2026
5.0.22 88 8/28/2026
5.0.21 84 8/28/2026
5.0.20 96 8/28/2026
5.0.19 93 8/28/2026
5.0.18 94 8/27/2026
5.0.17 87 8/27/2026
5.0.16 91 8/27/2026
5.0.15 97 8/27/2026
Loading failed