Issue
I would like to note that this is my first .Net Core Angular project and i apologize if the question may seem obvious, i looked at similar questions but my problem still persists so i guess i am doing something wrong.
So i have created a .Net Core 3.0 Angular project in Visual Studio and created a select menu that on change sends a POST request with the selected value, however on the controller the received POST is always NULL
This is my HTML
<select class="form-control" (change)="languageChanged($event.target.value)">
<option *ngFor="let language of languages | keyvalue:returnZero" value="{{language.key}}">{{language.value}}</option>
</select>
For the POST request on the client side i have tried the two following approaches :
this.http.post("Language", lang).subscribe(result => {
console.log(result);
}, error => console.error(error));
and
this.http.post<LanguageInterface>("Language", lan).subscribe(result => {
console.log(result);
}, error => console.error(error));
where
export interface LanguageInterface { language: string; }
On the server side
public class Language
{
public string language { get; set; }
}
on the HTTP post i have also tried two things
public IActionResult Post(Language lan)
{
// logic
return Ok();
}
and i have tried to change the method to
public async Task<IActionResult> Post([FromForm]Language lan)
Any help would be appreciated! Thank you for your time!
Solution
There are a few different questions in your post that I'd be happy to tackle for you:
Why doesn't Language get populated in your controller method?
You indicate that the method on your API controller looks like:
public IActionResult Post(Language lan)
{
// logic
return Ok();
}
You don't indicate if you're configuring Endpoints in your setup, so I'll assume not. You should update this with to instead look like the following. This will do two things: 1) The first line will inform ASP.NET Core that this method should match a POST request with the named template and 2) the [FromBody]
attribute in the argument tells ASP.NET Core where to populate the value from (your POST body).
[HttpPost("Language")] //Handles a call to /language as you attempt in both your first and second calls from Angular.
public IActionResult Post([FromBody]Language lan)
{
//logic
return Ok();
}
Should you use async
and Task<T>
in your last controller sample
Unless you're performing asynchronous activities in your //logic
comment, there's no reason to decorate the method with async
or have it return a Task<IActionResult>
. The example above is more than sufficient.
Are you even populating any data to send?
This would be worth a peek at your network request to verify, but unless you're doing some mapping in your Angular component, you're setting the value of the option field to "language.key", but in your call to this.http.post
, you pass in lang
and subsequently lan
which both are not otherwise used in your example code. As such, I can't dig much into what might be going on there, but it could be worth opening your network tools in your browser and confirm that the POST request to your server is actually populating with the intended data from the Angular component.
You might be misunderstanding the TypeScript syntax on the Angular side in your calls to this.http.post
You indicate that you're trying to send data with:
this.http.post<LanguageInterface>("Language", lan).subscribe(result => {
console.log(result);
}, error => console.error(error));
My concern here is merely derived from this second example you give given that you're passing in data from a LanguageInterface
, presumably into the lan
parameter somehow, but you also reference that at this.http.post<LanguageInterface>
. The use of <> on the method is to type the response that you're expecting from the call and is not properly used here. Rather, because your controller methods in ASP.NET Core both simply return an Ok()
ActionResult
, there's no anticipated type for the response, so this wouldn't make much sense here.
In this case, your first post call from Angular uses the correct syntax:
this.http.post("Language", lang).subscribe(result => {
console.log(result);
}, error => console.error(error));
The result will merely contain the HttpResponse
and there's not expected to be a body in the response back to you, much less one that should be typed to anything.
Conclusion
Again, I can't speak to how you're mapping between the form and your call to POST the data, but feel free to provide more of your sample code and notify me in a comment and I'd be happy to review it as well.
Within your Angular component
this.http.post("Language", lang).subscribe(result => {
console.log(result);
}, error => console.error(error));
Your ASP.NET Core controller method
[HttpPost("Language")] //Handles a call to /language as you attempt in both your first and second calls from Angular.
public IActionResult Post([FromBody]Language lan)
{
//logic
return Ok();
}
Why does [HttpPost("Language")]
break this?
You didn't originally provide the controller signature in your question, so this wasn't obvious before. Because your [Route]
attribute on the controller is set as [Route("[controller]")]
, it is using an ASP.NET Core convention to use the name of the controller before "Controller" - in your case, your class is "LanguageController", so any request to /Language will wind up pointing here as a valid option.
Since I then suggested a route on [HttpPost("Language")]
, that further adds to the pattern required to match. If you sent a POST request to localhost:<port>/Language/Language
, you'd see it match on the method as expected.
To remedy this then, merely changing the attribute on the method to [HttpPost]
and eliminating the template argument will mean that this will match a call to localhost:<port>/Language
, assuming this is the only POST method with this signature in the controller.
Answered By - Whit Waldo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.