EndpointTracker.AspNetCore 1.0.4

dotnet add package EndpointTracker.AspNetCore --version 1.0.4
                    
NuGet\Install-Package EndpointTracker.AspNetCore -Version 1.0.4
                    
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="EndpointTracker.AspNetCore" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EndpointTracker.AspNetCore" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="EndpointTracker.AspNetCore" />
                    
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 EndpointTracker.AspNetCore --version 1.0.4
                    
#r "nuget: EndpointTracker.AspNetCore, 1.0.4"
                    
#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 EndpointTracker.AspNetCore@1.0.4
                    
#: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=EndpointTracker.AspNetCore&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=EndpointTracker.AspNetCore&version=1.0.4
                    
Install as a Cake Tool

EndpointTracker.AspNetCore

NuGet License: MIT

A production-ready ASP.NET Core 8.0 middleware package that tracks API endpoint usage, counts hits, records access timestamps, and identifies unused endpoints. Perfect for monitoring, analytics, and identifying dead code in your APIs.

Features

  • Automatic Endpoint Discovery - Captures all mapped endpoints at startup
  • Thread-Safe Tracking - Uses ConcurrentDictionary and atomic operations for high-performance concurrent access
  • Hit Counting - Tracks how many times each endpoint has been accessed
  • Timestamp Tracking - Records last access time for each endpoint
  • Unused Endpoint Detection - Easily identify endpoints that have never been called
  • Built-in Metrics API - Exposes /metrics/endpoints and /metrics/unused routes
  • Zero Configuration - Works out of the box with minimal setup
  • Production Ready - Fully documented with XML comments, optimized for performance

Installation

dotnet add package EndpointTracker.AspNetCore

Quick Start

1. Register the Service

using EndpointTracker.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Register EndpointTracker
builder.Services.AddEndpointTracker();

var app = builder.Build();

2. Add Middleware

// Must be after UseRouting() (implicit in minimal APIs)
app.UseEndpointTracker();

3. Map Your Endpoints

app.MapGet("/api/users", () => Results.Ok(new[] { "User1", "User2" }))
   .WithName("GetUsers");

app.MapGet("/api/products/{id}", (int id) => Results.Ok($"Product {id}"))
   .WithName("GetProduct");

4. Add Metrics Endpoints & Register

// Add metrics routes
app.MapEndpointTrackerMetrics();

// Register all endpoints (must be AFTER all MapX calls)
app.UseEndpointTrackerRegistration();

app.Run();

Complete Example

using EndpointTracker.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Step 1: Add EndpointTracker service
builder.Services.AddEndpointTracker();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

// Step 2: Use tracking middleware
app.UseEndpointTracker();

// Step 3: Map your endpoints
app.MapGet("/api/users", () => Results.Ok(new { Users = new[] { "Alice", "Bob" } }))
   .WithName("GetUsers");

app.MapGet("/api/users/{id}", (int id) => Results.Ok(new { Id = id, Name = $"User{id}" }))
   .WithName("GetUserById");

app.MapPost("/api/users", (object user) => Results.Created("/api/users/123", user))
   .WithName("CreateUser");

// Step 4: Map metrics endpoints
app.MapEndpointTrackerMetrics();

// Step 5: Register all endpoints with tracker
app.UseEndpointTrackerRegistration();

app.Run();

Metrics API

GET /metrics/endpoints

Returns comprehensive endpoint usage statistics:

{
  "totalEndpoints": 10,
  "usedEndpoints": 7,
  "unusedEndpoints": 3,
  "totalRequests": 1543,
  "endpoints": [
    {
      "endpointPattern": "GET /api/users",
      "displayName": "GetUsers",
      "httpMethod": "GET",
      "hitCount": 342,
      "lastAccessedUtc": "2025-01-15T14:23:45.123Z",
      "registeredUtc": "2025-01-15T10:00:00.000Z"
    },
    {
      "endpointPattern": "GET /api/admin/settings",
      "displayName": "GetAdminSettings",
      "httpMethod": "GET",
      "hitCount": 0,
      "lastAccessedUtc": null,
      "registeredUtc": "2025-01-15T10:00:00.000Z"
    }
  ]
}

