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

如何在ASP.NET Core中捕获无服务器SQL Server冷启动异常并返回友好提示

解决方案

完全可以实现,你只需要先识别Azure无服务器SQL冷启动对应的特定异常类型和错误码,再通过全局异常处理机制捕获即可。

第一步:识别冷启动对应的特定异常

Azure无服务器SQL冷启动触发的连接超时/暂时不可用异常属于Microsoft.Data.SqlClient.SqlException,你可以通过匹配错误编号精准区分这类异常:

  • 连接超时错误号:-2
  • 数据库冷启动中暂时不可用错误号:40613

第二步:捕获异常并返回友好提示

推荐使用全局异常中间件方案,可覆盖所有业务场景的异常捕获:

方案1:全局异常中间件(全场景覆盖)

  1. 编写自定义中间件代码:
using Microsoft.Data.SqlClient;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class SqlColdStartHandleMiddleware
{
    private readonly RequestDelegate _next;

    public SqlColdStartHandleMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (SqlException ex) when (ex.Number is -2 or 40613)
        {
            // 匹配到冷启动异常,返回自定义提示
            context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
            // 如果是接口请求返回JSON
            if (context.Request.Path.StartsWithSegments("/api"))
            {
                context.Response.ContentType = "application/json";
                await context.Response.WriteAsJsonAsync(new
                {
                    msg = "数据库正在预热,请10秒后刷新重试",
                    retryAfter = 10
                });
            }
            // 如果是页面请求跳转至友好提示页
            else
            {
                context.Response.Redirect("/DbWarmingTip");
            }
        }
    }
}
  1. 在Startup.cs的Configure方法最顶部注册中间件,确保优先级高于其他业务中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMiddleware<SqlColdStartHandleMiddleware>();
    // 其余中间件(路由、鉴权、MVC等)注册逻辑放在下方
}

方案2:EF Core拦截器(仅处理EF发起的数据库请求)

如果仅需要捕获通过EF Core操作触发的冷启动异常,可以用EF Core自带的拦截器:

  1. 编写自定义拦截器:
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;

public class SqlColdStartInterceptor : DbCommandInterceptor
{
    public override async ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result, CancellationToken cancellationToken = default)
    {
        try
        {
            return await base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
        }
        catch (SqlException ex) when (ex.Number is -2 or 40613)
        {
            throw new InvalidOperationException("数据库正在预热,请稍后刷新重试", ex);
        }
    }
    // 按需覆盖NonQueryExecutingAsync、ScalarExecutingAsync等其他执行方法
}
  1. 在Startup.cs中注册拦截器到DbContext:
services.AddDbContext<你的DbContext类名>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("你的数据库连接字符串配置名"))
           .AddInterceptors(new SqlColdStartInterceptor()));

可选优化:从根源降低冷启动异常出现概率

你可以搭配以下配置减少用户遇到该提示的概率:

  • 开启Azure App Service的始终开启(Always On)功能,避免应用实例被回收
  • 配置EF Core内置的SQL重试策略,自动重试冷启动期间的失败请求:
services.AddDbContext<你的DbContext类名>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("你的数据库连接字符串配置名"),
        sqlOpt => sqlOpt.EnableRetryOnFailure(
            maxRetryCount: 3,
            maxRetryDelay: TimeSpan.FromSeconds(10),
            errorNumbersToAdd: new[] { -2, 40613 })));
  • 配置App Service的应用初始化预热路径,应用启动时主动触发一次轻量数据库查询,提前唤醒SQL实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:06:03