I am trying to run the .NET 8 Rate Limiting Middleware, with a global rate limit, as well as a specific policy for certain endpoints. The global policy is working as expected, but I cannot get the endpoint specific policy to work.
I have added the following into my Startup.cs
<code>private void AddRateLimiter(IServiceCollection services)
{
logger.Information("Adding Rate Limiter");
services.AddRateLimiter(options =>
{
options.OnRejected = async (context, cancellationToken) =>
{
context.HttpContext.Response.StatusCode = 429;
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
await context.HttpContext.Response.WriteAsync(
$"Too many requests. Please try again after {retryAfter.TotalMinutes} minute(s). ", cancellationToken);
}
else
{
await context.HttpContext.Response.WriteAsync(
"Too many requests. Please try again later. ", cancellationToken);
}
};
options.AddPolicy("ThrottlePolicy", request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For: {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 2,
Window = TimeSpan.FromHours(1)
});
});
options.GlobalLimiter = PartitionedRateLimiter.CreateChained(
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-minute window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 300,
Window = TimeSpan.FromMinutes(1)
});
}),
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-hour window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 3000,
Window = TimeSpan.FromHours(1)
});
}));
});
}
</code>
<code>private void AddRateLimiter(IServiceCollection services)
{
logger.Information("Adding Rate Limiter");
services.AddRateLimiter(options =>
{
options.OnRejected = async (context, cancellationToken) =>
{
context.HttpContext.Response.StatusCode = 429;
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
await context.HttpContext.Response.WriteAsync(
$"Too many requests. Please try again after {retryAfter.TotalMinutes} minute(s). ", cancellationToken);
}
else
{
await context.HttpContext.Response.WriteAsync(
"Too many requests. Please try again later. ", cancellationToken);
}
};
options.AddPolicy("ThrottlePolicy", request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For: {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 2,
Window = TimeSpan.FromHours(1)
});
});
options.GlobalLimiter = PartitionedRateLimiter.CreateChained(
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-minute window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 300,
Window = TimeSpan.FromMinutes(1)
});
}),
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-hour window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 3000,
Window = TimeSpan.FromHours(1)
});
}));
});
}
</code>
private void AddRateLimiter(IServiceCollection services)
{
logger.Information("Adding Rate Limiter");
services.AddRateLimiter(options =>
{
options.OnRejected = async (context, cancellationToken) =>
{
context.HttpContext.Response.StatusCode = 429;
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
await context.HttpContext.Response.WriteAsync(
$"Too many requests. Please try again after {retryAfter.TotalMinutes} minute(s). ", cancellationToken);
}
else
{
await context.HttpContext.Response.WriteAsync(
"Too many requests. Please try again later. ", cancellationToken);
}
};
options.AddPolicy("ThrottlePolicy", request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For: {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 2,
Window = TimeSpan.FromHours(1)
});
});
options.GlobalLimiter = PartitionedRateLimiter.CreateChained(
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-minute window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 300,
Window = TimeSpan.FromMinutes(1)
});
}),
PartitionedRateLimiter.Create<HttpContext, string>(request =>
{
var ipAddress = request.Request.Headers["X-Forwarded-For"].ToString();
Console.WriteLine($"X-Forwarded-For (1-hour window): {ipAddress}");
return RateLimitPartition.GetFixedWindowLimiter(ipAddress, partition =>
new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 3000,
Window = TimeSpan.FromHours(1)
});
}));
});
}
And then on the controller endpoint I have:
<code> [EnableRateLimiting(policyName: "ThrottlePolicy")]
[Authorize(Policy = "ViewPolicy")]
[HttpPost("{incident_Id}/[controller]")]
[DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(FileModel))]
public Task<IActionResult> Post(string incident_Id, [FromForm] FilePostModel evidence)
{
return HandleRequestAsync(new FileAddRequest()
{
IncidentId = incident_Id,
NewEntity = evidence
});
}
</code>
<code> [EnableRateLimiting(policyName: "ThrottlePolicy")]
[Authorize(Policy = "ViewPolicy")]
[HttpPost("{incident_Id}/[controller]")]
[DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(FileModel))]
public Task<IActionResult> Post(string incident_Id, [FromForm] FilePostModel evidence)
{
return HandleRequestAsync(new FileAddRequest()
{
IncidentId = incident_Id,
NewEntity = evidence
});
}
</code>
[EnableRateLimiting(policyName: "ThrottlePolicy")]
[Authorize(Policy = "ViewPolicy")]
[HttpPost("{incident_Id}/[controller]")]
[DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(FileModel))]
public Task<IActionResult> Post(string incident_Id, [FromForm] FilePostModel evidence)
{
return HandleRequestAsync(new FileAddRequest()
{
IncidentId = incident_Id,
NewEntity = evidence
});
}
With the Console Logging I can see the global policies being hit, but I never get any logging for the ThrottlePolicy. Not sure what I’m missing here.