Jason Meckley
Jason Meckley

Reputation: 7591

Deserialize HttpError ModelState

Wit the latest webapi bits I now have

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

My client is an MVC website that reads the value from the response. I finally got it to read the HttpError object from the response, but loading the ModelState is... not intuitive to say the least.

Is there a cleaner way to write this?

var httpError = response.Read<HttpError>();
 var errors = httpError["ModelState"] as JObject;

 foreach (var error in errors)
 foreach (var message in error.Value.Values<string>())
 {
     modelState.AddModelError(error.Key, message);
 }

Upvotes: 4

Views: 3714

Answers (2)

Snixtor
Snixtor

Reputation: 4297

While an error response, as you've identified, can readily be deserialised into an HttpError, the ModelState value within it only ends up as a JObject.

You've probably already tried something like:

var errors = ((JObject)errorMsg["ModelState"])
             .ToObject<ModelStateDictionary>();

Or maybe:

var errors = ((JObject)errorMsg["ModelState"])
             .ToObject<Dictionary<string, ICollection<ModelError>>>();

And found that it won't convert. The best alternative I could find was:

var errors = ((JObject)errorMsg["ModelState"])
             .ToObject<Dictionary<string, IList<string>>>();

Which makes your iteration marginally neater:

foreach (var err in errors)
foreach (var msg in err.Value)
{
    modelStateDictionary.AddModelError(err.Key, msg);
}

The problem, as I see it, is a string won't deserialise to a ModelError instance, and is further compounded by ModelErrorCollection unfortunately hiding its base class constructor of Collection(IList list).

Upvotes: 3

Vinney Kelly
Vinney Kelly

Reputation: 5095

How are you making the API calls? Client-side? If so, I noticed Brad Wilson using the below format for receiving AJAX responses via jQuery in a recent demo. This may not be what you're looking for but it's been working well for me:

$.ajax({
    url: "/apicontorller/action/",
    contentType: "application/json",
    type: "POST",
    data: jsonData,
    statusCode: {
        200: function (data) {

        },
        404: function () {
            alert('404');
        },
        400: function () {
            alert('invalid');
        },
        500: function () {
            alert('error');
        },
        // ...
    }
});

The nice thing about this is you can handle the actual HTTP status codes. In my experience, error messages/data can be accessed by providing a parameter to the predicate function. I'm still learning about REST and the WebAPI platform so if anyone can provide a better implementation, I certainly welcome it!

Upvotes: 0

Related Questions