62

How can I restart an app in asp.net core programmatically?

I want to clear cache and cause the application to re-enter the startup.

eadam
  • 23,151
  • 18
  • 48
  • 71

7 Answers7

41

Before you read my answer: This solution is going to stop the app and cause the application to re-enter the startup in the next request.

.NET Core 2 There may come a time when you wish to force your ASP.Net Core 2 site to recycle programmatically. Even in MVC/WebForms days this wasn't necessarily a recommended practice but alas, there is a way. ASP.Net Core 2 allows for the injection of an IApplicationLifetime object that will let you do a few handy things. First, it will let you register events for Startup, Shutting Down and Shutdown similar to what might have been available via a Global.asax back in the day. But, it also exposes a method to allow you to shutdown the site (without a hack!). You'll need to inject this into your site, then simply call it. Below is an example of a controller with a route that will shutdown a site.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;

namespace MySite.Controllers
{
    public class WebServicesController : Controller
    {
        private IApplicationLifetime ApplicationLifetime { get; set; }

        public WebServicesController(IApplicationLifetime appLifetime)
        {
            ApplicationLifetime = appLifetime;
        }

        public async Task ShutdownSite()
        {
            ApplicationLifetime.StopApplication();
            return "Done";
        }

    }
}

Source: http://www.blakepell.com/asp-net-core-ability-to-restart-your-site-programatically-updated-for-2-0

halfer
  • 19,824
  • 17
  • 99
  • 186
Mohammad Karimi
  • 4,151
  • 2
  • 21
  • 19
37

Update: Mirask's answer is more correct for .NET Core 2.

In Program.cs you will see the call to host.Run(). This method has an overload which accepts a System.Threading.CancellationToken. This is what I am doing:

public class Program {

    private static CancellationTokenSource cancelTokenSource = new System.Threading.CancellationTokenSource();

    public static void Main(string[] args) {

        var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

        host.Run(cancelTokenSource.Token);
    }

    public static void Shutdown() {
        cancelTokenSource.Cancel();
    }
}

Then, in my Controller I can call Program.Shutdown() and after a few seconds the application dies. If it is behind IIS, another request will automatically start the application.

T.S.
  • 18,195
  • 11
  • 58
  • 78
Chet
  • 3,461
  • 1
  • 19
  • 24
  • This is absolutely perfect, thank you. In regards to handling this when hosted by IIS, this is much better than adding a reference to Microsoft.Web.Administration or tinkering with the web.config file to trick an IIS recycle. – Josh Schultz Jun 29 '17 at 14:53
  • 8
    Small update. I found that the method Run(token) no longer is availible to me in .NET Core 2.0. I used the following line to work around this: .RunAsync(cancellationTokenSource.Token).GetAwaiter().GetResult(); – Schwarzie2478 Nov 06 '17 at 10:16
  • Thanks, I was wondering how to do that since the update. You should make this an answer. – Chet Nov 06 '17 at 11:37
  • @Schwarzie2478, @Chet did you try to use `IApplicationLifetime.ApplicationStopping` - it looks like it would be enough to call `Cancel` on it to start shutdown. – Pavel Agarkov Dec 08 '17 at 13:49
  • I just tested this and you could indeed use `IApplicationLifetime.StopApplication()`. Do you want to add this as an answer? – Chet Dec 13 '17 at 15:57
  • I'm starting my asp.core size using `dotnet mySite.dll`. Can I use the approach in this answer to automatically restart my website when I upload a new dll? – Riki Dec 03 '18 at 17:11
  • This method will shutdown the app (kill the `dotnet` process). You will have to devise some way of starting a new instance. When running in the context of IIS, it will handle that for you. – Chet Jan 25 '19 at 15:34
  • If it's not being automatically restarted you could use `cancelTokenSource .Token.Register(() => Restart());` https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken.register?redirectedfrom=MSDN&view=net-7.0#overloads – clamchoda Jan 06 '23 at 20:01
29

ASP.NET Core 3+

Since the accepted answer is using IApplicationLifetime which became obsolete in ASP.NET Core 3 onwards, the new recommended way is to use IHostApplicationLifetime which is located in the Microsoft.Extensions.Hosting namespace.

