YARP (Yet Another Reverse Proxy) Production Guide: .NET 8 Patterns 2025

Nov 15, 2025
yarpreverse-proxy.netdotnet-8
0

YARP (Yet Another Reverse Proxy) is Microsoft's high-performance reverse proxy built on .NET, designed for modern microservices architectures. Unlike traditional reverse proxies, YARP is code-first, integrates seamlessly with .NET applications, and provides exceptional performance for routing, load balancing, and request transformation.

This comprehensive guide covers YARP production deployment patterns, performance optimization, configuration strategies, authentication integration, and enterprise-scale deployment practices. You'll learn how to configure YARP for high-throughput scenarios, implement advanced routing patterns, integrate with authentication systems, and monitor production deployments.

Understanding YARP

What is YARP?

YARP is a reverse proxy library for .NET that:

  • Routes requests to backend services
  • Load balances traffic across multiple instances
  • Transforms requests/responses on the fly
  • Handles authentication at the proxy layer
  • Provides observability through metrics and logging

YARP vs Other Solutions

YARP Advantages:

  • Native .NET integration
  • Code-first configuration
  • High performance (built on ASP.NET Core)
  • Extensible middleware pipeline
  • Microsoft-supported

When to Use YARP:

  • .NET-based microservices
  • Need for code-based configuration
  • High-performance requirements
  • Integration with .NET authentication

Getting Started with YARP

Installation

Install YARP NuGet package:

dotnet add package Yarp.ReverseProxy

Basic Configuration

Configure YARP in Program.cs:

var builder = WebApplication.CreateBuilder(args);

// Add YARP
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

// Use YARP
app.MapReverseProxy();

app.Run();

Configuration File

Define routes and clusters in appsettings.json:

{
  "ReverseProxy": {
    "Routes": {
      "api-route": {
        "ClusterId": "api-cluster",
        "Match": {
          "Path": "/api/{**catch-all}"
        }
      }
    },
    "Clusters": {
      "api-cluster": {
        "Destinations": {
          "destination1": {
            "Address": "https://api1.example.com/"
          },
          "destination2": {
            "Address": "https://api2.example.com/"
          }
        }
      }
    }
  }
}

Code-Based Configuration

Programmatic Route Configuration

Configure routes in code for flexibility:

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
    .LoadFromMemory(GetRoutes(), GetClusters());

static RouteConfig[] GetRoutes()
{
    return new[]
    {
        new RouteConfig
        {
            RouteId = "api-route",
            ClusterId = "api-cluster",
            Match = new RouteMatch
            {
                Path = "/api/{**catch-all}"
            },
            Transforms = new[]
            {
                new Dictionary<string, string>
                {
                    ["PathPattern"] = "/{**catch-all}"
                }
            }
        }
    };
}

static ClusterConfig[] GetClusters()
{
    return new[]
    {
        new ClusterConfig
        {
            ClusterId = "api-cluster",
            LoadBalancingPolicy = "RoundRobin",
            Destinations = new Dictionary<string, DestinationConfig>
            {
                ["destination1"] = new DestinationConfig
                {
                    Address = "https://api1.example.com/"
                },
                ["destination2"] = new DestinationConfig
                {
                    Address = "https://api2.example.com/"
                }
            },
            HealthCheck = new HealthCheckConfig
            {
                Enabled = true,
                Interval = TimeSpan.FromSeconds(30),
                Timeout = TimeSpan.FromSeconds(5),
                Path = "/health"
            }
        }
    };
}

Load Balancing Strategies

Round Robin

Distribute requests evenly:

new ClusterConfig
{
    ClusterId = "api-cluster",
    LoadBalancingPolicy = "RoundRobin",
    Destinations = /* ... */
}

Least Requests

Route to destination with fewest active requests:

new ClusterConfig
{
    ClusterId = "api-cluster",
    LoadBalancingPolicy = "LeastRequests",
    Destinations = /* ... */
}

Power of Two Choices

Select two random destinations, choose one with fewer requests:

new ClusterConfig
{
    ClusterId = "api-cluster",
    LoadBalancingPolicy = "PowerOfTwoChoices",
    Destinations = /* ... */
}

Custom Load Balancing

Implement custom load balancing policy:

