C# Json—从Json获取反序列化对象的对应行号,以便更好地处理错误

C# Json—从Json获取反序列化对象的对应行号,以便更好地处理错误,c#,json.net,C#,Json.net,我的应用程序接受来自我反序列化和处理的客户端的长JSON模板。我希望向客户提供更好的错误处理信息,这些信息包含JSON文本中无效对象的行号。请注意,这是针对后处理过程中发生的错误,而不是针对反序列化过程中发生的错误,因为这已经由Newtonsoft处理 例如,我有下面的JSON及其对应的.Net类型 { "Version": "1.0.0.0", "MyComplexObject": [ { "Prop1":

我的应用程序接受来自我反序列化和处理的客户端的长JSON模板。我希望向客户提供更好的错误处理信息,这些信息包含JSON文本中无效对象的行号。请注意,这是针对后处理过程中发生的错误,而不是针对反序列化过程中发生的错误,因为这已经由Newtonsoft处理

例如,我有下面的JSON及其对应的.Net类型

{
    "Version": "1.0.0.0",                        
    "MyComplexObject": [
    {
        "Prop1": "Val1",
        "Prop2": "Val2",
        "Prop3": 1
    }
    ]
}

public class MyComplexObject
{
    [JsonProperty]
    public string Prop1 { get; set; }

    [JsonProperty]
    public string Prop2 { get; set; }

    [JsonProperty]
    public int Prop3 { get; set; }

    **public int LineNumber;
    public int LinePosition;**
}

public class RootObject
{
    [JsonProperty]
    public string Version { get; set; }

    [JsonProperty]
    public List<MyComplexObject> MyComplexObject { get; set; }
}
{
“版本”:“1.0.0.0”,
“MyComplexObject”:[
{
“Prop1”:“Val1”,
“Prop2”:“Val2”,
“建议3”:1
}
]
}
公共类MyComplexObject
{
[JsonProperty]
公共字符串Prop1{get;set;}
[JsonProperty]
公共字符串Prop2{get;set;}
[JsonProperty]
公共int Prop3{get;set;}
**公共整数行号;
公共位置**
}
公共类根对象
{
[JsonProperty]
公共字符串版本{get;set;}
[JsonProperty]
公共列表MyComplexObject{get;set;}
}
我希望在反序列化时填充LineNumber和LinePosition属性,以便以后使用。我目前正在使用下面的代码反序列化JSON

JsonConvert.DeserializeObject<RootObject>(value: rawJson,settings: mysettings);
JsonConvert.DeserializeObject(值:rawJson,设置:mysettings);

感谢您的回复

我通过实现如下自定义转换器,解决了这个问题。任何实现JsonLineInfo的类在反序列化时都会自动获取自身的行号信息及其属性

public class LineInfo
{
    [JsonIgnore]
    public int LineNumber { get; set;}

    [JsonIgnore]
    public int LinePosition { get; set;}        
}

public abstract class JsonLineInfo : LineInfo
{
    [JsonIgnore]
    public Dictionary<string, LineInfo> PropertyLineInfos { get; set; }
}