GET /metrics/unused

Returns only endpoints that have never been accessed:

{
  "count": 3,
  "endpoints": [
    {
      "endpointPattern": "GET /api/admin/settings",
      "displayName": "GetAdminSettings",
      "httpMethod": "GET",
      "hitCount": 0,
      "lastAccessedUtc": null,
      "registeredUtc": "2025-01-15T10:00:00.000Z"
    }
  ]
}

Programmatic Access

Inject IEndpointTrackerService to access tracking data programmatically:

app.MapGet("/custom-metrics", (IEndpointTrackerService tracker) =>
{
    var allUsage = tracker.GetAllEndpointUsage();
    var unused = tracker.GetUnusedEndpoints();
    var metrics = tracker.GetMetrics();

    return Results.Ok(new { allUsage, unused, metrics });
});

Advanced Usage

Custom Metrics Endpoint

app.MapGet("/api/health/dead-endpoints", (IEndpointTrackerService tracker) =>
{
    var unused = tracker.GetUnusedEndpoints();
    if (unused.Any())
    {
        return Results.Json(new
        {
            Status = "Warning",
            DeadEndpoints = unused.Count(),
            Details = unused
        });
    }
    return Results.Ok(new { Status = "Healthy", DeadEndpoints = 0 });
});

Reset Tracking Data

app.MapPost("/admin/reset-metrics", (IEndpointTrackerService tracker) =>
{
    tracker.Reset();
    return Results.Ok("Metrics reset successfully");
})
.RequireAuthorization("Admin"); // Add appropriate authorization

Thread Safety

All operations are thread-safe:

  • Uses ConcurrentDictionary<string, EndpointUsageInfo> for storing endpoint data
  • Employs Interlocked.Increment for atomic counter updates
  • Safe for high-concurrency scenarios

Performance Considerations

  • Minimal Overhead - Lightweight middleware adds negligible latency
  • In-Memory Storage - All data stored in memory (not suitable for distributed systems without external storage)
  • Singleton Service - Single instance maintains state across all requests
  • No I/O Operations - Pure in-memory operations for maximum speed

Integration with Monitoring Tools

Export metrics to your monitoring system:

// Example: Export to Prometheus, Application Insights, etc.
app.MapGet("/metrics/prometheus", (IEndpointTrackerService tracker) =>
{
    var metrics = tracker.GetMetrics();
    var prometheusFormat = FormatAsPrometheus(metrics);
    return Results.Text(prometheusFormat, "text/plain");
});

Redis Support

For complete Redis documentation (quick start, configuration, troubleshooting, and more), see REDIS.md.

Quick Example

var redis = ConnectionMultiplexer.Connect("localhost:6379");
builder.Services.AddEndpointTrackerRedis(redis);

That's it! Your metrics are now distributed across instances and persistent in Redis.

For all details, see REDIS.md.

Best Practices

  1. Call UseEndpointTrackerRegistration() last - After all MapX() calls to ensure all endpoints are registered
  2. Secure metrics endpoints - Add authentication/authorization in production
  3. Monitor unused endpoints - Regularly review unused endpoints for potential removal
  4. Consider distributed scenarios - For multi-instance deployments, use Redis support
  5. Tune flush interval - For high-traffic applications, adjust FlushIntervalMs (lower for more frequent updates, higher to reduce Redis load)
  6. Redis persistence - Enable Redis AOF or RDB persistence if you want metrics to survive Redis restarts

Requirements

  • .NET 8.0 or higher
  • ASP.NET Core 8.0
  • StackExchange.Redis 2.7+ (only required for Redis mode)

License

This project is licensed under the MIT License.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues, questions, or contributions, please visit the GitHub repository.

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. 
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
1.0.4 106 1/19/2026
1.0.3 233 12/19/2025
1.0.2 121 12/12/2025
1.0.1 447 12/8/2025
1.0.0 437 12/8/2025