public class CustomLoadBalancingPolicy : ILoadBalancingPolicy
{
    public string Name => "Custom";

    public DestinationState PickDestination(
        HttpContext context,
        ClusterState cluster,
        IReadOnlyList<DestinationState> availableDestinations)
    {
        // Custom selection logic
        return availableDestinations
            .OrderBy(d => d.ConcurrentRequestCount)
            .First();
    }
}

// Register custom policy
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
    .AddLoadBalancingPolicy<CustomLoadBalancingPolicy>("Custom");

Request/Response Transformation

Path Transformation

Transform request paths:

new RouteConfig
{
    RouteId = "api-route",
    ClusterId = "api-cluster",
    Match = new RouteMatch
    {
        Path = "/api/v1/{**catch-all}"
    },
    Transforms = new[]
    {
        new Dictionary<string, string>
        {
            ["PathPattern"] = "/v1/{**catch-all}"
        }
    }
}

Header Transformation

Add, remove, or modify headers:

public class CustomTransform : RequestTransform
{
    public override ValueTask ApplyAsync(RequestTransformContext context)
    {
        // Add custom header
        context.HttpContext.Request.Headers.Add("X-Proxy-Request-Id", 
            Guid.NewGuid().ToString());
        
        // Remove header
        context.HttpContext.Request.Headers.Remove("X-Original-Header");
        
        return default;
    }
}

// Register transform
builder.Services.AddReverseProxy()
    .AddTransforms(builderContext =>
    {
        builderContext.AddRequestTransform(async transformContext =>
        {
            transformContext.HttpContext.Request.Headers.Add(
                "X-Proxy-Request-Id", Guid.NewGuid().ToString());
        });
    });

Response Transformation

Transform response content:

public class ResponseTransformMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        var originalBodyStream = context.Response.Body;
        
        using var responseBody = new MemoryStream();
        context.Response.Body = responseBody;

        await _next(context);

        // Transform response
        responseBody.Seek(0, SeekOrigin.Begin);
        var responseText = await new StreamReader(responseBody).ReadToEndAsync();
        
        // Apply transformation
        var transformedResponse = TransformResponse(responseText);
        
        // Write transformed response
        await context.Response.WriteAsync(transformedResponse);
    }
}

Authentication Integration

JWT Authentication

Validate JWT tokens at the proxy:

builder.Services.AddAuthentication()
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://auth.example.com";
        options.Audience = "api.example.com";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true
        };
    });

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapReverseProxy();

Forward Authentication

Forward authentication to backend:

public class ForwardAuthTransform : RequestTransform
{
    public override ValueTask ApplyAsync(RequestTransformContext context)
    {
        var user = context.HttpContext.User;
        
        if (user.Identity.IsAuthenticated)
        {
            // Forward user claims
            var claims = user.Claims.Select(c => $"{c.Type}={c.Value}");
            context.HttpContext.Request.Headers.Add("X-User-Claims", 
                string.Join(",", claims));
        }
        
        return default;
    }
}

Health Checks

Destination Health Checks

Monitor destination health:

new ClusterConfig
{
    ClusterId = "api-cluster",
    HealthCheck = new HealthCheckConfig
    {
        Enabled = true,
        Interval = TimeSpan.FromSeconds(30),
        Timeout = TimeSpan.FromSeconds(5),
        Path = "/health",
        Policy = "Passive"
    },
    Destinations = /* ... */
}

Custom Health Check

Implement custom health check logic:

public class CustomHealthCheckPolicy : IHealthCheckPolicy
{
    public string Name => "Custom";

    public Task<DestinationHealthState> CheckHealthAsync(
        HttpContext context,
        ClusterState cluster,
        DestinationState destination,
        CancellationToken cancellationToken)
    {
        // Custom health check logic
        var isHealthy = CheckDestinationHealth(destination);
        
        return Task.FromResult(new DestinationHealthState
        {
            Destination = destination,
            Health = isHealthy ? DestinationHealth.Healthy : DestinationHealth.Unhealthy
        });
    }
}

Performance Optimization

Connection Pooling

Optimize HTTP connection pooling:

