public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return(Host.CreateDefaultBuilder(args)
                   .ConfigureWebHostDefaults(webBuilder =>
            {
                // Custom Config
                var config = new ConfigurationBuilder()
                             .AddJsonFile("LiveReloadServer.json", optional: true)
                             .AddJsonFile("LiveReloadWebServer.json", optional: true)
                             .AddEnvironmentVariables()
                             .AddEnvironmentVariables("LIVERELOADSERVER_")
                             .AddEnvironmentVariables("LIVERELOADWEBSERVER_")
                             .AddCommandLine(args)
                             .Build();


                var environment = config["Environment"];
                if (environment == null)
                {
                    environment = "Production";
                }

                // Custom Logging
                webBuilder
                .ConfigureLogging(logging =>
                {
                    logging.ClearProviders();
                    logging.AddConsole();
                    logging.AddConfiguration(config);
                })
                .UseConfiguration(config);



                var webRoot = config["WebRoot"];
                if (!string.IsNullOrEmpty(webRoot))
                {
                    webBuilder.UseWebRoot(webRoot);
                }

                string sport = config["Port"];
                int.TryParse(sport, out int port);
                if (port == 0)
                {
                    port = 5200;
                }

                bool useSsl = Helpers.GetLogicalSetting("UseSsl", config);
                webBuilder.UseUrls($"http{(useSsl ? "s" : "")}://0.0.0.0:{port}");

                webBuilder
                .UseStartup <Startup>();
            }));
        }
Example #2
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Get Configuration Settings
            UseLiveReload = Helpers.GetLogicalSetting("LiveReloadEnabled", Configuration);
            UseRazor      = Helpers.GetLogicalSetting("UseRazor", Configuration);

            WebRoot = Configuration["WebRoot"];
            if (string.IsNullOrEmpty(WebRoot))
            {
                WebRoot = Environment.CurrentDirectory;
            }
            else
            {
                WebRoot = Path.GetFullPath(WebRoot, Environment.CurrentDirectory);
            }

            if (UseLiveReload)
            {
                services.AddLiveReload(opt =>
                {
                    opt.FolderToMonitor   = WebRoot;
                    opt.LiveReloadEnabled = UseLiveReload;

                    var extensions = Configuration["Extensions"];
                    if (!string.IsNullOrEmpty(extensions))
                    {
                        opt.ClientFileExtensions = extensions;
                    }
                });
            }


#if USE_RAZORPAGES
            if (UseRazor)
            {
                var mvcBuilder = services.AddRazorPages(opt => opt.RootDirectory = "/")
                                 .AddRazorRuntimeCompilation(
                    opt =>
                {
                    opt.FileProviders.Add(new PhysicalFileProvider(WebRoot));
                });

                LoadPrivateBinAssemblies(mvcBuilder);
            }
#endif
        }
