Asp.NetCore远程自启动、重启、关闭实现

时间:2023-03-09 20:14:29
Asp.NetCore远程自启动、重启、关闭实现

一、背景

NetCore作为微服务可以注册到服务中心,服务中心可以远程启动、重启、关闭该微服务

二、实现

1、创建一个NetCore 2.0 WebApi项目

2、创建一个进程去管理NetCore程序进程

public class ApplicationManager
{ private static ApplicationManager _appManager;
private IWebHost _web;
private CancellationTokenSource _tokenSource;
private bool _running;
private bool _restart; public bool Restarting => _restart; public ApplicationManager()
{
_running = false;
_restart = false; } public static ApplicationManager Load()
{
if (_appManager == null)
_appManager = new ApplicationManager(); return _appManager;
} public void Start()
{
if (_running)
return; if (_tokenSource != null && _tokenSource.IsCancellationRequested)
return; _tokenSource = new CancellationTokenSource();
_tokenSource.Token.ThrowIfCancellationRequested();
_running = true; _web = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build(); _web.Run(_tokenSource.Token);
} public void Stop()
{
if (!_running)
return; _tokenSource.Cancel();
_running = false;
} public void Restart()
{
Stop(); _restart = true;
_tokenSource = null;
}
}

  3、把ApplicationManager加入到Main中

public static void Main(string[] args)
{
try
{
var appManager = ApplicationManager.Load(); do
{
appManager.Start();
} while (appManager.Restarting); }
catch (Exception ex)
{ }
}

  4、在程序的ValuesController中实现重启、关闭的Api

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; namespace NetCoreWebApiDemo.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
private ApplicationManager appManager = ApplicationManager.Load(); // GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
} // GET api/values/5
[HttpGet("{cmd}")]
public string Get(string cmd)
{
switch (cmd)
{
case "restart": appManager.Restart(); break;
case "stop": appManager.Stop(); break;
case "start": appManager.Start(); break;
}
return cmd;
} // POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
} // PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
} // DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}

6、给程序启动和停止加入日志标签

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; namespace NetCoreWebApiDemo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseMvc(); lifetime.ApplicationStarted.Register(OnStart);//1:应用启动时加载配置,2:应用启动后注册服务中心
lifetime.ApplicationStopped.Register(UnRegService);//应用停止后从服务中心注销
}
private void OnStart()
{
LoadAppConfig();
RegService();
}
private void LoadAppConfig()
{
//加载应用配置
Console.WriteLine("ApplicationStarted:LoadAppConfig");
} private void RegService()
{
//先判断是否已经注册过了
//this code is called when the application stops
Console.WriteLine("ApplicationStarted:RegService");
}
private void UnRegService()
{
//this code is called when the application stops
Console.WriteLine("ApplicationStopped:UnRegService");
}
}
}

  

  

5、在程序根目录运行dotnet run

Asp.NetCore远程自启动、重启、关闭实现

访问:http://localhost:51062/api/values,显示:["Value1","Value2"]

Asp.NetCore远程自启动、重启、关闭实现

访问:http://localhost:51062/api/values/restart:显示restart,再访问http://localhost:51062/api/values正常返回["Value1","Value2"]

Asp.NetCore远程自启动、重启、关闭实现Asp.NetCore远程自启动、重启、关闭实现

访问:http://localhost:51062/api/values/stop,显示:stop,再访问http://localhost:51062/api/values就是404了

Asp.NetCore远程自启动、重启、关闭实现Asp.NetCore远程自启动、重启、关闭实现Asp.NetCore远程自启动、重启、关闭实现

stop后由于netcore进程已经被关闭,没有了http监听,通过url方式是无法重新启动了,这里可以借助类似supervisor的工具来停止进程,启动进程。

三、源码地址

https://github.com/andrewfry/AspNetCore-App-Restart

四、其它实现

1、除了上面,还可以通过中间件的形式,实现远程关闭

新增一个中间件的类:

public class RemoteStopMiddleware
{
private RequestDelegate _next;
private const string RequestHeader = "Stop-Application";
private const string ResponseHeader = "Application-Stopped"; public RemoteStopMiddleware(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext context, IApplicationLifetime lifetime)
{
if (context.Request.Method == "HEAD" && context.Request.Headers[RequestHeader].FirstOrDefault() == "Yes")
{
context.Response.Headers.Add(ResponseHeader, "Yes");
lifetime.StopApplication();
}
else if (context.Request.Method == "HEAD" && context.Request.Headers[RequestHeader].FirstOrDefault() == "No")
{
context.Response.Headers.Add(ResponseHeader, "No");
// See you on the next request.
//Program.Shutdown();
}
else
{
await _next(context);
}
}
}

2、注册中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseMvc();
app.UseMiddleware<RemoteStopMiddleware>();
lifetime.ApplicationStarted.Register(OnStart);//1:应用启动时加载配置,2:应用启动后注册服务中心
lifetime.ApplicationStopped.Register(UnRegService);//应用停止后从服务中心注销
}

3、运行程序,用postman发起一个head请求,请求头中加

{

Stop-Application:Yes

}

详细说明可参考:https://www.cnblogs.com/artech/p/application-life-time.html