You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现从浏览器到SQL Server经MVC/Web API的请求取消链式传递

浏览器到后端的请求取消链式实现方案

针对你需要实现的从jQuery Ajax到MVC、Web API、SQL存储过程的链式取消需求,以下是完整的实现方案和代码示例,同时纠正你测试代码中的问题:


1. 前端jQuery Ajax取消逻辑

通过jQuery的jqXHR.abort()触发请求取消,ASP.NET会自动将客户端断开事件关联到后端的CancellationToken:

let ajaxRequest;

// 发起搜索请求
$('#searchBtn').click(() => {
  ajaxRequest = $.ajax({
    url: '/Home/Search',
    type: 'POST',
    data: { keyword: $('#keyword').val() },
    success: (data) => { /* 处理返回结果 */ },
    error: (xhr) => {
      if (xhr.statusText === 'abort') {
        console.log('搜索请求已取消');
      }
    }
  });
});

// 绑定取消按钮事件
$('#cancelBtn').click(() => {
  ajaxRequest?.abort();
});

2. MVC层:接收并传递取消信号

ASP.NET MVC控制器方法可直接注入CancellationToken参数,该token会自动响应客户端的取消操作。你的测试代码存在3个核心问题:未等待异步任务完成、取消检查时机错误、冗余使用TaskCompletionSource,以下是纠正后的代码:

正确的MVC异步控制器代码

public async Task<JsonResult> Search(string keyword, CancellationToken token)
{
    try
    {
        // 模拟耗时业务逻辑(替换为实际调用Web API/数据库操作)
        await Task.Run(() =>
        {
            for (int i = 0; i < 100000; i++)
            {
                // 关键:在耗时循环中定期检查取消信号
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
                Console.WriteLine("value" + i);
            }
        }, token);

        // 实际业务:调用Web API时传递取消token
        // var apiResult = await _webApiClient.SearchProducts(keyword, token);

        return Json(new { success = true, data = "搜索结果" }, JsonRequestBehavior.AllowGet);
    }
    catch (OperationCanceledException)
    {
        // 处理取消逻辑:记录日志/返回提示
        return Json(new { success = false, message = "请求已取消" }, JsonRequestBehavior.AllowGet);
    }
}

原代码问题说明

  1. 使用Task.Factory.StartNew后未等待任务完成,直接返回结果,导致异步任务在后台无效执行
  2. 取消检查放在循环结束后,无法及时响应客户端的取消请求
  3. 无需手动创建TaskCompletionSource,MVC支持直接返回async Task<JsonResult>

3. Web API层:传递取消信号到下游

调用Web API时,将MVC层的CancellationToken传递给HttpClient的异步方法,实现请求级别的取消:

public async Task<SearchResult> SearchProducts(string keyword, CancellationToken token)
{
    using var client = new HttpClient();
    var response = await client.GetAsync(
        $"https://your-api-domain/api/products?keyword={keyword}", 
        token
    );
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadFromJsonAsync<SearchResult>(cancellationToken: token);
}

4. SQL存储层:取消正在执行的存储过程

将CancellationToken与SqlCommand绑定,触发取消时自动终止存储过程执行:

public async Task<List<Product>> ExecuteSearchProc(string keyword, CancellationToken token)
{
    using var conn = new SqlConnection("your-connection-string");
    await conn.OpenAsync(token);

    using var cmd = new SqlCommand("dbo.SearchProducts", conn)
    {
        CommandType = CommandType.StoredProcedure
    };
    cmd.Parameters.AddWithValue("@Keyword", keyword);

    // 绑定取消信号:当token触发时自动调用cmd.Cancel()
    using (token.Register(() => cmd.Cancel()))
    {
        using var reader = await cmd.ExecuteReaderAsync(token);
        var products = new List<Product>();
        while (await reader.ReadAsync(token))
        {
            products.Add(new Product
            {
                Id = reader.GetInt32(0),
                Name = reader.GetString(1)
            });
        }
        return products;
    }
}

注意:SQL Server仅会在语句执行间隙响应取消,无法立即终止正在运行的核心查询,需在存储过程中设计可中断的逻辑(如循环中检查@@SPID状态)


核心实现建议

  • 全程传递CancellationToken:从MVC控制器到Web API、数据库操作,不要中途丢弃取消信号
  • 定期检查取消状态:在耗时循环、IO操作前后检查token.IsCancellationRequested,避免无效执行
  • 优先使用异步API:所有IO操作(HTTP、数据库)必须使用异步版本并传递token,同步API无法有效响应取消
  • 统一处理取消异常:在各层捕获OperationCanceledException,返回友好提示或记录日志

内容的提问来源于stack exchange,提问作者Kunal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:05:21