Example #3
0
        /// <summary>
        /// Loads and fixes up configuration values from the configuraton.
        /// </summary>
        /// <remarks>
        /// Note we're custom loading this to allow for not overly string command line syntax
        /// </remarks>
        /// <param name="Configuration">.NET Core Configuration Provider</param>
        public bool LoadFromConfiguration(IConfiguration Configuration)
        {
            Current = this;

            WebRoot = Configuration["WebRoot"];
            if (string.IsNullOrEmpty(WebRoot))
            {
                WebRoot = Environment.CurrentDirectory;
            }
            else
            {
                WebRoot = Path.GetFullPath(WebRoot, Environment.CurrentDirectory);
            }

            Port         = Helpers.GetIntegerSetting("Port", Configuration, Port);
            UseSsl       = Helpers.GetLogicalSetting("UseSsl", Configuration, UseSsl);
            Host         = Helpers.GetStringSetting("Host", Configuration, Host);
            DefaultFiles = Helpers.GetStringSetting("DefaultFiles", Configuration, DefaultFiles);
            Extensions   = Helpers.GetStringSetting("Extensions", Configuration, Extensions);


            UseLiveReload = Helpers.GetLogicalSetting("UseLiveReload", Configuration, UseLiveReload);
            UseRazor      = Helpers.GetLogicalSetting("UseRazor", Configuration);
            ShowUrls      = Helpers.GetLogicalSetting("ShowUrls", Configuration, ShowUrls);
            OpenBrowser   = Helpers.GetLogicalSetting("OpenBrowser", Configuration, OpenBrowser);

            FolderNotFoundFallbackPath = Helpers.GetStringSetting("FolderNotFoundFallbackPath", Configuration, null);

            // Enables Markdown Middleware and optionally copies Markdown Templates into output folder
            UseMarkdown = Helpers.GetLogicalSetting("UseMarkdown", Configuration, false);
            if (UseMarkdown)
            {
                // defaults to true but only if Markdown is enabled!
                CopyMarkdownResources = Helpers.GetLogicalSetting("CopyMarkdownResources", Configuration, CopyMarkdownResources);
            }
            MarkdownTemplate    = Helpers.GetStringSetting("MarkdownTemplate", Configuration, MarkdownTemplate);
            MarkdownTheme       = Helpers.GetStringSetting("MarkdownTheme", Configuration, MarkdownTheme);
            MarkdownSyntaxTheme = Helpers.GetStringSetting("MarkdownSyntaxTheme", Configuration, MarkdownSyntaxTheme);

            return(true);
        }
        /// <summary>
        /// Loads and fixes up configuration values from the configuraton.
        /// </summary>
        /// <remarks>
        /// Note we're custom loading this to allow for not overly string command line syntax
        /// </remarks>
        /// <param name="Configuration">.NET Core Configuration Provider</param>
        public bool LoadFromConfiguration(IConfiguration Configuration)
        {
            Current = this;

            WebRoot = Configuration["WebRoot"];
            if (string.IsNullOrEmpty(WebRoot))
            {
                // if not set but the first arg does not start with the - it's the folder
                var args = Environment.GetCommandLineArgs();
                if (args.Length > 1 && !args[1].StartsWith("-"))
                {
                    WebRoot = args[1];
                }
            }
            if (string.IsNullOrEmpty(WebRoot))
            {
                WebRoot = Environment.CurrentDirectory;
            }
            else
            {
                var expandedPath = FileUtils.ExpandPathEnvironmentVariables(WebRoot);
                WebRoot = Path.GetFullPath(expandedPath, Environment.CurrentDirectory);
            }

            Port         = Helpers.GetIntegerSetting("Port", Configuration, Port);
            UseSsl       = Helpers.GetLogicalSetting("UseSsl", Configuration, UseSsl);
            Host         = Helpers.GetStringSetting("Host", Configuration, Host);
            DefaultFiles = Helpers.GetStringSetting("DefaultFiles", Configuration, DefaultFiles);
            Extensions   = Helpers.GetStringSetting("Extensions", Configuration, Extensions);

            UseLiveReload = Helpers.GetLogicalSetting("UseLiveReload", Configuration, UseLiveReload);
            UseRazor      = Helpers.GetLogicalSetting("UseRazor", Configuration);
            ShowUrls      = Helpers.GetLogicalSetting("ShowUrls", Configuration, ShowUrls);

            OpenBrowser         = Helpers.GetLogicalSetting("OpenBrowser", Configuration, OpenBrowser);
            OpenEditor          = Helpers.GetLogicalSetting("OpenEditor", Configuration, OpenEditor);
            EditorLaunchCommand = Helpers.GetStringSetting("EditorLaunchCommand", Configuration, EditorLaunchCommand);


            DetailedErrors = Helpers.GetLogicalSetting("DetailedErrors", Configuration, DetailedErrors);

            FolderNotFoundFallbackPath = Helpers.GetStringSetting("FolderNotFoundFallbackPath", Configuration, null);

            // Enables Markdown Middleware and optionally copies Markdown Templates into output folder
            UseMarkdown = Helpers.GetLogicalSetting("UseMarkdown", Configuration, false);
            if (UseMarkdown)
            {
                // defaults to true but only if Markdown is enabled!
                CopyMarkdownResources = Helpers.GetLogicalSetting("CopyMarkdownResources", Configuration, CopyMarkdownResources);
            }
            MarkdownTemplate    = Helpers.GetStringSetting("MarkdownTemplate", Configuration, MarkdownTemplate);
            MarkdownTheme       = Helpers.GetStringSetting("MarkdownTheme", Configuration, MarkdownTheme);
            MarkdownSyntaxTheme = Helpers.GetStringSetting("MarkdownSyntaxTheme", Configuration, MarkdownSyntaxTheme);


            // Fix ups
            if (Extensions is null)
            {
                Extensions = string.Empty;
            }

            if (UseMarkdown)
            {
                if (!Extensions.Contains(".md"))
                {
                    Extensions += ",.md";
                }
                if (!Extensions.Contains(".markdown"))
                {
                    Extensions += ",.markdown";
                }

                if (!DefaultFiles.Contains(".md"))
                {
                    DefaultFiles = DefaultFiles.Trim(',') + ",README.md,index.md";
                }
            }

            return(true);
        }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            WebRoot = Configuration["WebRoot"];
            if (string.IsNullOrEmpty(WebRoot))
            {
                WebRoot = Environment.CurrentDirectory;
            }
            else
            {
                WebRoot = Path.GetFullPath(WebRoot, Environment.CurrentDirectory);
            }

            // Enable Live Reload Middleware
            UseLiveReload = Helpers.GetLogicalSetting("UseLiveReload", Configuration, true);

            // Razor enables compilation and Razor Page Engine
            UseRazor = Helpers.GetLogicalSetting("UseRazor", Configuration);

            // Enables Markdown Middleware and optionally copies Markdown Templates into output folder
            UseMarkdown           = Helpers.GetLogicalSetting("UseMarkdown", Configuration, false);
            CopyMarkdownResources = false;
            if (UseMarkdown)
            {
                // defaults to true but only if Markdown is enabled!
                CopyMarkdownResources = Helpers.GetLogicalSetting("CopyMarkdownResources", Configuration, false);
                MarkdownTemplate      = Configuration["MarkdownTemplate"] ?? MarkdownTemplate;
                MarkdownTheme         = Configuration["MarkdownTheme"] ?? "github";
                MarkdownSyntaxTheme   = Configuration["MarkdownSyntaxTheme"] ?? "github";
            }


            if (UseLiveReload)
            {
                services.AddLiveReload(opt =>
                {
                    opt.FolderToMonitor   = WebRoot;
                    opt.LiveReloadEnabled = UseLiveReload;

                    var extensions = Configuration["Extensions"];
                    if (!string.IsNullOrEmpty(extensions))
                    {
                        opt.ClientFileExtensions = extensions;
                    }

                    if (UseMarkdown && !opt.ClientFileExtensions.Contains(".md", StringComparison.OrdinalIgnoreCase))
                    {
                        opt.ClientFileExtensions += ",.md,.mkdown";
                    }
                });
            }

            IMvcBuilder mvcBuilder = null;

