/// <summary> /// Asynchronous processing of Middleware /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Invoke(HttpContext context) { var checkResult = await _algorithm.CheckAsync(context); if (checkResult.IsLimit) { context.Response.StatusCode = _error.HttpStatusCode; Dictionary <string, StringValues> headers = null; if (_error.BuildHttpHeadersAsync != null) { headers = await _error.BuildHttpHeadersAsync(context, checkResult).ConfigureAwait(false); } else if (_error.BuildHttpHeaders != null) { headers = _error.BuildHttpHeaders(context, checkResult); } if (headers != null && headers.Count > 0) { foreach (var h in headers) { context.Response.Headers.Append(h.Key, h.Value); } } string content = null; if (_error.BuildHttpContentAsync != null) { content = await _error.BuildHttpContentAsync(context, checkResult).ConfigureAwait(false); } else if (_error.BuildHttpContent != null) { content = _error.BuildHttpContent(context, checkResult); } if (!string.IsNullOrWhiteSpace(content)) { var bodyContent = Encoding.UTF8.GetBytes(content); await context.Response.Body.WriteAsync(bodyContent, 0, bodyContent.Length).ConfigureAwait(false); } else { await context.Response.WriteAsync(string.Empty).ConfigureAwait(false); } } else { // Simulation leaky bucket algorithm queuing mechanism var wait = checkResult.RuleCheckResults.Max(d => d.Wait); if (wait > 0) { await Task.Delay((int)wait); } await _next(context); } }
/// <summary> /// Asynchronous processing of Middleware /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Invoke(HttpContext context) { await DoOnBeforeCheck(context, _algorithm).ConfigureAwait(false); var checkResult = await _algorithm.CheckAsync(context); await DoOnAfterCheck(context, checkResult).ConfigureAwait(false); if (checkResult.IsLimit) { await DoOnTriggered(context, checkResult).ConfigureAwait(false); context.Response.StatusCode = _error.HttpStatusCode; var headers = await BuildHttpHeaders(context, checkResult).ConfigureAwait(false); if (headers != null && headers.Count > 0) { foreach (var h in headers) { context.Response.Headers.Append(h.Key, h.Value); } } string content = await BuildHttpContent(context, checkResult).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(content)) { var bodyContent = Encoding.UTF8.GetBytes(content); await context.Response.Body.WriteAsync(bodyContent, 0, bodyContent.Length).ConfigureAwait(false); } else { await context.Response.WriteAsync(string.Empty).ConfigureAwait(false); } } else { await DoOnBreforUntriggeredDoNext(context, checkResult).ConfigureAwait(false); if (checkResult.RuleCheckResults.Any()) { await DoLeakyBucketWait(checkResult).ConfigureAwait(false); } //Debug.WriteLine("R-Count" + checkResult.RuleCheckResults.First().Count + " " + DateTimeOffset.Now.ToString("mm:ss.fff")); await _next(context); await DoOnAfterUntriggeredDoNext(context, checkResult).ConfigureAwait(false); } }
/// <summary> /// Asynchronous processing of Middleware /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Invoke(HttpContext context) { #region check whether need RateLimit and local Attribute is prority then other rules string methodCacheName = ContextMethodNameHandler(context); var requestNeedRateLimt = await RequestNeedRateLimitAsync(context, methodCacheName); if (!requestNeedRateLimt.Item1) { return; } EnableRateLimitAttribute enableRateLimitAttribute = requestNeedRateLimt.Item2; #endregion check whether need RateLimit and local Attribute is prority then other rules //local method attribute var getMethodAttrRateLimitData = GetRateLimitTypeAttributeData(context); // context.Items.Add("PollyRequire", _specialRule != null ? _specialRule.EnablePolly : false); await DoOnBeforeCheck(context, _algorithm).ConfigureAwait(false); AlgorithmCheckResult checkResult;//= await _algorithm.CheckAsync(context); #region Polly bool enablePolly = enableRateLimitAttribute == null ? (_specialRule != null ? _specialRule.EnablePolly : false) : enableRateLimitAttribute.EnablePolly; if (enablePolly) { checkResult = await PollyRateLimitAdvancedCircuitBreakerAsync(context.Request.Path.Value, enableRateLimitAttribute) .ExecuteAsync(async() => { return(await _algorithm.CheckAsync(context, getMethodAttrRateLimitData)); }); } else { checkResult = await _algorithm.CheckAsync(context, getMethodAttrRateLimitData); } #endregion Polly await DoOnAfterCheck(context, checkResult).ConfigureAwait(false); if (checkResult.IsLimit) { if (checkResult.RuleCheckResults != null && checkResult.RuleCheckResults.Any()) { var checkException = checkResult.RuleCheckResults.FirstOrDefault(x => x.RateLimitExceptionThrow == true); if (checkException != null) { throw new RateLimitException(methodCacheName); } } await DoOnTriggered(context, checkResult).ConfigureAwait(false); context.Response.StatusCode = _error.HttpStatusCode; await SetHeaders(context, checkResult).ConfigureAwait(false); await ReponseWithTooManyRequests(context, checkResult).ConfigureAwait(false); } else { await DoOnBreforUntriggeredDoNext(context, checkResult).ConfigureAwait(false); await DoLeakyBucketWait(checkResult).ConfigureAwait(false); //Debug.WriteLine("R-Count" + checkResult.RuleCheckResults.First().Count + " " + DateTimeOffset.Now.ToString("mm:ss.fff")); await _next(context); await DoOnAfterUntriggeredDoNext(context, checkResult).ConfigureAwait(false); } }