Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何停止和恢复工人服务?_C#_Wpf_.net Core_Task_Ihostedservice - Fatal编程技术网

C# 如何停止和恢复工人服务?

C# 如何停止和恢复工人服务?,c#,wpf,.net-core,task,ihostedservice,C#,Wpf,.net Core,Task,Ihostedservice,在WPF应用程序中,我配置了一个托管服务,以便在后台执行特定的活动(如下所示)。 这是在App.xaml.cs中配置托管服务的方式 public App() { var environmentName = Environment.GetEnvironmentVariable("HEALTHBOOSTER_ENVIRONMENT") ?? "Development"; IConfigurationRoot configuration

在WPF应用程序中,我配置了一个托管服务,以便在后台执行特定的活动(如下所示)。 这是在App.xaml.cs中配置托管服务的方式

public App()
        {
            var environmentName = Environment.GetEnvironmentVariable("HEALTHBOOSTER_ENVIRONMENT") ?? "Development";
            IConfigurationRoot configuration = SetupConfiguration(environmentName);
            ConfigureLogger(configuration);
            _host = Host.CreateDefaultBuilder()
                .UseSerilog()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>()
                    .AddOptions()
                    .AddSingleton<IMailSender, MailSender>()
                    .AddSingleton<ITimeTracker, TimeTracker>()
                    .AddSingleton<NotificationViewModel, NotificationViewModel>()
                    .AddTransient<NotificationWindow, NotificationWindow>()
                    .Configure<AppSettings>(configuration.GetSection("AppSettings"));
                }).Build();

            AssemblyLoadContext.Default.Unloading += Default_Unloading;

            Console.CancelKeyPress += Console_CancelKeyPress;

            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
        }