#if USE_RAZORPAGES
            if (UseRazor)
            {
                mvcBuilder = services.AddRazorPages(opt =>
                {
                    opt.RootDirectory = "/";
                });
            }
#endif

            if (UseMarkdown)
            {
                services.AddMarkdown(config =>
                {
                    //var templatePath = Path.Combine(WebRoot, "markdown-themes/__MarkdownPageTemplate.cshtml");
                    //if (!File.Exists(templatePath))
                    //    templatePath = Path.Combine(Environment.CurrentDirectory,"markdown-themes/__MarkdownPageTemplate.cshtml");
                    //else
                    var templatePath = MarkdownTemplate;
                    templatePath     = templatePath.Replace("\\", "/");

                    var folderConfig = config.AddMarkdownProcessingFolder("/", templatePath);

                    // Optional configuration settings
                    folderConfig.ProcessExtensionlessUrls = true; // default
                    folderConfig.ProcessMdFiles           = true; // default

                    folderConfig.RenderTheme = MarkdownTheme;
                    folderConfig.SyntaxTheme = MarkdownSyntaxTheme;
                });

                // we have to force MVC in order for the controller routing to work
                mvcBuilder = services
                             .AddMvc();

                // copy Markdown Template and resources if it doesn't exist
                if (CopyMarkdownResources)
                {
                    CopyMarkdownTemplateResources();
                }
            }

            // If Razor or Markdown are enabled we need custom folders
            if (mvcBuilder != null)
            {
                mvcBuilder.AddRazorRuntimeCompilation(
                    opt =>
                {
                    opt.FileProviders.Clear();
                    opt.FileProviders.Add(new PhysicalFileProvider(WebRoot));
                    opt.FileProviders.Add(new PhysicalFileProvider(Path.Combine(Startup.StartupPath, "templates")));
                });

                LoadPrivateBinAssemblies(mvcBuilder);
            }
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)
        {
            bool useSsl      = Helpers.GetLogicalSetting("useSsl", Configuration, false);
            bool showUrls    = Helpers.GetLogicalSetting("ShowUrls", Configuration, true);
            bool openBrowser = Helpers.GetLogicalSetting("OpenBrowser", Configuration, true);

            string defaultFiles = Configuration["DefaultFiles"];

            if (string.IsNullOrEmpty(defaultFiles))
            {
                defaultFiles = "index.html,default.htm,default.html";
            }

            var strPort = Configuration["Port"];

            if (!int.TryParse(strPort, out Port))
            {
                Port = 5200;
            }

            if (UseLiveReload)
            {
                app.UseLiveReload();
            }

            ////if (env.IsDevelopment())
            ////    app.UseDeveloperExceptionPage();
            ////else
            app.UseExceptionHandler("/Error");

            if (showUrls)
            {
                var socketUrl = Configuration["LiveReload:WebSocketUrl"];

                app.Use(async(context, next) =>
                {
                    var originalPath = context.Request.Path.Value;

                    Stopwatch sw = new Stopwatch();
                    sw.Start();

                    await next();

                    // ignore Web socket requests
                    if (context.Request.Path.Value == socketUrl)
                    {
                        return;
                    }

                    // need to ensure this happens all at once otherwise multiple threads
                    // write intermixed console output on simultaneous requests
                    lock (consoleLock)
                    {
                        WriteConsoleLogDisplay(context, sw, originalPath);
                    }
                });
            }

            if (UseMarkdown)
            {
                app.UseMarkdown();
            }

            app.UseDefaultFiles(new DefaultFilesOptions
            {
                FileProvider     = new PhysicalFileProvider(WebRoot),
                DefaultFileNames = new List <string>(defaultFiles.Split(',', ';'))
            });

            // add static files to WebRoot and our templates folder which provides markdown templates
            // and potentially other library resources in the future

            var wrProvider = new PhysicalFileProvider(WebRoot);
            var tpProvider = new PhysicalFileProvider(Path.Combine(Startup.StartupPath, "templates"));

            var extensionProvider = new FileExtensionContentTypeProvider();

            extensionProvider.Mappings.Add(".dll", "application/octet-stream");
            if (LiveReloadConfiguration.Current.AdditionalMimeMappings != null)
            {
                foreach (var map in LiveReloadConfiguration.Current.AdditionalMimeMappings)
                {
                    extensionProvider.Mappings[map.Key] = map.Value;
                }
            }

            var compositeProvider = new CompositeFileProvider(wrProvider, tpProvider);

            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider          = compositeProvider, //new PhysicalFileProvider(WebRoot),
                RequestPath           = new PathString(""),
                ContentTypeProvider   = extensionProvider,
                ServeUnknownFileTypes = true
            });

            if (UseRazor || UseMarkdown)
            {
                app.UseRouting();
            }

