1

I have the following structure:

public class SampleEntity{
    public string Name { get; set; }
    public OtherEntity Relation { get; set; }
}

public class OtherEntity {
    public string Name { get; set; }
}

When i make a call to update an object in my web.api with the following request body:

"{'Name':'Nome', 'Relation':''}"

The deserializer fills the object with null value, but i think the correct action is throw an exception like 'invalid value for field Relation' and i can return a status code 400.

I tried to make a custom converter to do this, but i'm not happy with the solution and i am quite concerned with the performance of this.

 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            var @object = JObject.Load(reader);
            var target = Activator.CreateInstance(objectType);

            var objectProperties = target.GetType().GetProperties().Where(x => x.PropertyType.IsPrimitive == false && x.PropertyType != typeof(string));

            foreach (var prop in objectProperties)
            {
                var value = @object[prop.Name];
                if (value != null && value.ToString() == string.Empty)
                    throw new Exception();
            }

            serializer.Populate(@object.CreateReader(), target);
            return target;
        }

        return reader.Value;
    }
2
  • Why should it throw an exception? I can't tell from looking at public OtherEntity Relation { get; set; } that it would be unexpected for Relation to be null. Why don't you just deserialize it, then check to see if it's null and thrown an exception if it is? Commented Jul 11, 2014 at 20:23
  • Thanks for help @mason, in my controller i do a verification if my object is null for update it or not, but in this case the request is not passing a null object, it's trying to update the object with a empty value, i cannot assuming that it is null and bypass my verification and return a 204 status code. I need to inform that empty value is an invalid value for this object. Commented Jul 11, 2014 at 21:18

1 Answer 1

2

The Web API does not automatically return an error to the client when validation fails. It is up to the controller action to check the model state and respond appropriately. While @loop's answer will work, you may want to consider another option whereby you won't even have to enter your controller's action method.

To do this, you can create an action filter to check the model state before the controller action is even invoked.

For example:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid == false)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

Note that you will STILL need to decorate your model with attributes that describe the validation rules. This would be similar to what @loop has suggested.

If model validation fails, this filter returns an HTTP response that contains the validation errors. In that case, the controller action is not invoked.

To apply this filter to all Web API controllers, add an instance of the filter to the HttpConfiguration.Filters collection during configuration:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ValidateModelAttribute());

        // ...
    }
}

Another option is to set the filter as an attribute on individual controllers or controller actions:

public class EntitiesController : ApiController
{
    [ValidateModel]
    public HttpResponseMessage Post(SampleEntity entity)
    {
        // ...
    }
}

For a more detailed explanation, take a look at this article. To learn about the various model annotations that you can use to define validation rules, e.g. [Required], etc., have a look at this MSDN page.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.