예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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));
        }