Introduction to Middleware
What is Middleware?

Middleware in ASP.NET Core is software components that are assembled into an application pipeline to handle requests and responses. Each component:

  • Chooses whether to pass the request to the next component
  • Can perform work before and after the next component

// Simple middleware concept
app.Use(async (context, next) =>
{
    // Do work before the next middleware
    await next.Invoke();
    // Do work after the next middleware
});


Real-Life Analogy: Airport Security Check
Think of middleware as airport security checks:

  • Ticket Verification - Check if you have a valid ticket
  • Security Screening - Scan luggage and personal items
  • Passport Control - Verify travel documents
  • Boarding Gate - Final check before boarding

Each step can either pass you to the next or reject you entirely.

2. Understanding the Request Pipeline
Basic Pipeline Structure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Pipeline Flow Visualization

Request → Middleware 1 → Middleware 2 → ... → Middleware N → Endpoint → Response

Lifecycle Example: E-Commerce Request
// Program.cs - Complete pipeline setup
var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddControllers();
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();

var app = builder.Build();

// Configure pipeline
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseRequestLogging(); // Custom middleware
app.UsePerformanceMonitoring(); // Custom middleware

app.MapControllers();

app.Run();

3. Built-in Middleware Components
Essential Built-in Middleware

3.1 Static Files Middleware
// Serve static files like HTML, CSS, JavaScript, images
app.UseStaticFiles();

// Serve files from custom directory
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});


3.2 Routing Middleware
app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");

    endpoints.MapGet("/hello", async context =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
});


3.3 Authentication & Authorization
app.UseAuthentication();
app.UseAuthorization();

3.4 CORS Middleware
// Add CORS service
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll",
        builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        });
});

// Use CORS middleware
app.UseCors("AllowAll");


4. Creating Custom Middleware
4.1 Inline Middleware

app.Use(async (context, next) =>
{
    var startTime = DateTime.UtcNow;

    // Call the next middleware
    await next();

    var endTime = DateTime.UtcNow;
    var duration = endTime - startTime;

    Console.WriteLine($"Request took: {duration.TotalMilliseconds}ms");
});


4.2 Class-Based Middleware
Basic Custom Middleware Class
// Custom logging middleware
public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var startTime = DateTime.UtcNow;

        _logger.LogInformation($"Starting request: {context.Request.Method} {context.Request.Path}");

        try
        {
            await _next(context);
        }
        finally
        {
            var endTime = DateTime.UtcNow;
            var duration = endTime - startTime;

            _logger.LogInformation(
                $"Completed request: {context.Request.Method} {context.Request.Path} " +
                $"with status: {context.Response.StatusCode} in {duration.TotalMilliseconds}ms");
        }
    }
}

// Extension method for easy use
public static class RequestLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestLoggingMiddleware>();
    }
}


4.3 Factory-Based Middleware
// Factory-activated middleware
public class TimingMiddleware : IMiddleware
{
    private readonly ILogger<TimingMiddleware> _logger;

    public TimingMiddleware(ILogger<TimingMiddleware> logger)
    {
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var stopwatch = Stopwatch.StartNew();

        _logger.LogInformation($"Starting request: {context.Request.Path}");

        await next(context);

        stopwatch.Stop();
        _logger.LogInformation($"Request {context.Request.Path} completed in {stopwatch.ElapsedMilliseconds}ms");
    }
}

// Register in DI container
builder.Services.AddTransient<TimingMiddleware>();


5. Real-World Middleware Examples
5.1 API Key Authentication Middleware

