ASP.NET WebAPI method with two parameters, one array - asp.net-web-api

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}"]
}

Related

Send 2 or more Raw Body Parameters Post Request with Postman

I have an ASP.NET Core 2.0 API Method:
[HttpPost("api/days")]
GetDays([FromBody] DateTime startTime, [FromBody]DateTime endTime)
{
}
And I tried to send a Post request with Postman, but there is a problem, the parameters always have default values.
Here is my Post request looks like:
Result: Not Worked; Both parameters in API method get the default values.
If I change my API params to:
[HttpPost("api/days")]
GetDays([FromBody] Inputparam param)
{
}
public class Inputparam
{
public DateTime startTime { get; set; }
public DateTime endTime { get; set; }
}
That's worked perfectly!
But I wanna to send parameters directly and not inside wrapper object.
So, I came back with first API method and then I tried:
Result: Not Worked; Both parameters in API method get the default values.
And This one:
Result: Not Worked perfectly; Just first parameter (startTime) set it and second parameter still have default value.
And This one:
Result: Not Worked; Both parameters in API method get the default values.
I also tried [FromForm] instead of [FromBody] in API, nothings changed.
If I don't use [FromBody] in api and send the request via x-www-form-urlencoded that's worked perfectly.
But I need send a raw body with JSon.
How could I sent 2 different parameters as a raw body json?
Any idea?
Where is the problem?
I found that it's just one [FromBody] is allowed in API, and that makes sense. So probably the answer is: There is no way to have 2 or more parameters with [FromBody] attribute.
[FromUri] can do the Job.For your reference Microsoft Documentation
public class DateTimes
{
public datetime startdate { get; set; }
public datetime enddate { get; set; }
}
GetDays([FromBody] DateTimes _date)
{
//Controller action
}
URI:
api/values/?startdate=2018-06-01&endate=2018-07-01

How to configure odata web api route for method that always returns single entity

I'd like to configure a route that always returns a single entity.
The controller looks like:
class StatsController: ODataController {
public Stats Get() {
return new Stats();
}
}
The url to access it should be: GET ~/service-prefix/stats
All the options I've seen involve having to return IQueryable, or when returning a single entity, passing in a key in a form of ~/service-prefix/EntitySet(1)
Is there a way to achieve the above without having to return an IQueriable?
By default any action of the following forms should be reachable for your scenario:
Example:
public Stat Get([FromODataUri] int key) { }
or
public Stat Get#your-entity-name#([FromODataUri] int key) { }
To access a single object without needing to have an entityset, odata v4 introduces the concept of singletons.
From OData v4 spec:
A singleton allows addressing a single entity directly from the entity container without having to know its key, and without requiring an entity set.
More info:
Use Singleton to define your special entity
ODataLib for OData v4: Singletons and Containment
I believe Singleton could meet your requirement, but it is not implemented in WebApi. Fortunately, there is another option: unbound function. Just follow this sample: http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataFunctionSample/.
There is a method in ProductsController:
[HttpGet]
[ODataRoute("GetSalesTaxRate(state={state})")]
public IHttpActionResult GetSalesTaxRate([FromODataUri] string state)
{
return Ok(GetRate(state));
}
It is requested through this URL: ~/service-prefix/GetSalesTaxReate(state='WA') and is very close to your scenario. The only thing you need to do is to remove the parameter of the function:
[HttpGet]
[ODataRoute("GetStats()")]
public IHttpActionResult GetStats()
{
return Ok(new Stats());
}
Now you can request ~/sevice-prefix/GetStats().

Does a WebAPI2 method receiving a class as param needs FromBody

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.

Is there any way to pass a whole model via html.actionlink in ASP.NET MVC 3?

How do I pass a whole model via html.actionlink or using any other method except form submission? Is there any way or tips for it?
Though it's not advisable in complex cases, you can still do that!
public class QueryViewModel
{
public string Search { get; set; }
public string Category { get; set; }
public int Page { get; set; }
}
// just for testing
#{
var queryViewModel = new QueryViewModel
{
Search = "routing",
Category = "mvc",
Page = 23
};
}
#Html.ActionLink("Looking for something", "SearchAction", "SearchController"
queryViewModel, null);
This will generate an action link with href like this,
/SearchController/SearchAction?Search=routing&Category=mvc&Page=23
Here will be your action,
public ViewResult SearchAction(QueryViewModel query)
{
...
}
No, you cannot pass entire complex objects with links or forms. You have a couple of possible approaches that you could take:
Include each individual property of the object as query string parameters (or input fields if you are using a form) so that the default model binder is able to reconstruct the object back in the controller action
Pass only an id as query string parameter (or input field if you are using a form) and have the controller action use this id to retrieve the actual object from some data store
Use session
You could use javascript to detect a click on the link, serialize the form (or whatever data you want to pass) and append it to your request parameters. This should achieve what you're looking to achieve...

ASP.NET MVC AllowHtml bug or something I didn't use correctly

My model contains a string field called "longdescription" which gets the value of the tinymce editor's content
Public class ArticleModel:BaseModel{
[StringLength(8000, ErrorMessage = "Long description must be in 8000 characters or less"), AllowHtml]
public string LongDescription { get; set; }
}
Here is my controller code
[HttpPost]
public ActionResult AddEdit(ArticleModel model)
{
string buttonName = Request.Form["Button"];
if (buttonName == "Cancel")
return RedirectToAction("Index");
// something failed
if (!ModelState.IsValid)
{
}
// Update the articles
}
My problem is when I use Request.Form to access the post value, it's working fine without throwing "A potentially dangerous...." error, but when I use Request.Params["Button"], it threw that errors. Is something I am missing?
Thanks
Updated
Sorry the answer Adam gave doesn't really answer my question. Can anyone give more suggestion?
Ideally you shouldn't really be using either. Those are more Web Forms centric values even though they 'can' be used.
Either pass in a FormsCollection item and check it there using collection["Button"] or even better - your cancel button itself should probably just do the redirect. Why post when you do nothing but redirect?
In your view you can emit the url via Url.Action() and put that into your button's click handler (client side)
It is the HttpRequest.Params getter that is throwing this exception. This getter basically builds and returns a key/value pair collection which is the aggregation of the QueryString, Form, Cookies and ServerVariables collections in that order. Now what is important is that when you use this getter it will always perform request validation and this no matter whether you used the [AllowHtml] attribute on some model property or if you decorated the controller action with the [ValidateInput(false)] attribute and disabled all input validation.
So this is not really a bug in the AllowHtml attribute. It is how the Params property is designed.
As #Adam mentioned in his answer you should avoid accessing request values manually. You should use value providers which take into account things such as disabled request validation for some fields.
So simply add another property to your view model:
public class ArticleModel: BaseModel
{
[StringLength(8000, ErrorMessage = "Long description must be in 8000 characters or less")]
[AllowHtml]
public string LongDescription { get; set; }
public string Button { get; set; }
}
and then in your controller action:
[HttpPost]
public ActionResult AddEdit(ArticleModel model)
{
string buttonName = model.Button;
if (buttonName == "Cancel")
{
return RedirectToAction("Index");
}
// something failed
if (!ModelState.IsValid)
{
}
// Update the articles
}

Resources