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
相关产品推荐
相关产品推荐

