ASP.NET Core: BackgroundService停止(StopAsync)后无法重新启动(StartAsync)的问题
这里的 BackgroundService 是指:
Microsoft.Extensions.Hosting.BackgroundService
1. 问题复现
继承该BackgroundService,实现自己的MyService :
public class MyService : BackgroundService
{
private CancellationTokenSource _CancelSource; public async Task StartAsync()
{
_CancelSource = new CancellationTokenSource();
await base.StartAsync(_CancelSource.Token);
Console.WriteLine("Start");
} public async Task CancelAsync()
{
await base.StopAsync(_CancelSource.Token);
Console.WriteLine("Stop");
} protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(, stoppingToken).ContinueWith(tsk =>
{
Console.WriteLine(string.Format("{0} working...", DateTime.Now.ToString("mm:ss")));
});
}
}
}
实例化后可以启动运行,然后停止。但是再次调用该实例的 StartAsync()就启动不了了。
当然,从 BackgroundService 实现的接口(IHostedService)来看,可能这个类本身就没打算让你手动控制启停。
2. 原因
一句话概括就是
作为函数输入参数的 CancellationToken 并没有用到
这也就是难怪网上的教程都是直接使用 CancellationToken.None 作为输入参数的原因。
下面是详细分析
直接贴下 BackgroundService 的 源码:
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System;
using System.Threading;
using System.Threading.Tasks; namespace Microsoft.Extensions.Hosting
{
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); /// <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)
{
// 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();
}
}
}
可以看到上面 StartAsync 函数调用 ExecuteAsync 时给它赋的参数直接是一个内部的只读变量,你在外部调用 StartAsync 给它输入的参数根本就没有用到。
结果就是,调用 StopAsync 之后,_stoppingCts 触发了Cancel请求,那么 _stoppingCts.IsCancellationRequested 就变成了 true,因为是只读的,所以再次调用StartAsync 来启动,进入 ExecuteAsync 之后 while判断直接就是false跳出了。
3. 解决办法
方法一:跳过StartAsync、StopAsync ,直接调用 ExecuteAsync ;
方法二:仿照官方的 BackgroundService,实现 IHostedService 接口,自己写一个 BackgroundService
方法三:使用 BackgroundWorker
ASP.NET Core: BackgroundService停止(StopAsync)后无法重新启动(StartAsync)的问题的更多相关文章
- asp.net core 1.1 升级后,操作mysql出错的解决办法。
遇到问题 core的版本从1.0升级到1.1,操作mysql数据库,查询数据时遇到MissingMethodException问题,更新.插入操作没有问题. 如果你也遇到这个问题,请参照以下步骤进行升 ...
- ASP.NET CORE的Code Fist后Models更改了怎么办?
上次我写到MVC的code fist后,自动生成数据库并自动生成web页面了 点击打开链接 那么随着项目需求的逐步明确,model变化了怎么办呢?其实和上次一样的,有两条关键的语句要记住 Add-Mi ...
- ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)
前言 本文主要是详解一下在ASP.NET Core中,采用替换后的Autofac来实现AOP拦截 觉得有帮助的朋友~可以左上角点个关注,右下角点个推荐 这里就不详细的赘述IOC是什么 以及DI是什么了 ...
- ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍
在上一章中,我们介绍了 ASP.NET Core 的启动过程,主要是对 WebHost 源码的探索.而本文则是对上文的一个补充,更加偏向于实战,详细的介绍一下我们在实际开发中需要对 Hosting 做 ...
- ASP.NET Core MVC+EF Core从开发到部署
笔记本电脑装了双系统(Windows 10和Ubuntu16.04)快半年了,平时有时间就喜欢切换到Ubuntu系统下耍耍Linux,熟悉熟悉Linux命令.Shell脚本以及Linux下的各种应用的 ...
- 系列13 docker asp.net core部署
一.介绍 本篇完整介绍asp.net core web api如何部署到docker容器中,并通过外部访问web api服务.在编写完成dockerfile之后,可以通过docker [image ...
- ASP.NET 5 改名 ASP.NET Core 1.0
今天,Scott Hanselman在其博客上宣布<ASP.NET 5 is dead - Introducing ASP.NET Core 1.0 and .NET Core 1.0>, ...
- 初识ASP.NET Core 1.0
本文将对微软下一代ASP.NET框架做个概括性介绍,方便大家进一步熟悉该框架. 在介绍ASP.NET Core 1.0之前有必要澄清一些产品名称及版本号.ASP.NET Core1.0是微软下一代AS ...
- Asp.net Core 1.0.1升级到Asp.net Core 1.1.0 Preview版本发布到Windows Server2008 R2 IIS中的各种坑
Asp.net Core 1.0.1升级到Asp.net Core 1.1.0后,程序无法运行了 解决方案:在project.json中加入runtime节点 "runtimes" ...
随机推荐
- Java正则表达式详细解析
元字符 正则表达式使用一些特定的元字符来检索.匹配和替换符合规则的字符串 元字符:普通字符.标准字符.限定字符(量词).定位字符(边界字符) 正则表达式引擎 正则表达式是一个用正则符号写出来的公式 程 ...
- arcgis api for javascript 学习(二) 发布并调用地图切片
文章将从发布切片地图到调用切片地图整个过程都展示出来. (一).切片地图的发布 1.还是前面的arcgis展示的地图 2.与发布动态地图前面的步骤是一样的 打开分享后,如图 3.一切就绪后,到达缓存的 ...
- MySQL中日期和时间类型
1 日期类型 MySql中关于日期的类型有Date/Datetime/Timestamp三种类型. 日期赋值时,允许"不严格"语法:任何标点符都可以用做日期部分或时间部分之间的间割 ...
- TICK技术栈(一)TICK技术栈介绍
1.什么是TICK技术栈? 1.1 简介 TICK 是由 InfluxData开发的一套开源工具栈,由 Telegraf, InfluxDB, Chronograf, Kapacitor 四个工具的首 ...
- 无法打开“Visual Studio Code”,因为Apple无法检查其是否包含恶意软件。”的问题解决
解决方法: 1.系统偏好设置==> 安全性与隐私 ===> 在下方允许就可以了. 2.一劳永逸 但是注意安全性 打开terminal 命令行工具输入命令:sudo spctl --mast ...
- 源码编译Kubeadm二进制文件
kubeadm是Kubernetes官方提供的用于快速安装Kubernetes集群的工具,伴随Kubernetes每个版本的发布都会同步更新,kubeadm会对集群配置方面的一些实践做调整,通过实验k ...
- 一,java框架学习
一,java框架学习 Hibernate概述Hibernate是一个开放源代码的ORM(对象关系映射)框架,对jdbc进行了轻量级的封装,是的java开发人员可以使用面向对象编程思想操作数据库,简化操 ...
- 【CodeChef EDGEST】Edges in Spanning Trees(树链剖分+树上启发式合并)
点此看题面 大致题意: 给你两棵\(n\)个点的树,对于第一棵树中的每条边\(e_1\),求存在多少条第二棵树中的边\(e_2\),使得第一棵树删掉\(e_1\)加上\(e_2\).第二棵树删掉\(e ...
- 游戏引擎架构 (Jason Gregory 著)
第一部分 基础 第1章 导论 (已看) 第2章 专业工具 (已看) 第3章 游戏软件工程基础 (已看) 第4章 游戏所需的三维数学 (已看) 第二部分 低阶引擎系统 第5章 游戏支持系统 (已看) 第 ...
- 58同城笔试题:数组去重;分饼干(分糖果);最小路径和(leetcode64)
1. 数组去重 题目描述 /** * 有序数组去重 * 输出最终的数字个数 * 输入:1,2,2 * 输出:2 * @author Turing * */ 代码 import java.util.*; ...