Heroku部署单层Web应用报connectionString为空异常排查
Heroku部署ABP单层应用报connectionString为空异常排查方案
问题背景
- 多层架构ABP应用按现有流程可正常部署到Heroku,同流程部署单层Web应用时访问报错
- 应用本地开发环境运行无任何报错,Heroku部署流程中已完成数据库迁移,登录Heroku数据库确认数据配置正常
- 部署后访问应用抛出异常:
System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
完整错误日志:
2022-06-01T16:46:05.058614+00:00 heroku[router]: at=info method=GET path="/" host=kriptodonacija.herokuapp.com request_id=30d7bf9f-eda8-43c1-baaf-10ce5792aa44 fwd="94.189.137.130" dyno=web.1 connect=0ms service=3ms status=500 bytes=130 protocol=https 2022-06-01T16:46:05.057150+00:00 app[web.1]: [16:46:05 INF] Request starting HTTP/1.1 GET http://kriptodonacija.herokuapp.com/ - - 2022-06-01T16:46:05.060435+00:00 app[web.1]: [16:46:05 ERR] Connection id "0HMI3T8NBRKQO", Request id "0HMI3T8NBRKQO:00000002": An unhandled exception was thrown by the application. 2022-06-01T16:46:05.060447+00:00 app[web.1]: Autofac.Core.DependencyResolutionException: An exception was thrown while activating Volo.Abp.SettingManagement.EntityFrameworkCore.SettingManagementDbContext -> λ:Microsoft.EntityFrameworkCore.DbContextOptions`1[[Volo.Abp.SettingManagement.EntityFrameworkCore.SettingManagementDbContext, Volo.Abp.SettingManagement.EntityFrameworkCore, Version=5.2.2.0, Culture=neutral, PublicKeyToken=null]]. 2022-06-01T16:46:05.060448+00:00 app[web.1]: ---> System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString') 2022-06-01T16:46:05.060449+00:00 app[web.1]: at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName) 2022-06-01T16:46:05.060450+00:00 app[web.1]: at Microsoft.EntityFrameworkCore.NpgsqlDbContextOptionsBuilderExtensions.UseNpgsql(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 npgsqlOptionsAction) 2022-06-01T16:46:05.060451+00:00 app[web.1]: at Volo.Abp.EntityFrameworkCore.AbpDbContextConfigurationContextPostgreSqlExtensions.UseNpgsql(AbpDbContextConfigurationContext context, Action`1 postgreSqlOptionsAction) 2022-06-01T16:46:05.060451+00:00 app[web.1]: at CryptoDonor.CryptoDonorModule.<>c.<ConfigureEfCore>b__14_2(AbpDbContextConfigurationContext configurationContext) in /tmp/build_1a1be254/CryptoDonor/CryptoDonorModule.cs:line 290 2022-06-01T16:46:05.060452+00:00 app[web.1]: at Volo.Abp.EntityFrameworkCore.DependencyInjection.DbContextOptionsFactory.Configure[TDbContext](AbpDbContextOptions options, AbpDbContextConfigurationContext`1 context) 2022-06-01T16:46:05.060452+00:00 app[web.1]: at Volo.Abp.EntityFrameworkCore.DependencyInjection.DbContextOptionsFactory.Create[TDbContext](IServiceProvider serviceProvider) 2022-06-01T16:46:05.060453+00:00 app[web.1]: at Autofac.Extensions.DependencyInjection.AutofacRegistration.<>c__DisplayClass3_0.<Register>b__0(IComponentContext context, IEnumerable`1 parameters) 2022-06-01T16:46:05.060454+00:00 app[web.1]: at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) 2022-06-01T16:46:05.060454+00:00 app[web.1]: at Autofac.Core.Activators.Delegate.DelegateActivator.<ConfigurePipeline>b__2_0(ResolveRequestContext ctxt, Action`1 next) 2022-06-01T16:46:05.060457+00:00 app[web.1]: at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next) 2022-06-01T16:46:05.060457+00:00 app[web.1]: at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next) 2022-06-01T16:46:05.060458+00:00 app[web.1]: --- End of inner exception stack trace --- 2022-06-01T16:46:05.060459+00:00 app[web.1]: at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next) 2022-06-01T16:46:05.060459+00:00 app[web.1]: at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next) 2022-06-01T16:46:05.060460+00:00 app[web.1]: at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next) 2022-06-01T16:46:05.060460+00:00 app[web.1]: at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request) 2022-06-01T16:46:05.060460+00:00 app[web.1]: at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request) 2022-06-01T16:46:05.060461+00:00 app[web.1]: at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) 2022-06-01T16:46:05.060461+00:00 app[web.1]: at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) 2022-06-01T16:46:05.060462+00:00 app[web.1]: at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) 2022-06-01T16:46:05.060462+00:00 app[web.1]: at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork) 2022-06-01T16:46:05.060462+00:00 app[web.1]: at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString) 2022-06-01T16:46:05.060463+00:00 app[web.1]: at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync() 2022-06-01T16:46:05.060463+00:00 app[web.1]: at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetDbSetAsync() 2022-06-01T16:46:05.060465+00:00 app[web.1]: at Volo.Abp.SettingManagement.EntityFrameworkCore.EfCoreSettingRepository.GetListAsync(String providerName, String providerKey, CancellationToken cancellationToken) 2022-06-01T16:46:05.060466+00:00 app[web.1]: at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) 2022-06-01T16:46:05.060466+00:00 app[web.1]: at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() 2022-06-01T16:46:05.060467+00:00 app[web.1]: at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) 2022-06-01T16:46:05.060467+00:00 app[web.1]: at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) 2022-06-01T16:46:05.060467+00:00 app[web.1]: at Volo.Abp.SettingManagement.SettingManagementStore.SetCacheItemsAsync(String providerName, String providerKey, String currentName, SettingCacheItem currentCacheItem) 2022-06-01T16:46:05.060470+00:00 app[web.1]: at Volo.Abp.SettingManagement.SettingManagementStore.GetCacheItemAsync(String name, String providerName, String providerKey) 2022-06-01T16:46:05.060470+00:00 app[web.1]: at Volo.Abp.SettingManagement.SettingManagementStore.GetOrNullAsync(String name, String providerName, String providerKey) 2022-06-01T16:46:05.060471+00:00 app[web.1]: at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) 2022-06-01T16:46:05.060471+00:00 app[web.1]: at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() 2022-06-01T16:46:05.060471+00:00 app[web.1]: at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) 2022-06-01T16:46:05.060474+00:00 app[web.1]: at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) 2022-06-01T16:46:05.060475+00:00 app[web.1]: at Volo.Abp.Settings.TenantSettingValueProvider.GetOrNullAsync(SettingDefinition setting) 2022-06-01T16:46:05.060476+00:00 app[web.1]: at Volo.Abp.Settings.SettingProvider.GetOrNullValueFromProvidersAsync(IEnumerable`1 providers, SettingDefinition setting) 2022-06-01T16:46:05.060477+00:00 app[web.1]: at Volo.Abp.Settings.SettingProvider.GetOrNullAsync(String name) 2022-06-01T16:46:05.060480+00:00 app[web.1]: at Microsoft.AspNetCore.RequestLocalization.DefaultAbpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync() 2022-06-01T16:46:05.060480+00:00 app[web.1]: at Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) 2022-06-01T16:46:05.060482+00:00 app[web.1]: at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext() 2022-06-01T16:46:05.060483+00:00 app[web.1]: --- End of stack trace from previous location ---
根因定位
从错误栈可直接锁定异常触发位置:CryptoDonorModule.cs第290行配置EF Core PostgreSQL上下文时,传入UseNpgsql方法的connectionString参数为null。
本地运行正常、Heroku数据库侧配置正常,说明问题和数据库本身、迁移操作无关,核心原因是Heroku运行时环境下,应用没有正确读取到数据库连接字符串配置。
排查解决步骤
- 检查配置读取逻辑兼容性
本地环境默认从项目内appsettings.json读取配置,但Heroku运行时不会主动加载项目中的配置文件,必须通过环境变量注入配置。- 确认代码没有硬编码仅从
appsettings.json读取连接字符串,要使用.NET配置体系的默认优先级(环境变量 > 命令行参数 > 配置文件)读取值 - 登录Heroku后台进入应用的Settings页,查看Config Vars中配置的连接字符串变量名,和代码中读取的变量名完全一致,注意大小写、拼写错误
- 确认代码没有硬编码仅从
- 处理Heroku Postgres连接字符串格式差异
如果使用Heroku自带的Postgres插件,平台会默认注入名为DATABASE_URL的环境变量,这个值是URL格式(postgres://<用户名>:<密码>@<主机>:<端口>/<库名>),和Npgsql要求的键值对连接字符串格式不兼容,直接传入会被识别为null。需要在代码中做格式转换:var databaseUrl = Environment.GetEnvironmentVariable("DATABASE_URL"); string defaultConnStr; if (!string.IsNullOrWhiteSpace(databaseUrl)) { var dbUri = new Uri(databaseUrl); var userInfo = dbUri.UserInfo.Split(':'); defaultConnStr = new NpgsqlConnectionStringBuilder { Host = dbUri.Host, Port = dbUri.Port, Database = dbUri.AbsolutePath.TrimStart('/'), Username = userInfo[0], Password = userInfo[1], SslMode = SslMode.Require, TrustServerCertificate = true }.ToString(); } else { // 本地环境走配置文件读取 defaultConnStr = context.Services.GetConfiguration().GetConnectionString("Default"); } - 修复ABP模块DbContext配置漏配问题
错误栈显示异常是在激活ABP内置的SettingManagementDbContext时抛出,说明你可能仅给业务主DbContext配置了连接字符串,没有给ABP内置的模块DbContext(设置管理、权限管理、审计
相关产品推荐
相关产品推荐

