• InvalidOperationException Cannot modify ServiceCollection after application is built .Net6 异常


    背景

    我用了一个叫Unchase.Swashbuckle.AspNetCore.Extensions的库来加强Swagger的文档,我一般写法是这样的:

    builder.Services.AddSwaggerGen(c =>
                {
                    //文档
                    c.SwaggerDoc("v1", new OpenApiInfo
                    {
                        Title = "『xxx』后端接口:myapi",
                        Version = "v1"
                    });
                    c.SwaggerDoc("v2", new OpenApiInfo { Title = "v2", Version = "v2" });
                    c.MapType<long>(() => new OpenApiSchema { Type = "string" });
    
                    //获取注释
                    var apiXmlPath = Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
                    c.IncludeXmlComments(apiXmlPath);
    
                    c.DescribeAllParametersInCamelCase();                
                    c.AddEnumsWithValuesFixFilters(services, o =>
                    {
                        o.IncludeDescriptions = true;
                        o.IncludeXEnumRemarks = true;
                        o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;
                        o.IncludeXmlCommentsFrom(apiXmlPath);
                    });
                });
     
    ...
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    ...
    

    在.net core 3.1 和.net5 都运行好好的,在.net6就报异常:

    InvalidOperationException: Cannot modify ServiceCollection after application is built.

    System.InvalidOperationException: Cannot modify ServiceCollection after application is built.
       at Microsoft.AspNetCore.WebApplicationServiceCollection.CheckServicesAccess()
       at Microsoft.AspNetCore.WebApplicationServiceCollection.Add(ServiceDescriptor item)
       at Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(IServiceCollection services, Type serviceType, Object implementationInstance)
       at Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton[TService](IServiceCollection services, TService implementationInstance)
       at Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.Configure[TOptions](IServiceCollection services, String name, Action`1 configureOptions)
       at Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.Configure[TOptions](IServiceCollection services, Action`1 configureOptions)
       at Unchase.Swashbuckle.AspNetCore.Extensions.Extensions.SwaggerGenOptionsExtensions.AddEnumsWithValuesFixFilters(SwaggerGenOptions swaggerGenOptions, IServiceCollection services, Action`1 configureOptions)
       at WebApi6._0.Bootstrapper.<>c__DisplayClass0_0.<AddSwagger>b__0(SwaggerGenOptions c) in D:\learn\netcoreTest\WebApi6.0\Bootstrapper.cs:line 32
       at Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure(String name, TOptions options)
       at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
       at Microsoft.Extensions.Options.UnnamedOptionsManager`1.get_Value()
       at Swashbuckle.AspNetCore.SwaggerGen.ConfigureSwaggerGeneratorOptions..ctor(IOptions`1 swaggerGenOptionsAccessor, IServiceProvider serviceProvider, IWebHostEnvironment hostingEnv)
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
       at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
       at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
       at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
       at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
       at Microsoft.Extensions.DependencyInjection.SwaggerGenServiceCollectionExtensions.<>c.<AddSwaggerGen>b__0_1(IServiceProvider s)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
       at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
       at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.GetService(IServiceProvider sp, Type type, Type middleware)
       at lambda_method1(Closure , Object , HttpContext , IServiceProvider )
       at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<UseMiddleware>b__2(HttpContext context)
       at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
       at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    

    下了源码下来发现,问题应该出现在这行:

    ...
    c.AddEnumsWithValuesFixFilters(services, o =>
                    {
                        o.IncludeDescriptions = true;
                        o.IncludeXEnumRemarks = true;
                        o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;
                        o.IncludeXmlCommentsFrom(apiXmlPath);
                    });
    ...
    

    对应nuget源码的这行:

       if (configureOptions != null)
       {
      		 services?.Configure(configureOptions);
       }
    

    https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions/blob/d710cb6557944c49824d0cb31b72b90ad0319c1f/src/Unchase.Swashbuckle.AspNetCore.Extensions/Extensions/SwaggerGenOptionsExtensions.cs#L82

    原因是:.net6之后已经不允许在

    var app = builder.Build();
    

    app build后再做 services?.Configure()操作

    那简单;

    解决

    思路是,先在build操作之前就把services?.Configure()这种操作写好

    所以我这里的写法可以改为:

    1、先更换引用的nuget包(因为在作者修改这个问题前暂时打了一个自己的nuget)

    <PackageReference Include="Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.6.12" />
    
    //改为
     <PackageReference Include="Hei.Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.6.12.1" />
    

    2、上面代码改为:

    var apiXmlPath = Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
    //这里提前
    var action = new Action<FixEnumsOptions>(o =>
    {
        o.IncludeDescriptions = true;
        o.IncludeXEnumRemarks = true;
        o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;
        o.IncludeXmlCommentsFrom(apiXmlPath);
    });
    
    services.AddSwaggerGen(c =>
    {
        //文档
        c.SwaggerDoc("v1", new OpenApiInfo
        {
             Title = "『xxx』后端接口:myapi",
             Version = "v1",
        });
        c.SwaggerDoc("v2", new OpenApiInfo { Title = "v2", Version = "v2" });
        c.SwaggerDoc("v3", new OpenApiInfo { Title = "v3", Version = "v3" });
        c.SwaggerDoc("v4", new OpenApiInfo { Title = "华为服务号相关/健康币", Version = "v4" });
        c.MapType<long>(() => new OpenApiSchema { Type = "string" });
        c.IncludeXmlComments(apiXmlPath);
        c.DescribeAllParametersInCamelCase();
        //这里改为
        c.AddEnumsWithValuesFixFilters(action);
    });
    

    问题解决!

    总结

    在同样.net6报这个错的时候注意看看:没页面先在build操作之前就把services?.Configure()这种操作写好

  • 相关阅读:
    18_09_05 textarea高度自适应 和 Z-index
    18_08_20 jQuery 获取URL中的参数
    18_08_20 jQuery 光标聚焦文字之后
    18_08_20 jQuery 将前台 多张图片 和 多个附件 转化为 附件 向后台请求
    18_8_20 Bootstrap ul标题太多的处理方式
    Http (java)的post和get方式
    18_8_20 java 时间延后的通用写法
    iOS设计模式-组合
    iOS设计模式-迭代器
    iOS设计模式-观察者
  • 原文地址:https://www.cnblogs.com/xiaxiaolu/p/16247490.html
Copyright © 2020-2023  润新知