You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core ABP项目Swashbuckle生成Swagger报StringBuilder内存溢出

Swashbuckle生成Swagger JSON内存溢出问题处理方案

报错信息

RequestAborted: Exception of type 'System.OutOfMemoryException' was thrown.. Request Path: /swagger/v1/swagger.json
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.Text.StringBuilder.ToString()
   at System.IO.StringWriter.ToString()
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.RespondWithSwaggerJson(HttpResponse response, OpenApiDocument swagger)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Abp.AspNetZeroCore.Web.Authentication.JwtBearer.JwtTokenMiddleware.<>c__DisplayClass0_0.<<UseJwtTokenMiddleware>b__0>d.MoveNext()

触发原因

  • 单Swagger文档体积过大:项目接口数量多、参数模型嵌套层级深、泛型模型滥用,序列化后的JSON体积过大,StringBuilder.ToString()需要申请连续内存块,托管堆无法提供足够连续空间时就会抛出OOM,32位进程下因用户态内存上限仅2G更容易触发该问题。
  • Swashbuckle旧版本设计缺陷:低版本Swashbuckle生成JSON时会先将全量内容写入StringWriter,再一次性转字符串输出到响应流,大文档场景下内存占用极高。
  • ABP框架自动暴露接口的特性:ASP.NET Boilerplate默认会将所有应用服务方法自动注册为API接口,未做过滤时会将大量内部接口、ABP内置接口也加入Swagger文档,进一步放大文档体积。

排查步骤

  • 统计当前暴露的API总数:如果可偶尔正常打开swagger.json,直接统计paths节点的接口数量,单文档超过1000个接口就属于高风险场景。
  • 确认进程运行位数:检查项目是否运行在32位进程模式下,32位进程的内存上限极易触发OOM。
  • 排查模型循环引用:检查接口入参出参模型是否存在循环依赖(如A引用B、B又引用A),循环引用会导致Swashbuckle序列化时无限展开,内存暴涨。

解决方法

1. 过滤不需要暴露的接口

通过DocInclusionPredicate配置过滤规则,排除ABP内置接口、内部非公开接口:

services.AddSwaggerGen(options =>
{
    options.DocInclusionPredicate((docName, apiDesc) =>
    {
        // 过滤ABP内置接口、内部业务接口
        if (apiDesc.RelativePath.StartsWith("api/abp/") || apiDesc.RelativePath.StartsWith("api/internal/"))
        {
            return false;
        }
        // 补充自定义过滤逻辑
        return true;
    });
});

2. 拆分多分组Swagger文档

按业务模块、接口使用方拆分多个独立的Swagger文档,避免单个JSON体积过大:

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1-admin", new OpenApiInfo { Title = "管理端接口", Version = "v1" });
    options.SwaggerDoc("v1-client", new OpenApiInfo { Title = "客户端接口", Version = "v1" });
    // 搭配DocInclusionPredicate给不同分组分配对应接口
});

3. 升级Swashbuckle版本启用流式输出

将Swashbuckle.AspNetCore升级到5.x以上适配.NET Core 3.1的版本,启用流式序列化直接输出到响应流,避免StringBuilder的内存占用:

app.UseSwagger(options =>
{
    options.RouteTemplate = "swagger/{documentName}/swagger.json";
    options.SerializeAsV2 = false;
});

4. 配置模型忽略规则

自定义Schema过滤器,忽略不需要在Swagger中展示的内部模型、敏感属性:

services.AddSwaggerGen(options =>
{
    options.SchemaFilter<IgnorePropertySchemaFilter>();
});

public class IgnorePropertySchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        // 忽略指定内部模型
        if (context.Type == typeof(内部通用模型类))
        {
            schema.Properties.Clear();
        }
        // 忽略标记了自定义[SwaggerIgnore]特性的属性
        var ignoredProperties = context.Type.GetProperties()
            .Where(p => p.GetCustomAttribute<SwaggerIgnoreAttribute>() != null);
        foreach (var prop in ignoredProperties)
        {
            var camelCaseName = char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1);
            schema.Properties.Remove(camelCaseName);
        }
    }
}

5. 调整进程运行配置

确保项目运行在64位进程模式下,IIS部署时关闭"启用32位应用程序"选项,自宿主部署时选择x64运行时。

内容的提问来源于stack exchange,提问作者André Haupt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 15:36:04