In my Blazor application, I can use following code:

@inject IHostApplicationLifetime AppLifetime

<button @onclick="() => AppLifetime.StopApplication()">Restart</button>
ˈvɔlə
  • 9,204
  • 10
  • 63
  • 89
  • Hi @WΩLLE is it possible to do it from the backend ? i tried but it give me an NullReference exception ... maybe i did it wrong... my app is using too much cache and i want to restart the app because of that but dont know how to release the cache by code... is it possible to use your solution? – Khalid Ab Jul 05 '21 at 15:21
  • 1
    Ths shuts down the app but the question was how to restart it and that, is not accomplished with this. In fact, I don't even think is possible because once the app is down, it looses the connection with the client, showing an error. Only a new request will restart the app. – Hugo A. Apr 14 '22 at 13:51
  • @HugoA. Do you want to restart the application and keep all connections alive? This sounds like an impossible requirement. – ˈvɔlə Apr 14 '22 at 16:00
5

For .NET Core 2.2 you can use following code:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using System.Threading;

namespace BuildMonitor
{
    public class Program
    {
        private static CancellationTokenSource cancelTokenSource = new System.Threading.CancellationTokenSource();

        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();
            host.RunAsync(cancelTokenSource.Token).GetAwaiter().GetResult();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();

        public static void Shutdown()
        {
            cancelTokenSource.Cancel();
        }
    }
}

And server shutdown could be placed for example behind some web page:

using System;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace BuildMonitor.Pages
{
    public class StopServerModel : PageModel
    {
        public void OnGet()
        {
            Console.WriteLine("Forcing server shutdown.");
            Program.Shutdown();
        }
    }
}

stopServer.bat could be for example like this:

@echo off
rem curl http://localhost:5000/StopServer >nul 2>&1
powershell.exe -Command (new-object System.Net.WebClient).DownloadString('http://localhost:5000/StopServer') >nul
exit /b 0
T.S.
  • 18,195
  • 11
  • 58
  • 78
TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
4

None of the solutions above did what I wanted. So that is what I came up with:

 public class Program
{
    private static CancellationTokenSource cts = new CancellationTokenSource();
    private static string[] _args;
    private static bool _restartRequest;

    public static async Task Main(string[] args)
    {
        _args = args;

        await StartServer();
        while (_restartRequest)
        {
            _restartRequest = false;
            Console.WriteLine("Restarting App");
            await StartServer();
        }
    }

    public static void Restart()
    {
        _restartRequest = true;
        cts.Cancel();
    }

    private static async Task StartServer()
    {
        try
        {
            cts = new CancellationTokenSource();
            await CreateHostBuilder(_args).RunConsoleAsync(cts.Token);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e);
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
detachmode
  • 61
  • 8
  • I used your code and it works practically. Also I called *StopApplication* before *Restart* method. Did you use it in production environment ? – Armin Torkashvand Nov 03 '21 at 10:19
2

If you need this just for a development scenario then you can use dotnet-watch(for dotnet) or dnx-watch(for dnx).

If you want your application to restart in production, then you have to implement something similar to what the watcher does. You need an external process to kill and restart the process. Or you need your app to launch an instance of itself and then kill itself. Unfortunately, there's nothing out of the box for this.

Victor Hurdugaci
  • 28,177
  • 5
  • 87
  • 103
  • 5
    It would be a hack, but can the app programmatically change a config file that would trigger an app restart? – Jeff Putz Sep 15 '16 at 00:03
0

Dotnet 7.0. It's a quick hack when not working behind IIS. Stop the application and get the running process path to restart the process in same terminal window.

public MyController(ILogger<MyController> logger, Microsoft.AspNetCore.Hosting.IApplicationLifetime appLifetime)
{
    this.logger = logger;
    this.appLifetime = appLifetime;
}

/// <summary>
/// Restarts the API
/// </summary>
[HttpPost("Restart")]
public async Task<int> Restart()
{
    appLifetime.StopApplication();

    string _currentProcess = Path.GetFullPath(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);

    Process.Start(_currentProcess);

    return await Task.FromResult(0);
}
David Graham
  • 389
  • 5
  • 15