Does a WebAPI2 method receiving a class as param needs FromBody - asp.net-web-api

My normal Post params looks like this:
public Product Foo([FromBody] Product item)
{
// ...do something
return item;
}
But I keep seeing many samples on the net where the Post method does not have the [FromBody]:
public Product Foo(Product item)
{
// ...do something
return item;
}
Is there a difference between these two methods?
Can they be called the same way from the client?

You only need [FromBody] when you post a simple type, like an int. The model binder automatically looks for complex types in the request body.
In your example you don't need [FromBody], as Product is a complex type.

Related

Manipulate WebAPi POST

I have a WebAPI POST controller like the one below:
[ResponseType(typeof(Product))]
public async Task<IHttpActionResult> PostProduct(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = product.Id }, product);
}
To be valid, it expects several values, lets say Name, Price, URL, ManufactureID, StatusID.
However, the POST will not always contain a value for StatusID for example, and therefore the above will fail, as i cannot be null.
But when the value is not sent by the POST, i want to 'intercept' and set the value in code. Let say to int 1.
How would i go about this?
I have been using DTOes for extraxting data from the API, in a nice and viewable way. Can DToes be used in POST also? If so, how? Or any other approach, to setting data, if it does not excist in the POST?
I would say create your Product request model which will be defined in your WebAPI models and there your can define your StatusID as a nullable. After your receive request you can map your Product request data to ProductDto and in that mapping you set your default values if you need them.
Altough you can intercept request on client side and update it but I'm not sure is that something that will work for you.
You should create a POST product class that is agnostic of the persistence. Don't use the generated Product class of your ORM. Using your example above, you should have a ProductModel class that will only contain the properties that the API client can update. Then do the mapping of the DTO to your product data model.
public async Task<IHttpActionResult> PostProduct(ProductModel model)
{
...
var product = db.Products.New();
//mapping here
product.Name = model.Name;
product.Price = model.Price;
}

Missing HttpParameterBinding and ParameterBindingAttribute

