.NET 8 WebAPI中System.TimeProvider服务注册问题求助
将基于.NET Core 3.1的ASP.NET课程项目升级到.NET 8 WebAPI时,配置Identity后出现无法解析System.TimeProvider服务的错误。原代码使用的ISystemClock、SystemClock已标记为过时,提示改用TimeProvider,但尝试通过builder.Services.AddSingleton<TimeProvider>()注册时失败,报错无法实例化抽象类型。
错误信息
运行时错误
未处理的异常。System.AggregateException: 某些服务无法构造(验证服务描述符 'ServiceType: Microsoft.AspNetCore.Identity.ISecurityStampValidator Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.SecurityStampValidator
1[Dominio.Usuario]' 时出错:尝试激活 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时,无法解析类型为 'System.TimeProvider' 的服务。)(验证服务描述符 'ServiceType: Microsoft.AspNetCore.Identity.ITwoFactorSecurityStampValidator Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.TwoFactorSecurityStampValidator1[Dominio.Usuario]' 时出错:尝试激活 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时,无法解析类型为 'System.TimeProvider' 的服务。)(验证服务描述符 'ServiceType: Microsoft.Extensions.Options.IPostConfigureOptions1[Microsoft.AspNetCore.Identity.SecurityStampValidatorOptions] Lifetime: Singleton ImplementationType: Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时出错:尝试激活 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时,无法解析类型为 'System.TimeProvider' 的服务。) ---> System.InvalidOperationException: 验证服务描述符 'ServiceType: Microsoft.AspNetCore.Identity.ISecurityStampValidator Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.SecurityStampValidator1[Dominio.Usuario]' 时出错:尝试激活 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时,无法解析类型为 'System.TimeProvider' 的服务。
---> System.InvalidOperationException: 尝试激活 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions' 时,无法解析类型为 'System.TimeProvider' 的服务。
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot, Boolean throwOnConstraintViolation) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot, Boolean throwOnConstraintViolation) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options) at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options) at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build() at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build() at Program.<Main>$(String[] args) in C:\Users\Nicolas\Documents\ProyectoCore\WebAPI\Program.cs:line 54 ---> (Inner Exception #1) System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Identity.ITwoFactorSecurityStampValidator Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.TwoFactorSecurityStampValidator`1[Dominio.Usuario]': Unable to resolve service for type 'System.TimeProvider' while attempting to activate 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions'. ---> System.InvalidOperationException: Unable to resolve service for type 'System.TimeProvider' while attempting to activate 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot, Boolean throwOnConstraintViolation) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot, Boolean throwOnConstraintViolation) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)<--- ---> (Inner Exception #2) System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Options.IPostConfigureOptions`1[Microsoft.AspNetCore.Identity.SecurityStampValidatorOptions] Lifetime: Singleton ImplementationType: Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions': Unable to resolve service for type 'System.TimeProvider' while attempting to activate 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions'. ---> System.InvalidOperationException: Unable to resolve service for type 'System.TimeProvider' while attempting to activate 'Microsoft.AspNetCore.Identity.IdentityBuilderExtensions+PostConfigureSecurityStampValidatorOptions'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) --- End of inner exception stack trace --- at Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(ServiceDescriptor descriptor) at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)<---
编译警告
CS0618 'ISystemClock' 已过时: '请改用 TimeProvider。' CS0618 'SystemClock' 已过时: '请改用 TimeProvider。'
尝试直接注册TimeProvider后的错误
未处理的异常。System.ArgumentException: 无法为服务类型 'System.TimeProvider' 实例化实现类型 'System.TimeProvider'。
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.Populate() at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options) at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options) at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build() at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build() at Program.<Main>$(String[] args) in C:\Users\Nicolas\Documents\ProyectoCore\WebAPI\Program.cs:line 54
解决方案
System.TimeProvider是抽象类,不能直接注册实例,需使用它的默认实现TimeProvider.System- 移除过时的
ISystemClock注册代码,替换为注册TimeProvider的正确方式 - .NET 8中
AddIdentityCore支持链式调用,可简化原有的IdentityBuilder手动创建代码
修改后的关键代码
// 移除这行过时代码 // builder.Services.AddSingleton<ISystemClock, SystemClock>(); // 注册TimeProvider的默认实现 builder.Services.AddSingleton(TimeProvider.System); // 也可显式指定类型,效果一致 // builder.Services.AddSingleton<TimeProvider>(TimeProvider.System);
完整修改后的Program.cs
using Aplicacion.Cursos; using Dominio; using FluentValidation; using FluentValidation.AspNetCore; using MediatR; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using Persistencia; using System.Reflection; using WebAPI.Middleware; var builder = WebApplication.CreateBuilder(args); // 注册控制器服务 builder.Services.AddControllers(); builder.Services.AddFluentValidationAutoValidation(); builder.Services.AddFluentValidationClientsideAdapters(); builder.Services.AddValidatorsFromAssemblyContaining<Nuevo>(); // 数据库上下文配置 builder.Services.AddDbContext<CursosOnlineContext>(opt => opt.UseSqlServer(builder.Configuration.GetConnectionString("conexionSQLServer"))); // Identity核心配置(.NET 8简化写法) builder.Services.AddIdentityCore<Usuario>() .AddEntityFrameworkStores<CursosOnlineContext>() .AddSignInManager<SignInManager<Usuario>>(); // 注册TimeProvider默认实现,替代过时的ISystemClock builder.Services.AddSingleton(TimeProvider.System); // MediatR服务配置 builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Consulta.Manejador).Assembly)); // Swagger配置 builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "API Proyecto Core", Version = "v1" }); c.CustomSchemaIds(type => type.FullName?.Replace("+", ".")); }); var app = builder.Build(); // 开发环境启用Swagger if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // 数据库迁移与测试数据插入 using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; try { var userManager = services.GetRequiredService<UserManager<Usuario>>(); var context = services.GetRequiredService<CursosOnlineContext>(); context.Database.Migrate(); DataPrueba.InsertarData(context, userManager).Wait(); } catch(Exception) { var logger = services.GetRequiredService<ILogger<Program>>(); logger.LogError("迁移过程中发生错误"); } } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.UseMiddleware<ManejadorErrorMiddleware>(); app.Run();
说明
TimeProvider.System是.NET 6+引入的默认时间提供器实现,功能等价于原有的SystemClock- 移除过时的
ISystemClock注册后,Identity的依赖注入链会自动使用已注册的TimeProvider实例 - .NET 8中
AddIdentityCore的链式调用写法更简洁,无需手动创建IdentityBuilder
内容的提问来源于stack exchange,提问作者Nicolás Olmedo