// API Key Authentication Middleware
public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;
    private const string API_KEY_HEADER = "X-API-Key";

    public ApiKeyMiddleware(RequestDelegate next, IConfiguration configuration)
    {
        _next = next;
        _configuration = configuration;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Skip API key check for certain paths
        if (context.Request.Path.StartsWithSegments("/public"))
        {
            await _next(context);
            return;
        }

        if (!context.Request.Headers.TryGetValue(API_KEY_HEADER, out var extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("API Key is missing");
            return;
        }

        var validApiKeys = _configuration.GetSection("ValidApiKeys").Get<List<string>>();

        if (!validApiKeys.Contains(extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid API Key");
            return;
        }

        await _next(context);
    }
}

// Extension method
public static class ApiKeyMiddlewareExtensions
{
    public static IApplicationBuilder UseApiKeyAuthentication(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ApiKeyMiddleware>();
    }
}

5.2 Request/Response Logging Middleware
// Detailed request/response logging middleware
public class DetailedLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<DetailedLoggingMiddleware> _logger;

    public DetailedLoggingMiddleware(RequestDelegate next, ILogger<DetailedLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Log request
        await LogRequest(context);

        // Copy original response body stream
        var originalBodyStream = context.Response.Body;

        using var responseBody = new MemoryStream();
        context.Response.Body = responseBody;

        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred");
            throw;
        }
        finally
        {
            // Log response
            await LogResponse(context, responseBody, originalBodyStream);
        }
    }

    private async Task LogRequest(HttpContext context)
    {
        context.Request.EnableBuffering();

        var request = $"{context.Request.Method} {context.Request.Path}{context.Request.QueryString}";
        var headers = string.Join(", ", context.Request.Headers.Select(h => $"{h.Key}: {h.Value}"));

        _logger.LogInformation($"Request: {request}");
        _logger.LogDebug($"Headers: {headers}");

        if (context.Request.ContentLength > 0)
        {
            using var reader = new StreamReader(context.Request.Body, Encoding.UTF8,
                leaveOpen: true);
            var body = await reader.ReadToEndAsync();
            context.Request.Body.Position = 0;

            _logger.LogDebug($"Request Body: {body}");
        }
    }

    private async Task LogResponse(HttpContext context, MemoryStream responseBody, Stream originalBodyStream)
    {
        responseBody.Position = 0;
        var responseText = await new StreamReader(responseBody).ReadToEndAsync();
        responseBody.Position = 0;

        _logger.LogInformation($"Response: {context.Response.StatusCode}");
        _logger.LogDebug($"Response Body: {responseText}");

        await responseBody.CopyToAsync(originalBodyStream);
        context.Response.Body = originalBodyStream;
    }
}

5.3 Rate Limiting Middleware
// Simple rate limiting middleware
public class RateLimitingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly Dictionary<string, List<DateTime>> _requestLog = new();
    private readonly object _lockObject = new object();
    private readonly int _maxRequests = 100;
    private readonly TimeSpan _timeWindow = TimeSpan.FromMinutes(1);

    public RateLimitingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "unknown";

        if (IsRateLimited(clientIp))
        {
            context.Response.StatusCode = 429; // Too Many Requests
            await context.Response.WriteAsync("Rate limit exceeded. Please try again later.");
            return;
        }

        await _next(context);
    }

    private bool IsRateLimited(string clientIp)
    {
        lock (_lockObject)
        {
            var now = DateTime.UtcNow;

            if (!_requestLog.ContainsKey(clientIp))
            {
                _requestLog[clientIp] = new List<DateTime>();
            }

            // Remove old requests outside the time window
            _requestLog[clientIp].RemoveAll(time => now - time > _timeWindow);

            // Check if over limit
            if (_requestLog[clientIp].Count >= _maxRequests)
            {
                return true;
            }

            // Log this request
            _requestLog[clientIp].Add(now);
            return false;
        }
    }
}

5.4 Correlation ID Middleware
// Correlation ID middleware for request tracking
public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    private const string CORRELATION_ID_HEADER = "X-Correlation-ID";

    public CorrelationIdMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, ILogger<CorrelationIdMiddleware> logger)
    {
        var correlationId = GetOrCreateCorrelationId(context);

        // Add correlation ID to response headers
        context.Response.OnStarting(() =>
        {
            context.Response.Headers[CORRELATION_ID_HEADER] = correlationId;
            return Task.CompletedTask;
        });

        // Add to logger scope
        using (logger.BeginScope("{CorrelationId}", correlationId))
        {
            await _next(context);
        }
    }

    private string GetOrCreateCorrelationId(HttpContext context)
    {
        if (context.Request.Headers.TryGetValue(CORRELATION_ID_HEADER, out var correlationId))
        {
            return correlationId!;
        }

        return Guid.NewGuid().ToString();
    }
}

