27

We are creating RestService with Asp.Net WebApi. But for some reason Name property is ignored in DataMember attribute when trying to deserialize complex property with [FromURI] attribute.

For example we might have: Method:

public IHttpActionResult Get([FromUri]User user)

Model:

[DataContract]
public class User
{
    [DataMember(Name = "username")]
    public string Username{ get; set; }
    [DataMember(Name = "isActive", IsRequired = false)]
    public bool? Active { get; set; }
}

When deserializing user we get username as expected, but null for Active. On the other hand when serializing data we get both isActive and username as expected. If we send request with active in query string it works as expected.

It's obviously problem with IModelBinder. It doesn't use DataMember's Name property for some reason. I checked what formaters are included and 4 default ones are registered:

System.Net.Http.Formatting.JsonMediaTypeFormatter
System.Net.Http.Formatting.XmlMediaTypeFormatter
System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter
System.Net.Http.Formatting.JQueryMvcFormUrlEncodedFormatter

I don't have a way to check which one is used on request. I would assume that its FormUrlEncodedMediaTypeFormatter but I can't be sure. Also, I am not sure if it even supports Name property.

I already checked for a solution and closest topic I could find was WebAPI DataMember Name not used when de/serializing via application/x-www-form-urlencoded but it doesn't use [FromUri] but application/x-www-form-urlencoded property and it wasn't really solved.

Any ideas, pointers or suggestions would be much appreciated.

Community
  • 1
  • 1
Igor
  • 3,054
  • 1
  • 22
  • 28
  • 4
    Did u ever figure out, what was wrong? I am facing the same issue. – Zuhaib Dec 07 '15 at 21:51
  • 2
    Unfortunately no... I made peace with this bug in WebApi and worked around it... – Igor Dec 09 '15 at 10:27
  • This was also reported here https://forums.asp.net/t/2095416.aspx?Binding+FromUri+to+complex+object+ignores+DataMember+Name. If you want to use DataContract then I recommend changing from HttpGet to HttpPost. Otherwise you'll need to deal with the bug. My 2 cents. – Tim Smojver Jul 28 '17 at 16:40
  • Can you show how do you send the object from in JSON format? – Rod Ramírez Oct 29 '20 at 19:28
  • Hi, could you also write full url with request data? I'd like to see how you send those parameters. Doesn't FromUri expect "User.isActive" to be correctly recognized in that situation? – jaro Mar 01 '21 at 11:09
  • 1
    Heya @jaroslaw, this question is 5 years old and as such is quite a bit outdated, am not sure if it's still relevant in this day and age... If you have a particular related question I would advise you to open a separate question on SO. – Igor Mar 04 '21 at 12:00
  • Does this works fine in FromBody ?? – Harkirat singh Jun 20 '21 at 17:43
  • Did you tried doing setting Active from Nullable ? – Harkirat singh Jun 20 '21 at 17:45

2 Answers2

1

Use [FromQuery] instead other attributes.

And model for your request http://localhost:8080/api/users?username=John&isActive=true

[Route("api/users")]
public class UsersController : Controller
{
    [HttpGet]
    public IHttpActionResult Get(User user)
    {
        //...
    }
}

Will looks like

public class User
{
    [FromQuery(Name = "username")]
    public string Username{ get; set; }
    [FromQuery(Name = "isActive")]
    public bool? Active { get; set; }
}

Anyway best practice is to keep names in model as it parameters names in query. In this case you dont have to provide "Name" parameter, only keep [FromQuery] on queryClass, and lower casing .Net provide automaticly.

Leonid Pavlov
  • 671
  • 8
  • 13
0

You must check your "get" request. Your get request must be like this;

GET api/foo?username=fooname&active=false

You don't have to DataContract and DataMember attribute to just achieve this. These attribute just for another thing, its not the main reason to use for.

After get valid hit on your get method, in your method you can check modelstate like;

if (ModelState.IsValid) {
/// your code goes here    
}
orhun.begendi
  • 937
  • 3
  • 16
  • 31
  • 1
    Hello orhun.begendi and thank you for trying to help. Unfortunately that is not an issue. The request goes through and I "get" it :) The problem lies in that Name defined in DataMember descriptor is ignored. Try reading the whole description again :) – Igor Feb 25 '17 at 12:48
  • Hello, did you look at this article ? http://aspnetwebstack.codeplex.com/workitem/270 I find quite useful to this topic, with this you can force to use datamember attribute in web api request with this configuration, GlobalConfiguration.Configuration.Services.RemoveAll( typeof(System.Web.Http.Validation.ModelValidatorProvider), v => v is InvalidModelValidatorProvider); I hope its useful. – orhun.begendi Feb 25 '17 at 13:55
  • hello again, you can try build your own model binding maybe. inherited from IModelBinder. Could be helpful, you can check this article http://www.strathweb.com/2013/04/asp-net-web-api-parameter-binding-part-1-understanding-binding-from-uri/ – orhun.begendi Feb 25 '17 at 15:39
  • The OP wants to use `..&isActive=false`, eg. There is nothing to check here, because nothing is assigned to check.. – user2864740 Feb 17 '18 at 03:09