Search code examples
json.netserializationjson.net

Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: {. Path


I'm trying to parse a string to JSON, and it works if I parse it to JObject, but if I try to parse to my own custom type, I'm getting an error when it tries to parse the Properties property

error: Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: {. Path 'Properties', line 1, position 212.'

var str2 = "{\"Timestamp\":\"2024-02-15T12:55:03.9797576+02:00\",\"Level\":\"Information\",\"MessageTemplate\":\"User profile is available. Using '{FullName}' as key repository and Windows DPAPI to encrypt keys at rest.\",\"Properties\":{\"FullName\":\"C:\\\\Users\\\\Buga\\\\AppData\\\\Local\\\\ASP.NET\\\\DataProtection-Keys\",\"EventId\":{\"Id\":63,\"Name\":\"UsingProfileAsKeyRepositoryWithDPAPI\"},\"SourceContext\":\"Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager\"}}";

var obj = JsonConvert.DeserializeObject<JObject>(str2); // this works
var obj2 = JsonConvert.DeserializeObject<LogItem>(str2);  // error here

 public class LogItem
 {
     public DateTimeOffset Timestamp { get; set; }

     public string Level { get; set; }

     public string MessageTemplate { get; set; }

     public string Properties { get; set; }

     public string SourceContext { get; set; }
 }

Solution

  • You have string Properties, so it is expecting something like:

    "Properties": "foo"
    

    but the JSON has an object:

    "Properties":{"FullName": ... }
    

    So, one of:

    • change the Properties type to be a suitable object
    • use JSON that has a string properties

    The model must match the data.

    Something like:

    public class LogItem
    {
        public DateTimeOffset Timestamp { get; set; }
    
        public string Level { get; set; }
    
        public string MessageTemplate { get; set; }
    
        public LogItemProperties Properties { get; set; }
        public string SourceContext { get; set; }
    }
    
    public class LogItemProperties
    {
        public LogEventId EventId { get; set; }
        public string FullName { get; set; }
    }
    public class LogEventId
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }
    

    As an aside: prefer "raw strings" for handling JSON literals (and XML literals, etc):

    var str2 = """{"Timestamp":"2024-02-15T12:55:03.9797576+02:00","Level":"Information","MessageTemplate":"User profile is available. Using '{FullName}' as key repository and Windows DPAPI to encrypt keys at rest.","Properties":{"FullName":"C:\\Users\\Buga\\AppData\\Local\\ASP.NET\\DataProtection-Keys","EventId":{"Id":63,"Name":"UsingProfileAsKeyRepositoryWithDPAPI"},"SourceContext":"Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager"}}""";
    

    or formatted, if you prefer (although this changes the string value:

    var str2 = """
    {
        "Timestamp":"2024-02-15T12:55:03.9797576+02:00",
        "Level":"Information",
        "MessageTemplate":"User profile is available. Using '{FullName}' as key repository and Windows DPAPI to encrypt keys at rest.",
        "Properties":{
            "FullName":"C:\\Users\\Buga\\AppData\\Local\\ASP.NET\\DataProtection-Keys",
            "EventId":{
                "Id":63,
                "Name":"UsingProfileAsKeyRepositoryWithDPAPI"
            },
            "SourceContext":"Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager"
        }
    }
    """;