如何在ASP.NET Core中绑定Swagger传入的动态模型?
解决方案:动态模型绑定实现
问题核心在于默认JSON序列化器无法自动根据JSON中的额外属性(如address/vendor)匹配对应的RequestItem子类,需要通过自定义JSON转换器实现类型识别与绑定。
步骤1:修正模型属性与JSON字段映射
确保C#属性名与JSON字段名严格匹配,可通过特性标记实现:
// System.Text.Json 特性 using System.Text.Json.Serialization; public class UpdateRequestItems { public List<RequestItem> RequestItems { get; set; } } [JsonConverter(typeof(RequestItemConverter))] // 标记使用自定义转换器 public class RequestItem { public Guid Id { get; set; } public DateOnly EventDate { get; set; } public string EventName { get; set; } public EventType EventType { get; set; } } public class RequestAddress : RequestItem { [JsonPropertyName("address")] // 匹配JSON中的"address"字段 public TripItineraryAddress? Address { get; set; } } public class RequestVendor : RequestItem { [JsonPropertyName("vendor")] public TripItineraryVendor? Vendor { get; set; } } public class RequestDescription : RequestItem { [JsonPropertyName("description")] public TripItineraryDescription? Description { get; set; } } public class TripItineraryAddress { [JsonPropertyName("address")] public string Address { get; set; } [JsonPropertyName("note")] public string Note { get; set; } } // 补充其他TripItineraryXXX类的属性映射
步骤2:实现自定义JSON转换器
创建RequestItemConverter,根据JSON中的属性或eventType值判断实例化的子类:
using System.Text.Json; using System.Text.Json.Serialization; public class RequestItemConverter : JsonConverter<RequestItem> { public override RequestItem Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // 优先通过EventType判断(更可靠) if (root.TryGetProperty("eventType", out JsonElement eventTypeElem) && eventTypeElem.TryGetInt32(out int eventTypeVal)) { return (EventType)eventTypeVal switch { EventType.AddressEvent => JsonSerializer.Deserialize<RequestAddress>(root.GetRawText(), options), EventType.VendorEvent => JsonSerializer.Deserialize<RequestVendor>(root.GetRawText(), options), EventType.DescriptionEvent => JsonSerializer.Deserialize<RequestDescription>(root.GetRawText(), options), _ => JsonSerializer.Deserialize<RequestItem>(root.GetRawText(), options) }; } // fallback:通过存在的属性判断 if (root.TryGetProperty("address", out _)) return JsonSerializer.Deserialize<RequestAddress>(root.GetRawText(), options); if (root.TryGetProperty("vendor", out _)) return JsonSerializer.Deserialize<RequestVendor>(root.GetRawText(), options); if (root.TryGetProperty("description", out _)) return JsonSerializer.Deserialize<RequestDescription>(root.GetRawText(), options); return JsonSerializer.Deserialize<RequestItem>(root.GetRawText(), options); } public override void Write(Utf8JsonWriter writer, RequestItem value, JsonSerializerOptions options) { // 序列化时根据实际类型输出 JsonSerializer.Serialize(writer, value, value.GetType(), options); } } // 假设EventType枚举定义如下(需与业务实际值匹配) public enum EventType { AddressEvent = 1601, VendorEvent = 1602, DescriptionEvent = 1603 }
步骤3:配置转换器(可选)
如果未在基类上标记[JsonConverter],可在Program.cs/Startup.cs中全局配置:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new RequestItemConverter()); });
验证
发送示例JSON请求后,UpdateRequestItems.RequestItems中的元素会被正确解析为对应的子类(如带address的项会是RequestAddress实例),子数据Address也会完成绑定。
内容的提问来源于stack exchange,提问作者Amresh
相关产品推荐
相关产品推荐

