public IInteraction TransformClientRequestForRealService(IInteraction clientRequest)
        {
            var builder = new MarkdownInteraction.Builder()
                          .From(clientRequest)
                          .RequestHeaders(clientRequest.RequestHeaders
                                          //Remove unwanted headers from client request
                                          .Where(h => !_requestHeaderExcludePatterns.Any(pattern => pattern.IsMatch($"{h.Item1}: {h.Item2}")))
                                          //Fix host header
                                          .Select(h =>
            {
                (string name, string value) = h;
                if (name.ToLower() == "host")
                {
                    return(name, _realServiceHost);
                }
                else
                {
                    return(h);
                }
            })
                                          );

            return(builder.Build());
        }
        public async Task <ServiceResponse> GetServiceResponseForRequest(Uri host, IInteraction interaction, bool lowerCaseHeaders)
        {
            var response = await _service.InvokeServiceEndpoint(
                interaction.Method, null, null,
                new Uri($"{_redirectHost.GetLeftPart(UriPartial.Authority)}{interaction.Path}"),
                interaction.RequestHeaders);

            var builder = new MarkdownInteraction.Builder()
                          .From(interaction)
                          .ResponseHeaders(response.Headers);

            if (response.Body != null && response.ContentType != null)
            {
                builder.ResponseBody(response.Body.ToString(), response.ContentType);
            }
            else
            {
                builder.RemoveResponseBody();
            }
            var interactionToRecord = builder.Build();

            _allInteractions[interactionToRecord.Number] = interactionToRecord;
            return(response);
        }
        //private static readonly
        private AspNetCoreServirtiumServer(IHostBuilder hostBuilder, IInteractionMonitor monitor, IInteractionTransforms interactionTransforms, int?port)
        {
            _interactionMonitor = monitor;
            _host = hostBuilder.ConfigureWebHostDefaults(webBuilder =>
            {
                if (port != null)
                {
                    //If a port is specified, override urls with specified port, listening on all available hosts, for HTTP.
                    webBuilder.UseUrls($"http://*:{port}");
                }
                webBuilder.Configure(app =>
                {
                    app.Run(async ctx =>
                    {
                        var targetHost         = new Uri($"{ctx.Request.Scheme}{Uri.SchemeDelimiter}{ctx.Request.Host}");
                        var requestInteraction = new MarkdownInteraction.Builder()
                                                 .Number(_interactionCounter.Bump())
                                                 .Method(new System.Net.Http.HttpMethod(ctx.Request.Method))
                                                 .Path($"{ctx.Request.Path}{ctx.Request.QueryString}")
                                                 //Remap headers from a dictionary of string lists to a list of (string, string) tuples
                                                 .RequestHeaders
                                                 (
                            ctx.Request.Headers
                            .SelectMany(kvp => kvp.Value.Select(val => (kvp.Key, val)))
                            .ToArray()
                                                 )
                                                 .Build();
                        var serviceRequestInteraction = interactionTransforms.TransformClientRequestForRealService(requestInteraction);
                        var responseFromService       = await monitor.GetServiceResponseForRequest(
                            targetHost,
                            serviceRequestInteraction,
                            false);
                        var clientResponse = interactionTransforms.TransformRealServiceResponseForClient(responseFromService);

                        //Always remove the 'Transfer-Encoding: chunked' header if present.
                        //If it's present in the response.Headers collection ast this point, Kestrel expects you to add chunk notation to the body yourself
                        //However if you just send it with no content-length, Kestrel will add the chunked header and chunk the body for you.
                        clientResponse = clientResponse
                                         .WithRevisedHeaders(
                            clientResponse.Headers
                            .Where((h) => !(h.Name.ToLower() == "transfer-encoding" && h.Value.ToLower() == "chunked")))
                                         .WithReadjustedContentLength();
                        ctx.Response.OnCompleted(() =>
                        {
                            Console.WriteLine($"{requestInteraction.Method} Request to {targetHost}{requestInteraction.Path} returned to client with code {ctx.Response.StatusCode}");
                            return(Task.CompletedTask);
                        });

                        //Transfer adjusted headers to the response going out to the client
                        foreach ((string headerName, string headerValue) in clientResponse.Headers)
                        {
                            if (ctx.Response.Headers.TryGetValue(headerName, out var headerInResponse))
                            {
                                ctx.Response.Headers[headerName] = new StringValues(headerInResponse.Append(headerValue).ToArray());
                            }
                            else
                            {
                                ctx.Response.Headers[headerName] = new StringValues(headerValue);
                            }
                        }
                        if (clientResponse.Body != null)
                        {
                            await ctx.Response.WriteAsync(clientResponse.Body.ToString());
                        }
                        await ctx.Response.CompleteAsync();
                    });
                });
            }).Build();
        }