labroo
labroo

Reputation: 2961

json.Net + handle deserialization error based on attribute on a property

I have the following class structure

public class Parent
{
    public int SomeProperty { get; set; }

    [IgnoreDeserializationErrors] // This attribute can be here
    public FirstLevel FirstLevelProperty { get; set; }
}

public class FirstLevel
{
    public int AnotherProperty { get; set; }

    [IgnoreDeserializationErrors] // Or this can be here
    public SecondLevel SecondLevelProperty { get; set; }
}

public class SecondLevel
{
    public int OneMoreProperty { get; set; }

    [IgnoreDeserializationErrors] //Or Here
    public string YetAnotherProperty { get; set; }
}

And this Attribute:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IgnoreDeserializationErrorsAttribute : Attribute
{

}

How can I tell Json.NET to ignore errors for all the properties which have the IgnoreDeserializationErrorsAttribute attribute.

I tried

var deserialized = JsonConvert.Deserialize<Parent>(someJson, new JsonSerializerSettings
        {
            Error = (s, e) => { 
                bool attributeDefined = true;//TODO: How do I get the properties attributes here.

                if (attributeDefined)
                {
                    e.ErrorContext.Handled = true 
                }
            }
        });

but I am unable to populate the attributeDefined variable inside the delegate.

Is this possible inside the error handler? or do I have to create a custom converter.

Upvotes: 0

Views: 1245

Answers (2)

Sergey
Sergey

Reputation: 1193

There is a built-in OnError attribute that can be used for this purpose. See below the sample from the official documentation:

public class PersonError
{
    private List<string> _roles;

    public string Name { get; set; }
    public int Age { get; set; }

    public List<string> Roles
    {
        get
        {
            if (_roles == null)
            {
                throw new Exception("Roles not loaded!");
            }

            return _roles;
        }
        set { _roles = value; }
    }

    public string Title { get; set; }

    [OnError]
    internal void OnError(StreamingContext context, ErrorContext errorContext)
    {
        errorContext.Handled = true;
    }
}

Check Serialization Error Handling article for more info.

Upvotes: 1

Ilija Dimov
Ilija Dimov

Reputation: 5299

Let's you have the following classes for the sake of simplicity:

public class Parent
{
    public int SomeProperty { get; set; }

    public FirstLevel FirstLevelProperty { get; set; }
}

public class FirstLevel
{
    public int AnotherProperty { get; set; }

    public SecondLevel SecondLevelProperty { get; set; }
}

public class SecondLevel
{
    public int OneMoreProperty { get; set; }

    [IgnoreDeserializationErrors]
    public int YetAnotherProperty { get; set; }
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IgnoreDeserializationErrorsAttribute : Attribute
{

}

As you can notice I changed the type of YetAnotherProperty to int and only this property is decorated with IgnoreDeserializationErrorsAttribute

var someJson = "{\"SomeProperty\": 3, \"FirstLevelProperty\": {\"AnotherProperty\": 35, \"SecondLevelProperty\": {\"OneMoreProperty\": 359, \"YetAnotherProperty\": \"test\"}}}";

var deserialized = JsonConvert.DeserializeObject<Parent>(someJson, new JsonSerializerSettings
{
    Error = (s, e) =>
    {
        bool attributeDefined = false;

        if (e.CurrentObject == null) return;

        PropertyInfo property = e.CurrentObject.GetType().GetProperty(e.ErrorContext.Member.ToString());

        if (property == null) return;

        var attr = property.GetCustomAttribute(typeof (IgnoreDeserializationErrorsAttribute));

        if (attr != null) attributeDefined = true;

        if (attributeDefined) e.ErrorContext.Handled = true;
    }
});

The code in the error handler reads the property that caused the error, checks if the property is decorated with IgnoreDeserializationErrorsAttribute and sets the Handled property of the ErrorContext accordingly.

Example: https://dotnetfiddle.net/zIj5RN

Upvotes: 0

Related Questions