builder.Services.AddHttpClient("YARP")
    .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
    {
        MaxConnectionsPerServer = 100,
        PooledConnectionLifetime = TimeSpan.FromMinutes(2)
    });

Caching

Implement response caching:

builder.Services.AddMemoryCache();

app.UseResponseCaching();

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        var cacheKey = context.Request.Path + context.Request.QueryString;
        
        if (context.Request.Method == "GET" && 
            await _cache.TryGetValueAsync(cacheKey, out var cachedResponse))
        {
            context.Response.StatusCode = 200;
            await context.Response.WriteAsync(cachedResponse);
            return;
        }
        
        await next();
        
        if (context.Response.StatusCode == 200)
        {
            var responseBody = await ReadResponseBody(context.Response);
            await _cache.SetAsync(cacheKey, responseBody, TimeSpan.FromMinutes(5));
        }
    });
});

Compression

Enable response compression:

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

app.UseResponseCompression();

Observability

Metrics

Track YARP metrics:

builder.Services.AddSingleton<IMetricsCollector, MetricsCollector>();

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        var stopwatch = Stopwatch.StartNew();
        
        await next();
        
        stopwatch.Stop();
        
        var metrics = context.RequestServices.GetRequiredService<IMetricsCollector>();
        metrics.RecordRequest(
            context.Request.Path,
            context.Response.StatusCode,
            stopwatch.ElapsedMilliseconds);
    });
});

Logging

Configure structured logging:

builder.Logging.AddConsole()
    .AddJsonConsole(options =>
    {
        options.IncludeScopes = true;
        options.TimestampFormat = "yyyy-MM-dd HH:mm:ss ";
    });

// Log proxy requests
app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        var logger = context.RequestServices
            .GetRequiredService<ILogger<Program>>();
        
        logger.LogInformation(
            "Proxying request: {Method} {Path} to {Destination}",
            context.Request.Method,
            context.Request.Path,
            context.GetRouteValue("destination"));
        
        await next();
    });
});

Advanced Patterns

Circuit Breaker

Implement circuit breaker pattern:

public class CircuitBreakerMiddleware
{
    private readonly ConcurrentDictionary<string, CircuitBreakerState> _circuits;
    
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var destination = GetDestination(context);
        var circuit = _circuits.GetOrAdd(destination, _ => new CircuitBreakerState());
        
        if (circuit.IsOpen)
        {
            context.Response.StatusCode = 503;
            await context.Response.WriteAsync("Service unavailable");
            return;
        }
        
        try
        {
            await next();
            circuit.RecordSuccess();
        }
        catch (Exception ex)
        {
            circuit.RecordFailure();
            throw;
        }
    }
}

Rate Limiting

Implement rate limiting:

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api", opt =>
    {
        opt.Window = TimeSpan.FromMinutes(1);
        opt.PermitLimit = 100;
    });
});

app.UseRateLimiter();

app.MapReverseProxy()
    .RequireRateLimiting("api");

Production Deployment

Configuration Management

Use environment-specific configuration:

builder.Configuration
    .AddJsonFile("appsettings.json")
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
    .AddEnvironmentVariables()
    .AddAzureKeyVault(/* ... */);

High Availability

Deploy multiple YARP instances:

# docker-compose.yml
services:
  yarp-proxy:
    image: yarp-proxy:latest
    replicas: 3
    ports:
      - "80:80"
      - "443:443"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production

Monitoring

Set up comprehensive monitoring:

builder.Services.AddApplicationInsightsTelemetry();

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        var telemetry = context.RequestServices
            .GetRequiredService<TelemetryClient>();
        
        var operation = telemetry.StartOperation<RequestTelemetry>(
            context.Request.Path);
        
        try
        {
            await next();
            operation.Telemetry.Success = context.Response.StatusCode < 400;
        }
        finally
        {
            telemetry.StopOperation(operation);
        }
    });
});

Best Practices

1. Use Health Checks

Always enable health checks for destinations:

HealthCheck = new HealthCheckConfig
{
    Enabled = true,
    Interval = TimeSpan.FromSeconds(30)
}

2. Implement Retry Logic

Add retry for transient failures:

builder.Services.AddHttpClient("YARP")
    .AddPolicyHandler(GetRetryPolicy());

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .WaitAndRetryAsync(3, retryAttempt =>
            TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}

