Beispiel #1
0
        /// <summary>
        /// Execute a request for the given requestModel asynchronously, executing the given callback upon completions
        /// other than cancellations (gui updates for cancellation should be done at point of cancellation).
        /// </summary>
        /// <param name="requestModel"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public CancellationTokenSource ExecuteAsync(RequestModel requestModel, Action <ResponseModel> callback)
        {
            //todo: add using statements for disposible objects
            var hasCookies = requestModel.RequestHeaders.ContainsKey("cookie");
            var hasExpect100ContinueHeader =
                requestModel.RequestHeaders.ContainsKey("expect") &&
                requestModel.RequestHeaders["expect"].Equals("100-continue", StringComparison.OrdinalIgnoreCase);

            var handler = new HttpClientHandler {
                AllowAutoRedirect     = followRedirects,
                UseCookies            = hasCookies,
                UseDefaultCredentials = true
            };

            if (!proxyServer.IsBlank())
            {
                handler.Proxy    = new WebProxy(proxyServer, false); //make second arg a config option.
                handler.UseProxy = true;
            }

            if (enableAutomaticContentDecompression)
            {
                foreach (var enc in requestModel.AcceptEncodings)
                {
                    switch (enc)
                    {
                    case "gzip":
                        handler.AutomaticDecompression |= DecompressionMethods.GZip;
                        break;

                    case "deflate":
                        handler.AutomaticDecompression |= DecompressionMethods.Deflate;
                        break;

                    default:
                        log.Warn("Automatic decompression of '{0}' content specified by the Accept-Encoding request header is not supported", enc);
                        break;
                    }
                }
            }

            // 20191203 William Velasquez http://creativosdigitales.co
            // Force TLS 1.2 Connection
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            var client  = new HttpClient(handler);
            var request = new HttpRequestMessage {
                RequestUri = requestModel.Url,
                Method     = requestModel.Method
            };

            foreach (var header in requestModel.RequestHeaders)
            {
                if (header.Key.Equals("cookie", StringComparison.OrdinalIgnoreCase))
                {
                    handler.CookieContainer.SetCookies(requestModel.Url, header.Value.Replace("; ", ", "));
                }
                else
                {
                    request.Headers.Add(header.Key, header.Value);
                }
            }

            request.Headers.ExpectContinue = hasExpect100ContinueHeader;

            if (!requestModel.Url.UserInfo.IsBlank())
            {
                var userInfoBase64Text = Base64EncodeUrlUserInfo(requestModel.Url);
                request.Headers.Authorization = new AuthenticationHeaderValue("Basic", userInfoBase64Text);
            }

            if (requestModel.Method != HttpMethod.Get && requestModel.Method != HttpMethod.Head && !requestModel.Body.IsBlank())
            {
                //default content-type: http://mattryall.net/blog/2008/03/default-content-type
                string textCt;
                requestModel.ContentHeaders.TryGetValue("Content-Type", out textCt);
                textCt = textCt.IsBlank() ? defaultRequestContentType : textCt;  //then try settings supplied
                textCt = textCt.IsBlank() ? "application/octet-stream" : textCt; // then try w3 spec default

                //get encoding
                var ct = new ContentType(textCt);
                //write content w/ BOM  if needed
                var contentBytes = GetEncodedBytes(requestModel.Body, ct.CharSet, includeUtf8Bom);
                var content      = new ByteArrayContent(contentBytes);

                foreach (var header in requestModel.ContentHeaders)
                {
                    content.Headers.Remove(header.Key);                                                //remove defaults
                    if (String.Equals(header.Key, "content-type", StringComparison.OrdinalIgnoreCase)) //treat special w/ defaults, etc.
                    {
                        content.Headers.Add(header.Key, textCt);
                    }
                    else
                    {
                        content.Headers.Add(header.Key, header.Value);
                    }
                }

                request.Content = content;
            }

            var start = DateTime.Now;

            var ctokenSource = new CancellationTokenSource();
            var ctoken       = ctokenSource.Token;

            client.SendAsync(request, ctoken).ContinueWith(responseTask => {
                try {
                    var end = DateTime.Now;
                    switch (responseTask.Status)
                    {
                    case TaskStatus.RanToCompletion: {
                        var response      = responseTask.Result;
                        var responseModel = new ResponseModel(response, start, end);
                        callback(responseModel);
                        break;
                    }

                    case TaskStatus.Canceled: {
                        log.Info("request canceled by user");
                        break;
                    }

                    case TaskStatus.Faulted: {
                        var aggException = responseTask.Exception.Flatten();

                        foreach (var exception in aggException.InnerExceptions)
                        {
                            log.Error(exception, "request terminated with an error");
                        }

                        string errMessage = String.Join(Environment.NewLine, aggException.InnerExceptions);
                        var responseModel = new ResponseModel(errMessage, start, end);
                        callback(responseModel);
                        break;
                    }

                    default: {
                        var errMessage = String.Format("The request terminated with an unexpected status={0}", responseTask.Status);
                        log.Warn(errMessage);
                        var responseModel = new ResponseModel(errMessage, start, end);
                        callback(responseModel);
                        break;
                    }
                    }
                } catch (Exception ex) {
                    log.Error(ex, "exception raised in request continuation, application will proceed in a corrupt state until Task is disposed, at which point the application will shut down with a fatal exception");
                    throw;
                }
            });

            return(ctokenSource);
        }
        private void bind(ResponseModel responseVm)
        {
            this.lastResponseModel = responseVm;

            lblResponseStatusValue.Text = responseVm.Status;
            lnkResponseStatusInfo.Visible = !responseVm.ErrorMessage.IsBlank();
            lnkCancelRequest.Visible = responseVm.Status == ResponseModel.Loading.Status;

            txtResponseHeaders.Text = responseVm.Headers;
            var elapsedMs = responseVm.ElapsedMilliseconds;
            lblResponseTimeValue.Text = elapsedMs == 0 ? "" : elapsedMs + " ms";

            updateResponseBodyOutput();
        }
        /// <summary>
        /// Execute a request for the given requestModel asynchronously, executing the given callback upon completions
        /// other than cancellations (gui updates for cancellation should be done at point of cancellation).
        /// </summary>
        /// <param name="requestModel"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public CancellationTokenSource ExecuteAsync(RequestModel requestModel, Action<ResponseModel> callback)
        {
            //todo: add using statements for disposible objects
            var hasCookies = requestModel.RequestHeaders.ContainsKey("cookie");
            var hasExpect100ContinueHeader =
                requestModel.RequestHeaders.ContainsKey("expect") &&
                requestModel.RequestHeaders["expect"].Equals("100-continue", StringComparison.OrdinalIgnoreCase);

            var handler = new HttpClientHandler {
                AllowAutoRedirect = followRedirects,
                UseCookies = hasCookies
            };

            if (!proxyServer.IsBlank()) {
                handler.Proxy = new WebProxy(proxyServer, false); //make second arg a config option.
                handler.UseProxy = true;
            }

            if (enableAutomaticContentDecompression) {
                foreach (var enc in requestModel.AcceptEncodings) {
                    switch (enc) {
                        case "gzip":
                            handler.AutomaticDecompression |= DecompressionMethods.GZip;
                            break;
                        case "deflate":
                            handler.AutomaticDecompression |= DecompressionMethods.Deflate;
                            break;
                        default:
                            log.Warn("Automatic decompression of '{0}' content specified by the Accept-Encoding request header is not supported", enc);
                            break;
                    }
                }
            }

            var client = new HttpClient(handler);
            var request = new HttpRequestMessage {
                RequestUri = requestModel.Url,
                Method = requestModel.Method
            };

            foreach (var header in requestModel.RequestHeaders) {
                if(header.Key.Equals("cookie", StringComparison.OrdinalIgnoreCase))
                    handler.CookieContainer.SetCookies(requestModel.Url, header.Value.Replace("; ", ", "));
                else
                    request.Headers.Add(header.Key, header.Value);
            }

            request.Headers.ExpectContinue = hasExpect100ContinueHeader;

            if (!requestModel.Url.UserInfo.IsBlank()) {
                var userInfoBase64Text = Base64EncodeUrlUserInfo(requestModel.Url);
                request.Headers.Authorization = new AuthenticationHeaderValue("Basic", userInfoBase64Text);
            }

            if (requestModel.Method != HttpMethod.Get && requestModel.Method != HttpMethod.Head && !requestModel.Body.IsBlank()) {
                //default content-type: http://mattryall.net/blog/2008/03/default-content-type
                string textCt;
                requestModel.ContentHeaders.TryGetValue("Content-Type", out textCt);
                textCt = textCt.IsBlank() ? defaultRequestContentType : textCt; //then try settings supplied
                textCt = textCt.IsBlank() ? "application/octet-stream" : textCt; // then try w3 spec default

                //get encoding
                var ct = new ContentType(textCt);
                //write content w/ BOM  if needed
                var contentBytes = GetEncodedBytes(requestModel.Body, ct.CharSet, includeUtf8Bom);
                var content = new ByteArrayContent(contentBytes);

                foreach (var header in requestModel.ContentHeaders) {
                    content.Headers.Remove(header.Key); //remove defaults
                    if (String.Equals(header.Key, "content-type", StringComparison.OrdinalIgnoreCase)) //treat special w/ defaults, etc.
                        content.Headers.Add(header.Key, textCt);
                    else
                        content.Headers.Add(header.Key, header.Value);
                }

                request.Content = content;
            }

            var start = DateTime.Now;

            var ctokenSource = new CancellationTokenSource();
            var ctoken = ctokenSource.Token;

            client.SendAsync(request,ctoken).ContinueWith(responseTask => {
                try {
                    var end = DateTime.Now;
                    switch (responseTask.Status) {
                        case TaskStatus.RanToCompletion: {
                                var response = responseTask.Result;
                                var responseModel = new ResponseModel(response, start, end);
                                callback(responseModel);
                                break;
                            }
                        case TaskStatus.Canceled: {
                                log.Info("request canceled by user");
                                break;
                            }
                        case TaskStatus.Faulted: {
                                var aggException = responseTask.Exception.Flatten();

                                foreach (var exception in aggException.InnerExceptions)
                                    log.Error("request terminated with an error", exception);

                                string errMessage = String.Join(Environment.NewLine, aggException.InnerExceptions);
                                var responseModel = new ResponseModel(errMessage, start, end);
                                callback(responseModel);
                                break;
                            }
                        default: {
                                var errMessage = String.Format("The request terminated with an unexpected status={0}", responseTask.Status);
                                log.Warn(errMessage);
                                var responseModel = new ResponseModel(errMessage, start, end);
                                callback(responseModel);
                                break;
                            }
                    }
                } catch(Exception ex) {
                    log.Error("exception raised in request continuation, application will proceed in a corrupt state until Task is disposed, at which point the application will shut down with a fatal exception", ex);
                    throw;
                }
            });

            return ctokenSource;
        }
        private void addRequestResponseSnapshot(RequestViewModel requestVm, ResponseModel responseModel)
        {
            //update the model
            snapshots.Add(new RequestResponseSnapshot() { request = requestVm, response = responseModel });

            //update the view
            bindSnapshots();
        }