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

Blazor Server项目保存数据时偶现“当前回路未处理异常”问题排查

问题描述

我正在使用VS 2022开发Blazor Server项目,调用以下updateObject方法保存数据时偶发未处理异常提示,错误核心信息为:
System.InvalidOperationException: An exception was thrown while activating Microsoft.AspNetCore.Components.Server.Circuits.CircuitAccessor.
该错误为偶发,调试时无异常提示,且每次操作的数据均已正常保存,仅在操作完成后出现上述错误提示。

相关代码

数据层方法

async public static Task<bool> updateObject(Firecall obj)
{
    Firecall r;
    try
    {
        using (var context = new sptContext())
        {
            r = context.Firecalls.Where(c => c.Mguid == obj.Mguid).FirstOrDefault();
            bool новое = (r == null);
            if (новое)
            {
                r = new Firecall();
            }
            r.comment = obj.comment;

            if (новое)
                await context.Firecalls.AddAsync(r);

            if (busy)
                return false;
            try
            {
                busy = true;
                await context.SaveChangesAsync();
            }
            catch (Exception)
            {

                return false;
            }
            finally {
                busy = false;
            }
        }
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}   

Razor视图调用代码

async private void SaveChanges()
{
  bool rez = await firecallRepository.updateObject(_currentFireCall);
}
解决方案

1. 替换async void为async Task

Blazor Server中组件的异步方法不能用async void,这种写法会导致异步操作的异常无法被Blazor框架捕获,进而触发全局未处理异常提示。修改Razor中的调用方法:

async private Task SaveChanges()
{
  bool rez = await firecallRepository.updateObject(_currentFireCall);
}

UI触发时直接绑定方法即可,比如按钮点击用@onclick="SaveChanges",确保框架能正确跟踪异步操作的生命周期。

2. 修复静态busy变量的线程安全问题

updateObject是静态方法,且使用了全局共享的静态busy字段,在Blazor Server多用户/并发场景下会互相干扰,导致逻辑混乱和异常。解决方式:

  • 若要防止同一用户重复提交,将busy改为组件级别的实例变量(比如组件内的private bool _isBusy),在调用保存方法前先判断状态。
  • 若要实现全局并发控制,使用线程安全的SemaphoreSlim替代静态布尔值:
// 替换静态busy为线程安全的信号量
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

async public static Task<bool> updateObject(Firecall obj)
{
    Firecall r;
    try
    {
        using (var context = new sptContext())
        {
            r = context.Firecalls.Where(c => c.Mguid == obj.Mguid).FirstOrDefault();
            bool новое = (r == null);
            if (новое)
            {
                r = new Firecall();
            }
            r.comment = obj.comment;

            if (новое)
                await context.Firecalls.AddAsync(r);

            // 等待信号量,避免并发操作冲突
            await _semaphore.WaitAsync();
            try
            {
                await context.SaveChangesAsync();
            }
            catch (Exception)
            {
                return false;
            }
            finally {
                _semaphore.Release();
            }
        }
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}   

3. 取消仓库方法的静态特性,改用依赖注入

静态类/方法在Blazor Server中会带来全局状态污染问题,建议将仓库改为实例类,通过依赖注入(Scoped或Transient)注入到组件中,同时添加日志记录便于排查偶发异常:

// 仓库类改为实例类,注入ILogger
public class FirecallRepository
{
    private readonly ILogger<FirecallRepository> _logger;
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public FirecallRepository(ILogger<FirecallRepository> logger)
    {
        _logger = logger;
    }

    async public Task<bool> updateObject(Firecall obj)
    {
        Firecall r;
        try
        {
            using (var context = new sptContext())
            {
                r = context.Firecalls.Where(c => c.Mguid == obj.Mguid).FirstOrDefault();
                bool новое = (r == null);
                if (новое)
                {
                    r = new Firecall();
                }
                r.comment = obj.comment;

                if (новое)
                    await context.Firecalls.AddAsync(r);

                await _semaphore.WaitAsync();
                try
                {
                    await context.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "保存Firecall数据失败");
                    return false;
                }
                finally {
                    _semaphore.Release();
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理Firecall数据时发生异常");
            return false;
        }
    }
}

在Program.cs中注册仓库:

builder.Services.AddScoped<FirecallRepository>();

4. 验证DbContext的注册方式

确保sptContext在Blazor Server中注册为Scoped(默认推荐方式),避免并发操作时的上下文冲突:

builder.Services.AddDbContext<sptContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnectionString")));

内容的提问来源于stack exchange,提问作者А.Терентьев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:16:03