3. Monitor Performance

Track key metrics:

  • Request latency
  • Error rates
  • Destination health
  • Throughput

4. Secure Configuration

Store sensitive configuration securely:

  • Use Azure Key Vault
  • Use environment variables
  • Never commit secrets

Advanced YARP Patterns

Dynamic Route Configuration

Configure routes dynamically at runtime:

public class DynamicRouteManager
{
    private readonly IProxyConfigProvider _configProvider;

    public async Task AddRouteAsync(RouteConfig route)
    {
        var config = await _configProvider.GetConfigAsync();
        config.Routes.Add(route);
        await _configProvider.UpdateConfigAsync(config);
    }

    public async Task RemoveRouteAsync(string routeId)
    {
        var config = await _configProvider.GetConfigAsync();
        config.Routes.RemoveAll(r => r.RouteId == routeId);
        await _configProvider.UpdateConfigAsync(config);
    }
}

Custom Load Balancing

Implement custom load balancing algorithms:

public class WeightedRoundRobinPolicy : ILoadBalancingPolicy
{
    public string Name => "WeightedRoundRobin";

    public DestinationState PickDestination(
        HttpContext context,
        ClusterState cluster,
        IReadOnlyList<DestinationState> availableDestinations)
    {
        var totalWeight = availableDestinations.Sum(d => d.Weight);
        var random = new Random().NextDouble() * totalWeight;
        
        var current = 0.0;
        foreach (var destination in availableDestinations)
        {
            current += destination.Weight;
            if (random <= current)
            {
                return destination;
            }
        }

        return availableDestinations.Last();
    }
}

Real-World Deployment Scenarios

Scenario 1: Multi-Region Deployment

Deploy YARP across multiple regions:

public class MultiRegionYarpConfig
{
    public ClusterConfig CreateMultiRegionCluster()
    {
        return new ClusterConfig
        {
            ClusterId = "global-api-cluster",
            LoadBalancingPolicy = "WeightedRoundRobin",
            Destinations = new Dictionary<string, DestinationConfig>
            {
                ["us-east"] = new DestinationConfig
                {
                    Address = "https://api-us-east.example.com",
                    Weight = 3
                },
                ["eu-west"] = new DestinationConfig
                {
                    Address = "https://api-eu-west.example.com",
                    Weight = 2
                },
                ["asia-pacific"] = new DestinationConfig
                {
                    Address = "https://api-asia.example.com",
                    Weight = 1
                }
            }
        };
    }
}

Scenario 2: Blue-Green Deployment

Support blue-green deployments:

public class BlueGreenDeploymentManager
{
    public async Task SwitchToGreenAsync()
    {
        var config = await GetCurrentConfigAsync();
        
        // Update all routes to point to green
        foreach (var route in config.Routes)
        {
            route.ClusterId = "green-cluster";
        }
        
        await UpdateConfigAsync(config);
        
        // Monitor green cluster health
        await MonitorGreenClusterHealthAsync();
    }
}

Performance Tuning

Connection Pool Optimization

Optimize connection pooling:

builder.Services.AddHttpClient("YARP", client =>
{
    client.Timeout = TimeSpan.FromSeconds(30);
})
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
    MaxConnectionsPerServer = 200,
    PooledConnectionLifetime = TimeSpan.FromMinutes(2),
    PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
    UseCookies = false,
    AllowAutoRedirect = false
});

Response Caching

Implement intelligent caching:

public class IntelligentCacheMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var cacheKey = GenerateCacheKey(context.Request);
        
        if (await _cache.TryGetValueAsync(cacheKey, out var cachedResponse))
        {
            context.Response.StatusCode = 200;
            await context.Response.WriteAsync(cachedResponse);
            return;
        }

        await next(context);

        if (context.Response.StatusCode == 200 && IsCacheable(context.Request))
        {
            var responseBody = await ReadResponseBodyAsync(context.Response);
            await _cache.SetAsync(cacheKey, responseBody, GetCacheDuration(context.Request));
        }
    }

    private bool IsCacheable(HttpRequest request)
    {
        return request.Method == "GET" && 
               !request.Headers.ContainsKey("Cache-Control");
    }
}

Extended FAQ

