/// <summary>
        /// Sendet einen PUT Request an die PROFFIX REST API asynchron.
        /// </summary>
        /// <param name="path">Der Pfad zum Endpunkt der PROFFIX REST API.</param>
        /// <param name="body">Der Body, der gesendet werden soll.</param>
        /// <param name="queryString">Benötigte URL-Parameter.</param>
        /// <returns>Gibt einen Task mit der Response der PROFFIX REST API zurück.</returns>
        public async Task <PxRestApiResponse> PutAsync(string path, object body = null, string queryString = null)
        {
            var request = new PxRestApiRequest()
            {
                Method      = HttpMethod.Put.Method,
                Path        = path,
                QueryString = queryString
            };

            request.SetBody(body);

            return(await SendAsync(request));
        }
        /// <summary>
        /// Sendet einen beliebigen Request an die PROFFIX REST API asynchron.
        /// </summary>
        /// <param name="request">Der Request mit allen benötigten Informationen.</param>
        /// <param name="addKey">Gibt an, ob der Key-URL-Parameter dem Request hinzugefügt werden soll.</param>
        /// <returns>Gibt einen Task mit der Response der PROFFIX REST API zurück.</returns>
        public async Task <PxRestApiResponse> SendAsync(PxRestApiRequest request, bool addKey = false)
        {
            HttpContext context = this.httpContextAccessor.HttpContext;

            string sessionId = context.Request.Headers[PxSessionIdHeader];
            string publicUrl = context.Request.Headers[PxPublicUrlHeader];

            string[] addresses = context.Request.Headers[PxAddressHeader];
            string   key       = addKey ? (string)context.Request.Headers[PxKeyHeader] : null;

            List <string> baseUrls = new List <string>(2);

            const string scheme = "http://";

            string httpAddress = addresses?.FirstOrDefault(address => address?.StartsWith(scheme) ?? false);

            if (httpAddress != null)
            {
                string host = this.GetHostFromAddress(httpAddress);

                if (host != null)
                {
                    string afterHost = httpAddress.Substring(scheme.Length + host.Length);

                    if (host == "+" ||
                        host == "*" || (
                            IPAddress.TryParse(host, out IPAddress address) && (
                                address.Equals(IPAddress.Any) ||
                                address.Equals(IPAddress.IPv6Any))))
                    {
                        host = "localhost";
                    }

                    baseUrls.Add($"{scheme}{host}{afterHost}");
                }
            }

            if (!string.IsNullOrWhiteSpace(publicUrl))
            {
                baseUrls.Add(publicUrl);
            }

            foreach (string baseUrl in baseUrls)
            {
                using (HttpRequestMessage requestMessage = await CreateRequestAsync(baseUrl, sessionId, key, request)) {
                    try {
                        using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) {
                            return(await CreateResponseAsync(responseMessage));
                        }
                    }
                    catch (HttpRequestException) { }
                    catch (OperationCanceledException) {
                        if (context.RequestAborted.IsCancellationRequested)
                        {
                            throw;
                        }
                    }
                }
            }

            throw new InvalidOperationException("Die Anfrage konnte nicht an die PROFFIX REST API gesendet werden, da keine gültige Basis-URL verfügbar ist.");
        }
        private async Task <HttpRequestMessage> CreateRequestAsync(string baseUrl, string sessionId, string key, PxRestApiRequest request)
        {
            HttpRequestMessage requestMessage = new HttpRequestMessage();

            requestMessage.Method  = new HttpMethod(request.Method);
            requestMessage.Version = new Version(request.Protocol ?? "1.1");
            requestMessage.Headers.TryAddWithoutValidation(PxSessionIdHeader, sessionId);

            if (request.Body != null)
            {
                MemoryStream body = new MemoryStream();

                using (StreamWriter writer = new StreamWriter(body, this.utf8WithoutBom, 1024, true)) {
                    JsonSerializer jsonSerializer = new JsonSerializer();
                    jsonSerializer.Serialize(writer, request.Body);
                }

                body.Position          = 0;
                requestMessage.Content = new StreamContent(body);
            }

            if (request.Headers != null)
            {
                foreach (KeyValuePair <string, string[]> header in request.Headers)
                {
                    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value))
                    {
                        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
                    }
                }
            }

            if (request.Body != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }

            string uri = baseUrl.EndsWith("/") ? baseUrl.TrimEnd('/') : baseUrl;

            string path = request.Path;

            if (!string.IsNullOrWhiteSpace(path))
            {
                uri += path.StartsWith("/") ? path : "/" + path;
            }

            string queryString = request.QueryString;

            if (!string.IsNullOrWhiteSpace(key))
            {
                if (string.IsNullOrWhiteSpace(queryString))
                {
                    queryString = $"?key={key}";
                }
                else
                {
                    queryString += $"&key={key}";
                }
            }

            if (!string.IsNullOrWhiteSpace(queryString))
            {
                uri += queryString.StartsWith("?") ? queryString : "?" + queryString;
            }

            requestMessage.RequestUri   = new Uri(uri);
            requestMessage.Headers.Host = requestMessage.RequestUri.Host;

            return(await Task.FromResult(requestMessage));
        }