6. Middleware Ordering and Execution
Critical Middleware Order

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 1. Exception/Error Handling
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    // 2. HTTPS Redirection
    app.UseHttpsRedirection();

    // 3. Static Files
    app.UseStaticFiles();

    // 4. Routing
    app.UseRouting();

    // 5. Custom Middleware (Authentication, Logging, etc.)
    app.UseCorrelationId();
    app.UseRequestLogging();
    app.UseApiKeyAuthentication();

    // 6. CORS
    app.UseCors("AllowAll");

    // 7. Authentication & Authorization
    app.UseAuthentication();
    app.UseAuthorization();

    // 8. Endpoints
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}


Ordering Impact Example
// Wrong order - Authentication won't work properly
app.UseEndpoints(endpoints => { /* ... */ });
app.UseAuthentication(); // This won't be called for endpoint requests

// Correct order
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { /* ... */ });

7. Advanced Middleware Patterns
7.1 Conditional Middleware

// Conditional middleware based on request path
public class ConditionalMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _pathStartsWith;

    public ConditionalMiddleware(RequestDelegate next, string pathStartsWith)
    {
        _next = next;
        _pathStartsWith = pathStartsWith;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (context.Request.Path.StartsWithSegments(_pathStartsWith))
        {
            // Custom logic for specific paths
            context.Items["CustomFeature"] = "Enabled";
        }

        await _next(context);
    }
}

// Usage with multiple conditions
app.MapWhen(context => context.Request.Path.StartsWithSegments("/api"),
    apiApp =>
    {
        apiApp.UseMiddleware<ApiSpecificMiddleware>();
        apiApp.UseRouting();
        apiApp.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    });

7.2 Branching Middleware Pipeline
// Branching for different pipeline configurations
app.Map("/admin", adminApp =>
{
    adminApp.UseMiddleware<AdminAuthenticationMiddleware>();
    adminApp.UseRouting();
    adminApp.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "admin",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
});

app.Map("/api", apiApp =>
{
    apiApp.UseMiddleware<ApiKeyMiddleware>();
    apiApp.UseRouting();
    apiApp.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
});

7.3 Middleware with Configuration
// Configurable middleware
public class ConfigurableMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ConfigurableMiddlewareOptions _options;

    public ConfigurableMiddleware(RequestDelegate next, IOptions<ConfigurableMiddlewareOptions> options)
    {
        _next = next;
        _options = options.Value;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        if (_options.EnableFeature && context.Request.Path.StartsWithSegments(_options.ApplyToPath))
        {
            // Apply middleware logic
            await ApplyCustomLogic(context);
        }

        await _next(context);
    }

    private async Task ApplyCustomLogic(HttpContext context)
    {
        // Custom implementation
        context.Items["CustomFeatureApplied"] = true;
    }
}

public class ConfigurableMiddlewareOptions
{
    public bool EnableFeature { get; set; }
    public string ApplyToPath { get; set; } = "/api";
}

// Registration
builder.Services.Configure<ConfigurableMiddlewareOptions>(options =>
{
    options.EnableFeature = true;
    options.ApplyToPath = "/secure";
});


8. Error Handling Middleware
Global Exception Handling Middleware

// Comprehensive error handling middleware
public class GlobalExceptionHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionHandlerMiddleware> _logger;
    private readonly IWebHostEnvironment _env;

    public GlobalExceptionHandlerMiddleware(
        RequestDelegate next,
        ILogger<GlobalExceptionHandlerMiddleware> logger,
        IWebHostEnvironment env)
    {
        _next = next;
        _logger = logger;
        _env = env;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred");
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";

        var errorResponse = new ErrorResponse
        {
            Success = false,
            Error = "An unexpected error occurred"
        };

        switch (exception)
        {
            case UnauthorizedAccessException:
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                errorResponse.Error = "Unauthorized access";
                break;

            case KeyNotFoundException:
                context.Response.StatusCode = StatusCodes.Status404NotFound;
                errorResponse.Error = "Resource not found";
                break;

            case ValidationException vex:
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                errorResponse.Error = "Validation failed";
                errorResponse.Details = vex.Errors;
                break;

            default:
                context.Response.StatusCode = StatusCodes.Status500InternalServerError;
                if (_env.IsDevelopment())
                {
                    errorResponse.Details = exception.ToString();
                }
                break;
        }

        var json = JsonSerializer.Serialize(errorResponse, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });

        await context.Response.WriteAsync(json);
    }
}

