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

.NET Core视图lock语句中使用asp-*标签助手报CS1996错误

问题描述

我们采用.NET Core 3.1 MVC架构,视图Index.cshtml需渲染单例服务返回的内存内集合。为避免多线程修改集合时foreach枚举抛出“Collection was modified; enumeration operation may not execute”异常,我们使用lock语句,但在lock块内使用asp-*标签助手时,编译报错CS1996“Cannot await in the body of a lock statement”;移除asp-*标签助手则编译正常。已知示例中lockObj初始化方式不合理,仅用于复现问题,现咨询:

  1. 该错误原因是什么?
  2. asp-*标签助手内部是否使用异步方法?
  3. 能否在lock语句内使用asp-*标签助手?
解答

1. 错误原因

C#的lock语句基于Monitor.Enter和Monitor.Exit实现线程独占逻辑,它的设计要求锁块内不能包含异步等待(await)操作。因为异步等待会让当前线程释放锁,后续恢复执行时可能切换到其他线程,这会彻底破坏锁的线程独占性,引发不可预测的线程安全问题。因此编译器会直接拦截这种写法,抛出CS1996错误。

2. asp-*标签助手内部是否使用异步方法?

是的,不少asp-*标签助手内部会调用异步方法。比如路由类标签助手(asp-action、asp-controller)在生成URL时,可能异步访问路由服务获取路由数据;模型绑定类标签助手(asp-for)处理复杂模型验证、数据转换时也可能涉及异步逻辑。这些异步操作最终会触发await调用,这就是在lock块内使用它们会触发编译错误的核心原因。

3. 能否在lock语句内使用asp-*标签助手?

不能直接在lock块内使用。因为标签助手的异步逻辑必然会引入await,而C#语法明确禁止在lock块内执行异步等待操作。

可行替代方案

  • 提前生成集合快照:在lock块内仅做集合复制操作,生成独立的快照后立即释放锁,后续在锁块外遍历快照并使用标签助手渲染:
List<YourModel> collectionSnapshot;
lock(lockObj)
{
    collectionSnapshot = _singletonService.TargetCollection.ToList();
}

@foreach(var item in collectionSnapshot)
{
    <a asp-action="ViewDetail" asp-route-id="@item.Id">@item.Title</a>
}
  • 替换为线程安全集合:将原内存集合替换为ConcurrentBag<T>、ConcurrentDictionary<TKey, TValue>这类.NET内置线程安全集合,它们支持多线程场景下的安全枚举,无需手动加lock。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:20:26