Q: How do I handle WebSocket connections with YARP?

A: YARP supports WebSocket proxying:

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.UseWebSockets();
});

Q: Can I use YARP with gRPC?

A: Yes, YARP supports gRPC:

builder.Services.AddGrpc();
app.MapGrpcService<MyGrpcService>();
app.MapReverseProxy();

Q: How do I implement custom routing logic?

A: Use custom middleware:

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        // Custom routing logic
        var route = DetermineRoute(context);
        context.Request.Path = route;
        await next();
    });
});

Conclusion

YARP provides a powerful, high-performance reverse proxy solution for .NET applications. By following the patterns and practices outlined in this guide, you can build production-ready reverse proxy deployments that handle high traffic, provide excellent observability, and integrate seamlessly with your .NET ecosystem.

Key Takeaways:

  1. Use code-based configuration for flexibility
  2. Implement health checks for all destinations
  3. Enable observability with metrics and logging
  4. Optimize performance with connection pooling and caching
  5. Secure authentication at the proxy layer
  6. Monitor production deployments comprehensively
  7. Dynamic configuration for runtime changes
  8. Custom load balancing for advanced scenarios
  9. Multi-region support for global deployments
  10. Performance tuning for optimal throughput

Next Steps:

  1. Set up YARP in your application
  2. Configure routes and clusters
  3. Implement health checks
  4. Add authentication
  5. Set up monitoring
  6. Optimize performance
  7. Plan for scale

Production Deployment Checklist

Pre-Deployment

  • Configure health checks for all destinations
  • Set up monitoring and alerting
  • Configure authentication and authorization
  • Set up rate limiting
  • Test failover scenarios
  • Document configuration
  • Review security settings
  • Load test the proxy

Post-Deployment

  • Monitor proxy metrics
  • Review error logs
  • Check destination health
  • Verify authentication works
  • Monitor performance
  • Review security events
  • Optimize based on metrics

Additional Resources

YARP Documentation

  • Official YARP documentation
  • YARP GitHub repository
  • YARP samples
  • YARP community discussions
  • API Gateway patterns
  • Reverse proxy best practices
  • Load balancing strategies
  • Service mesh integration

YARP Configuration Examples

Basic Configuration

Simple reverse proxy setup:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

app.MapReverseProxy();

app.Run();

Advanced Configuration

Code-based configuration:

builder.Services.AddReverseProxy()
    .LoadFromMemory(new[]
    {
        new RouteConfig
        {
            RouteId = "api-route",
            ClusterId = "api-cluster",
            Match = new RouteMatch
            {
                Path = "/api/{**catch-all}"
            }
        }
    }, new[]
    {
        new ClusterConfig
        {
            ClusterId = "api-cluster",
            Destinations = new Dictionary<string, DestinationConfig>
            {
                ["destination1"] = new DestinationConfig
                {
                    Address = "https://api1.example.com"
                },
                ["destination2"] = new DestinationConfig
                {
                    Address = "https://api2.example.com"
                }
            }
        }
    });

Monitoring and Diagnostics

Health Check Integration

Integrate with health checks:

builder.Services.AddHealthChecks()
    .AddCheck<YarpHealthCheck>("yarp");

app.MapHealthChecks("/health");

Metrics Collection

Collect YARP metrics:

builder.Services.AddSingleton<IMetricsConsumer<YarpMetrics>>(
    new PrometheusMetricsConsumer());

app.UseMetricServer();

YARP Advanced Features

Request/Response Transformation

Transform requests and responses:

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        // Transform request
        context.Request.Headers.Add("X-Forwarded-For", 
            context.Connection.RemoteIpAddress.ToString());
        
        await next();
        
        // Transform response
        if (context.Response.StatusCode == 200)
        {
            context.Response.Headers.Add("X-Processed-By", "YARP");
        }
    });
});

Custom Routing Logic

Implement custom routing:

public class CustomRouteMatcher
{
    public RouteConfig MatchRoute(HttpContext context)
    {
        var path = context.Request.Path.Value;
        
        if (path.StartsWith("/api/v1/"))
        {
            return new RouteConfig
            {
                RouteId = "api-v1",
                ClusterId = "api-v1-cluster"
            };
        }
        
        if (path.StartsWith("/api/v2/"))
        {
            return new RouteConfig
            {
                RouteId = "api-v2",
                ClusterId = "api-v2-cluster"
            };
        }
        
        return null;
    }
}

