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

Blazor Server部署后IHttpContextAccessor返回空引用异常问题

动态根据登录用户设置数据库连接字符串,部署后出现空引用异常

我通过登录用户动态设置数据库连接字符串,本地调试完全正常,但部署后触发空引用异常。DbContext的OnConfigure方法中处理连接字符串逻辑,代码如下:

namespace SwordfishCRM.Services.ApplicationDbContext
{
    public class PrimaryApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        private readonly HttpContext context;
        private readonly IConfiguration configuration;

        public PrimaryApplicationDbContext(DbContextOptions<PrimaryApplicationDbContext> options, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : base(options)
        {
            this.context = httpContextAccessor.HttpContext;
            this.configuration = configuration;
        }

        //Tables
        public DbSet<Address> Addresses { get; set; }
        public DbSet<ChimneySweepCycle> ChimneySweepCycles { get; set; }
        public DbSet<ChimneySweepMethod> ChimneySweepMethods { get; set; }
        public DbSet<ContactMethod> ContactMethods { get; set; }
        public DbSet<ContactPreference> ContactPreferences { get; set; }
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Diary> Diary { get; set; }
        public DbSet<DiaryDate> DiaryDates { get; set; }
        public DbSet<DiaryOption> DiaryOptions { get; set; }
        public DbSet<Gender> Genders { get; set; }
        public DbSet<Job> Jobs { get; set; }
        public DbSet<JobActualLine> JobActualLines { get; set; }
        public DbSet<JobApproval> JobApprovals { get; set; }
        public DbSet<JobQuoteLine> JobQuoteLines { get; set; }
        public DbSet<JobStatus> JobStatuses { get; set; }
        public DbSet<JobType> JobTypes { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Report> Reports { get; set; }
        public DbSet<RetroSweepingCertificate> RetroSweepingCertificates { get; set; }
        public DbSet<ScheduleDay> ScheduleDays { get; set; }
        public DbSet<ScheduleExceptionDay> ScheduleExceptionDays { get; set; }
        public DbSet<Title> Titles { get; set; }

        //Views
        public virtual DbSet<vwAvailableApoointment> vwAvailableApoointments { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder
                .Entity<vwAvailableApoointment>(eb =>
                {
                    eb.HasNoKey();
                    eb.ToView("vwAvailableApoointments");
                });
        }


        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var userId = context.User.Identity.Name;
            if (userId == null)
            {
                optionsBuilder.UseSqlServer(configuration.GetConnectionString("Master"));
            }
            else
            {
                var prefix = IdentitySupport.GetConnectionPrefix(userId);
                optionsBuilder.UseSqlServer(configuration.GetConnectionString(prefix));
            }        
        }
    }
}

部署后控制台抛出以下错误:

Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at SwordfishCRM.Services.ApplicationDbContext.PrimaryApplicationDbContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder) in D:\a\1\s\SwordfishCRM.Services\ApplicationDbContext\PrimaryApplicationDbContext .cs:line 67
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_Model()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at System.Linq.Queryable.OrderBy[TSource,TKey](IQueryable`1 source, Expression`1 keySelector)
   at SwordfishCRM.Web.Pages.Swordfish.DiaryScheduleExceptionDates.OnInitializedAsync() in D:\a\1\s\SwordfishCRM.Web\Pages\Swordfish\DiaryScheduleExceptionDates.razor:line 25
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

我不解为何本地正常但部署后出错,尝试过多种HttpContext用法都无效。预期是获取登录用户信息得到对应连接字符串前缀,未登录用户无法访问该页面,且已配置Master数据库作为降级方案,寻求技术支持。


问题根源

空引用异常出现在OnConfiguring方法的context.User.Identity.Name行,说明context或context.User或context.User.Identity为null,核心原因:

  • 部署环境中DbContext初始化时机早于HttpContext填充(比如EF Core预编译模型、非请求线程创建DbContext实例)
  • Blazor场景下,组件初始化阶段HttpContext可能未就绪,直接在构造函数中取值会导致空引用

修复方案

1. 延迟获取HttpContext,避免构造函数直接赋值

不要在构造函数中直接获取HttpContext,改为在OnConfiguring方法中通过IHttpContextAccessor实时获取,并增加空值判断:

private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IConfiguration _configuration;

public PrimaryApplicationDbContext(DbContextOptions<PrimaryApplicationDbContext> options, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : base(options)
{
    _httpContextAccessor = httpContextAccessor; // 仅保存访问器,不直接取HttpContext
    _configuration = configuration;
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    var context = _httpContextAccessor.HttpContext;
    // 逐层判断空值,避免空引用
    if (context == null || context.User?.Identity == null || string.IsNullOrEmpty(context.User.Identity.Name))
    {
        optionsBuilder.UseSqlServer(_configuration.GetConnectionString("Master"));
    }
    else
    {
        var prefix = IdentitySupport.GetConnectionPrefix(context.User.Identity.Name);
        optionsBuilder.UseSqlServer(_configuration.GetConnectionString(prefix));
    }        
}

2. 确认IHttpContextAccessor已注册

在Program.cs中确保添加服务注册:

builder.Services.AddHttpContextAccessor();

3. Blazor场景额外处理

如果是Blazor Server应用,组件初始化时HttpContext可能未就绪,建议通过AuthenticationStateProvider获取用户信息后再操作DbContext:

// 在Blazor组件中
[Inject] private AuthenticationStateProvider AuthStateProvider { get; set; }
[Inject] private PrimaryApplicationDbContext DbContext { get; set; }

protected override async Task OnInitializedAsync()
{
    var authState = await AuthStateProvider.GetAuthenticationStateAsync();
    var user = authState.User;
    
    // 确保用户已登录后再执行数据操作
    if (user.Identity.IsAuthenticated)
    {
        var exceptionDates = await DbContext.ScheduleExceptionDays.OrderBy(d => d.Date).ToListAsync();
        // 后续业务逻辑
    }
}

4. 处理EF Core模型预编译影响

如果启用了EF Core模型预编译,预编译过程中无HttpContext会触发降级逻辑,可通过静态构造函数规避:

static PrimaryApplicationDbContext()
{
    AppContext.SetSwitch("Microsoft.EntityFrameworkCore.PreventingDbContextCreationOnModelInitialization", true);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:20:44