#if USE_RAZORPAGES
            if (UseRazor)
            {
                app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); });
            }
#endif
            if (UseMarkdown)
            {
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapDefaultControllerRoute();
                });
            }

            // 404  - fall through middleware
            if (!string.IsNullOrEmpty(LiveReloadConfiguration.Current.FolderNotFoundFallbackPath))
            {
                app.Use(async(context, next) =>
                {
                    var path = context.Request.Path;
                    if (string.IsNullOrEmpty(Path.GetExtension(path)))
                    {
                        var fi = new FileInfo(Path.Combine(WebRoot, LiveReloadConfiguration.Current.FolderNotFoundFallbackPath.Trim('/', '\\')));
                        await context.Response.SendFileAsync(new PhysicalFileInfo(fi));
                        await context.Response.CompleteAsync();
                    }
                });
            }

            var url        = $"http{(useSsl ? "s" : "")}://localhost:{Port}";
            var extensions = Configuration["Extensions"];

            string headerLine = new string('-', Helpers.AppHeader.Length);
            Console.WriteLine(headerLine);
            ConsoleHelper.WriteLine(Helpers.AppHeader, ConsoleColor.Yellow);
            Console.WriteLine(headerLine);
            Console.WriteLine($"(c) West Wind Technologies, 2019-{DateTime.Now.Year}\r\n");

            Console.Write($"Site Url     : ");
            ConsoleHelper.WriteLine(url, ConsoleColor.DarkCyan);
            Console.WriteLine($"Web Root     : {WebRoot}");
            Console.WriteLine($"Executable   : {Assembly.GetExecutingAssembly().Location}");
            Console.WriteLine(
                $"Extensions   : {(string.IsNullOrEmpty(extensions) ? $"{(UseRazor ? ".cshtml," : "")}.css,.js,.htm,.html,.ts" : extensions)}");
            Console.WriteLine($"Live Reload  : {UseLiveReload}");

