Call .NET Core controller method from React with values - reactjs

I'm new to React and I just can't find clear information on how to call a controller in my .NET Core application, send it values from the form inputs and then get a result back from it. Doesn't seem like it should be hard to do but maybe I know so little that I'm asking Google the wrong questions. Anyway...
I have a controller method that looks like this. I have called it from Postman and it seems to work.
[ApiController]
[Route("user")]
public class UserController : ControllerBase
{
[HttpGet]
[Route("login/authenticate")]
public async Task<IActionResult> AuthenticateUserAsync([FromBody] AuthenticateUserRequest request)
{
... // sends request to back-end and gets a response
return Ok(response);
}
}
There's a request class that looks like this, and I want the UserID and Password properties from the React form to be set here.
public class AuthenticateUserRequest: Request
{
public string UserID { get; set; }
public string Password { get; set; }
}
The response that is returned contains a list of strings which is used to authenticate the user with an identity in the controller. I want to return this list to React to show what permissions the user has.
public class AuthenticateUserResponse: Response
{
public List<String> Permissions { get; set; }
}
And I'm trying to call it with something like this:
I got this fetch example from here: ASP.NET Core React project template - how to link to C# backend
but it doesn't seem to work.
handleSubmit(event) {
if (this.state.userId == "" || this.state.password == "") {
alert('Please enter User ID and Password.');
event.preventDefault();
}
else {
fetch('user/login/authenticate', {
method: 'get',
headers: { 'Content-Type': 'application/json' },
body: {
"UserID": this.state.userId.value,
"Password": this.state.password.value
}
})
.then(response => response.json())
.then(data => {
alert(data);
});
}
}
The alert never gets called and I don't know if it's doing anything at all. When I press the Submit button the form clears, and that's it.

When you use get in ajax to request the action in the Core API, you need to accept the parameters by using [FromQuery] attribute instead of [FromBody] attribute.
[HttpGet]
[Route("login/authenticate")]
public async Task<IActionResult> AuthenticateUserAsync([FromQuery] AuthenticateUserRequest request)
{
... // sends request to back-end and gets a response
return Ok();
}
Refer to this.

Related

No 'Access-Control-Allow-Origin' header is present on the requested resource. When using ajax

I have REST API which I wrote on Spring Boot.
I want to write a frontend for it using React. To begin with, I decided to make sure that my frontend correctly receives data from the API.
Here is my rest controller code:
#RestController
#RequestMapping("/api/restaurants")
public class RestaurantRestController {
private final RestaurantService restaurantService;
public RestaurantRestController(RestaurantService restaurantService) {
this.restaurantService = restaurantService;
}
#GetMapping
// #PreAuthorize("hasAuthority('everything:read entries')")
#ApiOperation("Get all restaurants")
public ResponseEntity<List<RestaurantDto>> getAll() {
List<RestaurantDto> result = restaurantService.findAll().stream()
.map(RestaurantDto::fromRestaurant)
.collect(Collectors.toList());
return new ResponseEntity<>(result, HttpStatus.OK);
}
I wrote a configuration class on the backend side:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000/")
.allowedMethods("GET", "POST, "PUT", "DELETE")
.allowCredentials(true).maxAge(3600);
}
}
And I access my controller from the frontend with this method:
import axios from 'axios';
const REST_URL = "http://localhost:8080/api/restaurants";
export default class RestaurantsAPI {
static async getAll() {
const response = await axios.get(REST_URL);
return response.data
}
}
And I get the correct answer.
Then I add credentials to my request:
import axios from 'axios';
const REST_URL = "http://localhost:8080/api/restaurants";
export default class RestaurantsAPI {
static async getAll() {
const response = await axios.get(REST_URL, {
auth: {
username: 'admin', password: 'admin'
}
});
return response.data
}
}
Now I see this in the console:
enter image description here
At the same time, it doesn’t matter, I leave access to the method open to everyone, using this configuration:
.antMatchers(HttpMethod.GET, "/api/restaurants").permitAll()
Or vice versa, I comment this configuration and apply an annotation to the method:
#PreAuthorize("hasAuthority('everything:read entries')")
I still get the same error.
Thanks to Postman and JUnit Tests, I know that Spring Security is configured and working properly.
Please explain what is the reason for this behavior and what should I do to fix it. Thank you.

using multiple parameters in get method from (axios) reactjs front-end to asp.net core webapi Back-end

