/// <inheritdoc cref="IConnection.RequestAsync{TResponse}"/>>
        public virtual async Task <TResponse> RequestAsync <TResponse>(RequestData requestData,
                                                                       CancellationToken cancellationToken
                                                                       )
            where TResponse : class, ITransportResponse, new()
        {
            Action unregisterWaitHandle   = null;
            int?   statusCode             = null;
            IEnumerable <string> warnings = null;
            Stream    responseStream      = null;
            Exception ex       = null;
            string    mimeType = null;
            ReadOnlyDictionary <TcpState, int> tcpStats = null;
            ReadOnlyDictionary <string, ThreadPoolStatistics> threadPoolStats = null;

            try
            {
                var data    = requestData.PostData;
                var request = CreateHttpWebRequest(requestData);
                using (cancellationToken.Register(() => request.Abort()))
                {
                    if (data != null)
                    {
                        var apmGetRequestStreamTask =
                            Task.Factory.FromAsync(request.BeginGetRequestStream, r => request.EndGetRequestStream(r), null);
                        unregisterWaitHandle = RegisterApmTaskTimeout(apmGetRequestStreamTask, request, requestData);

                        using (var stream = await apmGetRequestStreamTask.ConfigureAwait(false))
                        {
                            if (requestData.HttpCompression)
                            {
                                using var zipStream = new GZipStream(stream, CompressionMode.Compress);
                                await data.WriteAsync(zipStream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false);
                            }
                            else
                            {
                                await data.WriteAsync(stream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false);
                            }
                        }
                        unregisterWaitHandle?.Invoke();
                    }
                    requestData.MadeItToResponse = true;
                    //http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx
                    //Either the stream or the response object needs to be closed but not both although it won't
                    //throw any errors if both are closed atleast one of them has to be Closed.
                    //Since we expose the stream we let closing the stream determining when to close the connection

                    var apmGetResponseTask = Task.Factory.FromAsync(request.BeginGetResponse, r => request.EndGetResponse(r), null);
                    unregisterWaitHandle = RegisterApmTaskTimeout(apmGetResponseTask, request, requestData);

                    if (requestData.TcpStats)
                    {
                        tcpStats = TcpStats.GetStates();
                    }

                    if (requestData.ThreadPoolStats)
                    {
                        threadPoolStats = ThreadPoolStats.GetStats();
                    }

                    var httpWebResponse = (HttpWebResponse)await apmGetResponseTask.ConfigureAwait(false);

                    HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);
                    if (httpWebResponse.SupportsHeaders && httpWebResponse.Headers.HasKeys() && httpWebResponse.Headers.AllKeys.Contains("Warning"))
                    {
                        warnings = httpWebResponse.Headers.GetValues("Warning");
                    }
                }
            }
            catch (WebException e)
            {
                ex = e;
                if (e.Response is HttpWebResponse httpWebResponse)
                {
                    HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);
                }
            }
            finally
            {
                unregisterWaitHandle?.Invoke();
            }
            responseStream ??= Stream.Null;
            var response = await ResponseBuilder.ToResponseAsync <TResponse>
                               (requestData, ex, statusCode, warnings, responseStream, mimeType, cancellationToken)
                           .ConfigureAwait(false);

            // set TCP and threadpool stats on the response here so that in the event the request fails after the point of
            // gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse,
            // but doing so would be a breaking change in 7.x
            response.ApiCall.TcpStats        = tcpStats;
            response.ApiCall.ThreadPoolStats = threadPoolStats;
            return(response);
        }
        /// <inheritdoc cref="IConnection.Request{TResponse}"/>>
        public virtual TResponse Request <TResponse>(RequestData requestData)
            where TResponse : class, ITransportResponse, new()
        {
            int?statusCode = null;
            IEnumerable <string> warnings = null;
            Stream    responseStream      = null;
            Exception ex       = null;
            string    mimeType = null;
            ReadOnlyDictionary <TcpState, int> tcpStats = null;
            ReadOnlyDictionary <string, ThreadPoolStatistics> threadPoolStats = null;

            try
            {
                var request = CreateHttpWebRequest(requestData);
                var data    = requestData.PostData;

                if (data != null)
                {
                    using (var stream = request.GetRequestStream())
                    {
                        if (requestData.HttpCompression)
                        {
                            using var zipStream = new GZipStream(stream, CompressionMode.Compress);
                            data.Write(zipStream, requestData.ConnectionSettings);
                        }
                        else
                        {
                            data.Write(stream, requestData.ConnectionSettings);
                        }
                    }
                }
                requestData.MadeItToResponse = true;

                if (requestData.TcpStats)
                {
                    tcpStats = TcpStats.GetStates();
                }

                if (requestData.ThreadPoolStats)
                {
                    threadPoolStats = ThreadPoolStats.GetStats();
                }

                //http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx
                //Either the stream or the response object needs to be closed but not both although it won't
                //throw any errors if both are closed atleast one of them has to be Closed.
                //Since we expose the stream we let closing the stream determining when to close the connection
                var httpWebResponse = (HttpWebResponse)request.GetResponse();
                HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);

                //response.Headers.HasKeys() can return false even if response.Headers.AllKeys has values.
                if (httpWebResponse.SupportsHeaders && httpWebResponse.Headers.Count > 0 && httpWebResponse.Headers.AllKeys.Contains("Warning"))
                {
                    warnings = httpWebResponse.Headers.GetValues("Warning");
                }
            }
            catch (WebException e)
            {
                ex = e;
                if (e.Response is HttpWebResponse httpWebResponse)
                {
                    HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);
                }
            }

            responseStream ??= Stream.Null;
            var response = ResponseBuilder.ToResponse <TResponse>(requestData, ex, statusCode, warnings, responseStream, mimeType);

            // set TCP and threadpool stats on the response here so that in the event the request fails after the point of
            // gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse,
            // but doing so would be a breaking change in 7.x
            response.ApiCall.TcpStats        = tcpStats;
            response.ApiCall.ThreadPoolStats = threadPoolStats;
            return(response);
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            // Settings table
            TableHeaderRow headerRow = new TableHeaderRow();

            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Name"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Value"
            });
            Settings.Rows.AddAt(0, headerRow);

            Type myType = typeof(ScoringDaemonSettings);

            PropertyInfo[] properties = myType.GetProperties(
                BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
            foreach (PropertyInfo property in properties)
            {
                // We dont want to show any secure attributes on the UI (stuff with passwords)
                if (property.GetCustomAttributes(true).OfType <SecureAttribute>().Any())
                {
                    continue;
                }

                TableRow tableRow = new TableRow();
                tableRow.Cells.Add(new TableCell {
                    Text = property.Name
                });
                var propObj = property.GetValue(myType, null);
                tableRow.Cells.Add(new TableCell {
                    Text = convertToString(propObj)
                });
                Settings.Rows.Add(tableRow);
            }

            //hubInfo
            headerRow = new TableHeaderRow();
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "ClientName"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Environment"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "DB IP"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "DB Name"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Last Poll"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Tasks Executed"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Tasks Waiting"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Min Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Ave Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Max Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Min Task Execution Time"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Ave Task Execution Time"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Max Task Execution Time"
            });
            HubInfo.Rows.AddAt(0, headerRow);

            foreach (ReponseRepoMonitor hub in MonitorCollection.GetAll())
            {
                TableRow tableRow = new TableRow();
                tableRow.Cells.Add(new TableCell {
                    Text = hub.ClientName
                });
                tableRow.Cells.Add(new TableCell {
                    Text = hub.Environment
                });
                tableRow.Cells.Add(new TableCell {
                    Text = hub.DBIP
                });
                tableRow.Cells.Add(new TableCell {
                    Text = hub.DBName
                });
                tableRow.Cells.Add(new TableCell {
                    Text = hub.LastRun.ToString()
                });

                ThreadPoolStats tpStats = hub.Stats;
                if (tpStats != null)
                {
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.TasksExecuted.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.TasksInQCount.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.MinQDelay.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.AveQDelay.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.MaxQDelay.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.MinTaskExecutionTime.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.AveTaskExecutionTime.ToString()
                    });
                    tableRow.Cells.Add(new TableCell {
                        Text = tpStats.MaxTaskExecutionTime.ToString()
                    });
                }

                HubInfo.Rows.Add(tableRow);
            }

            // Item scoring callback
            headerRow = new TableHeaderRow();
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Tasks Executed"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Tasks Waiting"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Min Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Ave Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Max Task QDelay"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Min Task Execution Time"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Ave Task Execution Time"
            });
            headerRow.Cells.Add(new TableHeaderCell {
                Text = "Max Task Execution Time"
            });
            CallBackInfo.Rows.AddAt(0, headerRow);

            ThreadPoolStats tpStats1 = ItemScoringCallbackHandler.Stats;

            if (tpStats1 != null)
            {
                TableRow tableRow = new TableRow();
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.TasksExecuted.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.TasksInQCount.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.MinQDelay.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.AveQDelay.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.MaxQDelay.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.MinTaskExecutionTime.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.AveTaskExecutionTime.ToString()
                });
                tableRow.Cells.Add(new TableCell {
                    Text = tpStats1.MaxTaskExecutionTime.ToString()
                });
                CallBackInfo.Rows.Add(tableRow);
            }
        }