#if USE_RAZORPAGES
            Console.WriteLine($"Use Razor    : {UseRazor}");
#endif

            Console.WriteLine($"Use Markdown : {UseMarkdown}");
            if (UseMarkdown)
            {
                Console.WriteLine($"  Resources  : {CopyMarkdownResources}");
                Console.WriteLine($"  Template   : {MarkdownTemplate}");
                Console.WriteLine($"  Theme      : {MarkdownTheme}");
                Console.WriteLine($"  SyntaxTheme: {MarkdownSyntaxTheme}");
            }
            Console.WriteLine($"Show Urls    : {showUrls}");
            Console.WriteLine($"Open Browser : {openBrowser}");
            Console.WriteLine($"Default Pages: {defaultFiles}");
            Console.WriteLine($"Environment  : {env.EnvironmentName}");

            Console.WriteLine();
            ConsoleHelper.Write(Helpers.ExeName + "--help", ConsoleColor.DarkCyan);
            Console.WriteLine(" for start options...");
            Console.WriteLine();
            ConsoleHelper.WriteLine("Ctrl-C or Ctrl-Break to exit...", ConsoleColor.Yellow);

            Console.WriteLine("----------------------------------------------");

            var oldColor = Console.ForegroundColor;
            foreach (var assmbly in LoadedPrivateAssemblies)
            {
                var fname = Path.GetFileName(assmbly);
                ConsoleHelper.WriteLine("Additional Assembly: " + fname, ConsoleColor.DarkGreen);
            }

            foreach (var assmbly in FailedPrivateAssemblies)
            {
                var fname = Path.GetFileName(assmbly);
                ConsoleHelper.WriteLine("Failed Additional Assembly: " + fname, ConsoleColor.DarkGreen);
            }

            Console.ForegroundColor = oldColor;

            if (openBrowser)
            {
                Helpers.OpenUrl(url);
            }
        }
Example #7
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)
        {
            bool useSsl      = Helpers.GetLogicalSetting("useSsl", Configuration);
            bool showUrls    = Helpers.GetLogicalSetting("ShowUrls", Configuration);
            bool openBrowser = Helpers.GetLogicalSetting("OpenBrowser", Configuration);

            string defaultFiles = Configuration["DefaultFiles"];

            if (string.IsNullOrEmpty(defaultFiles))
            {
                defaultFiles = "index.html,default.htm,default.html";
            }

            var strPort = Configuration["Port"];

            if (!int.TryParse(strPort, out Port))
            {
                Port = 5000;
            }

            if (UseLiveReload)
            {
                app.UseLiveReload();
            }

            ////if (env.IsDevelopment())
            ////    app.UseDeveloperExceptionPage();
            ////else
            app.UseExceptionHandler("/Error");

            if (showUrls)
            {
                app.Use(async(context, next) =>
                {
                    var url =
                        $"{context.Request.Method}  {context.Request.Scheme}://{context.Request.Host}  {context.Request.Path}{context.Request.QueryString}";
                    Console.WriteLine(url);
                    await next();
                });
            }

            app.UseDefaultFiles(new DefaultFilesOptions
            {
                FileProvider     = new PhysicalFileProvider(WebRoot),
                DefaultFileNames = new List <string>(defaultFiles.Split(',', ';'))
            });

            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(WebRoot), RequestPath = new PathString("")
            });

