我收到以下错误。
InvalidOperationException: Can't use schemaId "$Registration" for type "$PortalService.Models.Registration". The same schemaId is already used for type "$PortalService.Models.Registration"
我已尝试以下链接中的建议,但没有成功。
招摇错误:schemaIds 冲突:检测到类型 A 和 B 的重复 schemaIds
我在模型中只有一个注册类。我尝试过重命名该类,但没有成功。
我正在使用 OData .Net Core 3.1 项目。
配置Swagger如下
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n
Enter 'Bearer' [space] and then your token in the text input below.
\r\n\r\nExample: 'Bearer 12345abcdef'",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
});
使用 Swagger 如下
app.UseSwagger(c =>
{
//c.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.BasePath = basepath);
c.PreSerializeFilters.Add((swaggerDoc, httpReq) => {
Microsoft.OpenApi.Models.OpenApiPaths paths = new Microsoft.OpenApi.Models.OpenApiPaths();
foreach (var path in swaggerDoc.Paths)
{
paths.Add(path.Key.Replace(path.Key, basepath + path.Key), path.Value);
}
swaggerDoc.Paths = paths;
});
});
app.UseSwaggerUI(
options =>
{
options.RoutePrefix = string.Empty;
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"{basepath}/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
这似乎与
有关我发现,如果我注释掉注册中的合作伙伴反向引用,错误就会消失,但我需要此引用。我不清楚如何解决这种情况。
[ForeignKey("Partner")]
[DataMember(Name = "PartnerOID")]
[Column(TypeName = "VARCHAR(100)")]
public string PartnerOID { get; set; }
//public virtual Partner Partner { get; set; }
试试这个约翰:https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1607#issuecomment-607170559 帮助了我。
我能理解正在发生的事情;我有几个带有“状态”或“类型”的枚举。 使用
options.CustomSchemaIds( type => type.ToString() );
解决了这个问题。
唯一需要更改的是方法中的
Startup.cs
ConfigureServices
。
您应该添加以下内容:
services.AddSwaggerGen(options =>
{
options.CustomSchemaIds(type => type.ToString());
});
我一直在使用
options.CustomSchemaIds(type => type.ToString());
和 options.CustomSchemaIds(type => $"{type.Name}_{System.Guid.NewGuid().ToString().Replace("-", "")}")
来创建模式名称的唯一性。两者都会导致我讨厌更长的模式名称。
这是一种跟踪名称重复的不同方法,我更喜欢这种方法。
助手类:
internal static class SwashbuckleSchemaHelper
{
private static readonly Dictionary<string, int> _schemaNameRepetition = new Dictionary<string, int>();
public static string GetSchemaId(Type type)
{
string id = type.Name;
if (!_schemaNameRepetition.ContainsKey(id))
_schemaNameRepetition.Add(id, 0);
int count = (_schemaNameRepetition[id] + 1);
_schemaNameRepetition[id] = count;
return type.Name + (count > 1 ? count.ToString() : "");
}
}
用途:
options.CustomSchemaIds(type => SwashbuckleSchemaHelper.GetSchemaId(type));
如果类名重复,结果如下。
这是一个稍微灵活的解决方案
options.CustomSchemaIds(type => SwashbuckleSchemaHelper.GetSchemaId(type));
帮手
public static class SwashbuckleSchemaHelper
{
private static readonly string _rootNamespace;
private static readonly string _dtoFolder = "Dtos";
static SwashbuckleSchemaHelper()
{
_rootNamespace = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().ManifestModule.Name);
}
private static string GetRelativeNamespace(string typeNamespace)
{
if (!typeNamespace.StartsWith(_rootNamespace))
{
return typeNamespace;
}
var relativenamespace = typeNamespace.Substring(_rootNamespace.Length + _dtoFolder.Length + 1).TrimStart('.');
if (string.IsNullOrEmpty(relativenamespace))
{
return string.Empty;
}
return $"{relativenamespace}.";
}
public static string GetSchemaId(Type type)
{
var schemaBase = $"{GetRelativeNamespace(type.Namespace)}{type.Name}";
if (type.IsGenericType)
{
string? schemaGeneric;
if (type.GenericTypeArguments.Length > 0)
{
var firstItem = type.GenericTypeArguments.First();
schemaGeneric = $"<{GetRelativeNamespace(firstItem.Namespace)}{firstItem.Name}>";
}
else
{
schemaGeneric = $"<{Guid.NewGuid()}>";
}
return $"{schemaBase}{schemaGeneric}";
}
return $"{schemaBase}";
}
}
为了获得一个稍微好一点的类型名称,我想出了这个:
public class SwashbuckleSchemaHelper
{
private readonly Dictionary<string, int> _schemaNameRepetition = new();
// borrowed from https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/95cb4d370e08e54eb04cf14e7e6388ca974a686e/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGeneratorOptions.cs#L44
private string DefaultSchemaIdSelector(Type modelType)
{
if (!modelType.IsConstructedGenericType) return modelType.Name.Replace("[]", "Array");
var prefix = modelType.GetGenericArguments()
.Select(genericArg => DefaultSchemaIdSelector(genericArg))
.Aggregate((previous, current) => previous + current);
return prefix + modelType.Name.Split('`').First();
}
public string GetSchemaId(Type modelType)
{
string id = DefaultSchemaIdSelector(modelType);
if (!_schemaNameRepetition.ContainsKey(id))
_schemaNameRepetition.Add(id, 0);
int count = _schemaNameRepetition[id] + 1;
_schemaNameRepetition[id] = count;
return $"{id}{(count > 1 ? count.ToString() : "")}";
}
}
用法如下:
services.AddSwaggerGen(options =>
{
var schemaHelper = new SwashbuckleSchemaHelper();
options.CustomSchemaIds(type => schemaHelper.GetSchemaId(type));
});
更多详情请点击这里:
https://blog.johnnyreilly.com/2022/08/31/swashbuckle-schemaid-already-used
刚刚遇到这个问题,这就是我想出的支持泛型的方法:
c.CustomSchemaIds(type =>
{
if (!type.IsGenericType)
{
return type.Name;
}
var typeName = type.Name[..type.Name.IndexOf("`", StringComparison.Ordinal)];
var genericTypeNames = type.GetGenericArguments().Select(a => a.Name);
var genericNamesJoined = string.Join(".", genericTypeNames);
return $"{typeName}.{genericNamesJoined}";
});
所以像这样的类型
Wrapper<FirstGeneric, SecondGeneric>
会有 schemaId Wrapper.FirstGeneric.SecondGeneric
。
与这里的其他一些答案类似,但我觉得这段代码更容易理解。
这是我的版本
SwashbuckleSchemaHelper
public static class SwashbuckleSchemaHelper
{
public static string GetSchemaId(Type type)
{
var sb = new StringBuilder();
sb.Append(type.Namespace);
sb.Append('.');
sb.Append(type.Name);
if (type.IsGenericType)
{
sb.Append('<');
var arguments = type.GenericTypeArguments
.Select(GetSchemaId)
.ToArray();
sb.Append(string.Join(',', arguments));
sb.Append('>');
}
return sb.ToString();
}
}