Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing OData.Error messages

I have an ASP.NET application that uses the Azure AD Graph API. Often, when an invalid operation is performed against the Graph API, an exception is thrown.

The following code shows an invalid Graph API call that would trigger an exception:

// Query the Azure AD User
var userToUpdate = await activeDirectoryClient.Users.GetByObjectId("[email protected]").ExecuteAsync();

// Set given name to an empty string (not allowed)
userToUpdate.GivenName = "";

try
{
    // Update the user in Azure AD
    await userToUpdate.UpdateAsync();
}
catch (Exception e)
{
    // Return exception message
}

The message of the inner exception is a JSON string with forward slashes before each quotation mark. It looks something like this:

"{\"odata.error\":{\"code\":\"Request_BadRequest\",\"message\":{\"lang\":\"en\",\"value\":\"Invalid value specified for property 'givenName' of resource 'User'.\"},\"values\":[{\"item\":\"PropertyName\",\"value\":\"givenName\"},{\"item\":\"PropertyErrorCode\",\"value\":\"InvalidValue\"}]}}"

Attaching a screenshot of the Locals window where the exception message is found: Exception details

I would like to convert this JSON to a .NET object to return informative error details. I am using the JSON.NET library for this, and I am assuming that the JSON will deserialize to an ODataError object:

var error = Newtonsoft.Json.JsonConvert.DeserializeObject<ODataError>(e.InnerException.Message);

However, the deserialized object always has a value of null, which means that the conversion is not working as expected.

That being said, what class should the above JSON string map to? Also, should I be removing the forward slashes from the string for proper deserialization?

like image 779
miguelarcilla Avatar asked Oct 05 '15 08:10

miguelarcilla


1 Answers

The reason you've got null after deserialization is your JSON object properties names differs from Microsoft.Azure.ActiveDirectory.GraphClient.ODataError class properties names - "odata.error" property can not be deserialized to Error property of Microsoft.Azure.ActiveDirectory.GraphClient.ODataError

As workaround I've added my own types for correct deserialization:

internal class ODataError
    {
        [JsonProperty("odata.error")]
        public ODataErrorCodeMessage Error { get; set; }
    }

    internal class ODataErrorCodeMessage
    {
        public string Code { get; set; }

        public ODataErrorMessage Message { get; set; }

        public List<ExtendedErrorValue> Values { get; set; }
    }

    internal class ExtendedErrorValue
    {
        public string Item { get; set; }

        public string Value { get; set; }
    }

    internal class ODataErrorMessage
    {
        public string Lang { get; set; }

        public string Value { get; set; }
    }

After that JSON message was properly deserialized:

...
    try
    {
        await ADClient.Users.AddUserAsync(newUser);
        return Result.Ok();
    }
    catch (DataServiceRequestException ex)
    {
        var innerException = ex.InnerException;
        var error = JsonConvert.DeserializeObject<ODataError>(innerException.Message);
        return Result.Fail(new Error(error.Error.Message.Value, error.Error.Code, ex));
    }
like image 115
Sergey Morozenko Avatar answered Nov 18 '22 06:11

Sergey Morozenko