如何在ASP.NET 5中启用转义JSON字符串解析?
ASP.NET 5全局解析转义JSON字符串方案
你的问题核心是请求体是包裹在字符串中的JSON对象,而默认JSON解析器直接期望目标类型的JSON结构,因此抛出转换异常。以下是两种全局生效的解决方案,分别适配System.Text.Json和Newtonsoft.Json:
一、使用System.Text.Json实现全局兼容
1. 编写通用转换器工厂
创建一个能处理所有复杂类型的转换器工厂,自动解析外层字符串包裹的JSON:
public class WrappedStringJsonConverterFactory : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { // 仅处理非基础类型(排除string、DateTime等) return !typeToConvert.IsPrimitive && typeToConvert != typeof(string) && typeToConvert != typeof(DateTime) && typeToConvert != typeof(DateTimeOffset); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { return (JsonConverter)Activator.CreateInstance( typeof(WrappedStringJsonConverter<>).MakeGenericType(typeToConvert), BindingFlags.Instance | BindingFlags.Public, binder: null, args: new object[] { options }, culture: null)!; } private class WrappedStringJsonConverter<T> : JsonConverter<T> { private readonly JsonSerializerOptions _options; public WrappedStringJsonConverter(JsonSerializerOptions options) { // 克隆配置避免递归调用 _options = new JsonSerializerOptions(options); _options.Converters.RemoveAll(c => c.GetType() == typeof(WrappedStringJsonConverter<T>)); } public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { var jsonStr = reader.GetString(); return string.IsNullOrEmpty(jsonStr) ? default : JsonSerializer.Deserialize<T>(jsonStr, _options); } // 兼容直接发送对象JSON的场景 return JsonSerializer.Deserialize<T>(ref reader, _options); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } } }
2. 全局注册转换器
在Program.cs中配置控制器时添加该转换器:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new WrappedStringJsonConverterFactory()); }); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
二、使用Newtonsoft.Json实现全局兼容
1. 编写通用转换器工厂
public class WrappedStringJsonConverter<T> : JsonConverter<T> { public override T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { var jsonStr = reader.Value.ToString(); return string.IsNullOrEmpty(jsonStr) ? default : JsonConvert.DeserializeObject<T>(jsonStr); } return serializer.Deserialize<T>(reader); } public override void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer) { serializer.Serialize(writer, value); } public override bool CanWrite => true; } public class WrappedStringJsonConverterFactory : JsonConverterFactory { public override bool CanConvert(Type objectType) { return !objectType.IsPrimitive && objectType != typeof(string) && objectType != typeof(DateTime) && objectType != typeof(DateTimeOffset); } public override JsonConverter CreateConverter(Type objectType, JsonSerializer settings) { return (JsonConverter)Activator.CreateInstance( typeof(WrappedStringJsonConverter<>).MakeGenericType(objectType), BindingFlags.Instance | BindingFlags.Public, binder: null, args: null, culture: null)!; } }
2. 全局注册转换器
在Program.cs中切换为Newtonsoft并添加转换器:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new WrappedStringJsonConverterFactory()); }); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
说明
两种方案都能同时兼容两种请求格式:
- 直接发送
TestClass的JSON对象(无外层字符串包裹) - 发送包裹在字符串中的JSON对象(即你当前curl请求的格式)
内容的提问来源于stack exchange,提问作者Lakshin Karunaratne
相关产品推荐
相关产品推荐

