I want to ask if there is a difference between the annotation [FromForm] and Request.Form. Is there a difference in the way they access the Request object? For reference this is the code
public IActionResult Test ([FromForm] IFormFile File1)
{
var File2 = Request.Form.File[0];
}
If there is a difference then how do you send the file in case of [FromForm] from a angular app.
The [FromForm] annotation merely tells the compiler that the value for argument "File1" should come from the request object's "form".
Here is the documentation:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
FromQuery - Gets values from the query string.
FromRoute - Gets values from route data.
FromForm - Gets values from posted form fields.
FromBody - Gets values from the request body.
FromHeader - Gets values from HTTP headers.
Your action handler, "Test()", has "File1" as a parameter.
But "Test()" should also be able to read "File1" from the Request.Form object.
Different "abstractions" - same thing.
Related
how to get the devId from the body, even using [FromBody], it keeps identifying the devId as a query
public async Task<ActionResult<Module>> PostModule([FromBody]Module module, long devId){}
You can only have 1 argument with a FromBody applied.
From the documentation
Don't apply [FromBody] to more than one parameter per action method. Once the request stream is read by an input formatter, it's no longer available to be read again for binding other [FromBody] parameters.
If you want that devId being read from the body, you'll have to include that one as e.g. a property in your Module class.
How can I get the parameters of an ASP.NET Core MVC controller action from the properties of a JSON object that was sent in the HTTP request body?
If the request body contains form data and the content type is appropriate, the action method parameters are populated automatically as expected.
But nothing works if the POST data format is JSON and the content type is "application/json". I think this is quite common for API requests? I tried adding the [FromBody] attribute to all parameters, but the documentation says I can only apply that once. Well, I can write it multiple times and nobody complains, but neither helps. Even if I want to bind all the JSON to a single string parameter, it remains null.
Can ASP.NET Core actually handle JSON POST data? In the usual parameter binding comfort? Or are we down to the feature level of PHP (or below) when it comes to JSON requests? Should I not use such advanced technology and revert my client-side code to plain old HTTP form data instead?
I think I used this before and saw it working. But can't find out what the difference is here. Maybe it only works in controllers with the [ApiController] attribute? This case is a regular web page controller, not a separate API. But it needs to provide functions to JavaScript as well, so it does both.
I tried adding the [FromBody] attribute to all parameters
This sounds fishy to me. Are you trying to send your params as a json object and expecting them to get unwrapped into individual action params?
Consider the following data type and MVC controller endpoint:
public class Sample
{
public int Id { get; set; }
public string Name { get; set; }
}
[HttpPost]
public IActionResult Post([FromBody] Sample sample)
=> new JsonResult(sample);
This is all you need for a typical POST to an MVC controller. The key point is probably the type that I'm using to bind to the body. As you can see, I create a matching json object in Postman and it binds correctly and returns what I sent.
To get what you want, I think you'd have to rely on query params. (or some other technique I'm unaware of) Here's an example if you need it.
[HttpPost]
public IActionResult PostQuery([FromQuery] int id, [FromQuery] string name)
=> new JsonResult(new Sample {Id = id, Name = name});
In ASP.NET Core, if an action accepts directly an enum type, and that enum for example has defined 1 to something, if we pass a value different than 1, we'll get a validation error.
This is good! But it doesn't work for when the enum is inside a complex object type, when they are built from the body of a request ([FromBody] attribute).
Why is this happening? I know that anything coming from the body, is being handled by JSON Converters. Why can't they handle this for us, when the Query binder (what/where is it?) does it for us?
Example Enum:
public Enum Example
{
One = 1
}
Example Action:
public object ExampleAction(Enum hello)
{
return Ok();
}
If you hit the action with a HTTP request, passing in the hello parameter in a query string with a value different than 1, you will get a validation error.
Now, if you annotate the hello parameter with the [FromBody] attribute and make a new request (passing in this time the data via the body instead of the query string), that behavior is lost.
I'm using:
return RedirectToAction("GetSchedule", new { requirements = preCheckParams.Requirements, weightValues = preCheckParams.WeightValues});
in my aspnetcore app. Next I want to reuse the values I pass to the anonymous object in another action:
public IActionResult GetSchedule(List<string> requirements, Dictionary<string, int> weightValues)
Strangely, the first value gets bound to the List in GetSchedule action, yet the second object, which is a dictionary, is empty. Are there any special rules regarding dictionaries in such cases?
You can't pass classes in the routeValues parameter of RedirectToAction.
RedirectToAction method return value is HTTP 302 (Status302Found) which produces a GET request to the specified action. Which means that all your parameters will be put in URL as query string.
List/Array of strings requirements can be passed in URL since it binds to ?requirements=value1&requirements=value2&.. etc in query string, but anything more complex than that cannot be bound, only primitive values.
You have several options that first come to my mind:
Serialize object to JSON and pass it as a string. This will result in ugly and confusing URL, but it's least painful way.
Use temporary storage if you don't require strictly stateless mechanism. Store before the action and retrieve the dictionary when you enter it.
If you can retrieve weight values from the backend, you may pass some identifier to query by it.
I want to have a WebAPI path that takes an Id, but also, an optional query.
So, usually, the client will send:
http://localhost:49487/api/template/5b31b31c-ecd9-4e7a-bcdb-1c263399c86f
But sometimes, I need to return a bit of extra details in the payload. So I want them to send:
http://localhost:49487/api/template/5b31b31c-ecd9-4e7a-bcdb-1c263399c86f?IncludePreview=true
My .Net Web API Controller enpoint is defined like this, and handles the first case.
[Route("{Id}"), HttpGet]
public IActionResult GetTemplate(Guid Id, bool IncludePreview = false)
But as soon as I sent the second version, with the query string, the api controller fires (I have a breakpoint on it), but, Id is always Guid.Empty.
How can I have my API method accept both versions? Or do I need to create a separate endpoint for both versions?
You are assigning the Include Preview Boolean value as a fixed value. So event though your call catches the IncludePreview=true in GetTemplate method ,it get reassign. Please try to use a nullable Boolean with 'null' as assigned value.
public IActionResult GetTemplate(Guid Id, bool? IncludePreview=null)