4

I have been trying to get the example from this link to work.

I'm trying to detect extra fields in a json request and return an error if they are present.

Here's what I have:

ApiController:

public class MyClassController : ApiController
{
    public IHttpActionResult Add(MyClass myClass)
    {
        if (myClass.ContainsExtra)
        {
            return BadRequest(ModelState);
        }
        ...
     }
...
}

DynamicObject:

public class MyClass : DynamicObject
{
    private Dictionary<string, object> fields =
                        new Dictionary<string, object>(
                             StringComparer.OrdinalIgnoreCase);

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    public bool ContainsExtra { get; private set; }

    [JsonIgnore]
    public Dictionary<string, object> Extra
    {
        get { return fields; }
    }

    public override bool TryGetMember(GetMemberBinder binder,
                                              out object value)
    {
        return fields.TryGetValue(binder.Name, out value);
    }

    public override bool TrySetMember(SetMemberBinder binder,
                                                  object value)
    {
        this.ContainsExtra = true;

        fields[binder.Name] = value;
        return true;
    }
}

If I send this Json from Fiddler

{“FirstName”:”Test”, “LastName”:”Test”, “City”:”New York”}

The TrySetMember method should fire and it should set the bool ContainsExtra to true so it can be evaluated in the Add method on MyClassController. When it does contain an extra field, it should return an error to the client.

Unfortunately I just can't seem to get the TrySetMember to fire.

What am I Missing ?

user1848850
  • 463
  • 7
  • 20
  • 1
    Not an answer, just thinking if [accessing properties like this example](http://stackoverflow.com/a/6529408/304683) and "validating" that way would be simpler? – EdSF Jul 04 '14 at 03:02
  • I found a SerializerSetting "MissingMemberHandling" and by default it's set to Ignore, what i did was: – user1848850 Jul 04 '14 at 03:59
  • var jsonFormatter = config.Formatters.OfType().ElementAtOrDefault(1); jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error; – user1848850 Jul 04 '14 at 04:10
  • now it sets the ModelState.IsValid == false when there's an extra field and I can return the ModelState to the client. Only problem is I can't figure out a way to have it use different names for the class { "Message":"The request is invalid.", "ModelState":{ "myClass.City":[ "Could not find member 'City' on object of type 'myClass'. Path 'City', line 1, position 16." ] } } – user1848850 Jul 04 '14 at 04:11

1 Answers1

4

I got the functionality that i wanted by simply setting the MissingMemberHandling setting of the JSONMediaTypeFormatter to MissingMemberHandling.Error, in my case I:

WebConfigFile:

// Set up The Json Media Type Formatter
var JsonMTF = new JsonMediaTypeFormatter
{
  SerializerSettings = { MissingMemberHandling = MissingMemberHandling.Error }
};

// Clear all formatters
config.Formatters.Clear();

// Add the JSON formatter
config.Formatters.Add(JsonMTF);

Then write an ActionFilterAttribute:

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

Finally add the filter in the WebConfigFile:

// Add Validate Model Filter Attribute 
config.Filters.Add(new ValidateModelFilterAttribute());
user1848850
  • 463
  • 7
  • 20
  • This solution works if request body extra parameter which is invalid, Ex:{“FirstName”:”Test”, “LastName”:”Test”, “City”:”New York”} where city is invalid property It doesn't work if extra parameter is valid property Ex:{“FirstName”:”Test”, “LastName”:”Test”, “FirstName”:”Test1”} – Siddharood Jan 30 '15 at 06:48