public async Task Invoke(HttpContext context) { var endpoint = context.GetEndpoint(); RequestLimitAttribute requestLimit = endpoint?.Metadata.GetMetadata <RequestLimitAttribute>(); RequestCount requestCount = null; try { if (requestLimit != null) { requestCount = _requestCounts.GetOrAdd(endpoint.DisplayName, (_) => new RequestCount()); int newRequestCount = requestCount.Increment(); if (newRequestCount > requestLimit.MaxConcurrency) { _logger.ThrottledEndpoint(requestLimit.MaxConcurrency, newRequestCount); context.Response.StatusCode = (int)HttpStatusCode.TooManyRequests; return; } } await _next(context); } finally { //IMPORTANT This will not work for operation style apis, such as when returning a 202 for egress calls. requestCount?.Decrement(); } }
public async Task Invoke(HttpContext context) { var endpoint = context.GetEndpoint(); RequestLimitAttribute requestLimit = endpoint?.Metadata.GetMetadata <RequestLimitAttribute>(); IDisposable incrementor = null; try { //Operations and middleware both share the same increment limits, but //we don't want the middleware to increment the limit if the operation is doing it as well. if ((requestLimit != null) && !context.Request.Query.ContainsKey(EgressQuery)) { incrementor = _limitTracker.Increment(requestLimit.LimitKey, out bool allowOperation); if (!allowOperation) { //We should report the same kind of error from Middleware and the Mvc layer. context.Response.StatusCode = StatusCodes.Status429TooManyRequests; context.Response.ContentType = ContentTypes.ApplicationProblemJson; await context.Response.WriteAsync(JsonSerializer.Serialize(new ProblemDetails { Status = StatusCodes.Status429TooManyRequests, Detail = Microsoft.Diagnostics.Monitoring.WebApi.Strings.ErrorMessage_TooManyRequests }), context.RequestAborted); return; } } await _next(context); } finally { incrementor?.Dispose(); } }