C# Web API和取消令牌
我试图让一个Web API和取消令牌一起工作,但由于某些原因,它似乎不能很好地发挥作用 这是我的Web API代码。它包含取消令牌属性和方法C# Web API和取消令牌,c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,我试图让一个Web API和取消令牌一起工作,但由于某些原因,它似乎不能很好地发挥作用 这是我的Web API代码。它包含取消令牌属性和方法 public class TokenCancellationApiController : ApiController { private static CancellationTokenSource cTokenSource = new CancellationTokenSource(); // Create a cancellation
public class TokenCancellationApiController : ApiController
{
private static CancellationTokenSource cTokenSource = new CancellationTokenSource();
// Create a cancellation token from CancellationTokenSource
private static CancellationToken cToken = cTokenSource.Token;
// Create a task and pass the cancellation token
[HttpGet]
public string BeginLongProcess()
{
string returnMessage = "The running process has finished!";
try
{
LongRunningFunc(cToken, 6);
}
catch (OperationCanceledException cancelEx)
{
returnMessage = "The running process has been cancelled.";
}
finally
{
cTokenSource.Dispose();
}
return returnMessage;
}
[HttpGet]
public string CancelLongProcess()
{
// cancelling task
cTokenSource.Cancel();
return "Cancellation Requested";
}
private static void LongRunningFunc(CancellationToken token, int seconds)
{
Console.WriteLine("Long running method");
for (int j = 0; j < seconds; j++)
{
Thread.Sleep(1000);
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation observed.");
throw new OperationCanceledException(token); // acknowledge cancellation
}
}
Console.WriteLine("Done looping");
}
}
公共类令牌取消ApiController:ApiController
{
私有静态CancellationTokenSource cTokenSource=新的CancellationTokenSource();
//从CancellationTokenSource创建取消令牌
私有静态取消令牌cToken=cTokenSource.Token;
//创建任务并传递取消令牌
[HttpGet]
公共字符串BeginLongProcess()
{
string returnMessage=“正在运行的进程已完成!”;
尝试
{
龙润宁Func(cToken,6);
}
捕获(操作取消异常取消)
{
returnMessage=“正在运行的进程已被取消。”;
}
最后
{
cTokenSource.Dispose();
}
返回消息;
}
[HttpGet]
公共字符串进程()
{
//取消任务
cTokenSource.Cancel();
返回“请求取消”;
}
私有静态void LongRunningFunc(取消令牌令牌,整数秒)
{
WriteLine(“长时间运行方法”);
对于(int j=0;j
我有以下HTML代码:
<script>
function BeginLongProcess()
{
alert("Will now send AJAX request to start long 6 second process...");
$.ajax({
url: "/api/TokenCancellationApi/BeginLongProcess",
type: "GET",
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
console.error(err.Message)
}
});
}
function CancelLongProcess() {
$.ajax({
url: "/api/TokenCancellationApi/CancelLongProcess",
type: "GET",
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
console.error(err.Message)
}
});
}
</script>
<form id="aForm" runat="server">
<p>
<button type="button" onclick="BeginLongProcess()">Begin Long Process</button>
</p>
<p>
<button type="button" onclick="CancelLongProcess()">Cancel Long Process</button>
</p>
</form>
函数BeginLongProcess()
{
警报(“现在将发送AJAX请求以启动长6秒的进程…”);
$.ajax({
url:“/api/TokenCancellationApi/BeginLongProcess”,
键入:“获取”,
数据类型:“json”,
成功:功能(结果){
警报(结果);
},
错误:函数(xhr、状态、错误){
var err=eval(“+xhr.responseText+”);
控制台错误(错误消息)
}
});
}
函数进程(){
$.ajax({
url:“/api/TokenCancellationApi/CancelLongProcess”,
键入:“获取”,
数据类型:“json”,
成功:功能(结果){
警报(结果);
},
错误:函数(xhr、状态、错误){
var err=eval(“+xhr.responseText+”);
控制台错误(错误消息)
}
});
}
开始漫长的过程
取消长流程
Web API方法调用得很好。
当我单击按钮开始长流程,然后单击“取消”时,我希望它取消长流程,并返回一条警告消息,告诉我该流程已取消
但事实并非如此。虽然有一个令牌取消请求,但它似乎没有注册,并且长时间的进程一直运行到完成为止
有人能告诉我为什么它不能像我希望的那样工作吗?您的线程睡眠是确定的,因为当您单击“取消”时,这样的线程不会醒来。此外,若请求取消,则应在迭代期间进行检查。由于已将令牌源设置为静态,因此一次只能运行一个长时间运行的调用。这就是为什么在开始长时间运行的流程之前,您还必须检查一个流程是否已经启动。添加了必要的锁以确保实例正确同步 稍微修改了代码,但工作正常。使其运行于配置的迭代中以方便测试。另外,睡眠时间增加到5秒。根据需要进行更改 如果您想要异步运行长时间运行的方法,这也会起作用。在begin方法中取消注释注释代码
public class TokenCancellationApiController : ApiController
{
private static object _lock = new object();
public static string _lastError;
// Static types will mean that you can only run
// one long running process at a time.
// If more than 1 needs to run, you will have to
// make them instance variable and manage
// threading and lifecycle
private static CancellationTokenSource cTokenSource;
private static CancellationToken cToken;
[HttpGet]
[Route("api/TokenCancellationApi/BeginLongProcess/{seconds}")]
public string BeginLongProcess(int seconds)
{
//Lock and check if process has already started or not.
lock (_lock)
{
if (null != cTokenSource)
{
return "A long running is already underway.";
}
cTokenSource = new CancellationTokenSource();
}
//if running asynchronously
//var task = Task.Factory.StartNew(() => LongRunningFunc(cTokenSource.Token, seconds));
//task.ContinueWith(Cleanup);
//return "Long running process has started!";
//if running synchronusly
try
{
LongRunningFunc(cTokenSource.Token, seconds);
}
catch(OperationCanceledException)
{
return "The running process has been cancelled";
}
catch(Exception ex)
{
_lastError = ex.Message;
return ex.Message;
}
finally
{
Cleanup(null);
}
return "Long running process has completed!";
}
[HttpGet]
public string CancelLongProcess()
{
// cancelling task
if (null != cTokenSource)
{
lock (_lock)
{
if (null != cTokenSource)
{
cTokenSource.Cancel();
}
return "Cancellation Requested";
}
}
else
{
return "Long running task already completed";
}
}
[HttpGet]
public string GetLastError()
{
return (string.IsNullOrEmpty(_lastError)) ? "No Error" : _lastError;
}
private static void Cleanup(Task task)
{
if (null != task && task.IsFaulted)
{
System.Diagnostics.Debug.WriteLine("Error encountered while running task");
_lastError = task.Exception.GetBaseException().Message;
}
lock (_lock)
{
if (null != cTokenSource)
{
cTokenSource.Dispose();
}
cTokenSource = null;
}
}
private static void LongRunningFunc(CancellationToken token, int seconds)
{
System.Diagnostics.Debug.WriteLine("Long running method");
int j = 0;
//Long running loop should always check if cancellation requested.
while(!token.IsCancellationRequested && j < seconds)
{
//Wait on token instead of deterministic sleep
//This way, thread will wakeup as soon as canellation
//is requested even if sleep time hasn't elapsed.
//Waiting 5 seconds
token.WaitHandle.WaitOne(5000);
j++;
}
if (token.IsCancellationRequested)
{
throw new OperationCanceledException();
}
System.Diagnostics.Debug.WriteLine("Done looping");
}
}
公共类令牌取消ApiController:ApiController
{
私有静态对象_lock=新对象();
公共静态字符串\u lastError;
//静态类型将意味着您只能运行
//一次一个长时间运行的进程。
//如果需要运行超过1个,则必须
//使它们成为实例变量并进行管理
//线程和生命周期
私有静态取消令牌源cTokenSource;
私有静态取消令牌;
[HttpGet]
[路由(“api/TokenCancellationApi/BeginLongProcess/{seconds}”)]
公共字符串BeginLongProcess(整数秒)
{
//锁定并检查进程是否已启动。
锁
{
如果(null!=cTokenSource)
{
return“长时间运行已经开始了。”;
}
cTokenSource=新的CancellationTokenSource();
}
//如果异步运行
//var task=task.Factory.StartNew(()=>LongRunningFunc(cTokenSource.Token,秒));
//任务。继续(清理);
//return“长时间运行的进程已启动!”;
//如果同步运行
尝试
{
LongRunningFunc(cTokenSource.Token,秒);
}
捕获(操作取消异常)
{
返回“正在运行的进程已被取消”;
}
捕获(例外情况除外)
{
_lastError=ex.消息;
返回ex.消息;
}
最后
{
清除(空);
}
return“长时间运行的流程已完成!”;
}
[HttpGet]
公共字符串进程()
{
//取消任务
如果(null!=cTokenSource)
{
锁
{
如果(null!=cTokenSource)
{
cTokenSource.Cancel();
}
return“取消”
<script>
function BeginLongProcess()
{
alert("Will now send AJAX request to start long 6 second process...");
var seconds = $("#seconds").val();
$.ajax({
url: "/api/TokenCancellationApi/BeginLongProcess/"+seconds,
type: "GET",
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
console.error(err.Message)
}
});
}
function CancelLongProcess() {
$.ajax({
url: "/api/TokenCancellationApi/CancelLongProcess",
type: "GET",
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
console.error(err.Message)
}
});
}
function GetLastError() {
$.ajax({
url: "/api/TokenCancellationApi/GetLastError",
type: "GET",
dataType: 'json',
success: function (result) {
alert(result);
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
console.error(err.Message)
}
});
}
</script>
<form id="form1" runat="server">
<div>
<p>
Iterations: <input id="seconds" type="text" value="10" /> <br />
<button type="button" onclick="BeginLongProcess()">Begin Long Process</button>
</p>
<p>
<button type="button" onclick="CancelLongProcess()">Cancel Long Process</button>
</p>
<p>
<button type="button" onclick="GetLastError()">Get Last Error</button>
</p>
</div>
</form>
xhr.abort()