不使用NewtonSoft时,如何解决动态对象的ValueKind = Object问题?
解决Dynamic类型Model的ValueKind = Object转换问题
请求负载会存入声明为Dynamic类型的parts.Model中,这是一个多端点共用的服务,需要保留结构同时解决ValueKind = Object的处理问题。
示例Model结构
"Model": { "CustomerSurname": "Johnson", "Title": "Mr", "PlanType": "Help Extension", "ServiceAdvisor": "Jeff Matle", "DealershipName": "Goldwagen Pretoria" }
尝试过的无效代码
之前多次用JsonSerializer.Deserialize都没效果,代码如下:
public async Task<IActionResult> SendSms([FromBody] CreatePart parts) { parts.DateMessageScheduled = DateTime.Now; parts.DateCutOff = DateTime.MaxValue; parts.CommunicationTypeId = CommunicationType.Codes.SMS; dynamic obj = parts.Model; JsonElement jsonString = obj; var dynamicObject = JsonSerializer.Deserialize<JsonElement>(jsonString); var result = await _createNewPartService.Post(parts); return new JsonResult(result); }
执行后dynamicObject的结果:
ValueKind = Object : "{ "CustomerSurname": "Johnson", "Title": "Mr", "PlanType": "Help Extension", "ServiceAdvisor": "Jeff Matle", "DealershipName": "Goldwagen Pretoria" }"
解决方案
问题核心:ASP.NET Core会把动态JSON自动反序列化为JsonElement类型,所以parts.Model本质就是JsonElement,不需要重复反序列化,直接处理这个对象即可。
方法1:转成动态ExpandoObject(保留完整结构)
写一个扩展方法把JsonElement转成可直接访问属性的动态对象:
using System.Dynamic; using System.Text.Json; public static class JsonElementExtensions { public static ExpandoObject ToExpandoObject(this JsonElement element) { var expando = new ExpandoObject(); var dictionary = (IDictionary<string, object>)expando; foreach (var property in element.EnumerateObject()) { switch (property.Value.ValueKind) { case JsonValueKind.Object: dictionary[property.Name] = property.Value.ToExpandoObject(); break; case JsonValueKind.Array: var arrayList = new List<object>(); foreach (var item in property.Value.EnumerateArray()) { arrayList.Add(item.ValueKind == JsonValueKind.Object ? item.ToExpandoObject() : item.GetValue()); } dictionary[property.Name] = arrayList; break; default: dictionary[property.Name] = property.Value.GetValue(); break; } } return expando; } private static object GetValue(this JsonElement element) { return element.ValueKind switch { JsonValueKind.String => element.GetString(), JsonValueKind.Number => element.TryGetInt64(out long l) ? l : element.GetDouble(), JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.Null => null, _ => element.ToString() }; } }
然后在接口方法里使用:
public async Task<IActionResult> SendSms([FromBody] CreatePart parts) { parts.DateMessageScheduled = DateTime.Now; parts.DateCutOff = DateTime.MaxValue; parts.CommunicationTypeId = CommunicationType.Codes.SMS; // 直接转换为动态对象 dynamic dynamicModel = ((JsonElement)parts.Model).ToExpandoObject(); // 可以直接访问属性,比如获取姓氏 var customerSurname = dynamicModel.CustomerSurname; var result = await _createNewPartService.Post(parts); return new JsonResult(result); }
方法2:直接读取JsonElement属性(仅需读取特定值时用)
如果不需要完整的动态对象,只是读取个别属性,直接操作JsonElement更简单:
public async Task<IActionResult> SendSms([FromBody] CreatePart parts) { parts.DateMessageScheduled = DateTime.Now; parts.DateCutOff = DateTime.MaxValue; parts.CommunicationTypeId = CommunicationType.Codes.SMS; JsonElement modelElement = (JsonElement)parts.Model; // 读取指定属性值 string customerSurname = modelElement.GetProperty("CustomerSurname").GetString(); string title = modelElement.GetProperty("Title").GetString(); var result = await _createNewPartService.Post(parts); return new JsonResult(result); }
内容的提问来源于stack exchange,提问作者Zhilong Liang
相关产品推荐
相关产品推荐

