Topshelf阻止Windows Service停止原理及.NET 7自定义实现失效排查
.NET 7 Windows Service中阻止Stop命令失效问题排查
我需要在.NET 7 Windows Service中实现阻止Stop命令的行为:
- 参考Topshelf的实现逻辑:其服务宿主继承自
ServiceBase,在重写的OnStop方法中,若_serviceHandle.Stop(this)返回false,则抛出异常并设置ExitCode = 1064后重新抛出。 - 查看
ServiceBase的DeferredStop方法可知:调用OnStop时若抛出异常,会将服务状态重置为之前的运行状态并重新抛出异常。
但我基于WindowsServiceLifetime(该类继承自ServiceBase)编写的自定义类CancelableWindowsServiceLifetime,逻辑与Topshelf类似,却出现OnStop中抛出异常后服务仍会停止的问题。对比.NET 7版本的ServiceBase实现未发现明显差异,请问这是什么原因?
需求说明
当有作业运行时阻止服务停止;若在滑动窗口内收到足够多次停止请求,则允许停止并终止运行中的作业。
相关代码
Topshelf的OnStop实现
public class WindowsServiceHost : ServiceBase, Host, HostControl { // 省略其他代码 protected override void OnStop() { try { _log.Info("[Topshelf] Stopping"); if (!_serviceHandle.Stop(this)) throw new TopshelfException("The service did not stop successfully (return false)."); _log.Info("[Topshelf] Stopped"); } catch (Exception ex) { _settings.ExceptionCallback?.Invoke(ex); _log.Fatal("The service did not shut down gracefully", ex); ExitCode = (int) TopshelfExitCode.ServiceControlRequestFailed; throw; } } }
ServiceBase的DeferredStop方法实现
private unsafe void DeferredStop () { fixed (NativeMethods.SERVICE_STATUS *pStatus = &status) { int previousState = status.currentState; status.checkPoint = 0; status.waitHint = 0; status.currentState = NativeMethods.STATE_STOP_PENDING; NativeMethods.SetServiceStatus (statusHandle, pStatus); try { OnStop(); // 省略其他代码... } catch (Exception e) { status.currentState = previousState; NativeMethods.SetServiceStatus (statusHandle, pStatus); WriteEventLogEntry (Res.GetString (Res.StopFailed, e.ToString ()), EventLogEntryType.Error); throw; } } // fixed } // DeferredStop
自定义CancelableWindowsServiceLifetime实现
[System.Runtime.Versioning.SupportedOSPlatform( "windows" )] public class CancelableWindowsServiceLifetime : Microsoft.Extensions.Hosting.WindowsServices.WindowsServiceLifetime { private readonly ICancelableBackgroundService cancelableBackgroundService; public CancelableWindowsServiceLifetime( IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, ICancelableBackgroundService cancelableBackgroundService, ILoggerFactory loggerFactory, IOptions<HostOptions> optionsAccessor ) : this( environment, applicationLifetime, cancelableBackgroundService, loggerFactory, optionsAccessor, Options.Create( new WindowsServiceLifetimeOptions() ) ) { } public CancelableWindowsServiceLifetime( IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, ICancelableBackgroundService cancelableBackgroundService, ILoggerFactory loggerFactory, IOptions<HostOptions> optionsAccessor, IOptions<WindowsServiceLifetimeOptions> windowsServiceOptionsAccessor ) : base( environment, applicationLifetime, loggerFactory, optionsAccessor, windowsServiceOptionsAccessor ) { this.cancelableBackgroundService = cancelableBackgroundService; } protected override void OnStop() { if ( !cancelableBackgroundService.CanStop() ) { ExitCode = 1064; // ERROR_EXCEPTION_IN_SERVICE throw new ApplicationException( $"Unable to stop service at this time." ); } base.OnStop(); } }
内容的提问来源于stack exchange,提问作者Terry
相关产品推荐
相关产品推荐