I want to get shop by userId and userName if the shop for that user exists.
i have used the url in axios get call as follows:
const url = `${config.apiUrl}/api/Shops/`
useEffect(() => {
axios.get(url + `details?id=${user.id}&shopuser=${user.username}`)
.then((res) => {
setShop(res.data);
})
.catch((error)=>{
console.log(error);
}
)
At the back-end asp.net core web api I have used the following action Method:
[HttpGet("{dashboard}")]
public async Task<ActionResult<Shop>> Dashboard(int id,string shopuser)
{
var shop = await _context.Shops.FirstOrDefaultAsync(a=>a.UserId==id && a.UserName==shopuser);
if (shop == null)
{
return NotFound();
}
return shop;
}
The problem is that the call is not sent to this action method with correct parameters and hence the response with error error 500 .
The controller name is as follows:
{
[Route("api/[controller]")]
[ApiController]
public class ShopsController : ControllerBase
{
.......
....
}
}
I have checked the Network tab of console the parameters are sent as follows:
/api/Shops/details?id=1&shopuser=asifranjha
thanks in advance for help.
[HttpGet("{dashboard}")] annotation means that your get request is expecting a route parameter (dashboard).So if you want to trigger your method, you should call /api/Shops/1?shopuser=asifranjha (I recommend you to keep the same naming so you should change dashboard to id or the opposite, you could also provide the type for your route with route constraints).
If you want to use /api/Shops/details?id=1&shopuser=asifranjha, you should just change your annotation parameter so it would look like this: [HttpGet("details")] and everything should work.Good luck with your project!

Call .NET Core API from AngularJS using $https - 400 Bad Request

I'm trying to call a .NET Core API from AngularJS. In the AngularJS I'm calling the method like this:
$http({
method: 'POST',
url: '/api/message/transaction/' + this.transaction.id,
data: { "transactionJson": "hello"}
})
.then(function (response) {
var r = response;
})
My .NET Core API method is like this:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] string transactionJson)
{
I'm getting a 400 Bad Request response back from the server. How do I fix it?
I realised the type for the parameter must be a type that has a property named TransactionJson, so I need to define a new C# type:
public class TransactionData() {
public string TransactionJson
}
Then in the API method:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
getting a 400 Bad Request response back from the server. How do I fix it?
To fix the issue, as your mentioned, one solution is modifying action parameter, like below.
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
//...
//code logic here
TransactionData class
public class TransactionData
{
public string TransactionJson { get; set; }
}
Besides, we can also implement and use a custom plain text input formatter to make PostTransaction action method that accepts a string-type ACTION parameter work well.
public class TextPlainInputFormatter : TextInputFormatter
{
public TextPlainInputFormatter()
{
SupportedMediaTypes.Add("text/plain");
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
string data = null;
using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
{
data = await streamReader.ReadToEndAsync();
}
return InputFormatterResult.Success(data);
}
}
Add custom formatter support
services.AddControllers(opt => opt.InputFormatters.Insert(0, new TextPlainInputFormatter()));
Test Result

Passing Object in get Request to WebAPI 2

selectedLocation is always null on the Server
I am using Angular , what is the proper way of passing object to get method
This is Class that is defined on Server, which is being passed as parameter in get request
public class Location
{
public string LocationName { get; set; }
public string MFGName { get; set; }
}
This is the method in WebAPI that is being called.
[HttpGet]
[ActionName("RenewToken")]
[AllowAnonymous]
[ResponseType(typeof(string))]
public async Task<IHttpActionResult> RenewToken(Location selectedlocation)
{
}
The Captured Request looks like this(In google Chrome Developers Tool)
http://localhost:58146/api/Account/RenewToken?selectedlocation=%7B%22LocationName%22:%22Guad%22,%22MFGName%22:%22Flex%22%7D
What am i doing wrong ?
Okay so from what i got from this
Why do we have to specify FromBody and FromUri in ASP.NET Web-API?
when the parameter of the method is a complex type is looks in the body of the request
since you're using GET the data gets put into the uri instead of the body
couple options you could do are
public async Task<IHttpActionResult> RenewToken(string LocationName, string MFGName)
{
}
you could always change your verb to a post or something that accepts data in teh body
You might try changing your get in angular to something like
$http({
method: "GET",
url: "/api/Account/RenewToken",
params: {
LocationName: "Guad",
MFGName: "Flex"
}
})
which will parameterize the data

Web Api 2 with two method with the same HTTP verb an angularjs resources

I have this controller:
public class SeguiAttivazioneController : ApiController
{
[HttpGet]
public IHttpActionResult DoWork1()
{
...
return Ok();
}
[HttpGet]
public IHttpActionResult DoWork2()
{
...
return Ok();
}
[HttpGet] //I would like to have a search with GET verb, but I cannot validate my ModelState with dataAnnotation
public IHttpActionResult AnotherSearch(string filter1, string filter2, ...)
{
if (ModelState.IsValid)
{
...
return Ok();
}
return BadRequest(ModelState);
}
[HttpPost]
public IHttpActionResult DoSearch(SearchFilter filters)
{
if (ModelState.IsValid)
{
...
return Ok();
}
return BadRequest(ModelState);
}
[HttpPost]
public IHttpActionResult SubmitForm(FormData data)
{
...
return Ok();
}
}
As you can see I have two methods with same HttpVerbs (2 for GET and 2 for POST)... I don't know if I am violating REST principles... If so, I would like to avoid...
In this moment I am using AngularJs + NgResources to call my Controller..
public_area
.factory("SeguiAttivazioneService", function ($resource) {
//return {
// seguiAttivazione: $resource("/api/SeguiAttivazione/", null,
// {
// 'get2': { method: 'GET', url: '/api/SeguiAttivazione/GetActivationStatus2' }
// })
//};
return {
seguiAttivazione: $resource("/api/SeguiAttivazione/")
};
});
I am trying to do a GET:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
var request =
new SeguiAttivazioneService
.seguiAttivazione()
.$get({ }, getActivationStatusSuccess, getActivationStatusError);
}
};
But (correctly) I obtain an "Internal Server Error 500", because I have to GET method. How Can I solve this problem? (I suppose I will have same problem with POST too)
Thank you
UPDATE
Here the class of the filters
public class SearchFilter
{
[Required(ErrorMessage="")]
public string CodiceFiscale { get; set; }
[Required(ErrorMessage = "")]
[RegularExpression(#"^(?:\d{11,16})|(?:[a-zA-Z]{6}[a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{3}[a-zA-Z])$", ErrorMessage = "Codice Fiscale o Partita IVA non validi")]
public string CodiceRichiesta { get; set; }
}
With this class I can use data Annotation to validate my model... If I do a GET Method I cannot use data annotation validation anymore...
Here is some explanation about a the REST Endpoints.
In REST we are manipulating ressources. As collections or individual.
Classics endpoint would be :
GET /rest/houses DATA : none -> will return a collection of houses
GET /rest/houses/{id} DATA : none -> will return the house find by its {id}
POST /rest/houses DATA : {"street":"3 bdv NY-city"} -> will create a new house object with the given data
PUT /rest/houses/{id} DATA : { "id":"{id}", "street":"4 bvd NY-city"} -> will update the whole house ressource find by its {id}
PATCH /rest/houses/{id} DATA : { "street":"4bvd NY-city" } -> will update the given fields of the house ressource find by its {id}
DELETE /rest/houses/{id} DATA : none -> will delete the house ressource find by its id.
There is too much things to know about restfull API that i can't give you all the keys. But try to find some good articles on the subjects such as :
http://www.restapitutorial.com/index.html
Not sure if this answer your question, but i hope it'll help you.
EDIT 1 :
Since i have to add some point about a restfull way to give some complicated action i'll give you the restfull url way to go.
In a restful world (extremely rare) you know only one entry point of your rest API let say this :
GET /rest/
This uri will respond you will all the services that the api can provide
Exemple :
{
"resources":"/rest/ressources",
"apiInfo" : "/rest/api/info"
}
To get your ressources informations you'll follow the link
GET response.resources
I may respond something like :
{
"houses":"/rest/ressources/houses/",
"cars" :"/rest/ressources/cars"
}
Now we want the houses
GET response.houses
Response :
{
"fields":[{
"constructionYear","street"
}],
"search":"/rest/houses"
"create":"/rest/houses"
}
etc... And at this place you can add some non restful endpoints. In a restful way. This action will be hold by a restful resource. Somes API that are using this kind of great Restful.
Standard Rest API :
https://developers.soundcloud.com/docs/api/reference#users
Restful API :
https://www.salesforce.com/us/developer/docs/api_rest/
The question is that the Web API infrastructure must have a way to choose one of the possible methods.
One way is changing the Web API route configuration, including an /{action}/ segment. If you do so it will work exactly like MVC, and you have to always include the action name.
The other way is making the received parameters different in each method, so that the Web API infrastructure can discover which method you're trying to invoke. You can read this answer I've written today for a similar question: How can I add multiple Get actions with different input params when working RESTFUL?.
As a final comment in that answer I say that the parameters can be also discerned by using route contraints.
The first solution of having to include the action name in all invocation is not RESTful, but do you need or prefer it to be RESTful for any particular reason?

Resources