/// <summary> /// Send the request /// </summary> /// <param name="request">Request</param> /// <param name="cancellationToken">Cancellation token</param> /// <returns>HttpResponseMessage</returns> protected override async Task <HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { #region Get receiver-name and retry-times from Http Header // Retry Times request.Headers.TryGetValues(CustomHttpHeaderFactory.RetryTimes, out IEnumerable <string> retryTimesValues); int retryTimes = 0; int.TryParse(retryTimesValues.FirstOrDefault(), out retryTimes); // RequestCacheId request.Headers.TryGetValues(CustomHttpHeaderFactory.RequestCacheId, out IEnumerable <string> requestCacheIdValues); var requestCacheId = requestCacheIdValues.FirstOrDefault(); #endregion #region Encrypt the Http Request (Only in the first time) if (retryTimes.Equals(0)) { this.logger.LogDebug($"Start encrypting request..."); using (var rsa = new RsaService()) { #region Get public key var publicKey = await this.keyManager.GetPublicKeyAsync(KeyTypeEnum.RSA); #endregion #region Get original payload // Load payload string content = await request.Content.ReadAsStringAsync(); // Remove escapted character, eq. "\"xxxxx\"" => "xxxxx" var jsonPayload = JsonConvert.DeserializeObject <string>(content); #endregion #region Save the original payload before encrypted var cacheKey = requestCacheId; this.memoryCache.Set(cacheKey, jsonPayload, DateTimeOffset.Now.AddSeconds(CacheRequestTimeout)); this.logger.LogDebug($"Successfully caching original request to memory cache: {cacheKey}."); #endregion #region Encrypt // Encrypt string encryptedPayload = await rsa.EncryptAsync(publicKey, jsonPayload); // Replace the original content with the encrypted one var newContent = new System.Net.Http.StringContent($"\"{encryptedPayload}\"", Encoding.UTF8, "application/json"); ////newContent.Headers.ContentType.CharSet = string.Empty; request.Content = newContent; this.logger.LogDebug($"Successfully encrypting request."); #endregion } } #endregion // base.SendAsync calls the inner handler var response = await base.SendAsync(request, cancellationToken); return(response); }
/// <summary> /// Create Retry policy hander instance /// </summary> /// <returns>PolicyBuilder of HttpResponseMessage</returns> public async Task <Polly.Retry.AsyncRetryPolicy <HttpResponseMessage> > CreateAsync(int maxRetryTimes = DefaultMaxRetryTimes) { var retryPolicy = Policy.HandleResult <HttpResponseMessage>(r => r.StatusCode.Equals(HttpStatusCode.UnprocessableEntity)) .RetryAsync(maxRetryTimes, async(exception, retryCount) => { this.logger.LogWarning($"The encrypted data was rejected, update public key and will retry {retryCount}/{maxRetryTimes}(times/total)..."); var request = exception.Result.RequestMessage; var response = exception.Result; // Public key response.Headers.TryGetValues(CustomHttpHeaderFactory.PublicKey, out IEnumerable <string> publicKeyValues); var correctPublicKey = publicKeyValues.FirstOrDefault(); // RequestICached response.Headers.TryGetValues(CustomHttpHeaderFactory.RequestCacheId, out IEnumerable <string> requestCacheIdValues); var requestCacheId = requestCacheIdValues.FirstOrDefault(); if (string.IsNullOrEmpty(correctPublicKey)) { this.logger.LogWarning($"The response does not have required header: \"{CustomHttpHeaderFactory.PublicKey}\". Stop retrying the request!"); throw new OperationCanceledException(); } else if (string.IsNullOrEmpty(requestCacheId)) { this.logger.LogWarning($"The response does not have required header: \"{CustomHttpHeaderFactory.RequestCacheId}\" on response. Stop retrying the request!"); throw new OperationCanceledException(); } else { #region Get the original request var cacheKey = requestCacheId; this.memoryCache.TryGetValue(cacheKey, out string jsonPayload); if (string.IsNullOrEmpty(jsonPayload)) { this.logger.LogWarning($"Lost the original request in MemoryCache (Key: {cacheKey}). Stop retrying the request!"); throw new OperationCanceledException(); } #endregion #region Encrypt the original request by the new public key using (var rsa = new RsaService()) { string encryptedPayload = await rsa.EncryptAsync(correctPublicKey, jsonPayload); // Replace the original content with the encrypted one var newContent = new System.Net.Http.StringContent($"\"{encryptedPayload}\"", Encoding.UTF8, "application/json"); request.Content = newContent; this.logger.LogDebug($"Successfully encrypting request."); } #endregion #region Retry times incremental request.Headers.Remove(CustomHttpHeaderFactory.RetryTimes); request.Headers.Add(CustomHttpHeaderFactory.RetryTimes, retryCount.ToString()); #endregion #region Update the correct public key with KeyManager var key = (await this.keyManager.GetKeyAsync(KeyTypeEnum.RSA)); key.PublicKey = correctPublicKey; await this.keyManager.SaveKeyAsync(key); this.logger.LogWarning($"Updated the correct public key. Now start retrying sending request."); #endregion } }); return(await Task.FromResult(retryPolicy)); }