Implementing Yet Another Reverse Proxy (YARP) with ASP.NET Core
YARP is built on .NET using the infrastructure from ASP.NET and .NET (.NET 6 and newer). The key differentiator for YARP is that it's been designed to be easily customized and tweaked via .NET code to match the specific needs of each deployment scenario. 0 commentsBy Sopheaktra Eang | February 22, 2024
What is YARP?
YARP or Yet Another Reverse Proxy is a library to help create reverse proxy servers that are high-performance, production-ready, and highly customizable. YARP's github going to the GitHub repository
Why YARP?
We found a bunch of internal teams at Microsoft who were either building a reverse proxy for their service or had been asking about APIs and tech for building one, so we decided to get them all together to work on a common solution, this project. Each of these projects was doing something slightly off the beaten path which meant they were not well served by existing proxies, and customization of those proxies had a high cost and ongoing maintenance considerations.
Many of the existing proxies were built to support HTTP/1.1, but with workloads changing to include gRPC traffic, they require HTTP/2 support which requires a significantly more complex implementation. By using YARP the projects get to customize the routing and handling behavior without having to implement the http protocol.
Before using YARP
You will need:
- An understanding of ASP.NET and C#
- The .NET 6 SDK installed
- A C# code editor such as Visual Studio, JetBrains Rider or VS Code
- A local copy of this GitHub Repository (either downloaded or forked+cloned
Install dotnet SDK
Create Web-API with CLI
Create projects web-api
//Add Main Project
dotnet new sln -o Yarp_Project
//Directory to main project
cd Yarp_Project
//create api gateway yarp proxy
dotnet new webapi –-name Yarp_Proxy
//add yarp proxy to main project
dotnet sln Yarp_Project.sln add .\Yarp_proxy\Yarp_proxy.csproj
//create api course project
dotnet new webapi –-name Course.Api
//add api course project to main project
dotnet sln Yarp_Project.sln add .\Course.Api\Course.Api.csproj
//create api student project
dotnet new webapi –-name Student.Api
//add api student project to main project
dotnet sln Yarp_Project.sln add .\Student.Api\Student.Api.csproj
Add Package
Add package for Yarp_Proxy
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Yarp.ReverseProxy
Student and Course project is no need to add any package and also it's just simple web api cuz we're focus on YARP.
Configuration Yarp on project Yarp_Proxy
Add configuration to appsettings.json
"ReverseProxy": {
// Routes tell the proxy which requests to forward
"Routes": {
"student-route": {
// Matches anything and routes it to www.example.com
"ClusterId": "studentcluster",
"RateLimiterPolicy": "fixed",
// "AuthorizationPolicy": "authenticated",
"Match": {
"Path": "/student-service/{**catch-all}"
},
"Transforms": [
{ "PathPattern": "{**catch-all}" }
]
},
"course-route": {
// matches /something/* and routes to 2 external addresses
"ClusterId": "coursecluster",
"Match": {
"Path": "/course-service/{**catch-all}"
},
"Transforms": [
{ "PathPattern": "{**catch-all}" }
]
}
},
// Clusters tell the proxy where and how to forward requests
"Clusters": {
"studentcluster": {
"Destinations": {
"destination1": {
"Address": "http://localhost:5269/"
}
}
},
"coursecluster": {
"Destinations": {
"destination1": {
"Address": "http://localhost:5185/"
},
"destination2": {
"Address": "http://localhost:5186/"
}
},
"LoadBalancingPolicy": "PowerOfTwoChoices"
}
}
}
Replace your Program.cs
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("authenticated", policy =>
policy.RequireAuthenticatedUser());
});
builder.Services.AddRateLimiter(rateLimiterOptions =>
{
rateLimiterOptions.RejectionStatusCode = 429;
rateLimiterOptions.AddFixedWindowLimiter("fixed", options =>
{
options.Window = TimeSpan.FromSeconds(10);
options.PermitLimit = 1;
options.QueueLimit = 0; //if you don't want to reject your client and want to let them wait with queue set it bigger than zero
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.AutoReplenishment = true;
});
});
builder.Services
.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();
app.MapReverseProxy();
app.Run();
Languages and Tools
Summary
Download the source code for the sample application implementing an API with YARP. And you can understand to build multiple instances and configuration your load balancing base on yarp LoadBalancingPolicy:
- FirstAlphabetical: Select the alphabetically first available destination without considering load. This is useful for dual destination fail-over systems.
- LeastRequests: Select the destination with the least assigned requests. This requires examining all destinations.
- PowerOfTwoChoices: Select two random destinations and then select the one with the least assigned requests. This avoids the overhead of LeastRequests and the worst case for Random where it selects a busy destination.
- Random: Select a destination randomly.
- RoundRobin: Select a destination by cycling through them in order.