.NET API项目单机器启动失败:依赖注入解析异常排查
问题背景
我有一个基于.NET Framework/.NET Core的API项目,只需在appsettings.json中更新证书本地路径即可运行。项目在多台Windows 10/11机器上都能正常启动,但在某一台本地机器上启动时抛出以下错误:
---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: FSTProj.FSTClinModule.Domain.MedProfileDomain.IMedProfileDomain Lifetime: Scoped ImplementationType: FSTProj.FSTClinModule.Domain.MedProfileDomain.MedProfileDomain': Unable to resolve service for type 'FSTProj.FSTClinModule.Core.IFstUserResolverService' while attempting to activate 'FSTProj.FSTClinModule.Domain.MedProfileDomain.MedProfileDomain'.
相关代码与结构
Startup.cs 的 ConfigureServices 方法
using FSTProj.FSTClinModule.Core; using FSTProj.FSTClinModule.Domain.MedProfileDomain; using FSTProj.FSTClinModule.Infrastructure.Common; public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDBContext<DBContextVariable>(); AddDependencies(services); DomainDependencies(services); var contentRoot = Configuration.GetValue<string>(WebHostDefaults.ContentRootKey); var certPath = Path.Combine(contentRoot, Configuration["Certificate:Name"]); var signingCertificate = new X509Certificate2(certPath, Configuration["Certificate:Password"]); services.AddAuthenticationServices(Configuration, signingCertificate); services.AddDataProtectionServices(Configuration, signingCertificate); //services.AddAuthorizationPolicies<UserPermissionRole>(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "FSTProj.ClinModule.API", Version = "v1" }); var securityScheme = new OpenApiSecurityScheme { Name = "JWT Authentication", Description = "Enter JWT Bearer token **_only_**", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", // must be lower case BearerFormat = "JWT", Reference = new OpenApiReference { Id = JwtBearerDefaults.AuthenticationScheme, Type = ReferenceType.SecurityScheme } }; c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { securityScheme, new string[] { } } }); }); services.AddSingleton<ITelemetryInitializer, HttpContextRequestTelemetryInitializer>(); services.AddSingleton(c); services.AddOptions(); services.AddTransient<IFstUserResolverService, FstUserResolverService>(); }
IMedProfileDomain.cs
namespace FSTProj.FSTClinModule.Domain.MedProfileDomain { public interface IMedProfileDomain { List<CDMedProfile> GetMedications(int patientid, int vendorid); Task<Response> AddMedication(MedProfileActionRequest request); Task<MedicationList> GetMedication(MedicationListCommand command); } }
MedProfileDomain.cs
using FSTProj.FSTClinModule.Core; using FSTProj.FSTClinModule.Core.DbEntities.FST; using FSTProj.FSTClinModule.Core.DbEntities.FSTClinModule; using Microsoft.EntityFrameworkCore; namespace FSTProj.FSTClinModule.Domain.MedProfileDomain { public class MedProfileDomain : IMedProfileDomain { private FSTClinModuleDBContext _FSTClinModuleDBContext { get; set; } public IConfiguration _configuration { get; } private FSTDBContext _FSTDBContext { get; set; } private readonly IFstUserResolverService _fstUserResolverService; public MedProfileDomain(FSTClinModuleDBContext FSTClinModuleDBContext, FSTDBContext FSTDBContext, IConfiguration configuration, IFstUserResolverService fstUserResolverService) { _FSTClinModuleDBContext = FSTClinModuleDBContext; _FSTDBContext = FSTDBContext; _configuration = configuration; _fstUserResolverService = fstUserResolverService; } // 其余方法和属性已注释 } }
IFstUserResolverService.cs
namespace FSTProj.FSTClinModule.Core { #pragma warning disable SA1600 // Elements should be documented public interface IFstUserResolverService { int GetPayerId(); int GetUserId(); } #pragma warning restore SA1600 // Elements should be documented }
FstUserResolverService.cs
namespace FSTProj.FSTClinModule.Infrastructure.Common { public class FstUserResolverService: IFstUserResolverService { private readonly IHttpContextAccessor _httpContext; public FstUserResolverService(IHttpContextAccessor httpContext) { _httpContext = httpContext; } public int GetPayerId(){ } public int GetUserId() { } } }
更新信息
更新1:项目文件夹结构
FSTProj.sln | ├── FSTProj.FSTClinModule.Domain │ ├── Domain │ ├── IDomain │ └── MedProfileDomain │ └── MedProfileDomain.cs | ├── FSTProj.FSTClinModule.Infrastructure | ├── Common | └── FstUserResolverService.cs | └── FSTProj.FSTClinModule.Core ├── DbEntities ├── Enumns ├── Model └── IFstUserResolverService.cs
更新2:完整堆栈跟踪
---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: FSTProj.FSTClinModule.Domain.MedProfileDomain.IMedProfileDomain Lifetime: Scoped ImplementationType: FSTProj.FSTClinModule.Domain.MedProfileDomain.MedProfileDomain': Unable to resolve service for type 'FSTProj.FSTClinModule.Core.IFstUserResolverService' while attempting to activate 'FSTProj.FSTClinModule.Domain.MedProfileDomain.MedProfileDomain'.
问题
该API项目仅在这台特定机器上启动失败的可能原因是什么?同时希望得到可行的解决方案。
解决方案
可能原因分析
- DI注册顺序问题:
DomainDependencies(services)注册了IMedProfileDomain,但IFstUserResolverService的注册在该方法之后。部分机器可能因缓存不触发校验,但特定机器的DI容器严格按顺序执行,导致注册IMedProfileDomain时依赖的服务尚未注册。 - 项目编译不完整:该机器上的Infrastructure项目未正确编译生成,或API项目未正确引用该项目,导致DI找不到
IFstUserResolverService的实现类。 - 配置/环境异常:该机器上的证书路径错误、文件缺失或权限不足,导致证书加载失败,触发DI容器的连锁校验错误;或
WebHostDefaults.ContentRootKey对应的环境变量值异常,导致内容根目录错误。 - NuGet包版本不一致:该机器上的Microsoft.Extensions.DependencyInjection系列包版本与其他机器不同,DI容器的校验逻辑存在差异。
可行解决方案
- 调整DI注册顺序:将
IFstUserResolverService的注册移到DomainDependencies(services)之前,确保依赖服务先于被依赖服务注册:public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDBContext<DBContextVariable>(); AddDependencies(services); // 提前注册依赖服务 services.AddTransient<IFstUserResolverService, FstUserResolverService>(); DomainDependencies(services); // 其余代码保持不变 } - 清理并重新编译项目:
- 删除项目的
bin和obj文件夹 - 执行
dotnet clean和dotnet restore命令 - 重新编译整个解决方案
- 删除项目的
- 检查配置与环境:
- 验证
appsettings.json中的证书路径是否正确,证书文件是否存在且有读取权限 - 检查
WebHostDefaults.ContentRootKey对应的环境变量值,确保内容根目录指向正确的项目路径
- 验证
- 统一NuGet包版本:对比正常机器的NuGet包版本,将该机器上的Microsoft.Extensions.DependencyInjection系列包更新至相同版本
- 注册IHttpContextAccessor:
FstUserResolverService依赖IHttpContextAccessor,需显式添加注册:
放在services.AddHttpContextAccessor();AddTransient<IFstUserResolverService, FstUserResolverService>()之前。
内容的提问来源于stack exchange,提问作者humblefool
相关产品推荐
相关产品推荐

