web api controller action methods - asp.net-web-api

I am trying to get a web api call to work: I want to submit an email address and then on the server, the method will validate and return null or a message.
This is what I tried:
[Post]
public string validate(string email) {
return this._contextProvider.ValidateEmail(email);
}
However, I get this message returned to the client: No HTTP resource was found that matches the request URI 'https://localhost:44300/breeze/data/validate
The payload looks like this: {email: "Greg#gmail.com"}

The problem, it turns out, was the parameter binding.
In the Web API, binding is handling differently than MVC. By default, simple types are extracted from the URI, not the body. Complex types are extracted from the body of the message.
I then added the [FromBody] Attribute to the Action Method, and it then found the action method. But alas, the email parameter was null.
public string validate([FromBody]string email) {
return this._contextProvider.ValidateEmail(email);
}
Turns out when using this trick, the body must NOT be json, but constructed like a querystring - email=greg#gmail.com. I didn't want do do that, so ended up creating a class to accept the parameter, and that worked as expected.
public class ParameterizedAction {
public string Parameter { get; set; }
}
public string validate(ParameterizedAction arg) {
return this._contextProvider.ValidateEmail(arg.Parameter);
}
This article has more info: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection
as well as this one: http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/

Related

Web API Binding Always Null when Premitive type and application/x-www-form-urlencoded used

Following is default method from Web API template. Most of the time I am using application/json as Content-Type but when I used application/x-www-form-urlencoded and pass data to api as value=test. It is failed to recognize or bind.
public void Post([FromBody]string value)
{
}
This thing work when I pass value as =test instead of value=test but if I pass same thing to MVC controller it is working.
If I do something like this then it is working.
public class TestModel
{
public string value {get;set;}
}
public void Post([FromBody]TestModel model)
{
}
What is issue with first method and why it is not working ? Why it is working with MVC Controller or Binding and not with Web API Parameter Binding ?
When you use form data (application/x-www-form-urlencoded) put [FormForm] instead of [FromBody].

Ignore all parameters in binding except those excplicitly specified in actions signature

I have a web api controller like:
public HttpResponseMessage MyAction(string param1, string param2)
{
//do whatever
}
If i have requests like
Controller/MyAction?param1=a&param2=b
its all well and good.
But if i have something like
Controller/MyAction?param1=a&param2=b&excessParam=c
then i get that no action was found. I understand its due to web api binding rules/priorities.
What i am interested in is if there is some way of simply ignoring all parameters submitted in request except those explicitly specified in controller action signature?
ps.
not talking about optional params as i still have to specify them in actions signature.
i understand it is a bit against nature of web api bindings and i am sure it can potentially cause problems of overlapping/ambigious bindings but i am just curious if there is some solution to this.
But if i have something like
Controller/MyAction?param1=a&param2=b&excessParam=c
then i get that no action was found.
No, that's not quite true. You will get a 404 if you do not provide some of the known parameters:
Controller/MyAction?param2=b&excessParam=c
Excess parameters are ignored by the Web API and will not cause you any troubles.
In order to avoid those 404 errors you could make those parameters optional:
public IHttpActionResult MyAction(string param1 = null, string param2 = null)
{
}
Alternatively write a model containing the known parameters:
public class MyModel
{
public string Param1 { get; set; }
public string Param2 { get; set; }
}
and then:
public IHttpActionResult MyAction([FromUri] MyModel model)
{
}

Why do we have to specify FromBody and FromUri?

