2

I have a problem with post requests to OData controller when the json data contains more properties than required by Post method defined in OData controller. So called over-posting is supposed to be allowed for MVC controllers, but it seems that OData controllers don't accept it. Please review to following sample.

I have a simple entity class:

public class Skill
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [StringLength(100)]
    public string Name { get; set; }

    public SkillAffiliation ApplicableTo { get; set; }
}
  • SkillAffiliation is an enum.

And a simple OData controller with Post method that looks like this:

public IHttpActionResult Post(Skill skill)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    _dbContext.Skills.Add(skill);
    _dbContext.SaveChanges();

    return Created(skill);
}

The problem is that I use a third party web controls collection, and the control that is supposed to use my OData controller adds an additional json property, basically the POST request looks like this:

{"Name":"TEST2","ApplicableTo":"Vehicle","ApplicableTo_input":"Vehicle"}

So there is an extra ApplicableTo_input property - this unfortunately causes a model validation error. The ModelState.IsValid property is set to false, and there is an error message "The property 'ApplicableTo_input' does not exist on type 'Mango.Models.Skill'. Make sure to only use property names that are defined by the type." Adding this extra property is obviously a bug in their solution and will be fixed with next release, however until that time comes I have to find some workaround.

I've already tried to add [Bind(Exclude="ApplicableTo_input")] attribute to my post action parameter, but it doesn't seem to work. Any ideas?

bartosz
  • 21
  • 2

1 Answers1

1

Make SkillWrapper an open entity by add an dictionary property.

public class SkillWrapper 
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [StringLength(100)]
    public string Name { get; set; }

    public SkillAffiliation ApplicableTo { get; set; }

    public IDictionary<string, object> CustomerProperties { get; set; }
}

Use Skill to store value and save in DB.

public IHttpActionResult Post(SkillWrapper skill)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var value = new Skill();
    ...//get property value form skill
    _dbContext.Skills.Add(value);
    _dbContext.SaveChanges();

    return Created(value);
}
Fan Ouyang
  • 2,132
  • 1
  • 11
  • 13
  • I have already tried this approach, but instead of creating an open entity a new collection property is added for the edm model of my odata service: – bartosz Apr 22 '15 at 15:25
  • I consider your Skill in DB doesn't have the column CustomProperties, so suggest the wrapper, not change skill directly, So it works now? – Fan Ouyang Apr 24 '15 at 03:06
  • I agree that it's better to add a wrapper, but this is just a sample to demonstrate the problem. As I mentioned in my earlier comment, unfortunately this didn't help - when I go to odata/$metadata the Skill entity is not marked as an open entity, instead a new property called CustomProperties is added to the entity. I don't know why this is happening, I found many other tips that adding IDictionary property should make this an open entity, but somehow it does not work with this sample. – bartosz Apr 25 '15 at 07:20
  • 1
    You are using OData WebApi V4 or V3? V3 doesn't support open entity, and more detail about open entity type in V4 you can refer to http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/use-open-types-in-odata-v4 and http://odata.github.io/WebApi/#02-03-model-builder-nonconvention. – Fan Ouyang Apr 27 '15 at 01:31