Ocelot API Gateway: Simplifying Microservices Architecture in .NET
In modern microservices architectures, an API Gateway acts as a single entry point for all client requests, routing them to appropriate backend services. Ocelot is an open-source, lightweight API Gateway built specifically for .NET, making it an excellent choice for .NET-based microservices ecosystems.
What is Ocelot?
Ocelot is a .NET API Gateway that provides a simple way to route requests, aggregate responses, and apply cross-cutting concerns like authentication, rate limiting, and caching. It's built on top of ASP.NET Core and leverages its middleware pipeline.
Key Features
- Request Routing: Route incoming requests to downstream services based on configuration
- Request Aggregation: Combine multiple service calls into a single response
- Service Discovery: Integration with Consul, Eureka, and other service discovery tools
- Load Balancing: Distribute requests across multiple service instances
- Authentication & Authorization: Centralized security with JWT, OAuth2, and more
- Rate Limiting: Control request rates to protect backend services
- Caching: Cache responses to improve performance
- Quality of Service (QoS): Circuit breaker pattern and retry policies
Getting Started with Ocelot
Installation
First, install the Ocelot NuGet package:
dotnet add package Ocelot
Basic Configuration
Create an ocelot.json configuration file:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/orders/{id}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/orders/{id}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:5000"
}
}
Program.cs Setup
Configure Ocelot in your ASP.NET Core application:
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
// Add Ocelot configuration
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
// Add Ocelot services
builder.Services.AddOcelot();
var app = builder.Build();
// Use Ocelot middleware
await app.UseOcelot();
app.Run();
Advanced Features
1. Request Aggregation
Combine multiple service calls into a single response:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/products/{id}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{ "Host": "localhost", "Port": 5001 }
],
"UpstreamPathTemplate": "/products/{id}",
"UpstreamHttpMethod": [ "GET" ],
"Key": "Products"
},
{
"DownstreamPathTemplate": "/api/reviews/{id}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{ "Host": "localhost", "Port": 5003 }
],
"UpstreamPathTemplate": "/reviews/{id}",
"UpstreamHttpMethod": [ "GET" ],
"Key": "Reviews"
}
],
"Aggregates": [
{
"RouteKeys": [ "Products", "Reviews" ],
"UpstreamPathTemplate": "/productdetails/{id}"
}
]
}
2. Rate Limiting
Protect your services from excessive requests:
{
"DownstreamPathTemplate": "/api/products",
"UpstreamPathTemplate": "/products",
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "1s",
"PeriodTimespan": 1,
"Limit": 10
}
}
3. Authentication with JWT
Secure your gateway with JWT authentication:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Configure JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot();
var app = builder.Build();
app.UseAuthentication();
await app.UseOcelot();
app.Run();
In your ocelot.json:
{
"DownstreamPathTemplate": "/api/orders",
"UpstreamPathTemplate": "/orders",
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer",
"AllowedScopes": []
}
}
4. Load Balancing
Distribute requests across multiple instances:
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{ "Host": "localhost", "Port": 5001 },
{ "Host": "localhost", "Port": 5002 },
{ "Host": "localhost", "Port": 5003 }
],
"UpstreamPathTemplate": "/products",
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
Available load balancing strategies:
- LeastConnection: Routes to the service with fewest active connections
- RoundRobin: Distributes requests evenly across all instances
- NoLoadBalancer: Uses the first available service
5. Quality of Service (Circuit Breaker)
Implement resilience patterns:
{
"DownstreamPathTemplate": "/api/products",
"UpstreamPathTemplate": "/products",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 1000,
"TimeoutValue": 5000
}
}
6. Caching
Cache responses to improve performance:
builder.Services.AddOcelot()
.AddCacheManager(x =>
{
x.WithDictionaryHandle();
});
{
"DownstreamPathTemplate": "/api/products",
"UpstreamPathTemplate": "/products",
"FileCacheOptions": {
"TtlSeconds": 30,
"Region": "products"
}
}
Service Discovery Integration
Consul Integration
Integrate with Consul for dynamic service discovery:
dotnet add package Ocelot.Provider.Consul
builder.Services.AddOcelot()
.AddConsul();
{
"Routes": [
{
"DownstreamPathTemplate": "/api/products",
"UpstreamPathTemplate": "/products",
"ServiceName": "product-service",
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 8500,
"Type": "Consul"
}
}
}
Best Practices
- Use Environment-Specific Configurations: Maintain separate
ocelot.jsonfiles for different environments - Implement Proper Logging: Use Serilog or similar for comprehensive logging
- Enable CORS Carefully: Configure CORS policies appropriately for your frontend applications
- Monitor Performance: Use Application Insights or similar tools to monitor gateway performance
- Secure Your Gateway: Always use HTTPS and implement proper authentication/authorization
- Version Your APIs: Include API versioning in your routing strategy
- Use Health Checks: Implement health check endpoints for monitoring
Complete Example: E-Commerce Gateway
{
"Routes": [
{
"DownstreamPathTemplate": "/api/products/{everything}",
"DownstreamScheme": "https",
"ServiceName": "product-service",
"UpstreamPathTemplate": "/products/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer"
},
"RateLimitOptions": {
"EnableRateLimiting": true,
"Period": "1m",
"Limit": 100
},
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 5000,
"TimeoutValue": 10000
}
},
{
"DownstreamPathTemplate": "/api/orders/{everything}",
"DownstreamScheme": "https",
"ServiceName": "order-service",
"UpstreamPathTemplate": "/orders/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer"
}
},
{
"DownstreamPathTemplate": "/api/users/{everything}",
"DownstreamScheme": "https",
"ServiceName": "user-service",
"UpstreamPathTemplate": "/users/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer"
}
}
],
"GlobalConfiguration": {
"BaseUrl": "https://api.myecommerce.com",
"ServiceDiscoveryProvider": {
"Host": "consul",
"Port": 8500,
"Type": "Consul"
},
"RateLimitOptions": {
"DisableRateLimitHeaders": false,
"QuotaExceededMessage": "Rate limit exceeded. Please try again later.",
"HttpStatusCode": 429
}
}
}
Advantages of Ocelot
- Native .NET Integration: Built specifically for .NET ecosystem
- Lightweight: Minimal overhead and fast performance
- Easy Configuration: JSON-based configuration is simple and readable
- Extensible: Custom middleware and delegating handlers support
- Active Community: Well-maintained with regular updates
- Production-Ready: Used by many organizations in production
When to Use Ocelot
Ocelot is ideal when:
- Building microservices with .NET/ASP.NET Core
- Need a lightweight, simple API Gateway solution
- Want tight integration with .NET ecosystem
- Require basic to intermediate gateway features
- Working with Consul or Eureka for service discovery
Alternatives to Consider
While Ocelot is excellent for .NET, consider these alternatives based on your needs:
- Kong: More feature-rich, language-agnostic
- YARP (Yet Another Reverse Proxy): Microsoft's official reverse proxy library
- Traefik: Cloud-native, automatic service discovery
- Envoy: High-performance, used in service mesh architectures
Conclusion
Ocelot provides a powerful yet simple solution for implementing API Gateway patterns in .NET microservices architectures. Its configuration-driven approach, combined with robust features like load balancing, rate limiting, and service discovery integration, makes it an excellent choice for .NET developers building distributed systems.
Whether you're starting a new microservices project or modernizing an existing monolith, Ocelot can help you manage complexity, improve security, and enhance the overall architecture of your .NET applications.