I'm investigating Web Api in ASP.NET vNext using the daily builds. In a web api 2x project, I use HttpParameterBinding and ParameterBindingAttribute in some situations (see http://bit.ly/1sxAxdk); however, I can't seem to find either in vNext. Do/will these classes exist? If not, what are my alternatives?
Edit (1-22-15):
I want to be able to serialize a complex JS object to a JSON string, put the JSON string in a hidden form field (say name="data"), submit the form, and then bind my parameter to that JSON object on the server. This will never be done by a human, but rather by a machine. I also want this very same mechanism to work if the JSON is sent directly in the request body instead of form data. I also need this to work for several different types of objects.
I've been able to accomplish this scenario in Web Api 2.2 in a few different ways, including a custom ModelBinder; however, I remember reading an MSFT blog post that suggested to use a ModelBinder for query string binding, formatters for request body, and HttpParameterBinding for more general scenarios. Is it okay to read the request body in a ModelBinder ASP.NET 5, or is there a better mechanism for that? If so, then case closed and I will port my ModelBinder with a few minor changes.
I'm not sure that IInputFormatter will work for me in this case either.
Here are two rough approaches
Approach 1:
A quick and dirty approach would be to start with a Dto model
public class Dto
{
public Serializable Result { get; set; }
public Serializable FromForm
{
get { return Result; }
set { Result = value; }
}
[FromBody]
public Serializable FromBody
{
get { return Result; }
set { Result = value; }
}
}
public class Serializable
{
}
And an action method
public IActionResult DoSomething(Dto dto)
{
// Do something with Dto.Result
}
Then write a custom model binder for Serializable, that just works with Request.Form this way you never actually read the body yourself, and Form only reads it if it of type Form.
The down side of this is that ApiExplorer will not provide correct details (but I think since this is none-standard you are going to be in trouble here anyways).
Approach 2
You can alternatively just use the code from BodyModelBinder and create a custom binder for Serializable type above, that first tries to get it from the Form, and if it fails tries to get it from the Body. The Dto class in that case is not necessary.
Here is some pseudo code
if (inputType is yourtype)
{
if (request.Form["yourkey"] != null)
{
Use Json.Net to deserialize your object type
}
else
{
fall back to BodyModelBinder code
}
}
With this approach you can make it generic, and ApiExplorer will say the way to bind the type is unknown/custom (we haven't decided on the term yet :) )
Note:
Instead of registering the model binder you can use the [ModelBinder(typeof(customBinder))] attribute to apply it sparingly.
Here is a link to the BodyModelBinder code.
There is a new [FromHeader] attribute that allows you to bind directly to http header values if that is what you need.
https://github.com/aspnet/Mvc/issues/1671
https://github.com/aspnet/Mvc/search?utf8=%E2%9C%93&q=fromheader

ASP.NET Web API: convert Object Literal to CLR class

My Web API controller needs to take in a property bag, i.e. a list of key-value pairs, which it will use to insert or update records of indeterminate type. My ideal code would look something like this. This example would be to insert a new record.
Route:
/api/data/{EntityName}
Data from client, passed in using jQuery.ajax() (or similar) with POST:
URI:
http://mysite/api/data/employee
Post data:
"values":
{"FirstName":"Jim",
"LasName":"Nobody",
"StartDate": new Date(),
"Salary": 100000 }
Web API Controller function:
public HttpResponseMessage PutRecord(string entity, ??? values)
{
// confirm valid entity, look up metadata.
// Take values from "values" and feed them into my framework to insert a new employee.
}
What is the ideal configuration to accomplish this? What would be the type for "values" in the controller method - possibly a Dictionary< string,object>?
Thanks very much for your help.
If you create a model that has all of the properties, the model binder will map your post data directly to the model.
So your post would look more like this:
$.post(url, {FirstName:'Jim', LasName: 'NoBody',StartDate: someDate, Salary: 10000},
function(data){
// do something with callback
});
And your action would look like:
public HttpResponseMessage PutRecord(string entity, employeeModel model)
{
// confirm valid entity, look up metadata.
// Take values from "values" and feed them into my framework to insert a new employee.
}
This is a tad more type safe than the property bag approach, and save you a lot of casting and typing issues.

ASP.NET WebAPI method with two parameters, one array

i'm new to WebAPI and had a few qeustion to custom method calling.
So, im working with Entity Framework and created a WebAPI with basic CRUD methods.
But now i want to add some custom methods, is it possible to call arrays as parameters? And when yes, how?
This is my method:
public void AddRoles(Guid userid, Guid[] roleids)
So how it is possible to call this method through webapi?
I tryed it with
http://localhost:60690/api/MyController/AddRoles...
And is it possible to call void method? What is the response?
thanks and greetings,
Joerg
http://localhost:60690/api/MyController/AddRoles?userid=<user id guid here>&roleids=<guid1 here>&roleids=<guid2 here>...
As for the void method, of course it is possible, response will be with 200 code and empty body.
For GET you can refer to the following SO question:
How to pass an array of integers to ASP.NET Web API?
If you want to try to use POST then continue to read:
You should create a DTO for your parameters like such:
public class AddRoleModel
{
Guid UserId { get; set; }
Guid[] RoleIds { get; set; }
}
Change your method to accept accept POST and your new AddRoleModel DTO instead of the two different parameters like so:
[HttpPost]
public void AddRoles(AddRoleModel model)
{
...
}
And POST the json for that model to the method
json could look like this:
{
UserId: "{guid}",
RoleIds: ["{some guid}", "{some other guid}"]
}

ASP.NET Web API IQueryable<T> challenge

I want to use the following pattern in my controllers:
api/{controller}/{id}/{collection}
Example: api/customers/123/addresses
But I want to return IQueryable Of T from the corresponding Get action. I want something like this (simplified):
public IQueryable<????> GetCollection(int id, string collection)
{
switch(collection)
{
case "addresses":
return _addresses.AsQueryable();
break;
case "orders":
return _orders.AsQueryable();
break;
default:
throw new Exception(NotSupported);
}
}
Can this be done?
What would be the recommended approach?
#SLacks is correct that you should return IQueryable<object> or IQueryable<someBaseType> if you can.
The error your getting is a function of the DataContract Serializer. So you have a few options.
Switch to an alternate xml serlializer that supports what you want.
Swtitch to a form of output that bypasses the serializer at issue (say JSON using JSON.net)
Teach the data contract serializer how to serialize your object using the
For the "teach" option, you can teach in two ways.
(A) leverage the [KnownType(typeof(...))] attribute. Here's a post on the KnownType attribute. It's for WCF but should get you started.
(B) use a data contract resolver. This post should get you started.
Expanding on what #Ebarr said, the easiest way to accomplish this is to update the various classes which you want to be able to return this way, and have them inherit from a common base class or interface.
Example:
[KnownType(typeof(Address))]
[KnownType(typeof(Order))]
public abstract class _BaseObject { }
public partial class Address : _BaseObject { }
public partial class Order : _BaseObject { }
Now you can have your controller method look like:
public IQueryable<_BaseObject> GetCollection(int id, string collection) {
switch(collection) {
case "addresses":
return _addresses.AsQueryable();
case "orders":
return _orders.AsQueryable();
default:
throw new NotSupportedException();
}
}
Note that the [KnownType] attribute is in System.Runtime.Serialization. You should also be aware that this method will result in exactly what you would expect with regards to JSON serialization - but XML serialization will generally result in tags which show your objects as the base class (because that's what you returned) rather than the sub-classes.
Just return the non-generic IQueryable.
Or IQueryable<object> via covariance.

Resources