/// <inheritdoc /> public async Task Invoke(HttpContext httpContext) { var strategy = await _strategyProvider?.GetThrottleStrategyAsync(httpContext, null, null); if (strategy == null) { _logger.LogDebug("No strategy for current request."); await _next(httpContext); return; } var throttleContext = await _throttleService.EvaluateAsync(httpContext, strategy); if (throttleContext.HasAborted) { _logger.LogDebug("Throttling aborted. No throttling applied."); await _next(httpContext); return; } var response = httpContext.Response; if (_options.SendThrottleHeaders) { foreach (var header in throttleContext.ResponseHeaders.OrderBy(h => h.Key)) { response.Headers[header.Key] = header.Value; } } if (throttleContext.HasTooManyRequest) { _logger.LogInformation("Throttling applied."); string retryAfter = RetryAfterHelper.GetRetryAfterValue(_clock, _options.RetryAfterMode, throttleContext.RetryAfter); response.StatusCode = Constants.Status429TooManyRequests; // rfc6585 section 4 : Responses with the 429 status code MUST NOT be stored by a cache. response.Headers.SetCommaSeparatedValues("Cache-Control", "no-store", "no-cache"); response.Headers["Pragma"] = "no-cache"; // rfc6585 section 4 : The response [...] MAY include a Retry-After header indicating how long to wait before making a new request. if (retryAfter != null) { response.Headers["Retry-After"] = retryAfter; } } else { _logger.LogDebug("No throttling applied."); await _next(httpContext); } await _throttleService.PostEvaluateAsync(throttleContext); }
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (next == null) { throw new ArgumentNullException(nameof(next)); } if (!context.Cancel) { var resultExecutedContext = await next(); if (_throttleContext != null) { await _throttleService.PostEvaluateAsync(_throttleContext); } } }