public class ErrorResponse
{
    public bool Success { get; set; }
    public string Error { get; set; } = string.Empty;
    public object? Details { get; set; }
}


Custom Exception Classes
// Custom exception for business logic
public class BusinessException : Exception
{
    public string ErrorCode { get; }

    public BusinessException(string errorCode, string message) : base(message)
    {
        ErrorCode = errorCode;
    }
}

public class ValidationException : Exception
{
    public Dictionary<string, string[]> Errors { get; }

    public ValidationException(Dictionary<string, string[]> errors)
        : base("Validation failed")
    {
        Errors = errors;
    }
}


9. Performance Optimization
Response Caching Middleware

// Custom response caching middleware
public class ResponseCachingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMemoryCache _cache;
    private readonly ILogger<ResponseCachingMiddleware> _logger;

    public ResponseCachingMiddleware(
        RequestDelegate next,
        IMemoryCache cache,
        ILogger<ResponseCachingMiddleware> logger)
    {
        _next = next;
        _cache = cache;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var cacheKey = GenerateCacheKey(context.Request);

        if (context.Request.Method == "GET" && _cache.TryGetValue(cacheKey, out byte[]? cachedResponse))
        {
            _logger.LogInformation($"Serving cached response for {context.Request.Path}");
            context.Response.ContentType = "application/json";
            context.Response.ContentLength = cachedResponse?.Length ?? 0;
            await context.Response.Body.WriteAsync(cachedResponse!);
            return;
        }

        var originalBodyStream = context.Response.Body;
        using var responseBody = new MemoryStream();
        context.Response.Body = responseBody;

        await _next(context);

        if (context.Response.StatusCode == 200)
        {
            var responseData = responseBody.ToArray();

            // Cache the response
            var cacheOptions = new MemoryCacheEntryOptions()
                .SetAbsoluteExpiration(TimeSpan.FromMinutes(5))
                .SetSlidingExpiration(TimeSpan.FromMinutes(1));

            _cache.Set(cacheKey, responseData, cacheOptions);

            _logger.LogInformation($"Cached response for {context.Request.Path}");
        }

        await responseBody.CopyToAsync(originalBodyStream);
    }

    private string GenerateCacheKey(HttpRequest request)
    {
        return $"{request.Path}{request.QueryString}";
    }
}


Performance Monitoring Middleware
// Performance monitoring middleware
public class PerformanceMonitoringMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<PerformanceMonitoringMiddleware> _logger;

    public PerformanceMonitoringMiddleware(
        RequestDelegate next,
        ILogger<PerformanceMonitoringMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = Stopwatch.StartNew();
        var startMemory = GC.GetTotalMemory(false);

        try
        {
            await _next(context);
        }
        finally
        {
            stopwatch.Stop();
            var endMemory = GC.GetTotalMemory(false);
            var memoryUsed = endMemory - startMemory;

            _logger.LogInformation(
                $"Performance - Path: {context.Request.Path}, " +
                $"Duration: {stopwatch.ElapsedMilliseconds}ms, " +
                $"Memory: {memoryUsed} bytes, " +
                $"Status: {context.Response.StatusCode}");

            // Log warning for slow requests
            if (stopwatch.ElapsedMilliseconds > 1000)
            {
                _logger.LogWarning(
                    $"Slow request detected: {context.Request.Path} " +
                    $"took {stopwatch.ElapsedMilliseconds}ms");
            }
        }
    }
}


10. Testing Middleware
Unit Testing Middleware

// Unit tests for custom middleware
public class RequestLoggingMiddlewareTests
{
    [Fact]
    public async Task InvokeAsync_LogsRequestInformation()
    {
        // Arrange
        var loggerMock = new Mock<ILogger<RequestLoggingMiddleware>>();
        var nextMock = new Mock<RequestDelegate>();

        var middleware = new RequestLoggingMiddleware(nextMock.Object, loggerMock.Object);

        var context = new DefaultHttpContext();
        context.Request.Method = "GET";
        context.Request.Path = "/api/test";

        // Act
        await middleware.InvokeAsync(context);

        // Assert
        nextMock.Verify(next => next(context), Times.Once);
        // Verify logging calls
    }

