DataMember's Name property is ignored with [FromUri] property in WebApi service
Asked Answered
B

2

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.

Brittaneybrittani answered 9/11, 2015 at 15:8 Comment(8)
Did u ever figure out, what was wrong? I am facing the same issue.Ophiuchus
Unfortunately no... I made peace with this bug in WebApi and worked around it...Brittaneybrittani
This was also reported here forums.asp.net/t/…. 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.Tartaric
Can you show how do you send the object from in JSON format?Eyeglass
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?Hux
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.Brittaneybrittani
Does this works fine in FromBody ??Halfhardy
Did you tried doing setting Active from Nullable<Active> ?Halfhardy
A
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.

Analytic answered 3/12, 2021 at 5:16 Comment(0)
B
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    
}
Biz answered 24/2, 2017 at 22:15 Comment(4)
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 :)Brittaneybrittani
Hello, did you look at this article ? 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.Biz
hello again, you can try build your own model binding maybe. inherited from IModelBinder. Could be helpful, you can check this article strathweb.com/2013/04/…Biz
The OP wants to use ..&isActive=false, eg. There is nothing to check here, because nothing is assigned to check..Inure

© 2022 - 2024 — McMap. All rights reserved.