我正在使用继承的代码,与第三方设备进行通信。我的开发套件是VS 2015,使用C#和NewtonSoft.Json库。
我的“顶级”例程看起来有点像这样(为清楚起见省略了一些细节):
public JsonResponse<T> SendTypedApiRequest<T>(JsonCommand command,
string apiPath, string description, int expectedResponseCode = 0)
{
try
{
var r = SendPost(apiPath, command);
if (r.Code == OK && r.Response != null) {
var jsonResponse = JsonResponse<T>.Deserialize(r.Response);
if (jsonResponse.RetCode != expectedResponseCode) {
// handle errors
}
}
}
catch(){};
}
在另一个文件中,我有以下内容:
public static JsonResponse<T> Deserialize(string json,
JsonSerializerSettings settings = null)
{
return JsonConvert.DeserializeObject<JsonResponse<T>>(json, settings);
}
我希望从这个帖子的设备返回的是一个数值,所以在这种情况下T是'int'(或者更确切地说是int的JsonResponse):
{"retCode":0,"retMsg":"OK","data":41272}
然而,当不符合正确的前提条件时,我得到了这个:
{"retCode":1000,"retMsg":"No admin","data":{}}
看起来够公平吧?但是,由于这是一个类型化的响应反序列化器,它会在{}上发出阻塞,期望一个整数而不是开始的大括号。我得到的是一个JsonReaderException“解析值时遇到的意外字符:{。”我想得到的是来自Json响应的retCode和retMsg,所以我可以将实际的错误条件传递给用户。 JsonReaderException根本没用。
我尝试将JsonSerializerSettings用于Null和Empty值,但在这种情况下它们不起作用。我似乎找不到处理这种情况的标准方法。我可以在最后调用JsonConvert.DeserializeObject()时调用try / catch来从响应中提取实际错误并将其追回堆栈,但这看起来非常粗糙和笨拙 - 没有逻辑可以处理直到我在代码中达到3或4级(一切都期待一个类型化的响应)。
有一种优雅的方式可以解决这个问题吗?有没有规范的方法来解决这个问题?似乎我提出的每一种方法都是笨拙和丑陋,或根本不起作用。
TIA,戴夫
答案 0 :(得分:2)
一种可能的方法是为JsonConverter
创建自定义JsonResponse<T>
来处理类型差异。我们的想法是将JSON数据加载到中间JObject
,然后在单独的步骤中处理“行为良好”的属性(例如RetCode, RetMsg
)和可能不正确的Data
属性。这样,如果Data
属性的转换失败,您仍然可以恢复其余的响应。
以下是转换器的外观:
public class JsonResponseConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsGenericType &&
objectType.GetGenericTypeDefinition() == typeof(JsonResponse<>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load JSON data into a JObject
JObject obj = JObject.Load(reader);
// Remove the problematic data property from the JObject
JProperty dataProp = obj.Property("data");
if (dataProp != null) dataProp.Remove();
// Create a JsonResponse object and populate it with the
// well-behaved properties in the JObject (e.g. RetCode, RetMsg)
object jsonResponse = Activator.CreateInstance(objectType);
serializer.Populate(obj.CreateReader(), jsonResponse);
try
{
// Now try to add the data property into the same response
if (dataProp != null)
{
JObject data = new JObject(dataProp);
serializer.Populate(data.CreateReader(), jsonResponse);
}
}
catch (JsonException) { } // if it doesn't work, eat the exception
return jsonResponse;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要使用转换器,您可以将其添加到JsonSerializerSettings
方法中的SendTypedApiRequest<T>
,并将设置传递给JsonResponse<T>.Deserialize
方法。
var r = SendPost(apiPath, command);
if (r.Code == OK && r.Response != null)
{
var settings = new JsonSerializerSettings();
settings.Converters.Add(new JsonResponseConverter());
var jsonResponse = JsonResponse<T>.Deserialize(r.Response, settings);
...
}
答案 1 :(得分:0)
您可以作弊并将数据int
类型更改为dynamic
。有点黑客但它可能会解决你的问题。