我在 json.net 中编写了一个自定义 JSON 转换器类,但无法弄清楚为什么在反序列化时会出现以下异常。
填充对象时出现意外的初始标记“EndObject”。预期的 JSON 对象或数组。路径 '',第 1 行,位置 177。
我的项目中有其他转换器,它们的模型非常相似,它们可以正常工作,所以我不确定为什么会出现这样的问题。
这是被序列化的对象:
[JsonConverter(typeof(CreateCRMIntegrationPromptJsonConverter))]
public abstract class CreateCRMIntegrationDirectPromptBaseBindingModel
{
public bool IncludeInOutput { get; set; }
public string Label { get; set; }
public string Value { get; set; }
public IValidateCRMField Validator { get; set; }
public string ValidatorType { get; set; }
public CRMIntegrationDirectPromptType Type { get; set; }
}
public class CreateCRMIntegrationPromptMobilePhoneBindingModel : CreateCRMIntegrationDirectPromptBaseBindingModel
{
public bool FormatPhoneNumber { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
和转换器
public class CreateCRMIntegrationPromptJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Models.CreateCRMIntegrationDirectPromptBaseBindingModel);
}
public override bool CanWrite { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
{
JObject jo = JObject.Load(reader);
JsonReader jsonReader = jo.CreateReader();
Dictionary<string, string> values = new Dictionary<string, string>(jo.ToObject<IDictionary<string, string>>(), StringComparer.CurrentCultureIgnoreCase);
var typeValue = values["type"].ToString();
Models.CRMIntegrationDirectPromptType integrationPromptType = Models.CRMIntegrationDirectPromptType.Label;
if (!Enum.TryParse(typeValue, out integrationPromptType))
{
integrationPromptType = Models.CRMIntegrationDirectPromptType.Label;
}
switch (integrationPromptType)
{
.........
case Models.CRMIntegrationDirectPromptType.MobilePhone:
Models.CreateCRMIntegrationPromptMobilePhoneBindingModel cRMIntegrationPromptMobilePhoneReturnModel = new Models.CreateCRMIntegrationPromptMobilePhoneBindingModel();
serializer.Populate(reader, cRMIntegrationPromptMobilePhoneReturnModel);
return cRMIntegrationPromptMobilePhoneReturnModel;
.........
}
}
catch(Exception ex)
{
Models.CreateCRMIntegrationPromptLabelBindingModel cRMIntegrationPromptLabelReturnModelDefault = new Models.CreateCRMIntegrationPromptLabelBindingModel();
cRMIntegrationPromptLabelReturnModelDefault.IncludeInOutput = false;
cRMIntegrationPromptLabelReturnModelDefault.Label = string.Empty;
cRMIntegrationPromptLabelReturnModelDefault.Type = Models.CRMIntegrationDirectPromptType.Label;
return cRMIntegrationPromptLabelReturnModelDefault;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我使用此代码进行测试时,我可以捕获异常
var obj = new CreateCRMIntegrationPromptMobilePhoneBindingModel();
obj.IncludeInOutput = true;
obj.FormatPhoneNumber = true;
obj.Label = "Test";
obj.ValidatorType = "Answer1APILib.CRMIntegration.ValidateCRMField_NonRequired";
obj.Type = CRMIntegrationDirectPromptType.Label;
obj.Value = "";
var test = JsonConvert.SerializeObject(obj);
var output = JsonConvert.DeserializeObject<CreateCRMIntegrationDirectPromptBaseBindingModel>(test);
Run Code Online (Sandbox Code Playgroud)
这是序列化返回的JSON
{
"FormatPhoneNumber":true,
"IncludeInOutput":true,
"Label":"Test",
"Value":"",
"Validator":null,
"ValidatorType":"Answer1APILib.CRMIntegration.ValidateCRMField_NonRequired",
"Type":0
}
Run Code Online (Sandbox Code Playgroud)
您需要传递jsonReadertoserializer.Populate()而不是传入的reader。或者jsonReader完全消除变量并传入jo.CreateReader():
serializer.Populate(jo.CreateReader(), cRMIntegrationPromptMobilePhoneReturnModel);
Run Code Online (Sandbox Code Playgroud)
您需要这样做是因为您之前在传入的初始位置加载了对象JsonReader reader到JObject jo:
JObject jo = JObject.Load(reader);
Run Code Online (Sandbox Code Playgroud)
因此,传入reader已经通过对象前进到接下来发生的任何事情。使用reader第二次填充您的模型将进一步推进读者,最终导致Unexpected initial token 'EndObject'您看到。
您可能还想检查传入的 JSON 令牌是否null在将其作为对象加载之前:
if (reader.TokenType == JsonToken.Null)
return null;
JObject jo = JObject.Load(reader);
Run Code Online (Sandbox Code Playgroud)
由于null在JSON文件值实际上加载为非空JValue与JValue.Type等于JTokenType.Null,试图加载这样的令牌作为一个JObject将失败。
(最后,我不确定我是否会ReadJson()自己处理异常。Newtonsoft 已经有一个处理异常的机制,如果你在内部捕获并吞下所有异常ReadJson()而不是使用该机制,那么在阅读格式错误、截断的 JSON 文件。不过,这不是您所看到的问题的主要原因。)
因此,一个固定版本的ReadJson()看起来像:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jo = JObject.Load(reader);
var typeValue = (string)jo.GetValue("Type", StringComparison.OrdinalIgnoreCase);
Models.CRMIntegrationDirectPromptType integrationPromptType;
if (!Enum.TryParse(typeValue, out integrationPromptType))
{
integrationPromptType = Models.CRMIntegrationDirectPromptType.Label;
}
Models.CreateCRMIntegrationDirectPromptBaseBindingModel model;
switch (integrationPromptType)
{
case Models.CRMIntegrationDirectPromptType.MobilePhone:
model = new Models.CreateCRMIntegrationPromptMobilePhoneBindingModel();
break;
case Models.CRMIntegrationDirectPromptType.Label:
model = new Models.CreateCRMIntegrationPromptLabelBindingModel();
break;
// Add other cases as required.
default:
throw new JsonSerializationException(typeValue);
}
serializer.Populate(jo.CreateReader(), model);
return model;
}
Run Code Online (Sandbox Code Playgroud)
工作示例 .Net fiddle在这里。
| 归档时间: |
|
| 查看次数: |
1361 次 |
| 最近记录: |