运行时给定JSON Schema,如何反序列化为可加入ValueSet的C#可序列化对象?
解决方案:运行时JSON Schema验证与适配ValueSet的C#实现
针对你遇到的两个核心问题——Json.NET无法适配运行时JSON Schema反序列化和返回对象无法加入ValueSet,下面给出完整的实现方案:
一、依赖准备
首先需要安装Newtonsoft.Json和Newtonsoft.Json.Schema两个NuGet包,用于JSON Schema验证和动态JSON处理:
Install-Package Newtonsoft.Json Install-Package Newtonsoft.Json.Schema
二、核心实现思路
1. 解决运行时Schema验证问题
我们不需要依赖编译时定义的类,而是用JSchema加载运行时传入的Schema,将输入JSON解析为JObject后直接执行验证逻辑,完全适配动态Schema场景。
2. 解决ValueSet兼容性问题
Json.NET返回的JObject虽然能序列化,但可能无法直接加入某些ValueSet(比如要求原生.NET类型的集合)。我们可以将验证后的JObject递归转换为ExpandoObject或Dictionary<string, object>——这两种类型都是.NET原生支持序列化的,且能轻松加入大多数集合(包括自定义ValueSet)。
三、完整函数代码
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; using System; using System.Collections.Generic; using System.Dynamic; public class JsonSchemaProcessor { /// <summary> /// 验证输入字符串是否符合运行时JSON Schema,并返回可加入ValueSet的可序列化对象 /// </summary> /// <param name="jsonInput">待验证的JSON字符串</param> /// <param name="schemaJson">运行时提供的JSON Schema字符串</param> /// <returns>符合Schema的可序列化对象(ExpandoObject类型)</returns> /// <exception cref="ArgumentException">当JSON不符合Schema或输入无效时抛出</exception> public static object ValidateAndGetValueSetCompatibleObject(string jsonInput, string schemaJson) { // 1. 加载并验证运行时Schema的合法性 JSchema schema; try { schema = JSchema.Parse(schemaJson); } catch (JsonException ex) { throw new ArgumentException("传入的JSON Schema格式无效", nameof(schemaJson), ex); } // 2. 解析输入JSON并执行Schema验证 JObject jsonObject; IList<string> validationErrors = new List<string>(); try { jsonObject = JObject.Parse(jsonInput); } catch (JsonException ex) { throw new ArgumentException("输入的JSON字符串格式无效", nameof(jsonInput), ex); } bool isValid = jsonObject.IsValid(schema, out validationErrors); if (!isValid) { var errorDetails = string.Join(Environment.NewLine, validationErrors); throw new ArgumentException($"JSON不符合指定Schema:{Environment.NewLine}{errorDetails}"); } // 3. 将JObject转换为ExpandoObject(兼容序列化和ValueSet) var expandoResult = new ExpandoObject(); var expandoDict = (IDictionary<string, object>)expandoResult; foreach (var property in jsonObject.Properties()) { expandoDict[property.Name] = ConvertJTokenToNativeObject(property.Value); } return expandoResult; } /// <summary> /// 递归将JToken转换为.NET原生可序列化对象,处理嵌套结构 /// </summary> private static object ConvertJTokenToNativeObject(JToken token) { switch (token.Type) { case JTokenType.Object: var nestedExpando = new ExpandoObject(); var nestedDict = (IDictionary<string, object>)nestedExpando; foreach (var prop in token.Children<JProperty>()) { nestedDict[prop.Name] = ConvertJTokenToNativeObject(prop.Value); } return nestedExpando; case JTokenType.Array: var itemList = new List<object>(); foreach (var item in token.Children()) { itemList.Add(ConvertJTokenToNativeObject(item)); } return itemList; case JTokenType.Integer: case JTokenType.Float: case JTokenType.String: case JTokenType.Boolean: case JTokenType.Null: return token.ToObject<object>(); default: return token.ToString(); } } }
四、使用示例
// 运行时传入的Schema示例 string dynamicSchema = @" { ""type"": ""object"", ""properties"": { ""Username"": { ""type"": ""string"" }, ""Age"": { ""type"": ""integer"", ""minimum"": 16 }, ""IsVerified"": { ""type"": ""boolean"" } }, ""required"": [""Username"", ""Age""] }"; // 待验证的JSON字符串 string validJson = @"{""Username"":""Bob"",""Age"":22,""IsVerified"":true}"; try { var result = JsonSchemaProcessor.ValidateAndGetValueSetCompatibleObject(validJson, dynamicSchema); // 将结果加入ValueSet(这里用HashSet<object>模拟自定义ValueSet) var valueSet = new HashSet<object>(); valueSet.Add(result); // 测试序列化功能 string serializedJson = JsonConvert.SerializeObject(result); Console.WriteLine("序列化结果:" + serializedJson); } catch (ArgumentException ex) { Console.WriteLine("处理失败:" + ex.Message); }
关键说明
- 动态Schema适配:通过
JSchema.Parse加载运行时Schema,JObject.IsValid执行验证,完全摆脱编译时类的限制。 - ValueSet兼容性:
ExpandoObject实现了IDictionary<string, object>,既支持Json.NET序列化,也能直接加入绝大多数集合(包括自定义ValueSet)。如果你的ValueSet要求特定类型,也可以将转换逻辑改为返回Dictionary<string, object>,兼容性一致。 - 嵌套结构处理:递归转换逻辑确保JSON中的嵌套对象、数组都能转换为.NET原生类型,避免序列化或集合加入时出现异常。
内容的提问来源于stack exchange,提问作者user9514066
相关产品推荐
相关产品推荐

