How can I remotely close an ASP. NET Core application ?, Asp. netcore
In the "N methods of resource dependent injection" demonstration system automatically registers the service instance, we will find that the output list contains two special services, their corresponding service interfaces are IApplicationLifetime and IHostingEnvironment. Services that implement these two interfaces are collectively referred to in ApplicationLifetime and HostingEnvironment. We can see from its name that ApplicationLifetime is related to the application declaration cycle, while HostingEnvironment is used to represent the current execution environment. In this article, we will learn about ApplicationLifetime and the entire AASP. NET Core application lifecycle. [This Article has been synchronized to ASP. NET Core framework secrets]
Directory
1. ApplicationLifetime
Ii. WebHost Run Method
3. remotely close the application
1. ApplicationLifetime
From the perspective of naming, ApplicationLifetime seems to be a description of the current application lifecycle, in fact, it only serves to send signals or notifications to related components when the application is started or shut down. As shown in the following code snippet, The IApplicationLifetime interface has three CancellationToken-type attributes (ApplicationStarted, ApplicationStopping, and ApplicationStopped). If you need to perform an operation before and after the application is automatically terminated, we can register the corresponding callback on these three CancellationToken objects. In addition to the three types of CancellationToken attributes, the IApplicationLifetime interface also defines a StopApplication method. We can call this method to send a signal to close the application and eventually close the application.
1: public interface IApplicationLifetime
2: {
3: CancellationToken ApplicationStarted { get; }
4: CancellationToken ApplicationStopping { get; }
5: CancellationToken ApplicationStopped { get; }
6:
7: void StopApplication();
8: }
The default ApplicationLifetime used by ASP. NET Core is a type with the same name defined as follows. It can be seen that the CancellationToken object returned by the three attributes it implements is generated through three corresponding CancellationTokenSource. In addition to the StopApplication method that implements the IApplicationLifetime interface, this type also defines two additional methods (NotifyStarted and NotifyStopped) to send notifications with "enabled/disabled.
1: public class ApplicationLifetime : IApplicationLifetime
2: {
3: private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();
4: private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();
5: private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();
6:
7: public CancellationToken ApplicationStarted
8: {
9: get { return _startedSource.Token; }
10: }
11: public CancellationToken ApplicationStopped
12: {
13: get { return _stoppedSource.Token; }
14: }
15: public CancellationToken ApplicationStopping
16: {
17: get { return _stoppingSource.Token; }
18: }
19:
20: public void NotifyStarted()
21: {
22: _startedSource.Cancel(false);
23: }
24: public void NotifyStopped()
25: {
26: _stoppedSource.Cancel(false);
27: }
28: public void StopApplication()
29: {
30: _stoppingSource.Cancel(false);
31: }
32: }
When the WebHost is enabled because of the execution of the Start method, it will eventually call the notiflifelifetime NotifyStarted method to send the signal that the application is successfully started. I don't know whether the readers have noticed that WebHost only defines the Start method for starting an application and does not define the Stop or Close method for terminating the application, it only calls the StopApplication method of ApplicationLifetime in the Dispose method.
1: public class WebHost : IWebHost
2: {
3: private ApplicationLifetime _applicationLifetime;
4: public IServiceProvider Services { get;}
5:
6: public void Start()
7: {
8: ...
9: _applicationLifetime.NotifyStarted();
10: }
11:
12: public void Dispose()
13: {
14: _applicationLifetime.StopApplication();
15: (this.Services as IDisposable)?.Dispose();
16: _applicationLifetime.NotifyStopped();
17: }
18: ...
19: }
Ii. WebHost Run Method
We know that starting an application is done by calling the Start method of the WebHost that acts as the host, but none of the instances we demonstrated previously explicitly call this method, we call its extension method Run. Without a doubt, the WebHost Run method will certainly call the Start method to Start WebHost. But what are the special features of this Run method?
In addition to starting WebHost, the Run method actually blocks the current process until the application is closed. We know that the purpose of application shutdown is to use ApplicationLifetime to send the corresponding signal, so when this Run method starts WebHost, it waits until it receives the signal by blocking the current thread. The code snippets shown below basically reflect the implementation logic of the two extension methods Run.
1: public static class WebHostExtensions
2: {
3: public static void Run(this IWebHost host)
4: {
5: using (CancellationTokenSource cts = new CancellationTokenSource())
6: {
7: // Ctrl + C: Close the application
8: Console.CancelKeyPress += (sender, args) =>
9: {
10: cts.Cancel();
11: args.Cancel = true;
12: };
13: host.Run(cts.Token);
14: }
15: }
16:
17: public static void Run(this IWebHost host, CancellationToken token)
18: {
19: using (host)
20: {
21: // display basic application information
22: host.Start();
23: IApplicationLifetime applicationLifetime = host.Services.GetService<IApplicationLifetime>();
24: token.Register(state => ((IApplicationLifetime)state).StopApplication(), applicationLifetime);
25: applicationLifetime.ApplicationStopping.WaitHandle.WaitOne();
26: }
27: }
28: }
The above code snippet also shows another detail. Although WebHost implements the IDisposable interface, in principle, we need to explicitly call its Dispose method when disabling it. It is very important to call this method because its ServiceProvider can only be recycled and released when this method is called. However, this is not done for all the previously demonstrated instances, because the Run method will automatically help recycle and release the specified WebHost.
3. remotely close the application
Since WebHost will use ApplicationLifetime to wait for the Stopping signal to be sent after it is started, this means to form ASP. the server of the NET Core pipeline and any middleware can call the StopApplication of ApplicationLifetime as appropriate to close the application. For the KestrelServer introduced in "the server's leading position in the pipeline", we know that when constructing this object, we must specify an ApplicationLifetime object, the fundamental purpose is that when an error cannot be recovered is sent, the object can be used to close the application.
Next, we will demonstrate how to use this ApplicationLifetime object in a middleware to remotely close the application. Therefore, we name this middleware RemoteStopMiddleware. RemoteStopMiddleware: the principle of implementing remote Application shutdown is very simple. We send a Head request remotely and add a header named "Stop-Application" to the request to transfer it to the intent of shutting down the Application, after the middleware receives the request, the Application is closed, and a "Application-Stopped" header is added to the response, indicating that the Application has been closed.
1: public class RemoteStopMiddleware
2: {
3: private RequestDelegate _next;
4: private const string RequestHeader = "Stop-Application";
5: private const string ResponseHeader = "Application-Stopped";
6:
7: public RemoteStopMiddleware(RequestDelegate next)
8: {
9: _next = next;
10: }
11:
12: public async Task Invoke(HttpContext context, IApplicationLifetime lifetime)
13: {
14: if (context.Request.Method == "HEAD" && context.Request.Headers[RequestHeader].FirstOrDefault() == "Yes")
15: {
16: context.Response.Headers.Add(ResponseHeader, "Yes");
17: lifetime.StopApplication();
18: }
19: else
20: {
21: await _next(context);
22: }
23: }
24: }
The code snippet shown above is the complete definition of the RemoteStopMiddleware middleware. The implementation logic is simple and there is no need to explain it again. In a console application, we start a Hello World application using the following program and register the RemoteStopMiddleware middleware. After the application is started, we use Fiddler to send three requests to the target address, the first and third common GET requests, and the second to remotely close the application's HEAD requests. The following shows the three request and response content. Because the application is disabled by the second request, a 502 response is returned for the third request.
1: // 1st requests and responses
2: GET http://localhost:5000/ HTTP/1.1
3: User-Agent: Fiddler
4: Host: localhost:5000
5:
6: HTTP/1.1 200 OK
7: Date: Sun, 06 Nov 2016 06:15:03 GMT
8: Transfer-Encoding: chunked
9: Server: Kestrel
10:
11: Hello world!
12:
13: // 2nd requests and responses
14: HEAD http://localhost:5000/ HTTP/1.1
15: Stop-Application: Yes
16: User-Agent: Fiddler
17: Host: localhost:5000
18:
19: HTTP/1.1 200 OK
20: Date: Sun, 06 Nov 2016 06:15:34 GMT
21: Server: Kestrel
22: Application-Stopped: Yes
23:
24: // 3rd requests and responses
25: GET http://localhost:5000/ HTTP/1.1
26: User-Agent: Fiddler
27: Host: localhost:5000
28:
29: HTTP/1.1 502 Fiddler - Connection Failed
30: Date: Sun, 06 Nov 2016 06:15:44 GMT
31: Content-Type: text/html; charset=UTF-8
32: Connection: close
33: Cache-Control: no-cache, must-revalidate
34: Timestamp: 14:15:44.790
35:
36: [Fiddler] The connection to 'localhost' failed...