    [Fact]
    public async Task InvokeAsync_WhenException_LogsError()
    {
        // Arrange
        var loggerMock = new Mock<ILogger<RequestLoggingMiddleware>>();
        var nextMock = new Mock<RequestDelegate>();
        nextMock.Setup(next => next(It.IsAny<HttpContext>()))
                .ThrowsAsync(new Exception("Test exception"));

        var middleware = new RequestLoggingMiddleware(nextMock.Object, loggerMock.Object);
        var context = new DefaultHttpContext();

        // Act & Assert
        await Assert.ThrowsAsync<Exception>(() => middleware.InvokeAsync(context));

        // Verify error was logged
    }
}

// Integration testing
public class MiddlewareIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;

    public MiddlewareIntegrationTests(WebApplicationFactory<Program> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task CustomMiddleware_AddsCorrelationHeader()
    {
        // Arrange
        var client = _factory.CreateClient();

        // Act
        var response = await client.GetAsync("/api/test");

        // Assert
        response.Headers.Contains("X-Correlation-ID").Should().BeTrue();
    }
}

11. Best Practices and Alternatives
Middleware Best Practices


11.1 Do's and Don'ts
Do:

  • Keep middleware focused and single-purpose
  • Use dependency injection properly
  • Handle exceptions appropriately
  • Consider performance implications
  • Use appropriate logging levels

Don't:

  • Put business logic in middleware
  • Block the pipeline unnecessarily
  • Ignore async/await patterns
  • Forget to call next() when needed

11.2 Performance Considerations
// Good - Async all the way
public async Task InvokeAsync(HttpContext context)
{
    await SomeAsyncOperation();
    await _next(context);
}

// Bad - Mixing sync and async
public async Task InvokeAsync(HttpContext context)
{
    SomeSyncOperation(); // Blocks thread
    await _next(context);
}

Alternatives to Custom Middleware
11.3 Action Filters
// Use action filters for controller-specific logic
public class LogActionFilter : IActionFilter
{
    private readonly ILogger<LogActionFilter> _logger;

    public LogActionFilter(ILogger<LogActionFilter> logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation($"Executing action: {context.ActionDescriptor.DisplayName}");
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _logger.LogInformation($"Executed action: {context.ActionDescriptor.DisplayName}");
    }
}


11.4 Endpoint Filters
// Endpoint filters for minimal APIs
app.MapGet("/api/products", () =>
{
    return Results.Ok(products);
})
.AddEndpointFilter<LoggingEndpointFilter>();

public class LoggingEndpointFilter : IEndpointFilter
{
    public async ValueTask<object?> InvokeAsync(
        EndpointFilterInvocationContext context,
        EndpointFilterDelegate next)
    {
        Console.WriteLine($"Before: {context.HttpContext.Request.Path}");
        var result = await next(context);
        Console.WriteLine($"After: {context.HttpContext.Request.Path}");

        return result;
    }
}


Complete Real-World Example: E-Commerce Pipeline
// Complete e-commerce application pipeline
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Exception handling
    app.UseGlobalExceptionHandler();

    // Security
    app.UseHsts();
    app.UseHttpsRedirection();

    // Performance
    app.UseResponseCompression();
    app.UseResponseCaching();

    // Static files
    app.UseStaticFiles();

    // Routing
    app.UseRouting();

    // Custom middleware
    app.UseCorrelationId();
    app.UseRequestLogging();
    app.UsePerformanceMonitoring();

    // Authentication & Authorization
    app.UseAuthentication();
    app.UseAuthorization();

    // Rate limiting for API
    app.MapWhen(context => context.Request.Path.StartsWithSegments("/api"),
        apiApp =>
        {
            apiApp.UseRateLimiting();
            apiApp.UseApiKeyAuthentication();
        });

    // Endpoints
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();

        // Health check
        endpoints.MapHealthChecks("/health");
    });
}

HostForLIFE ASP.NET Core 10.0 Hosting

European Best, cheap and reliable ASP.NET Core 10.0 hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.