private ApplicationBuilder(ApplicationBuilder <TContext> builder)
 {
     Properties = builder.Properties;
 }
        public IServerHost <TContext> Build()
        {
            var services = new ServiceCollection();

            services.AddInstance <ILoggerFactory>(new LoggerFactory());
            services.AddLogging();
            services.AddOptions();
            services.AddSingleton <IApplicationLifetime, ApplicationLifetime>();

            services.AddSingleton <IFrameOutput, FrameOutput>();
            services.AddSingleton <IOutputProducerFactory, DefaultOutputProducerFactory>();
            services.AddSingleton(typeof(IDispatcher <>), typeof(Dispatcher <>));

            // known encoders
            services.AddCodec <JObject, JsonEncoder, JsonDecoder>();

            // Add known protocols
            services.AddSingleton(typeof(IContextFactory <TcpContext>), typeof(TcpContextFactory));

            // Add the startup type
            services.AddSingleton(_startupType);
            services.AddSingleton(typeof(IServerFactory), _serverFactoryType);

            _configureServices?.Invoke(services);

            var serviceProvider = services.BuildServiceProvider();

            var startup = serviceProvider.GetService(_startupType);

            var configure         = FindConfigureDelegate(_startupType);
            var configureServices = FindConfigureServicesDelegate(_startupType);

            // ConfigureServices
            var applicationServices = configureServices?.Invoke(startup, new object[] { services }) as IServiceProvider ??
                                      services.BuildServiceProvider();

            // Configure (will support DI at some point)
            // configure.Invoke(startup, new object[] { });
            var parameters = configure.GetParameters();
            var args       = new object[parameters.Length];

            if (parameters.Length == 0)
            {
                throw new InvalidOperationException("Invalid Configure signature");
            }

            var appBuilder = new ApplicationBuilder <TContext>(applicationServices);

            args[0] = appBuilder;

            for (int i = 1; i < parameters.Length; i++)
            {
                args[i] = applicationServices.GetRequiredService(parameters[i].ParameterType);
            }

            configure.Invoke(startup, args);

            var pipeline       = appBuilder.Build();
            var serverFactory  = applicationServices.GetRequiredService <IServerFactory>();
            var contextFactory = applicationServices.GetRequiredService <IContextFactory <TContext> >();
            var server         = serverFactory.CreateServer(_config);

            return(new ServerHost <TContext>(server, applicationServices, contextFactory, pipeline));
        }