#if USE_RAZORPAGES
            if (UseRazor)
            {
                app.UseRouting();
                app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); });
            }
#endif
            var url        = $"http{(useSsl ? "s" : "")}://localhost:{Port}";
            var extensions = Configuration["Extensions"];

            string headerLine = new string('-', Helpers.AppHeader.Length);
            Console.WriteLine(headerLine);
            Console.WriteLine(Helpers.AppHeader);
            Console.WriteLine(headerLine);
            Console.WriteLine($"(c) West Wind Technologies, 2018-{DateTime.Now.Year}\r\n");
            Console.Write($"Site Url     : ");
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(url);
            Console.ResetColor();
            Console.WriteLine($"Web Root     : {WebRoot}");
            Console.WriteLine(
                $"Extensions   : {(string.IsNullOrEmpty(extensions) ? $"{(UseRazor ? ".cshtml," : "")}.css,.js,.htm,.html,.ts" : extensions)}");
            Console.WriteLine($"Live Reload  : {UseLiveReload}");

#if USE_RAZORPAGES
            Console.WriteLine($"Use Razor    : {UseRazor}");
#endif
            Console.WriteLine($"Show Urls    : {showUrls}");
            Console.WriteLine($"Open Browser : {openBrowser}");
            Console.WriteLine($"Default Pages: {defaultFiles}");
            Console.WriteLine($"Environment  : {env.EnvironmentName}");

            Console.WriteLine();
            Console.WriteLine($"'{Helpers.ExeName} --help' for start options...");
            Console.WriteLine();
            Console.WriteLine("Ctrl-C or Ctrl-Break to exit...");

            Console.WriteLine("----------------------------------------------");

            var oldColor = Console.ForegroundColor;
            foreach (var assmbly in LoadedPrivateAssemblies)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Additional Assembly: " + assmbly);
            }

            foreach (var assmbly in FailedPrivateAssemblies)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Failed Additional Assembly: " + assmbly);
            }

            Console.ForegroundColor = oldColor;

            if (openBrowser)
            {
                Helpers.OpenUrl(url);
            }
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)
        {
            bool useSsl      = Helpers.GetLogicalSetting("useSsl", Configuration, false);
            bool showUrls    = Helpers.GetLogicalSetting("ShowUrls", Configuration, true);
            bool openBrowser = Helpers.GetLogicalSetting("OpenBrowser", Configuration, true);

            string defaultFiles = Configuration["DefaultFiles"];

            if (string.IsNullOrEmpty(defaultFiles))
            {
                defaultFiles = "index.html,default.htm,default.html";
            }

            var strPort = Configuration["Port"];

            if (!int.TryParse(strPort, out Port))
            {
                Port = 5200;
            }

            if (UseLiveReload)
            {
                app.UseLiveReload();
            }

            ////if (env.IsDevelopment())
            ////    app.UseDeveloperExceptionPage();
            ////else
            app.UseExceptionHandler("/Error");

            if (showUrls)
            {
                var socketUrl = Configuration["LiveReload:WebSocketUrl"];

                app.Use(async(context, next) =>
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();

                    await next();

                    // ignore Web socket requests
                    if (context.Request.Path.Value == socketUrl)
                    {
                        return;
                    }

                    lock (consoleLock)
                    {
                        var url =
                            $"{context.Request.Method}  {context.Request.Scheme}://{context.Request.Host}  {context.Request.Path}{context.Request.QueryString}";

                        url = url.PadRight(80, ' ');

                        var ct         = context.Response.ContentType;
                        bool isPrimary = ct != null &&
                                         (ct.StartsWith("text/html") ||
                                          ct.StartsWith("text/plain") ||
                                          ct.StartsWith("application/json") ||
                                          ct.StartsWith("text/xml"));

                        if (ct == null) // no response
                        {
                            ConsoleHelper.Write(url + " ", ConsoleColor.Red);
                            isPrimary = true;
                        }
                        else if (isPrimary)
                        {
                            ConsoleHelper.Write(url + " ", ConsoleColor.Gray);
                        }
                        else
                        {
                            ConsoleHelper.Write(url + " ", ConsoleColor.DarkGray);
                        }

                        var status = context.Response.StatusCode;
                        if (status >= 200 && status < 400)
                        {
                            ConsoleHelper.Write(status.ToString(),
                                                isPrimary ? ConsoleColor.Green : ConsoleColor.DarkGreen);
                        }
                        else if (status == 401)
                        {
                            ConsoleHelper.Write(status.ToString(),
                                                isPrimary ? ConsoleColor.Yellow : ConsoleColor.DarkYellow);
                        }
                        else if (status >= 400)
                        {
                            ConsoleHelper.Write(status.ToString(), isPrimary ? ConsoleColor.Red : ConsoleColor.DarkRed);
                        }

                        sw.Stop();
                        ConsoleHelper.WriteLine($" {sw.ElapsedMilliseconds:n0}ms".PadLeft(8), ConsoleColor.DarkGray);
                    }
                });
            }

            app.UseDefaultFiles(new DefaultFilesOptions
            {
                FileProvider     = new PhysicalFileProvider(WebRoot),
                DefaultFileNames = new List <string>(defaultFiles.Split(',', ';'))
            });

            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(WebRoot), RequestPath = new PathString("")
            });

