如何让ASP.NET ApiExplorer与NSwag将强类型Id识别为字符串?
解决ASP.NET 6中ApiExplorer将强类型Id识别为复杂对象的问题
你的问题根源在于ASP.NET的ApiExplorer默认会将带属性的Id记录识别为复杂对象,进而导致NSwag生成多余的参数。以下是三种可行的解决方案:
方案1:为强类型Id添加TypeConverter
ApiExplorer会根据类型的转换能力判断是否为简单类型,给Id实现TypeConverter后,框架会将其识别为可与字符串互转的简单类型。
首先实现自定义类型转换器:
public class IdTypeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string str && Guid.TryParse(str, out var guid)) { return new Id(guid); } return base.ConvertFrom(context, culture, value); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is Id id) { return id.Value.ToString(); } return base.ConvertTo(context, culture, value, destinationType); } }
然后给Id记录标记类型转换器特性:
[TypeConverter(typeof(IdTypeConverter))] public record Id(Guid Value);
方案2:自定义IApiDescriptionProvider修改参数描述
通过实现IApiDescriptionProvider,直接修改ApiExplorer生成的参数元数据,将Id类型替换为字符串类型。
实现自定义Provider:
public class IdApiDescriptionProvider : IApiDescriptionProvider { public void OnProvidersExecuting(ApiDescriptionProviderContext context) { foreach (var apiDescription in context.Results) { var targetParams = apiDescription.ParameterDescriptions .Where(p => p.ParameterType == typeof(Id)) .ToList(); foreach (var param in targetParams) { apiDescription.ParameterDescriptions.Remove(param); apiDescription.ParameterDescriptions.Add(new ApiParameterDescription { Name = param.Name, ParameterType = typeof(string), Source = param.Source, ModelMetadata = context.ModelMetadataProvider.GetMetadataForType(typeof(string)) }); } } } public void OnProvidersExecuted(ApiDescriptionProviderContext context) { // 无需额外处理 } }
在Program.cs中注册该服务:
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IApiDescriptionProvider, IdApiDescriptionProvider>());
方案3:直接配置NSwag的Schema生成规则
绕过ApiExplorer的判断,在NSwag层面强制将Id类型处理为字符串类型:
在Program.cs的NSwag配置中添加自定义Schema处理器:
builder.Services.AddOpenApiDocument(settings => { settings.SchemaGenerator.SchemaProcessors.Add(new IdSchemaProcessor()); }); public class IdSchemaProcessor : ISchemaProcessor { public void Process(SchemaProcessorContext context) { if (context.Type == typeof(Id) || context.ParameterInfo?.ParameterType == typeof(Id)) { context.Schema.Type = "string"; context.Schema.Format = "uuid"; context.Schema.Properties.Clear(); context.Schema.Required.Clear(); } } }
内容的提问来源于stack exchange,提问作者Christian Klemm
相关产品推荐
相关产品推荐

