public async Task Should_not_minify_plain_text()
        {
            string html = @"   <html>
                            </html>";

            var appfunc = HtmlMinify.Middleware(async env =>
            {
                var context = new OwinContext(env);
                context.Response.ContentType = "text/plain";
                var bytes = Encoding.UTF8.GetBytes(html);
                await context.Response.WriteAsync(bytes);
            });

            var handler = new OwinHttpMessageHandler(appfunc);

            using (var client = new HttpClient(handler))
            {
                var response = await client.GetAsync("http://localhost/");

                var body = await response.Content.ReadAsStringAsync();

                body.Should().Be(html);
            }
        }
        public async Task Blah()
        {
            var app = new AppBuilder();

            app.Run(ctx =>
            {
                ctx.Response.StatusCode   = 404;
                ctx.Response.ReasonPhrase = "Not Found";
                return(Task.CompletedTask);
            });
            var appFunc = app.Build();
            var handler = new OwinHttpMessageHandler(appFunc)
            {
                AllowAutoRedirect = true,
                UseCookies        = true
            };

            var client = new HttpClient(handler)
            {
                BaseAddress = new Uri("http://example.com")
            };

            await client.GetAsync("");
        }
示例#3
0
        async Task InitializeServiceControl(ScenarioContext context)
        {
            var instancePort    = FindAvailablePort(33333);
            var maintenancePort = FindAvailablePort(instancePort + 1);

            ConfigurationManager.AppSettings.Set("ServiceControl/TransportType", transportToUse.TypeName);

            var settings = new Settings(instanceName)
            {
                Port = instancePort,
                DatabaseMaintenancePort = maintenancePort,
                DbPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()),
                ForwardErrorMessages         = false,
                TransportCustomizationType   = transportToUse.TypeName,
                TransportConnectionString    = transportToUse.ConnectionString,
                ProcessRetryBatchesFrequency = TimeSpan.FromSeconds(2),
                MaximumConcurrencyLevel      = 2,
                HttpDefaultConnectionLimit   = int.MaxValue,
                RunInMemory = true,
                OnMessage   = (id, headers, body, @continue) =>
                {
                    var log = LogManager.GetLogger <ServiceControlComponentRunner>();
                    headers.TryGetValue(Headers.MessageId, out var originalMessageId);
                    log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty}).");

                    //Do not filter out CC, SA and HB messages as they can't be stamped
                    if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) &&
                        messageTypes.StartsWith("ServiceControl."))
                    {
                        return(@continue());
                    }

                    //Do not filter out subscribe messages as they can't be stamped
                    if (headers.TryGetValue(Headers.MessageIntent, out var intent) &&
                        intent == MessageIntentEnum.Subscribe.ToString())
                    {
                        return(@continue());
                    }

                    var currentSession = context.TestRunId.ToString();
                    if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession)
                    {
                        log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'.");
                        return(Task.FromResult(0));
                    }

                    return(@continue());
                }
            };

            setSettings(settings);
            Settings = settings;
            var configuration = new EndpointConfiguration(instanceName);

            configuration.EnableInstallers();

            configuration.GetSettings().Set("SC.ScenarioContext", context);
            configuration.GetSettings().Set(context);

            // This is a hack to ensure ServiceControl picks the correct type for the messages that come from plugins otherwise we pick the type from the plugins assembly and that is not the type we want, we need to pick the type from ServiceControl assembly.
            // This is needed because we no longer use the AppDomain separation.
            configuration.RegisterComponents(r => { configuration.GetSettings().Set("SC.ConfigureComponent", r); });

            configuration.RegisterComponents(r =>
            {
                r.RegisterSingleton(context.GetType(), context);
                r.RegisterSingleton(typeof(ScenarioContext), context);
            });

            configuration.Pipeline.Register <TraceIncomingBehavior.Registration>();
            configuration.Pipeline.Register <TraceOutgoingBehavior.Registration>();
            configuration.Pipeline.Register(new StampDispatchBehavior(context), "Stamps outgoing messages with session ID");
            configuration.Pipeline.Register(new DiscardMessagesBehavior(context), "Discards messages based on session ID");

            configuration.AssemblyScanner().ExcludeAssemblies(typeof(ServiceControlComponentRunner).Assembly.GetName().Name);

            customConfiguration(configuration);

            using (new DiagnosticTimer($"Initializing Bootstrapper for {instanceName}"))
            {
                var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(logPath);

                var loggingSettings = new LoggingSettings(settings.ServiceName, logPath: logPath);
                bootstrapper = new Bootstrapper(ctx =>
                {
                    var logitem = new ScenarioContext.LogItem
                    {
                        Endpoint   = settings.ServiceName,
                        Level      = LogLevel.Fatal,
                        LoggerName = $"{settings.ServiceName}.CriticalError",
                        Message    = $"{ctx.Error}{Environment.NewLine}{ctx.Exception}"
                    };
                    context.Logs.Enqueue(logitem);
                    ctx.Stop().GetAwaiter().GetResult();
                }, settings, configuration, loggingSettings, builder => { builder.RegisterType <FailedErrorsModule>().As <INancyModule>(); });
                bootstrapper.HttpClientFactory = HttpClientFactory;
            }

            using (new DiagnosticTimer($"Initializing AppBuilder for {instanceName}"))
            {
                StaticConfiguration.DisableErrorTraces = false;
                var app = new AppBuilder();
                bootstrapper.Startup.Configuration(app);
                var appFunc = app.Build();

                Handler = new OwinHttpMessageHandler(appFunc)
                {
                    UseCookies        = false,
                    AllowAutoRedirect = false
                };
                var httpClient = new HttpClient(Handler);
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpClient = httpClient;
            }

            using (new DiagnosticTimer($"Creating and starting Bus for {instanceName}"))
            {
                Bus = await bootstrapper.Start(true).ConfigureAwait(false);
            }
        }
        async Task InitializeServiceControl(ScenarioContext context, int instancePort, int maintenancePort, int auditInstanceApiPort)
        {
            var instanceName = Settings.DEFAULT_SERVICE_NAME;

            typeof(ScenarioContext).GetProperty("CurrentEndpoint", BindingFlags.Static | BindingFlags.NonPublic)?.SetValue(context, instanceName);

            ConfigurationManager.AppSettings.Set("ServiceControl/TransportType", transportToUse.TypeName);

            var settings = new Settings(instanceName)
            {
                Port = instancePort,
                DatabaseMaintenancePort = maintenancePort,
                DbPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()),
                ForwardErrorMessages                    = false,
                TransportCustomizationType              = transportToUse.TypeName,
                TransportConnectionString               = transportToUse.ConnectionString,
                ProcessRetryBatchesFrequency            = TimeSpan.FromSeconds(2),
                TimeToRestartErrorIngestionAfterFailure = TimeSpan.FromSeconds(2),
                MaximumConcurrencyLevel                 = 2,
                HttpDefaultConnectionLimit              = int.MaxValue,
                RunInMemory     = true,
                RemoteInstances = new[]
                {
                    new RemoteInstanceSetting
                    {
                        ApiUri = $"http://localhost:{auditInstanceApiPort}/api" // evil assumption for now
                    }
                },
                OnMessage = (id, headers, body, @continue) =>
                {
                    var log = LogManager.GetLogger <ServiceControlComponentRunner>();
                    headers.TryGetValue(Headers.MessageId, out var originalMessageId);
                    log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty}).");

                    //Do not filter out CC, SA and HB messages as they can't be stamped
                    if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) &&
                        messageTypes.StartsWith("ServiceControl."))
                    {
                        return(@continue());
                    }

                    //Do not filter out subscribe messages as they can't be stamped
                    if (headers.TryGetValue(Headers.MessageIntent, out var intent) &&
                        intent == MessageIntentEnum.Subscribe.ToString())
                    {
                        return(@continue());
                    }

                    var currentSession = context.TestRunId.ToString();
                    if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession)
                    {
                        log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'.");
                        return(Task.FromResult(0));
                    }

                    return(@continue());
                }
            };

            customServiceControlSettings(settings);
            SettingsPerInstance[instanceName] = settings;

            var configuration      = new EndpointConfiguration(instanceName);
            var scanner            = configuration.AssemblyScanner();
            var excludedAssemblies = new[]
            {
                Path.GetFileName(typeof(ServiceControl.Audit.Infrastructure.Settings.Settings).Assembly.CodeBase),
                typeof(ServiceControlComponentRunner).Assembly.GetName().Name
            };

            scanner.ExcludeAssemblies(excludedAssemblies);

            configuration.GetSettings().Set("SC.ScenarioContext", context);
            configuration.GetSettings().Set(context);

            // This is a hack to ensure ServiceControl picks the correct type for the messages that come from plugins otherwise we pick the type from the plugins assembly and that is not the type we want, we need to pick the type from ServiceControl assembly.
            // This is needed because we no longer use the AppDomain separation.
            configuration.RegisterComponents(r => { configuration.GetSettings().Set("SC.ConfigureComponent", r); });

            configuration.RegisterComponents(r =>
            {
                r.RegisterSingleton(context.GetType(), context);
                r.RegisterSingleton(typeof(ScenarioContext), context);
            });

            configuration.Pipeline.Register <TraceIncomingBehavior.Registration>();
            configuration.Pipeline.Register <TraceOutgoingBehavior.Registration>();
            configuration.Pipeline.Register(new StampDispatchBehavior(context), "Stamps outgoing messages with session ID");
            configuration.Pipeline.Register(new DiscardMessagesBehavior(context), "Discards messages based on session ID");

            customEndpointConfiguration(configuration);

            Bootstrapper bootstrapper;

            using (new DiagnosticTimer($"Initializing Bootstrapper for {instanceName}"))
            {
                var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(logPath);

                var loggingSettings = new LoggingSettings(settings.ServiceName, logPath: logPath);
                bootstrapper = new Bootstrapper(settings, configuration, loggingSettings, builder => { });
                bootstrappers[instanceName]    = bootstrapper;
                bootstrapper.HttpClientFactory = HttpClientFactory;
            }

            using (new DiagnosticTimer($"Initializing AppBuilder for {instanceName}"))
            {
                var app = new AppBuilder();
                bootstrapper.Startup.Configuration(app);
                var appFunc = app.Build();

                var handler = new OwinHttpMessageHandler(appFunc)
                {
                    UseCookies        = false,
                    AllowAutoRedirect = false
                };
                Handlers[instanceName]       = handler;
                portToHandler[settings.Port] = handler; // port should be unique enough
                var httpClient = new HttpClient(handler);
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpClients[instanceName] = httpClient;
            }

            using (new DiagnosticTimer($"Creating infrastructure for {instanceName}"))
            {
                var setupBootstrapper = new SetupBootstrapper(settings, excludeAssemblies: excludedAssemblies
                                                              .Concat(new [] { typeof(IComponentBehavior).Assembly.GetName().Name }).ToArray());
                await setupBootstrapper.Run(null);
            }

            using (new DiagnosticTimer($"Creating and starting Bus for {instanceName}"))
            {
                Busses[instanceName] = await bootstrapper.Start(true).ConfigureAwait(false);
            }
        }

        async Task InitializeServiceControlAudit(ScenarioContext context, int instancePort, int maintenancePort)
        {
            var instanceName = Audit.Infrastructure.Settings.Settings.DEFAULT_SERVICE_NAME;

            typeof(ScenarioContext).GetProperty("CurrentEndpoint", BindingFlags.Static | BindingFlags.NonPublic)?.SetValue(context, instanceName);

            ConfigurationManager.AppSettings.Set("ServiceControl.Audit/TransportType", transportToUse.TypeName);

            var settings = new ServiceControl.Audit.Infrastructure.Settings.Settings(instanceName)
            {
                Port = instancePort,
                DatabaseMaintenancePort = maintenancePort,
                DbPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()),
                TransportCustomizationType = transportToUse.TypeName,
                TransportConnectionString  = transportToUse.ConnectionString,
                MaximumConcurrencyLevel    = 2,
                HttpDefaultConnectionLimit = int.MaxValue,
                RunInMemory = true,
                ServiceControlQueueAddress = Settings.DEFAULT_SERVICE_NAME,
                OnMessage = (id, headers, body, @continue) =>
                {
                    var log = LogManager.GetLogger <ServiceControlComponentRunner>();
                    headers.TryGetValue(Headers.MessageId, out var originalMessageId);
                    log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty}).");

                    //Do not filter out CC, SA and HB messages as they can't be stamped
                    if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) &&
                        messageTypes.StartsWith("ServiceControl."))
                    {
                        return(@continue());
                    }

                    //Do not filter out subscribe messages as they can't be stamped
                    if (headers.TryGetValue(Headers.MessageIntent, out var intent) &&
                        intent == MessageIntentEnum.Subscribe.ToString())
                    {
                        return(@continue());
                    }

                    var currentSession = context.TestRunId.ToString();
                    if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession)
                    {
                        log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'.");
                        return(Task.FromResult(0));
                    }

                    return(@continue());
                }
            };

            customServiceControlAuditSettings(settings);
            SettingsPerInstance[instanceName] = settings;

            var configuration = new EndpointConfiguration(instanceName);

            configuration.EnableInstallers();
            var scanner            = configuration.AssemblyScanner();
            var excludedAssemblies = new[]
            {
                Path.GetFileName(typeof(Settings).Assembly.CodeBase),
                typeof(ServiceControlComponentRunner).Assembly.GetName().Name
            };

            scanner.ExcludeAssemblies(excludedAssemblies);

            configuration.GetSettings().Set("SC.ScenarioContext", context);
            configuration.GetSettings().Set(context);

            // This is a hack to ensure ServiceControl picks the correct type for the messages that come from plugins otherwise we pick the type from the plugins assembly and that is not the type we want, we need to pick the type from ServiceControl assembly.
            // This is needed because we no longer use the AppDomain separation.
            configuration.RegisterComponents(r => { configuration.GetSettings().Set("SC.ConfigureComponent", r); });

            configuration.RegisterComponents(r =>
            {
                r.RegisterSingleton(context.GetType(), context);
                r.RegisterSingleton(typeof(ScenarioContext), context);
            });

            configuration.Pipeline.Register <TraceIncomingBehavior.Registration>();
            configuration.Pipeline.Register <TraceOutgoingBehavior.Registration>();
            configuration.Pipeline.Register(new StampDispatchBehavior(context), "Stamps outgoing messages with session ID");
            configuration.Pipeline.Register(new DiscardMessagesBehavior(context), "Discards messages based on session ID");

            customAuditEndpointConfiguration(configuration);

            ServiceControl.Audit.Infrastructure.Bootstrapper bootstrapper;
            using (new DiagnosticTimer($"Initializing Bootstrapper for {instanceName}"))
            {
                var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(logPath);

                var loggingSettings = new ServiceControl.Audit.Infrastructure.Settings.LoggingSettings(settings.ServiceName, logPath: logPath);
                bootstrapper = new ServiceControl.Audit.Infrastructure.Bootstrapper(ctx =>
                {
                    var logitem = new ScenarioContext.LogItem
                    {
                        Endpoint   = settings.ServiceName,
                        Level      = LogLevel.Fatal,
                        LoggerName = $"{settings.ServiceName}.CriticalError",
                        Message    = $"{ctx.Error}{Environment.NewLine}{ctx.Exception}"
                    };
                    context.Logs.Enqueue(logitem);
                    ctx.Stop().GetAwaiter().GetResult();
                }, settings, configuration, loggingSettings, builder => { });
                bootstrappers[instanceName]    = bootstrapper;
                bootstrapper.HttpClientFactory = HttpClientFactory;
            }

            using (new DiagnosticTimer($"Initializing AppBuilder for {instanceName}"))
            {
                var app = new AppBuilder();
                bootstrapper.Startup.Configuration(app);
                var appFunc = app.Build();

                var handler = new OwinHttpMessageHandler(appFunc)
                {
                    UseCookies        = false,
                    AllowAutoRedirect = false
                };
                Handlers[instanceName]       = handler;
                portToHandler[settings.Port] = handler; // port should be unique enough
                var httpClient = new HttpClient(handler);
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpClients[instanceName] = httpClient;
            }

            using (new DiagnosticTimer($"Creating infrastructure for {instanceName}"))
            {
                var setupBootstrapper = new ServiceControl.Audit.Infrastructure.SetupBootstrapper(settings, excludeAssemblies: excludedAssemblies
                                                                                                  .Concat(new [] { typeof(IComponentBehavior).Assembly.GetName().Name }).ToArray());
                await setupBootstrapper.Run(null);
            }

            using (new DiagnosticTimer($"Creating and starting Bus for {instanceName}"))
            {
                Busses[instanceName] = await bootstrapper.Start(true).ConfigureAwait(false);
            }
        }
