Using Ocelot as an API Gateway in a .NET Core Microservices Architecture
Microservice introduce agility, scalability and autonomy for development teams but they also bring complexity in handling cross-cutting concerns like routing, authentication and load balancing across multiple services. An API Gateway centralizes these concerns, providing a single entry point for clients. In the .NET ecosystem, Ocelot is a lightweight, easy-to-configure API Gateway library for ASP.NET Core.
In this article, we will:
- Explain why you need an API Gateway in a microservice setup.
- Introduce Ocelot and its key features.
- Walk through setting up two sample .NET Core microservices.
- Configure an Ocelot Gateway project with routing, load balancing and authentication.
- Test the end-to-end setup.
Why Use an API Gateway?
- Single Entry Point: Clients communicate with one service url (endpoint) instead of multiple service urls (e.g payment.mydomain.com, identity.mydomain.com, messaging.mydomain.com e.t.c)
- Routing & Aggregation: Routes requests to appropriate downstream services and can combine responses.
- Cross-cutting Features: Implement authentication, rate limiting, caching, logging and circuit breakers in one place.
Without a gateway, each client must track and call multiple endpoints directly, increasing coupling and exposure of internal service urls.
Introducing Ocelot
Ocelot is an open-source API Gateway library for .NET Core. Its core features include:
- Routing: Map incoming (Upstream) paths to downstream services
- Load Balancing: Round-robing, least connection e.t.c
- Authentication & Authorization: Integrate with JWT, IdentityServer4 or custom schemes
- Rate Limiting & Throttling: Protect downstream (internal) services from traffic spikes.
- Caching & QoS: Reduce latency and implement fault tolerance.
Prerequisites
- .NET 8 SDK
- IDE: Visual Studio 2022/Rider IDE/VS Code
- Basic knowledge of ASP.NET Core Web API
Create Sample Microservices
Service A (Product API)
//Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapGet("/api/products", () => new[] { new { Id = 1, Name = "Widget" } });
await app.RunAsync();
Service B (Order API)
//Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapGet("/api/orders", () => new[] { new {OrderId = 100, ProductId = 1, Quantity = 2 }});
await app.RunAsync();
Run each service on a different port (e.g 5001 for Products, 5002 for Orders).
Create the Ocelot Gateway Project
dotnet new web -n ApiGateway
cd ApiGateway
dotnet add package Ocelot
Create a ocelot.json
{
"Routes": [
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [{ "Host": "localhost", "Port": 5001 }],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/orders",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [{ "Host": "localhost", "Port": 5002 }],
"UpstreamPathTemplate": "/orders",
"UpstreamHttpMethod": [ "GET" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:7000"
}
}
Program.cs for Gateway
var builder = WebApplication.CreateBuilder(args);
//Load ocelot config
builder.Configuration.AddJsonFile("ocelot.json");
//Register Ocelot
builder.Services.AddOcelot(builder.Configuration);
var app = builder.Build();
app.MapGet("/", () => "Api Gateway is Active");
await app.UseOcelot();
Run the gateway on port 7000 using dotnet run --urls "http://localhost:7000"
.
Test the setup
With all three projects running, open a terminal or postman:
# Products via gateway
curl http://localhost:7000/products
#Orders via gateway
curl http://localhost:7000/orders
Responses from downstream services should flow through the gateway seamlessly.
Advanced Features
Load Balancing
Add multiple ports for a downstream service and set:
{
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
},
{
"Host": "localhost",
"Port": 5003
}
],
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
JWT Authentication
- Protect downstream APIs with JWT
- In
ocelot.json
, add anAuthenticationOptions
section:
{
"AuthenticationOptions": {
"AuthenticationProviderKey": "JwtAuth",
"AllowedScopes": []
}
}
- In
Program.cs
, configure JWT bearer
builder.Services.AddAuthentication()
.AddJwtBearer("JwtAuth", options => { /* configure */ });
app.UseAuthentication();
app.UseAuthorization();
Rate Limiting & Caching
Configure RateLimitOptions
and FileCacheOptions
in ocelot.json
to protect services and reduce latency.
Conclusion
Using Ocelot as an API Gateway in your .NET Core microservices setup simplifies routing, security and cross-cutting concerns. This article walked through:
- Creating minimal microservices
- Configuring an Ocelot Gateway
- Testing routes
- Extending with load balancing and authentication
Explore additional Ocelot middleware such as circuit breakers, aggregation, dynamic configuration to further harden your gateway.