Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to specify [FromUri] to get this to work?

I am using Asp.NET WebApi and one thing that confuses me is the binding when a request is done.

I have this ViewModel:

[DataContract(Name="Store")]
public class StoreDm
{
    [DataMember(IsRequired = true)]
    [MinLength(3)]
    public string Name { get; set; }

    [DataMember(IsRequired = true)]
    public double Latitude { get; set; }

    [DataMember(IsRequired = true)]
    public double Longitude { get; set; }
}

public HttpResponseMessage GetStoreNames(StoreDm vm)
{
    if (ModelState.IsValid)
    {

    }
}

RestClient c = new RestClient("http://localhost:3333/api/store");
RestRequest r = new RestRequest("/GetStoreNames", Method.GET);
r.AddParameter("Name", autoComplete);
r.AddParameter("Latitude", "4");
r.AddParameter("Longitude", "-7");
var d =  c.BuildUri(r);
c.ExecuteAsync(r, response2 =>
  {
      var content = response2.Content;
  });

My StoreDm is Null.

I don't get this on so many levels. First I setup IsRequired on all my properties yet for whatever reason the ModelState thinks "null" ViewModel is valid.

Second I don't get why it is null. I have to add [FromUri] to get it to bind. What happens if this would have been a Post and have the same restClient code but also someone is using fiddler body request.

If I am forced to put [FromUri] then I don't think the fiddler body request will work.

How could I have it so both requests go through and bind properly?

like image 921
chobo2 Avatar asked Jun 04 '13 21:06

chobo2


1 Answers

The Web API paramter binding (extract from here:Routing and Action Selection) does this:

Parameter Bindings. A parameter binding is how Web API creates a value for a parameter. Here is the default rule for parameter binding:

  • Simple types are taken from the URI.
  • Complex types are taken from the request body.

So, any complex type (like the class StoreDm is) is by default expected to be part of the body

As stated in the standard defintion Hypertext Transfer Protocol 4.3 Message Body

The rules for when a message-body is allowed in a message differ for requests and responses.

The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers. A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests.

So, while Web API provides some common functionality, it tries to be general. There could be requests with or without message-body. So, having this, the action selection and param binding is common, without inferring of the "current" request specific, and maybe obvious settings (we would think, that GET would always have all parameters (properties of StoreDm object) in the URI... but the engine does not)

The POST would bind the StoreDm out of the box, because its properties will be found in the body, standard binding for complex objects.

The GET breaks the rules, the properties (of Complex type) are in the URI, so we only have to inform the framework: [FromUri]. In other cases, Method will be found, null (bounded from message-body) will be passed

like image 151
Radim Köhler Avatar answered Sep 28 '22 15:09

Radim Köhler