Why are the FromBody and FromUri attributes needed in ASP.NET Web API`?
What are the differences between using the attributes and not using them?
When the ASP.NET Web API calls a method on a controller, it must set values for the parameters, a process called parameter binding.
By default, Web API uses the following rules to bind parameters:
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string.
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
So, if you want to override the above default behaviour and force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter.
So, to answer your question, the need of the [FromBody] and [FromUri] attributes in Web API is simply to override, if necessary, the default behaviour as described above. Note that you can use both attributes for a controller method, but only for different parameters, as demonstrated here.
There is a lot more information on the web if you google "web api parameter binding".
The default behavior is:
If the parameter is a primitive type (int, bool, double, ...), Web API tries to get the value from the URI of the HTTP request.
For complex types (your own object, for example: Person), Web API tries to read the value from the body of the HTTP request.
So, if you have:
a primitive type in the URI, or
a complex type in the body
...then you don't have to add any attributes (neither [FromBody] nor [FromUri]).
But, if you have a primitive type in the body, then you have to add [FromBody] in front of your primitive type parameter in your WebAPI controller method. (Because, by default, WebAPI is looking for primitive types in the URI of the HTTP request.)
Or, if you have a complex type in your URI, then you must add [FromUri]. (Because, by default, WebAPI is looking for complex types in the body of the HTTP request by default.)
Primitive types:
public class UsersController : ApiController
{
// api/users
public HttpResponseMessage Post([FromBody]int id)
{
}
// api/users/id
public HttpResponseMessage Post(int id)
{
}
}
Complex types:
public class UsersController : ApiController
{
// api/users
public HttpResponseMessage Post(User user)
{
}
// api/users/user
public HttpResponseMessage Post([FromUri]User user)
{
}
}
This works as long as you send only one parameter in your HTTP request. When sending multiple, you need to create a custom model which has all your parameters like this:
public class MyModel
{
public string MyProperty { get; set; }
public string MyProperty2 { get; set; }
}
[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
// model.MyProperty;
// model.MyProperty2;
}
From Microsoft's documentation for parameter binding in ASP.NET Web API:
When a parameter has [FromBody], Web API uses the Content-Type header
to select a formatter. In this example, the content type is
"application/json" and the request body is a raw JSON string (not a
JSON object). At most one parameter is allowed to read from the
message body.
This should work:
public HttpResponseMessage Post([FromBody] string name) { ... }
This will not work:
// Caution: This won't work!
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }
The reason for this rule is that the request body might be stored in a
non-buffered stream that can only be read once.
Just addition to above answers ..
[FromUri] can also be used to bind complex types from uri parameters instead of passing parameters from querystring
For Ex..
public class GeoPoint
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
[Route("{Latitude}/{Longitude}")]
public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}
Can be called like:
http://localhost/api/values/47.678558/-122.130989
When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object).
At most one parameter is allowed to read from the message body. So this will not work:
// Caution: Will not work!
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }
The reason for this rule is that the request body might be stored in a non-buffered stream that can only be read once.
Please go through the website for more details:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Why does parameter binding work differently when there is an argument in the route template, e.g. /route/{id}?

I've found what seems to be an inconsistent behavior in ASP.NET Web API. Say I have the following controller:
public class FooController: ApiController
{
[HttpGet, Route("foo")]
public IHttpActionResult GetFoo([FromUri]Bar request)
{
}
[HttpGet, Route("foo/{id}")]
public IHttpActionResult GetFoo(int id, [FromUri]Bar request)
{
}
}
If I send a GET request to /foo, with no query string parameters, the first method will be executed and its request argument will be null - which makes sense. But that's not what happens when I send a request to foo/1. In this case, I'd expect only the id parameter to be filled with 1, but it turns out that both arguments are initialized.
Why is that so? If that's by design, what could I do in order to "normalize" that behavior, i.e., make the request parameter in both methods to be either null or initialized?

Return custom object AND controlling response code in JAX-RS

I'm using JAX-RS in my web application to return my own object.
I want to keep doing it, but I want to set the HTTP response code (e.g. 401 for unauthorized, etc.).
From the information I've found it seems like I have to return the type Response and not my custom object.
Is that correct?
My current code (simplified) - when MyReponse is an object that Jaxb knows how to deal with:
#POST
#Produces({MediaType.APPLICATION_XML , MediaType.APPLICATION_JSON})
public MyResponse RegisterUser (
#FormParam("userName") String userName,
#FormParam("password") String password) {
// add user logic
return new MyResponse(....<params to ctor...);
}
Yes, you are right.
You'll need to use something like:
#POST
#Produces({MediaType.APPLICATION_XML , MediaType.APPLICATION_JSON})
public Response RegisterUser (
#FormParam("userName") String userName,
#FormParam("password") String password) {
// add user logic
return Response.status(401).entity(new MyResponse(...)).build();
}
see http://jersey.java.net/nonav/documentation/latest/jax-rs.html#d4e355 (and other chapters) for additional useful information.
You can extend Response class and return your custom status when you override getStatus() method.

Resources