示例#5
0
        private void InitializeServiceControl(ScenarioContext context)
        {
            LogManager.Use <NLogFactory>();
            NLog.LogManager.Configuration = SetupLogging(Settings.DEFAULT_SERVICE_NAME);

            var settings = new Settings
            {
                Port   = port,
                DbPath = ravenPath,
                ForwardErrorMessages         = false,
                ForwardAuditMessages         = false,
                TransportType                = transportToUse.TypeName,
                TransportConnectionString    = transportToUse.ConnectionString,
                ProcessRetryBatchesFrequency = TimeSpan.FromSeconds(2),
                MaximumConcurrencyLevel      = 2,
                HttpDefaultConnectionLimit   = int.MaxValue
            };

            SetSettings(settings);

            var configuration = new BusConfiguration();

            configuration.TypesToScan(GetTypesScopedByTestClass(transportToUse).Concat(new[]
            {
                typeof(MessageMapperInterceptor),
                typeof(RegisterWrappers),
                typeof(SessionCopInBehavior),
                typeof(SessionCopInBehaviorForMainPipe),
                typeof(TraceIncomingBehavior),
                typeof(TraceOutgoingBehavior)
            }));
            configuration.EnableInstallers();

            configuration.GetSettings().SetDefault("ScaleOut.UseSingleBrokerQueue", true);
            configuration.GetSettings().Set("SC.ScenarioContext", context);

            // This is a hack to ensure ServiceControl picks the correct type for the messages that come from plugins otherwise we pick the type from the plugins assembly and that is not the type we want, we need to pick the type from ServiceControl assembly.
            // This is needed because we no longer use the AppDomain separation.
            configuration.EnableFeature <MessageMapperInterceptor>();
            configuration.RegisterComponents(r => { configuration.GetSettings().Set("SC.ConfigureComponent", r); });

            configuration.RegisterComponents(r =>
            {
                r.RegisterSingleton(context.GetType(), context);
                r.RegisterSingleton(typeof(ScenarioContext), context);
            });

            configuration.Pipeline.Register <SessionCopInBehavior.Registration>();
            configuration.Pipeline.Register <SessionCopInBehaviorForMainPipe.Registration>();
            configuration.Pipeline.Register <TraceIncomingBehavior.Registration>();
            configuration.Pipeline.Register <TraceOutgoingBehavior.Registration>();

            CustomConfiguration(configuration);

            using (new DiagnosticTimer("Initializing Bootstrapper"))
            {
                bootstrapper = new Bootstrapper(settings, configuration);
            }
            using (new DiagnosticTimer("Initializing AppBuilder"))
            {
                var app = new AppBuilder();
                bootstrapper.Startup.Configuration(app);
                var appFunc = app.Build();

                Handler = new OwinHttpMessageHandler(appFunc)
                {
                    UseCookies        = false,
                    AllowAutoRedirect = false
                };
                httpClient = new HttpClient(Handler);
            }

            using (new DiagnosticTimer("Creating and starting Bus"))
            {
                bus = bootstrapper.Start(true);
            }
        }
        private void InitializeServiceControl(ScenarioContext context, string[] instanceNames)
        {
            if (instanceNames.Length == 0)
            {
                instanceNames = new[] { Settings.DEFAULT_SERVICE_NAME };
            }

            // how to deal with the statics here?
            LogManager.Use <NLogFactory>();
            NLog.LogManager.Configuration = SetupLogging(Settings.DEFAULT_SERVICE_NAME);

            var startPort = 33333;

            foreach (var instanceName in instanceNames)
            {
                startPort = FindAvailablePort(startPort);
                var settings = new Settings(instanceName)
                {
                    Port   = startPort++,
                    DbPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()),
                    ForwardErrorMessages         = false,
                    ForwardAuditMessages         = false,
                    TransportType                = transportToUse.TypeName,
                    TransportConnectionString    = transportToUse.ConnectionString,
                    ProcessRetryBatchesFrequency = TimeSpan.FromSeconds(2),
                    MaximumConcurrencyLevel      = 2,
                    HttpDefaultConnectionLimit   = int.MaxValue
                };

                if (instanceName == Settings.DEFAULT_SERVICE_NAME)
                {
                    SetSettings(settings);
                }

                SetInstanceSettings(instanceName, settings);
                SettingsPerInstance[instanceName] = settings;

                var configuration = new BusConfiguration();
                configuration.TypesToScan(GetTypesScopedByTestClass(transportToUse).Concat(new[]
                {
                    typeof(MessageMapperInterceptor),
                    typeof(RegisterWrappers),
                    typeof(SessionCopInBehavior),
                    typeof(SessionCopInBehaviorForMainPipe),
                    typeof(TraceIncomingBehavior),
                    typeof(TraceOutgoingBehavior)
                }));
                configuration.EnableInstallers();

                configuration.GetSettings().SetDefault("ScaleOut.UseSingleBrokerQueue", true);
                configuration.GetSettings().Set("SC.ScenarioContext", context);

                // This is a hack to ensure ServiceControl picks the correct type for the messages that come from plugins otherwise we pick the type from the plugins assembly and that is not the type we want, we need to pick the type from ServiceControl assembly.
                // This is needed because we no longer use the AppDomain separation.
                configuration.EnableFeature <MessageMapperInterceptor>();
                configuration.RegisterComponents(r => { configuration.GetSettings().Set("SC.ConfigureComponent", r); });

                configuration.RegisterComponents(r =>
                {
                    r.RegisterSingleton(context.GetType(), context);
                    r.RegisterSingleton(typeof(ScenarioContext), context);
                });

                configuration.Pipeline.Register <SessionCopInBehavior.Registration>();
                configuration.Pipeline.Register <SessionCopInBehaviorForMainPipe.Registration>();
                configuration.Pipeline.Register <TraceIncomingBehavior.Registration>();
                configuration.Pipeline.Register <TraceOutgoingBehavior.Registration>();

                if (instanceName == Settings.DEFAULT_SERVICE_NAME)
                {
                    CustomConfiguration(configuration);
                }

                CustomInstanceConfiguration(instanceName, configuration);

                Bootstrapper bootstrapper;
                using (new DiagnosticTimer($"Initializing Bootstrapper for {instanceName}"))
                {
                    var loggingSettings = new LoggingSettings(settings.ServiceName);
                    bootstrapper = new Bootstrapper(() => { }, settings, configuration, loggingSettings);
                    bootstrappers[instanceName]    = bootstrapper;
                    bootstrapper.HttpClientFactory = HttpClientFactory;
                }
                using (new DiagnosticTimer($"Initializing AppBuilder for {instanceName}"))
                {
                    var app = new AppBuilder();
                    bootstrapper.Startup.Configuration(app);
                    var appFunc = app.Build();

                    var handler = new OwinHttpMessageHandler(appFunc)
                    {
                        UseCookies        = false,
                        AllowAutoRedirect = false
                    };
                    Handlers[instanceName]       = handler;
                    portToHandler[settings.Port] = handler; // port should be unique enough
                    var httpClient = new HttpClient(handler);
                    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                    httpClients[instanceName] = httpClient;
                }

                using (new DiagnosticTimer($"Creating and starting Bus for {instanceName}"))
                {
                    busses[instanceName] = bootstrapper.Start(true);
                }
            }

            // how to deal with the statics here?
            ArchivingManager.ArchiveOperations = new Dictionary <string, InMemoryArchive>();
            RetryingManager.RetryOperations    = new Dictionary <string, InMemoryRetry>();
        }