class LineNumberConverter : JsonConverter
{
    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException("Converter is not writable. Method should not be invoked");
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(JsonLineInfo).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType != JsonToken.Null)
        {
            int lineNumber = 0;
            int linePosition = 0;
            var jsonLineInfo = reader as IJsonLineInfo;
            if (jsonLineInfo != null && jsonLineInfo.HasLineInfo())
            {
                lineNumber = jsonLineInfo.LineNumber;
                linePosition = jsonLineInfo.LinePosition;
            }

            var rawJObject = JObject.Load(reader);
            var lineInfoObject = Activator.CreateInstance(objectType) as JsonLineInfo;
            serializer.Populate(this.CloneReader(reader, rawJObject), lineInfoObject);

            return this.PopulateLineInfo(
                lineInfoObject: lineInfoObject,
                lineNumber: lineNumber,
                linePosition: linePosition,
                rawJObject: rawJObject);
        }

        return null;
    }

    private JsonReader CloneReader(JsonReader reader, JObject jobject)
    {
        var clonedReader = jobject.CreateReader();

        clonedReader.Culture = reader.Culture;
        clonedReader.DateParseHandling = reader.DateParseHandling;
        clonedReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
        clonedReader.FloatParseHandling = reader.FloatParseHandling;
        clonedReader.MaxDepth = reader.MaxDepth;

        return clonedReader;
    }

    private object PopulateLineInfo(JsonLineInfo lineInfoObject, int lineNumber, int linePosition, JObject rawJObject)
    {
        if (lineInfoObject != null)
        {
            lineInfoObject.PropertyLineInfos = new Dictionary<string, LineInfo>(StringComparer.InvariantCultureIgnoreCase);
            lineInfoObject.LineNumber = lineNumber;
            lineInfoObject.LinePosition = linePosition;

            foreach (var property in rawJObject.Properties().CoalesceEnumerable())
            {
                var propertyLineInfo = property as IJsonLineInfo;
                if (propertyLineInfo != null)
                {
                    lineInfoObject.PropertyLineInfos.Add(
                        property.Name,
                        new LineInfo
                        {
                            LineNumber = propertyLineInfo.LineNumber,
                            LinePosition = propertyLineInfo.LinePosition
                        });
                }
            }
        }

        return lineInfoObject;
    }
}
公共类LineInfo
{
[JsonIgnore]
公共整数行号{get;set;}
[JsonIgnore]
public int LinePosition{get;set;}
}
公共抽象类JsonLineInfo:LineInfo
{
[JsonIgnore]
公共字典PropertyLineInfo{get;set;}
}
类LineNumberConverter:JsonConverter
{
公共覆盖布尔可写
{
获取{return false;}
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException(“转换器不可写。不应调用方法”);
}
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(JsonLineInfo).IsAssignableFrom(objectType);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType!=JsonToken.Null)
{
int lineNumber=0;
int linePosition=0;
var jsonLineInfo=读卡器为IJsonLineInfo;
if(jsonLineInfo!=null&&jsonLineInfo.HasLineInfo())
{
lineNumber=jsonLineInfo.lineNumber;
linePosition=jsonLineInfo.linePosition;
}
var rawJObject=JObject.Load(读卡器);
var lineInfoObject=Activator.CreateInstance(objectType)作为JsonLineInfo;
填充(this.CloneReader(reader,rawJObject),lineInfoObject);
返回此.PopulateLineInfo(
lineInfoObject:lineInfoObject,
行号:行号,
linePosition:linePosition,
rawJObject:rawJObject);
}
返回null;
}
私有JsonReader CloneReader(JsonReader,JObject-JObject)
{
var clonedReader=jobject.CreateReader();
clonedReader.Culture=reader.Culture;
clonedReader.DateParseHandling=reader.DateParseHandling;
clonedReader.DateTimeZoneHandling=reader.DateTimeZoneHandling;
clonedReader.FloatParseHandling=reader.FloatParseHandling;
clonedReader.MaxDepth=reader.MaxDepth;
返回克隆阅读器;
}
私有对象PopulateLineInfo(JsonLineInfo lineInfoObject、int lineNumber、int linePosition、JObject rawJObject)
{
if(lineInfoObject!=null)
{
lineInfoObject.propertylineinfo=新字典(StringComparer.InvariantCultureInogoreCase);
lineInfoObject.LineNumber=LineNumber;
lineInfoObject.LinePosition=LinePosition;
foreach(rawJObject.Properties().CoalesceEnumerable()中的var属性)
{
var propertyLineInfo=属性为IJsonLineInfo;
if(propertyLineInfo!=null)
{
lineInfoObject.PropertyLineInfo.Add(
property.Name,
新线路信息
{
LineNumber=propertyLineInfo.LineNumber,
LinePosition=propertyLineInfo.LinePosition
});
}
}
}
返回lineInfoObject;
}
}

您说这不是针对反序列化过程中发生的错误,而是说希望在反序列化过程中填充
LineNumber
LinePosition
。您试图准确捕获哪些错误?例如,如果上面示例中的Prop1是一个数据库名称,但数据库不存在(这是一个运行时检查),我希望能够抛出一个异常,并显示消息“Prop1位于第2行,位置10不存在”。这将对使用大型json模板的客户有很大帮助。我正在尝试使用json.Net获取反序列化对象的行号。我尝试了您的方法,但遇到了有关“CoalesceEnumerable()”方法的语法错误。使用blog必须写入哪个名称空间?另外,我可以请您给出一个“ReadJson”方法调用的示例吗?谢谢。@SerkanYılmaz您可以尝试这个简单的扩展:
使用System.Collections.Generic;公共静态类IEnumerableExtensions{公共静态IEnumerable CoalesceEnumerable(此IEnumerable源){返回so