protected override async Task <HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken
            )
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Method == null)
            {
                throw new ArgumentNullException(nameof(request.Method));
            }

            if (request.RequestUri == null)
            {
                throw new ArgumentNullException(nameof(request.RequestUri));
            }

            var requestMethod  = request.Method;
            var requestHeaders = request.Headers?.ToDictionary(pair => pair.Key, pair => pair.Value?.ToList()) ??
                                 new Dictionary <string, List <string> >();

            var requestUri = new Uri(request.RequestUri?.OriginalString);

            var response           = await(base.SendAsync(request, cancellationToken) ?? throw new InvalidOperationException());
            var responseStatusCode = response.StatusCode;
            var responseHeaders    = response.Headers?.ToDictionary(pair => pair.Key, pair => pair.Value?.ToList()) ??
                                     new Dictionary <string, List <string> >();

            var responseReasonPhrase = response.ReasonPhrase;

            var logLevel = responseStatusCode.ToIntersectLogLevel(requestMethod);

            // ReSharper disable once InvertIf
            if (logLevel < LogLevel)
            {
                var log = new RequestLog
                {
                    Time            = DateTime.UtcNow,
                    Level           = logLevel,
                    Method          = requestMethod.Method,
                    StatusCode      = (int)responseStatusCode,
                    StatusMessage   = responseReasonPhrase,
                    Uri             = requestUri.OriginalString,
                    RequestHeaders  = requestHeaders,
                    ResponseHeaders = responseHeaders
                };

                using (var context = LoggingContext.Create())
                {
                    context.Add(log);
                    try
                    {
                        await(context.SaveChangesAsync(cancellationToken) ?? throw new InvalidOperationException());
                    }
                    catch (Exception exception)
                    {
                        Log.Error(exception);

                        throw;
                    }
                }
            }

            return(response);
        }
        /// <inheritdoc />
        public override async Task Invoke(IOwinContext owinContext)
        {
            try
            {
                if (owinContext == null)
                {
                    throw new ArgumentNullException(nameof(owinContext));
                }

                if (owinContext.Request == null)
                {
                    throw new ArgumentNullException(nameof(owinContext.Request));
                }

                var request        = owinContext.Request;
                var requestMethod  = new HttpMethod(request.Method?.ToUpperInvariant() ?? HttpMethod.Get?.Method);
                var requestHeaders = request.Headers?.ToDictionary(pair => pair.Key, pair => pair.Value?.ToList()) ??
                                     new Dictionary <string, List <string> >();

                var requestUri = new Uri(
                    request.Uri?.OriginalString ?? throw new ArgumentNullException(nameof(request.Uri))
                    );

                var internalServerError = false;
                if (Next != null)
                {
                    try
                    {
                        var   task = Next.Invoke(owinContext) ?? throw new InvalidOperationException(@"Task is null");
                        await task;
                    }
                    catch (Exception exception)
                    {
                        Log.Error(exception);
                        internalServerError = true;
                    }
                }

                if (owinContext.Response == null)
                {
                    throw new ArgumentNullException(nameof(owinContext.Response));
                }

                var response           = owinContext.Response;
                var responseStatusCode = internalServerError
                    ? HttpStatusCode.InternalServerError
                    : (HttpStatusCode)response.StatusCode;

                var responseHeaders = new Dictionary <string, List <string> >();
                if (response.Headers != null)
                {
                    // This is necessary because *apparently* the response headers
                    // dictionary does not combine duplicate header keys into a
                    // single entry's value array, and regular dictionaries
                    // most definitely do not appreciate that, nor will JSON.
                    foreach (var responseHeaderPair in response.Headers)
                    {
                        var key = responseHeaderPair.Key;
                        if (string.IsNullOrWhiteSpace(key))
                        {
                            continue;
                        }

                        var aggregateValue = new List <string>();
                        if (responseHeaders.TryGetValue(key, out var existingValue) && existingValue != null)
                        {
                            aggregateValue.AddRange(existingValue);
                        }

                        var value = responseHeaderPair.Value;
                        if (value != null)
                        {
                            aggregateValue.AddRange(value);
                        }

                        responseHeaders[key] = aggregateValue;
                    }
                }

                var logLevel = responseStatusCode.ToIntersectLogLevel();

                // ReSharper disable once InvertIf
                if (logLevel < LogLevel)
                {
                    var log = new RequestLog
                    {
                        Time            = DateTime.UtcNow,
                        Level           = logLevel,
                        Method          = requestMethod.Method,
                        StatusCode      = (int)responseStatusCode,
                        StatusMessage   = response.ReasonPhrase,
                        Uri             = requestUri.OriginalString,
                        RequestHeaders  = requestHeaders,
                        ResponseHeaders = responseHeaders
                    };

                    using (var context = LoggingContext.Create())
                    {
                        context.Add(log);
                        await(context.SaveChangesAsync() ?? throw new InvalidOperationException());
                    }
                }
            }
            catch (Exception exception)
            {
                Log.Error(exception);

                throw;
            }
        }