Search code examples
asp.net-coreportkestrel

Change Kestrel port at runtime


My project uses .net core 3.1 and is a web app using builtin server Kestrel.
I setup the ports using .UseUrls("http://0.0.0.0:1234") during CreateWebHostBuilder() and works as it should.

In my interface I wanted the user to able to change port at runtime.
But I have to restart the application with the new saved config to get that working.
Are there any tips on how to change it at runtime?


Solution

  • I solved (quick and dirty) the restart-server function for Kestrel.
    This method is just a hack and should not be used in production. Maybe there are some clever heads out there who can make it better.

    public class Program
    {
        //Simple bool to tell the host to load again
        public static bool RestartWebserver { get; set; } = false;
        
        //Port to use
        public static int HttpPort { get; set; } = 80;
    
        //Main program
        public static int Main(string[] args)
        {
            //Infinityloop if 
            while(true)
            {
                CreateWebHostBuilder(args, Directory.GetCurrentDirectory()).Build().Run();
                
                //If RestartWebserver is false, exit everything...
                if (!RestartWebserver)
                {
                    Console.WriteLine("Restarting...");
                    break;
                }
                
                //Reset for the "new" host to be created.
                RestartWebserver = false;
            }
        }
    
        //Helper for creating host, returns a IWebHostBuilder to be Build and runned.
        public static IWebHostBuilder CreateWebHostBuilder(string[] args, string ContentRoot)
        {
            var Address = "0.0.0.0";
            string http = "http://" + Address + ":" + HttpPort;
    
            //Add arguments to the config (we could have a port set here too..)
            var configuration = new ConfigurationBuilder()
                    .AddCommandLine(args)
                    .Build();
            Startup.Configuration = configuration;
    
            //Return Webhost
            return WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseContentRoot(ContentRoot)
                .UseKestrel()
                .UseUrls(new string[] { http }));
        }
    }
    
    //Now in any controller you can force close the host like this
    public class RestartController : Controller
    {
        public IHostApplicationLifetime _applicationLifetime;
        
        public StatusController(IHostApplicationLifetime applicationLifetime)
        {
            _applicationLifetime = applicationLifetime;
        }
    
        public async Task<IActionResult> Index()
        {
            //Set new port
            Program.HttpPort = 12345;
            
            //Set the server to restart
            Program.RestartWebserver = true;
            
            //Quit current host
            _applicationLifetime.StopApplication();
    
            //This function will fail.
            //Suggest to create a javascript file to reload client to the new port...
            return View("Index");
        }
    }
    

    This method worked for me, but the code above is kind of sudo, it has never been compiled in its form. Concept though is tested and confirmed on dotnet v5.0.100