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

如何实现C# MVC Session与VueJS数据共享展示实时处理进度?

问题解决方案

核心错误原因

  • Session是C# MVC服务端进程内的存储对象,仅在后端代码运行时可访问,浏览器端的JS运行环境没有这个内置对象,直接在Vue代码中写Session["NumberProcessed"]必然抛出Session is not defined异常。
  • Cookie、LocalStorage是浏览器侧的本地存储,后端将进度值存入服务端Session后,不会自动同步到浏览器存储中,自然无法直接读取。
  • ASP.NET MVC默认对Session启用读写排他锁:如果处理批量任务的接口全程持有Session写锁,后续前端发来的轮询请求会被框架阻塞排队,直到批量任务全部执行完成才能拿到Session值,根本无法实现实时进度展示,这是进度类功能很容易踩的隐形坑。

具体实现步骤

1. 后端改造

不要用Session存实时进度,改用内存缓存(单实例部署)或分布式缓存(多实例部署,比如Redis)存储进度值,拆分两个接口:一个负责触发批量处理,一个负责返回实时进度。
以.NET Core MVC为例,先在Program.cs里注册内存缓存服务:

builder.Services.AddMemoryCache();

然后在控制器中注入IMemoryCache,编写两个接口:

private readonly IMemoryCache _memoryCache;
// 构造函数注入缓存实例
public ProcessController(IMemoryCache memoryCache)
{
    _memoryCache = memoryCache;
}

/// <summary>
/// 触发批量处理接口
/// </summary>
[HttpPost]
public IActionResult Update()
{
    // 生成本次处理任务的唯一ID,避免多用户/多任务进度混淆
    var taskId = Guid.NewGuid().ToString("N");
    // 初始化进度为0,设置10分钟缓存过期
    _memoryCache.Set($"Process:{taskId}", 0, TimeSpan.FromMinutes(10));
    
    var items = new List<int>(); // 替换成你实际要处理的条目集合
    var totalCount = items.Count;

    // 将长耗时处理丢到后台线程执行,接口立刻返回,不要等处理完再响应
    _ = Task.Run(() =>
    {
        int counter = 0;
        foreach (var item in items)
        {
            // 写入你的业务处理逻辑
            counter++;
            // 实时更新缓存中的进度
            _memoryCache.Set($"Process:{taskId}", counter, TimeSpan.FromMinutes(10));
        }
    });

    // 立刻返回任务ID和总条目数给前端
    return Ok(new { taskId, totalCount });
}

/// <summary>
/// 进度查询接口
/// </summary>
[HttpGet]
public IActionResult GetProgress(string taskId)
{
    // 从缓存读取当前已处理数量,不存在则返回0
    var processed = _memoryCache.Get<int?>($"Process:{taskId}") ?? 0;
    return Ok(new { processedCount = processed });
}

如果是.NET Framework 4.x的MVC项目,把IMemoryCache换成HttpRuntime.Cache即可,逻辑完全一致。

2. 前端Vue改造

调整轮询逻辑:点击处理按钮后先调用触发处理的接口拿到任务ID,再启动定时器轮询进度接口更新数值,处理完成后主动清除定时器。

export default {
  data() {
    return {
      timeCounter: 0,
      processedCount: 0,
      totalCount: 0,
      timer: null,
      currentTaskId: null
    }
  },
  methods: {
    processClick() {
      // 先清除可能存在的旧定时器,避免重复轮询
      if (this.timer) clearInterval(this.timer);
      this.processedCount = 0;
      this.timeCounter = 0;

      axios.post(`${api.hostname}/api/process/update`).then(res => {
        this.currentTaskId = res.data.taskId;
        this.totalCount = res.data.totalCount;
        // 拿到任务ID后启动1秒1次的轮询
        this.timer = setInterval(this.fetchProgress, 1000);
      });
    },
    fetchProgress() {
      this.timeCounter++;
      // 调用后端进度接口拿实时值
      axios.get(`${api.hostname}/api/process/getProgress`, {
        params: { taskId: this.currentTaskId }
      }).then(res => {
        this.processedCount = res.data.processedCount;
        // 进度达到总数量时停止轮询
        if (this.processedCount >= this.totalCount) {
          clearInterval(this.timer);
          this.timer = null;
          // 这里写处理完成后的业务逻辑
        }
      });
    }
  },
  beforeUnmount() {
    // 组件销毁时清除定时器,避免内存泄漏
    if (this.timer) clearInterval(this.timer);
  }
}

注意事项

  • 前端代码运行在用户浏览器中,永远无法直接访问服务端的Session、数据库、服务端内存变量这类资源,所有服务端数据都必须通过HTTP接口请求获取。
  • 长耗时任务不要放在接口的同步执行流里,否则接口会等待任务全部执行完才返回响应,前端无法提前拿到任务ID启动轮询。
  • 如果项目是多实例负载均衡部署,把内存缓存替换成Redis这类分布式缓存即可,接口逻辑不需要改动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:06:28