public应用程序()
{
var environmentName=Environment.GetEnvironmentVariable(“HEALTHBOOSTER_Environment”)??“Development”;
IConfigurationRoot配置=设置配置(环境名称);
配置记录器(配置);
_host=host.CreateDefaultBuilder()
.useserlog()
.ConfigureServices((主机上下文,服务)=>
{
services.AddHostedService()
.AddOptions()
.AddSingleton()
.AddSingleton()
.AddSingleton()
.AddTransient()
.Configure与之类似,但答案是根据配置暂停并重新启动服务,这似乎是一种黑客行为,因此我正在寻找一种标准方法

有什么想法吗?

如评论中所述,工作人员可以独立于主机启动和停止,尽管理想情况下主机应该处理工作人员的生命周期。
但由于.NET Core 3中存在缺陷,传递给
IHostedService
StartAsync
方法的取消令牌不会传播给workers
ExecuteAsync
方法。我已经为其创建了一个问题,详细信息可在此处找到-

对bug()的修复将是.NET 5的一部分,因此正如问题()中所建议的,我必须创建自己的类来模拟framework的
BackGroundService
类,该类将直接从
IHostedService
继承,并将取消令牌传播给工作人员

BackGroundService
class自定义实现在这里-

/// <summary>
    /// Base class for implementing a long running <see cref="IHostedService"/>.
    /// </summary>
    public abstract class BGService : IHostedService, IDisposable
    {
        private Task _executingTask;
        private CancellationTokenSource _stoppingCts;

        /// <summary>
        /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
        /// the lifetime of the long running operation(s) being performed.
        /// </summary>
        /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
        /// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
        protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

        /// <summary>
        /// Triggered when the application host is ready to start the service.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
        public virtual Task StartAsync(CancellationToken cancellationToken)
        {
            // Create linked token to allow cancelling executing task from provided token
            _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

            // Store the task we're executing
            _executingTask = ExecuteAsync(_stoppingCts.Token);

            // If the task is completed then return it, this will bubble cancellation and failure to the caller
            if (_executingTask.IsCompleted)
            {
                return _executingTask;
            }

            // Otherwise it's running
            return Task.CompletedTask;
        }

        /// <summary>
        /// Triggered when the application host is performing a graceful shutdown.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
        public virtual async Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop called without start
            if (_executingTask == null)
            {
                return;
            }

            try
            {
                // Signal cancellation to the executing method
                _stoppingCts.Cancel();
            }
            finally
            {
                // Wait until the task completes or the stop token triggers
                await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
            }

        }

        public virtual void Dispose()
        {
            _stoppingCts?.Cancel();
        }
    }
//
///用于实现长时间运行的基类。
/// 
公共抽象类BGService:IHostedService,IDisposable
{
私有任务(executingTask);;
私有取消令牌源_停止CTS;
/// 
///启动时调用此方法。实现应返回表示
///正在执行的长时间运行操作的生存期。
/// 
///调用时触发。
///表示长时间运行的操作的。
受保护的抽象任务ExecuteAsync(CancellationToken stoppingToken);
/// 
///当应用程序主机准备启动服务时触发。
/// 
///指示启动进程已中止。
公共虚拟任务StartAsync(CancellationToken CancellationToken)
{
//创建链接令牌以允许从提供的令牌取消执行任务
_stoppingCts=CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
//存储我们正在执行的任务
_executingTask=ExecuteAsync(_stoppingCts.Token);
//如果任务已完成,则将其返回,这将向调用者提示取消和失败
如果(_executingTask.IsCompleted)
{
返回执行任务;
}
//否则它就在运行
返回Task.CompletedTask;
}
/// 
///当应用程序主机执行正常关机时触发。
/// 
///指示关闭过程不应再正常。
公共虚拟异步任务StopAsync(CancellationToken CancellationToken)
{
//没有开始就叫停
如果(_executingTask==null)
{
返回;
}
尝试
{
//执行方法的信号消除
_stoppingCts.Cancel();
}
最后
{
//等待任务完成或停止令牌触发
wait Task.wheny(_executingTask,Task.Delay(Timeout.Infinite,cancellationToken));
}
}
公共虚拟void Dispose()
{
_停止?取消();
}
}
以及在系统暂停和恢复时分别停止和启动工人的逻辑

/// <summary>
        /// Handles system suspend and resume events
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            var workers = _host.Services.GetServices<IHostedService>();
            Log.Information($"Found IHostedService instances - {workers.ToCSV()}");
            switch (e.Mode)
            {
                case PowerModes.Resume:
                    Log.Warning("System is resuming. Restarting the workers");
                    try
                    {
                        _cancellationTokenSource = new CancellationTokenSource();
                        foreach (var worker in workers)
                        {
                            await worker.StartAsync(_cancellationTokenSource.Token);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, $"{ex.Message}");
                    }
                    break;

                case PowerModes.Suspend:
                    Log.Warning("System is suspending. Stopping the workers");
                    _cancellationTokenSource.Cancel();
                    try
                    {
                        foreach (var worker in workers)
                        {
                            await worker.StopAsync(_cancellationTokenSource.Token);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, $"{ex.Message}");
                    }
                    break;
            }
        }
//
///处理系统挂起和恢复事件
/// 
/// 
/// 
专用异步void SystemEvents\u PowerModeChanged(对象发送方,PowerModeChangedEventArgs e)
{
var workers=_host.Services.GetServices();
Log.Information($“找到IHostedService实例-{workers.ToCSV()}”);
开关(e模式)
{
机箱电源模式。继续:
日志警告(“系统正在恢复。正在重新启动工作人员”);
尝试
{
_cancellationTokenSource=新的cancellationTokenSource();
foreach(工人中的var工人)
{
wait worker.StartAsync(_cancellationTokenSource.Token);
}
}
捕获(例外情况除外)
{
Log.Error(例如,$“{ex.Message}”);
}
打破
机箱电源模式。挂起:
日志警告(“系统暂停。停止工人”);
_cancellationTokenSource.Cancel();
尝试
{
foreach(工人中的var工人)
{
wait worker.StopAsync(_cancellationTokenSource.Token);
}
}
捕获(例外情况除外)
{
Log.Error(例如,$“{ex.Message}”);
}
打破
}
}
/// <summary>
    /// Base class for implementing a long running <see cref="IHostedService"/>.
    /// </summary>
    public abstract class BGService : IHostedService, IDisposable
    {
        private Task _executingTask;
        private CancellationTokenSource _stoppingCts;

        /// <summary>
        /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
        /// the lifetime of the long running operation(s) being performed.
        /// </summary>
        /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
        /// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
        protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

        /// <summary>
        /// Triggered when the application host is ready to start the service.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
        public virtual Task StartAsync(CancellationToken cancellationToken)
        {
            // Create linked token to allow cancelling executing task from provided token
            _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

            // Store the task we're executing
            _executingTask = ExecuteAsync(_stoppingCts.Token);

            // If the task is completed then return it, this will bubble cancellation and failure to the caller
            if (_executingTask.IsCompleted)
            {
                return _executingTask;
            }

            // Otherwise it's running
            return Task.CompletedTask;
        }

        /// <summary>
        /// Triggered when the application host is performing a graceful shutdown.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
        public virtual async Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop called without start
            if (_executingTask == null)
            {
                return;
            }

            try
            {
                // Signal cancellation to the executing method
                _stoppingCts.Cancel();
            }
            finally
            {
                // Wait until the task completes or the stop token triggers
                await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
            }

        }

        public virtual void Dispose()
        {
            _stoppingCts?.Cancel();
        }
    }
/// <summary>
        /// Handles system suspend and resume events
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            var workers = _host.Services.GetServices<IHostedService>();
            Log.Information($"Found IHostedService instances - {workers.ToCSV()}");
            switch (e.Mode)
            {
                case PowerModes.Resume:
                    Log.Warning("System is resuming. Restarting the workers");
                    try
                    {
                        _cancellationTokenSource = new CancellationTokenSource();
                        foreach (var worker in workers)
                        {
                            await worker.StartAsync(_cancellationTokenSource.Token);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, $"{ex.Message}");
                    }
                    break;

                case PowerModes.Suspend:
                    Log.Warning("System is suspending. Stopping the workers");
                    _cancellationTokenSource.Cancel();
                    try
                    {
                        foreach (var worker in workers)
                        {
                            await worker.StopAsync(_cancellationTokenSource.Token);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, $"{ex.Message}");
                    }
                    break;
            }
        }