YARP Performance Tuning

Connection Management

Optimize connection handling:

builder.Services.AddHttpClient("YARP", client =>
{
    client.Timeout = TimeSpan.FromSeconds(30);
})
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(2),
    PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
    MaxConnectionsPerServer = 100,
    EnableMultipleHttp2Connections = true
});

Response Caching

Implement response caching:

app.UseResponseCaching();

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        if (context.Request.Method == "GET")
        {
            var cacheKey = GenerateCacheKey(context.Request);
            if (await TryGetCachedResponseAsync(cacheKey, context.Response))
            {
                return; // Return cached response
            }
        }
        
        await next();
        
        if (context.Response.StatusCode == 200 && IsCacheable(context.Request))
        {
            await CacheResponseAsync(context.Request, context.Response);
        }
    });
});

YARP Load Balancing

Load Balancing Strategies

Implement different load balancing strategies:

public class LoadBalancingConfig
{
    public static ClusterConfig CreateRoundRobinCluster()
    {
        return new ClusterConfig
        {
            ClusterId = "api-cluster",
            LoadBalancingPolicy = "RoundRobin",
            Destinations = new Dictionary<string, DestinationConfig>
            {
                ["destination1"] = new DestinationConfig { Address = "https://api1.example.com" },
                ["destination2"] = new DestinationConfig { Address = "https://api2.example.com" },
                ["destination3"] = new DestinationConfig { Address = "https://api3.example.com" }
            }
        };
    }

    public static ClusterConfig CreateLeastRequestsCluster()
    {
        return new ClusterConfig
        {
            ClusterId = "api-cluster",
            LoadBalancingPolicy = "LeastRequests",
            Destinations = new Dictionary<string, DestinationConfig>
            {
                ["destination1"] = new DestinationConfig { Address = "https://api1.example.com" },
                ["destination2"] = new DestinationConfig { Address = "https://api2.example.com" }
            }
        };
    }
}

Health Check Integration

Integrate health checks with load balancing:

builder.Services.AddReverseProxy()
    .LoadFromConfig(config.GetSection("ReverseProxy"))
    .AddProxyLoadBalancer<HealthCheckLoadBalancer>();

public class HealthCheckLoadBalancer : ILoadBalancer
{
    public DestinationState PickDestination(
        HttpContext context, 
        ClusterState cluster, 
        IReadOnlyList<DestinationState> availableDestinations)
    {
        var healthy = availableDestinations
            .Where(d => d.Health == DestinationHealth.Healthy)
            .ToList();

        if (healthy.Count == 0)
        {
            return availableDestinations.First(); // Fallback
        }

        // Round-robin among healthy destinations
        return healthy[_currentIndex++ % healthy.Count];
    }
}

YARP Security

Request Validation

Validate incoming requests:

public class RequestValidator
{
    public async Task<bool> ValidateRequestAsync(HttpContext context)
    {
        // Validate content length
        if (context.Request.ContentLength > MaxContentLength)
        {
            return false;
        }

        // Validate headers
        if (!ValidateHeaders(context.Request.Headers))
        {
            return false;
        }

        // Validate rate limits
        if (!await CheckRateLimitAsync(context))
        {
            return false;
        }

        return true;
    }
}

Response Security Headers

Add security headers to responses:

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        await next();

        // Add security headers
        context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
        context.Response.Headers.Add("X-Frame-Options", "DENY");
        context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
        context.Response.Headers.Add("Strict-Transport-Security", 
            "max-age=31536000; includeSubDomains");
    });
});

YARP Advanced Configuration

Dynamic Configuration

Update configuration dynamically:

public class DynamicYarpConfig
{
    private readonly IConfigurationManager _configManager;

    public async Task UpdateRouteAsync(RouteConfig route)
    {
        await _configManager.UpdateRouteAsync(route);
    }

    public async Task UpdateClusterAsync(ClusterConfig cluster)
    {
        await _configManager.UpdateClusterAsync(cluster);
    }
}

Configuration Validation

