取消 ASP.NET 开始的任务
Cancelling a Task started by ASP.NET
背景
以下服务器端代码用于启动一个长 运行 任务,该任务将 post 通过 SignalR 更新到 Web 前端。我在前端放置了一个按钮,然后我想根据用户的请求停止任务。
问题
前端触发Stop
方法时,tokenSource
为空。我怀疑,这是因为它没有到达生成任务的 ChartHub
的同一个实例。
代码
using System;
...
using System.Security.Principal;
namespace dvvWeb.Hubs
{
public class ChartHub : Hub
{
CancellationTokenSource tokenSource;
CancellationToken ct;
public void Start(string serverName, string dbName, string numberOfPoints, string pollingFrequency)
{
ConfigModel config = new ConfigModel();
tokenSource = new CancellationTokenSource();
ct = tokenSource.Token;
config.Servername = HttpUtility.UrlDecode(serverName);
config.DbName = HttpUtility.UrlDecode(dbName);
config.Preferences.NumberOfPoints = int.Parse(numberOfPoints);
config.Preferences.PollingFrequency = int.Parse(pollingFrequency);
dvvGraphingModel graphingModel = new dvvGraphingModel();
dvvGraphingHelper graphingHelper = new dvvGraphingHelper(graphingModel, config.Servername, config.DbName);
graphingModel = graphingHelper.Tick(config.Preferences);
var identity = WindowsIdentity.GetCurrent();
Task.Run(() => workItemAsync(ct, graphingModel, graphingHelper, config, identity));
}
public void Stop()
{
tokenSource.Cancel();
}
private async Task<CancellationToken> workItemAsync(CancellationToken ct, dvvGraphingModel graphingModel, dvvGraphingHelper graphingHelper, ConfigModel configModel, WindowsIdentity identity)
{
await addDataAsync(ct, graphingModel, graphingHelper, configModel, identity);
return ct;
}
private async Task<CancellationToken> addDataAsync(CancellationToken ct, dvvGraphingModel graphingModel, dvvGraphingHelper graphingHelper, ConfigModel configModel, WindowsIdentity identity)
{
try
{
while(!ct.IsCancellationRequested)
{
identity.Impersonate();
Clients.Caller.addPointToChart(JsonConvert.SerializeObject(graphingModel));
System.Threading.Thread.Sleep(configModel.Preferences.PollingFrequency * 1000);
graphingModel = graphingHelper.Tick(configModel.Preferences);
}
}
catch (TaskCanceledException tce)
{
Trace.TraceError("Caught TaskCanceledException - signaled cancellation " + tce.Message);
}
return ct;
}
}
}
我会创建一个 ConcurrentDictionary<string, CancellationTokenSource>
,其中 'string' 是用户 name/id 或者
ConcurrentDictionary<IUserIdentity, CancellationTokenSource>
。
嗯,那是在用户一次只能启动一个进程的情况下。
该词典将存在于 Hub 之外的单例 class 中。您的集线器将只是在您的单例中调用方法的代理。
YourSingleton.Instance.Start(userId, serverName, dbName, numberOfPoints, pollingFrequency);
和
YourSingleton.Instance.Stop(userId);
然后,您可以执行以下操作:
public void Stop(string userId)
{
CancellationTokenSource tokenSource;
if(dictionary.TryGetValue(userId, out tokenSource))
{
tokenSource.Cancel();
dictionary.TryRemove(userId out tokenSource);
}
}
背景
以下服务器端代码用于启动一个长 运行 任务,该任务将 post 通过 SignalR 更新到 Web 前端。我在前端放置了一个按钮,然后我想根据用户的请求停止任务。
问题
前端触发Stop
方法时,tokenSource
为空。我怀疑,这是因为它没有到达生成任务的 ChartHub
的同一个实例。
代码
using System;
...
using System.Security.Principal;
namespace dvvWeb.Hubs
{
public class ChartHub : Hub
{
CancellationTokenSource tokenSource;
CancellationToken ct;
public void Start(string serverName, string dbName, string numberOfPoints, string pollingFrequency)
{
ConfigModel config = new ConfigModel();
tokenSource = new CancellationTokenSource();
ct = tokenSource.Token;
config.Servername = HttpUtility.UrlDecode(serverName);
config.DbName = HttpUtility.UrlDecode(dbName);
config.Preferences.NumberOfPoints = int.Parse(numberOfPoints);
config.Preferences.PollingFrequency = int.Parse(pollingFrequency);
dvvGraphingModel graphingModel = new dvvGraphingModel();
dvvGraphingHelper graphingHelper = new dvvGraphingHelper(graphingModel, config.Servername, config.DbName);
graphingModel = graphingHelper.Tick(config.Preferences);
var identity = WindowsIdentity.GetCurrent();
Task.Run(() => workItemAsync(ct, graphingModel, graphingHelper, config, identity));
}
public void Stop()
{
tokenSource.Cancel();
}
private async Task<CancellationToken> workItemAsync(CancellationToken ct, dvvGraphingModel graphingModel, dvvGraphingHelper graphingHelper, ConfigModel configModel, WindowsIdentity identity)
{
await addDataAsync(ct, graphingModel, graphingHelper, configModel, identity);
return ct;
}
private async Task<CancellationToken> addDataAsync(CancellationToken ct, dvvGraphingModel graphingModel, dvvGraphingHelper graphingHelper, ConfigModel configModel, WindowsIdentity identity)
{
try
{
while(!ct.IsCancellationRequested)
{
identity.Impersonate();
Clients.Caller.addPointToChart(JsonConvert.SerializeObject(graphingModel));
System.Threading.Thread.Sleep(configModel.Preferences.PollingFrequency * 1000);
graphingModel = graphingHelper.Tick(configModel.Preferences);
}
}
catch (TaskCanceledException tce)
{
Trace.TraceError("Caught TaskCanceledException - signaled cancellation " + tce.Message);
}
return ct;
}
}
}
我会创建一个 ConcurrentDictionary<string, CancellationTokenSource>
,其中 'string' 是用户 name/id 或者
ConcurrentDictionary<IUserIdentity, CancellationTokenSource>
。
嗯,那是在用户一次只能启动一个进程的情况下。
该词典将存在于 Hub 之外的单例 class 中。您的集线器将只是在您的单例中调用方法的代理。
YourSingleton.Instance.Start(userId, serverName, dbName, numberOfPoints, pollingFrequency);
和
YourSingleton.Instance.Stop(userId);
然后,您可以执行以下操作:
public void Stop(string userId)
{
CancellationTokenSource tokenSource;
if(dictionary.TryGetValue(userId, out tokenSource))
{
tokenSource.Cancel();
dictionary.TryRemove(userId out tokenSource);
}
}