#if USE_RAZORPAGES
            if (UseRazor)
            {
                app.UseRouting();
                app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); });
            }
#endif
            var url        = $"http{(useSsl ? "s" : "")}://localhost:{Port}";
            var extensions = Configuration["Extensions"];

            string headerLine = new string('-', Helpers.AppHeader.Length);
            Console.WriteLine(headerLine);
            ConsoleHelper.WriteLine(Helpers.AppHeader, ConsoleColor.Yellow);
            Console.WriteLine(headerLine);
            Console.WriteLine($"(c) West Wind Technologies, 2019-{DateTime.Now.Year}\r\n");

            Console.Write($"Site Url     : ");
            ConsoleHelper.WriteLine(url, ConsoleColor.DarkCyan);
            Console.WriteLine($"Web Root     : {WebRoot}");
            Console.WriteLine($"Executable   : {Assembly.GetExecutingAssembly().Location}");
            Console.WriteLine(
                $"Extensions   : {(string.IsNullOrEmpty(extensions) ? $"{(UseRazor ? ".cshtml," : "")}.css,.js,.htm,.html,.ts" : extensions)}");
            Console.WriteLine($"Live Reload  : {UseLiveReload}");

#if USE_RAZORPAGES
            Console.WriteLine($"Use Razor    : {UseRazor}");
#endif
            Console.WriteLine($"Show Urls    : {showUrls}");
            Console.WriteLine($"Open Browser : {openBrowser}");
            Console.WriteLine($"Default Pages: {defaultFiles}");
            Console.WriteLine($"Environment  : {env.EnvironmentName}");

            Console.WriteLine();
            ConsoleHelper.Write(Helpers.ExeName + "--help", ConsoleColor.DarkCyan);
            Console.WriteLine(" for start options...");
            Console.WriteLine();
            ConsoleHelper.WriteLine("Ctrl-C or Ctrl-Break to exit...", ConsoleColor.Yellow);

            Console.WriteLine("----------------------------------------------");

            var oldColor = Console.ForegroundColor;
            foreach (var assmbly in LoadedPrivateAssemblies)
            {
                var fname = Path.GetFileName(assmbly);
                ConsoleHelper.WriteLine("Additional Assembly: " + fname, ConsoleColor.DarkGreen);
            }

            foreach (var assmbly in FailedPrivateAssemblies)
            {
                var fname = Path.GetFileName(assmbly);
                ConsoleHelper.WriteLine("Failed Additional Assembly: " + fname, ConsoleColor.DarkGreen);
            }

            Console.ForegroundColor = oldColor;

            if (openBrowser)
            {
                Helpers.OpenUrl(url);
            }
        }