Validate YARP configuration:

public class YarpConfigValidator
{
    public ValidationResult ValidateConfig(YarpConfig config)
    {
        var errors = new List<string>();

        // Validate routes
        foreach (var route in config.Routes)
        {
            if (string.IsNullOrEmpty(route.RouteId))
            {
                errors.Add($"Route missing RouteId");
            }

            if (string.IsNullOrEmpty(route.ClusterId))
            {
                errors.Add($"Route {route.RouteId} missing ClusterId");
            }
        }

        // Validate clusters
        foreach (var cluster in config.Clusters)
        {
            if (cluster.Destinations == null || !cluster.Destinations.Any())
            {
                errors.Add($"Cluster {cluster.ClusterId} has no destinations");
            }
        }

        return new ValidationResult
        {
            IsValid = errors.Count == 0,
            Errors = errors
        };
    }
}

YARP Troubleshooting

Common Issues

Troubleshoot common YARP issues:

public class YarpTroubleshooter
{
    public async Task<DiagnosticsResult> DiagnoseAsync()
    {
        var diagnostics = new DiagnosticsResult();

        // Check configuration
        diagnostics.ConfigurationValid = await ValidateConfigurationAsync();

        // Check destinations
        diagnostics.DestinationsHealthy = await CheckDestinationsAsync();

        // Check routing
        diagnostics.RoutingWorking = await TestRoutingAsync();

        return diagnostics;
    }
}

YARP Production Deployment

Deployment Checklist

Complete deployment checklist:

public class YarpDeploymentChecklist
{
    public async Task<DeploymentStatus> CheckDeploymentReadinessAsync()
    {
        var status = new DeploymentStatus();

        // Check configuration
        status.ConfigurationValid = await ValidateConfigurationAsync();

        // Check destinations
        status.DestinationsHealthy = await CheckAllDestinationsAsync();

        // Check health checks
        status.HealthChecksWorking = await TestHealthChecksAsync();

        // Check monitoring
        status.MonitoringConfigured = await CheckMonitoringAsync();

        // Check security
        status.SecurityConfigured = await CheckSecurityAsync();

        return status;
    }
}

Performance Tuning

Tune YARP performance:

public class YarpPerformanceTuner
{
    public void OptimizePerformance()
    {
        // Optimize connection pooling
        builder.Services.AddHttpClient("YARP", client =>
        {
            client.Timeout = TimeSpan.FromSeconds(30);
        })
        .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
        {
            PooledConnectionLifetime = TimeSpan.FromMinutes(2),
            PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
            MaxConnectionsPerServer = 100,
            EnableMultipleHttp2Connections = true
        });

        // Enable response compression
        builder.Services.AddResponseCompression();

        // Enable response caching
        builder.Services.AddResponseCaching();
    }
}

YARP Advanced Configuration

Dynamic Configuration Updates

Update configuration dynamically:

public class DynamicConfigurationUpdater
{
    public async Task UpdateConfigurationAsync(YarpConfig config)
    {
        // Validate configuration
        var validation = await ValidateConfigurationAsync(config);
        if (!validation.IsValid)
        {
            throw new InvalidOperationException("Invalid configuration");
        }

        // Update configuration
        await UpdateConfigAsync(config);

        // Notify YARP
        await NotifyYarpAsync(config);
    }
}

YARP Health Monitoring

Monitor YARP health:

public class YarpHealthMonitor
{
    public async Task<HealthStatus> GetYarpHealthAsync()
    {
        var health = new HealthStatus
        {
            Status = HealthStatus.Healthy
        };

        // Check destinations
        var destinationsHealth = await CheckDestinationsHealthAsync();
        if (!destinationsHealth.IsHealthy)
        {
            health.Status = HealthStatus.Degraded;
            health.Issues.Add("Some destinations unhealthy");
        }

        // Check configuration
        var configHealth = await CheckConfigurationHealthAsync();
        if (!configHealth.IsValid)
        {
            health.Status = HealthStatus.Unhealthy;
            health.Issues.Add("Configuration issues");
        }

        return health;
    }
}

For more API gateway guidance, explore our API Gateway Comparison: Ocelot vs YARP vs Kong or Ocelot API Gateway guide.

Related posts