예제 #1
0
        /// <summary>
        /// Send request
        /// </summary>
        /// <param name="httpRequest"></param>
        /// <param name="httpMethod"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task <IHttpResponse> SendAsync(IHttpRequest httpRequest,
                                                     HttpMethod httpMethod, CancellationToken ct)
        {
            if (!(httpRequest is HttpRequest wrapper))
            {
                throw new InvalidOperationException("Bad request");
            }

            using (var client = _factory.CreateClient(httpRequest.ResourceId ??
                                                      HttpHandlerFactory.DefaultResourceId)) {
                if (httpRequest.Options.Timeout.HasValue)
                {
                    client.Timeout = httpRequest.Options.Timeout.Value;
                }

                var sw = Stopwatch.StartNew();
                _logger.Verbose("Sending {method} request to {uri}...", httpMethod,
                                httpRequest.Uri);

                // We will use this local function for Exception formatting
                HttpRequestException generateHttpRequestException(Exception e)
                {
                    var errorMessage = e.Message;

                    if (e.InnerException != null)
                    {
                        errorMessage += " - " + e.InnerException.Message;
                    }
                    _logger.Warning("{method} to {uri} failed (after {elapsed}) : {message}!",
                                    httpMethod, httpRequest.Uri, sw.Elapsed, errorMessage);
                    _logger.Verbose(e, "{method} to {uri} failed (after {elapsed}) : {message}!",
                                    httpMethod, httpRequest.Uri, sw.Elapsed, errorMessage);
                    return(new HttpRequestException(errorMessage, e));
                }

                using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ct)) {
                    try {
                        wrapper.Request.Method = httpMethod;
                        using (var response = await client.SendAsync(wrapper.Request, linkedCts.Token)) {
                            var result = new HttpResponse {
                                ResourceId     = httpRequest.ResourceId,
                                StatusCode     = response.StatusCode,
                                Headers        = response.Headers,
                                ContentHeaders = response.Content.Headers,
                                Content        = await response.Content.ReadAsByteArrayAsync()
                            };
                            if (result.IsError())
                            {
                                _logger.Warning("{method} to {uri} returned {code} (took {elapsed}).",
                                                httpMethod, httpRequest.Uri, response.StatusCode, sw.Elapsed,
                                                result.GetContentAsString(Encoding.UTF8));
                            }
                            else
                            {
                                _logger.Verbose("{method} to {uri} returned {code} (took {elapsed}).",
                                                httpMethod, httpRequest.Uri, response.StatusCode, sw.Elapsed);
                            }
                            return(result);
                        }
                    }
                    catch (HttpRequestException e) {
                        var requestEx = generateHttpRequestException(e);
                        throw requestEx;
                    }
                    catch (OperationCanceledException e) {
                        if (ct.IsCancellationRequested)
                        {
                            // Cancel was called. We will call ct.ThrowIfCancellationRequested() because the
                            // token that is passed to the exception is the linked token. This way,
                            // information about usage of linked tokens will not be leaked to the caller.
                            ct.ThrowIfCancellationRequested();
                        }

                        // Operation timed out.
                        var requestEx = generateHttpRequestException(e);
                        throw requestEx;
                    }
                }
            }
        }