C# .NET中解析AWS SNS消息对象失败,请求技术排查
问题:C# .NET中AWS SNS消息JSON解析失败
在使用Newtonsoft.Json解析AWS SNS消息的JSON字符串时,无法反序列化为自定义实体类,出现解析错误。
获取到的JSON字符串(messageBody)
{ "Type" : "Nti_1", "MessageId" : "c1b7cd5b-3099-532e-9539-91376eea607b", "SequenceNumber" : "10000000000000128000", "TopicArn" : "arn:aws:sns:us-east-1:xxxxxxx:Project1-SNS.fifo", "Message" : "{'Prop1':'202020','Prop2':'Hi-I again reached','Prop3':'Testing String'}", "Timestamp" : "2023-02-05T07:35:15.905Z", "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:xxxxxx:PushNotification-SNS.fifo:08d0fac2-ac0f-4ff9-b583-61024a98672d", "MessageAttributes" : { "EventType" : {"Type":"String.Array","Value":"["SMS","ArialRoot"]"} } }
自定义的C#实体类
public class ParentObject { public string Type { get; set; } public string MessageId { get; set; } public string SequenceNumber { get; set; } public string TopicArn { get; set; } public ChildObject Message { get; set; } public string Timestamp { get; set; } public string UnsubscribeURL { get; set; } public string MessageAttributes { get; set; } } public class ChildObject { public string Prop1 { get; set; } public string Prop2 { get; set; } public string Prop3 { get; set; } }
解析代码
ParentObject obj = JsonConvert.DeserializeObject<ParentObject>(messageBody);
解析失败的原因
Message字段格式与类型不匹配:
- 原始JSON中
Message的值用单引号包裹,不符合标准JSON的双引号要求,本身是非法JSON片段。 - 即使格式合法,
Message是字符串类型的JSON片段,直接映射到ChildObject类型会失败,JsonConvert默认不会自动将字符串解析为嵌套对象。
- 原始JSON中
MessageAttributes类型定义错误:
原始JSON中MessageAttributes是嵌套对象,但代码中定义为string类型,类型不匹配导致解析失败。MessageAttributes.EventType.Value格式错误:
Value字段的值"["SMS","ArialRoot"]"内部双引号未转义,属于非法JSON语法,会导致整个JSON解析失败。
解决方案
步骤1:修复原始JSON格式(若可控制消息发送端)
- 将
Message字段的单引号替换为双引号,修正为合法JSON字符串:"{\"Prop1\":\"202020\",\"Prop2\":\"Hi-I again reached\",\"Prop3\":\"Testing String\"}" - 修正
MessageAttributes.EventType.Value的格式,转义内部双引号:"[\"SMS\",\"ArialRoot\"]"
步骤2:调整C#实体类定义
修正MessageAttributes的类型,并处理Message字段的嵌套解析:
方式1:二次解析Message字段
先将Message定义为字符串,解析完成后再二次反序列化为ChildObject:
public class ParentObject { public string Type { get; set; } public string MessageId { get; set; } public string SequenceNumber { get; set; } public string TopicArn { get; set; } // 先定义为字符串,后续二次解析 public string Message { get; set; } public string Timestamp { get; set; } public string UnsubscribeURL { get; set; } // 定义匹配的MessageAttributes实体类 public MessageAttributes MessageAttributes { get; set; } } public class MessageAttributes { public EventType EventType { get; set; } } public class EventType { public string Type { get; set; } // 若Value是数组字符串,可定义为string后续解析;格式正确也可直接定义为string[] public string Value { get; set; } } public class ChildObject { public string Prop1 { get; set; } public string Prop2 { get; set; } public string Prop3 { get; set; } }
解析代码:
// 先解析父对象 var parentObj = JsonConvert.DeserializeObject<ParentObject>(messageBody); // 处理Message字段的单引号问题(若无法修改发送端,手动替换) var cleanedMessage = parentObj.Message.Replace("'", "\""); // 二次解析为ChildObject var childObj = JsonConvert.DeserializeObject<ChildObject>(cleanedMessage); // 处理MessageAttributes的Value数组 var eventTypes = JsonConvert.DeserializeObject<string[]>(parentObj.MessageAttributes.EventType.Value.Replace("'", "\""));
方式2:使用JsonConverter自动解析Message字段
自定义转换器处理Message字段的字符串到ChildObject的解析:
public class StringToChildObjectConverter : JsonConverter<ChildObject> { public override ChildObject ReadJson(JsonReader reader, Type objectType, ChildObject existingValue, bool hasExistingValue, JsonSerializer serializer) { var messageStr = reader.Value.ToString(); // 替换单引号为双引号,修正格式 var cleanedStr = messageStr.Replace("'", "\""); return JsonConvert.DeserializeObject<ChildObject>(cleanedStr); } public override void WriteJson(JsonWriter writer, ChildObject value, JsonSerializer serializer) { throw new NotImplementedException(); } }
修改ParentObject的Message字段:
public class ParentObject { // 其他字段不变 [JsonConverter(typeof(StringToChildObjectConverter))] public ChildObject Message { get; set; } public MessageAttributes MessageAttributes { get; set; } }
此时直接调用原解析代码即可:
ParentObject obj = JsonConvert.DeserializeObject<ParentObject>(messageBody);
内容的提问来源于stack exchange,提问作者Hardik Parmar
相关产品推荐
相关产品推荐

