What is YARP and Why Use It?
YARP (Yet Another Reverse Proxy) is an open-source reverse proxy developed by Microsoft for ASP.NET Core.
With YARP, you can build scalable and efficient API gateways, load balancers, and reverse proxies. I personally like YARP a lot because it’s extremely customizable and well integrated into the ASP.NET Core pipeline. In a microservices architecture, a reverse proxy plays a crucial role in abstracting issues like authentication and acts as a central layer that unifies access to your microservices, ensuring security and scalability. This allows each microservice to focus solely on its business logic.
The cover photo is one I personally took on the Camino de Santiago. I believe it nicely illustrates how a proxy directs traffic to the appropriate destinations.
Advantages of Loading YARP Configuration from the Database
By default, YARP uses the appsettings.json
file to configure routes and clusters. However, this approach has limitations, such as requiring server access to edit proxy settings. Loading configuration from a database offers several benefits:
- Real-time updates with no downtime;
- Centralized management of routes and clusters;
- Better scalability and maintainability in distributed environments;
- Detailed control and auditing of changes;
- Simplified interface for less technical users to configure the proxy.
How to Load YARP Configuration from the Database
YARP doesn't provide a built-in mechanism to load configuration from a database, which makes sense since it's outside the library’s scope. Therefore, you need to implement a custom interface to provide your stored routes and clusters. For example, the interface IReverseProxyRepository
:
public interface IReverseProxyRepository
{
IReadOnlyList<RouteConfig> GetRoutes();
IReadOnlyList<ClusterConfig> GetClusters();
}
Implementation of IProxyConfigProvider
The IProxyConfigProvider
interface in YARP is responsible for supplying the current proxy configuration, including routes and clusters, to the ASP.NET Core pipeline. By implementing this interface, you can load and update configurations dynamically, such as from a database, without restarting the application.
public class DatabaseProxyConfigProvider : IProxyConfigProvider
{
private volatile IProxyConfig _config;
private readonly IReverseProxyRepository _repository;
public DatabaseProxyConfigProvider(IReverseProxyRepository repository)
{
_repository = repository;
_config = LoadConfig();
}
public IProxyConfig GetConfig() => _config;
private IProxyConfig LoadConfig()
{
var routes = _repository.GetRoutes();
var clusters = _repository.GetClusters();
return new DatabaseProxyConfig(routes, clusters);
}
public void Reload()
{
_config = LoadConfig();
_config.SignalChange();
}
}
Implementation of IProxyConfig
The IProxyConfig
interface represents the current configuration for YARP, containing route and cluster collections. It also exposes a ChangeToken
to allow YARP to detect configuration changes and dynamically update during runtime.
public class DatabaseProxyConfig : IProxyConfig
{
private CancellationTokenSource _cts = new CancellationTokenSource();
public DatabaseProxyConfig(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
{
Routes = routes;
Clusters = clusters;
ChangeToken = new CancellationChangeToken(_cts.Token);
}
public IReadOnlyList<RouteConfig> Routes { get; }
public IReadOnlyList<ClusterConfig> Clusters { get; }
public IChangeToken ChangeToken { get; private set; }
public void SignalChange()
{
var previousCts = Interlocked.Exchange(ref _cts, new CancellationTokenSource());
ChangeToken = new CancellationChangeToken(_cts.Token);
previousCts.Cancel();
}
}
Service Registration in Program.cs
Finally, register your services in Program.cs
. Personally, I prefer using extension methods to group service registrations, rather than the approach shown below, which is just for educational purposes. For more details, see this Microsoft example.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IReverseProxyRepository, ReverseProxyRepository>();
builder.Services.AddSingleton<IProxyConfigProvider, DatabaseProxyConfigProvider>();
builder.Services.AddReverseProxy();
var app = builder.Build();
app.MapReverseProxy();
app.Run();
Conclusion
By using IProxyConfigProvider
, YARP can load configuration directly from a database or any other preferred source, enabling dynamic updates and greater control over your reverse proxy.
Keep in mind that depending on your system and team, using appsettings.json
might be more practical, especially if your proxy configuration is static. I like the phrase "Premature optimization is the root of all evil." Always start simple and only add complexity when it's truly necessary. Sometimes a database configuration layer may just be unnecessary overhead.
Official YARP Documentation
For more technical details and examples, visit the official documentation: