10

Already spent couple of hours trying to resolve issue with ignored Name property on DataMemberAttribute when handling HTTP POST form request (Content-Type: application/x-www-form-urlencoded).

I'm having Microsoft.AspNet.WebApi 5.2.3 application running on .NET 4.5, hosted by IIS.

I have this model (demo):

// library
public interface IPayload
{
    string DataId { get; set; }
    int RelationId { get; set; }
}

// web app project
[DataContract]
public class MyPayload : IPayload
{
    [Required]
    [DataMember(Name = "id")]
    public string DataId { get; set; }

    [Required]
    [DataMember(Name = "rel")]
    public int RelationId { get; set; }
}

Then I have controller:

[HttpPost]
[Route("~/api/stuff")]
public async Task<HttpResponseMessage> DoMagic(MyPayload payload)
{
    // ... breakpoint
}

(Note I'm really using model type and not just interface in my controller)


When I send data like this:

curl -X POST --data '{"id":"foo","rel":1}' -H "Content-Type: application/json" -H "Content-Length: 20" http://localhost/api/stuff

I get my model deserialized correctly.


However, when I do:

curl --data "id=foo" --data "rel=1" http://localhost/api/stuff

... I'm getting empty model - custom name is ignored, all properties have default value.

Finally, when I do request like this:

curl --data "DataId=foo" --data "RelationId=1" http://localhost/api/stuff

... model is serialized correctly.


So I'm wondering, what am I doing wrong. I spent quite a lot of reading, most of cases I found were about missing DataContractAttribute which is present in my case.

Attribute FromBody in front of controller parameter is not changing anything as well.

In my application, these formatters are registered:

  • System.Net.Http.Formatting.JsonMediaTypeFormatter
  • System.Net.Http.Formatting.XmlMediaTypeFormatter
  • System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter
  • System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter

Only last two contain application/x-www-form-urlencoded in SupportedMediaTypes.

Zdeněk
  • 929
  • 1
  • 8
  • 25
  • Did you already try [FromUri] attribute? – boosts Apr 28 '15 at 17:16
  • To be honest, I haven't as content is really in body - and if I try to use it, I'm actually getting `null` I also tried `ModelBinder` (empty, as I haven't implemented any custom binder) and it didn't help me much as well. Also, I wouldn't go this way - for JSON it works, so why should I implement binder here? – Zdeněk Apr 28 '15 at 17:23
  • But you state "when handling HTTP POST form request (`Content-Type: application/x-www-form-urlencoded`)"? – boosts Apr 28 '15 at 17:41
  • Sorry for confusion, I meant simply when my action handler `DoMagic` is invoked due to POST request. I'm expecting data in request body (as would anyone expect from POST, right? :)) -- so basically, I'm sending POST payload. If I send JSON with appropriate `Content-Type` header, it works. It does not work when I submit form (`method="post"`). – Zdeněk Apr 28 '15 at 17:50
  • What does your `RequestContext.RouteData` and `Request.Content` look like? I'm not familiar with curl but what I see [here](http://blog.scottlowe.org/2014/02/19/using-curl-to-interact-with-a-restful-api/) is somewhat different than your posts. – boosts Apr 28 '15 at 18:02
  • Not really sure where are you heading: RouteData points to correct route, there is no Value in `HttpRouteValueDictionary` (which is correct, there's no query string parameter in my case); `Request.Content` has correct headers set `application/x-www-form-urlencoded` but when I read it's content via `Request.Content.ReadAsStringAsync()` I'm getting empty string. – Zdeněk Apr 28 '15 at 18:12

1 Answers1

11

After time spent on debugging, I have to answer myself.

System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter is not used as my model is not derived from FormDataCollection nor is JS token type. So formatter System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter is in use.

Binders used within CompositeModelBinder are:

  • TypeMatchModelBinder (skipped)
  • MutableObjectModelBinder (used)

I haven't found any trace of code, which would take in consideration Name attribute of DataMemberAttribute - so I have to implement own IModelBinder for my type, which will take care of customization.

Just note: when serializing object, everything works as expected - issue described above is related only to deserializing from request body.

Sources

I hope I haven't missed anything. If so, please correct me.

Zdeněk
  • 929
  • 1
  • 8
  • 25