I'm using the React template when creating a new project in Visual Studio. It has something like this for GET request:
fetch('api/SampleData/WeatherForecasts')
.then(response => response.json())
.then(data => {
this.setState({ forecasts: data, loading: false });
});
I'm learning how to do a POST request, so I modified the code to:
const formData = new FormData();
formData.append('values', this.state.values);
fetch('api/SampleData/WeatherForecasts', {
method: 'POST',
body: formData
}).then(response => response.json())
But not sure how to retrieve the formData on ASP.Net:
[HttpPost("[action]")]
public string WeatherForecasts()
{
// How to print out the values from formData here
// System.Diagnostics.Debug.WriteLine(Request.Form.ToString());
return "Hello";
}
Edit: I also don't know how to return a Json result from ASP.Net:
[HttpPost("[action]")]
public JsonResult WeatherForecasts()
{
// How to print out the values from formData here
// System.Diagnostics.Debug.WriteLine(Request.Form.ToString());
// How to return a Json here
// return {hello: 'Hello'};
}
My answer presumes that your this.state.values property contains a string for testing purposes only just like the following:
this.setState({
values: 'testingtext'
});
I guess you are on the right track, from front-end side I assume the data is being sent. You can additionally check in the browser's network tab how the data has been passed in the HTTP request's body.
I would modify the WeatherForcecasts() action as the following to capture the data on the back-end side:
[HttpPost]
public string WeatherForecasts([FromBody] string values)
{
// here you can check what has been passed to the values variable
return values;
}
About [FromBody] why you need to include into the attribute:
By default, Web API tries to get simple types from the request URI. The FromBody attribute tells Web API to read the value from the request body.
Source: Sending Simple Types
If you want to override the action name in your route then you can achieve that by adding into your method the [ActionName("YOUR_NEW_ACTION_NAME")] attribute but it is not a mandatory one:
You can override the action name by using the [ActionName] attribute.
Source: Routing by Action Name
I hope this helps! I guess this gives you an idea how to proceed further.
Related
I am currently using the fetch API to post a JSON object to a REST API created with Spring Boot. I am using formData to read in the form data and store it in a JSON object:
const data = new FormData(form);
const formJson = Object.fromEntries(data.entries());
let responsePromise = await fetch(
"http://localhost:8080/api/v1/student?id=" + studentId, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(formJson)
});
The Spring Boot backend expects a JSON that corresponds to the Student entity class, which will eventually be stored in my database:
#PutMapping
public ResponseEntity<Student> updateStudent(#RequestBody Student student, #RequestParam Long id) {
Student currentDatabaseEntry = studentService.getStudent(id);
currentDatabaseEntry.setFirstName(student.getFirstName());
...
return new ResponseEntity<>(currentDatabaseEntry , HttpStatus.FOUND);
}
This works fine.
Now, I have added a variable to the Student entity, which is of type byte[] and is suppossed to store an image of the student. So, I want to add an entry to my JSON object with key image and the value being a multipart file (the value of an input field of type "file").
From what I have read on the internet, it seems that whenever I want to upload a file, I should not upload a JSON, but instead the formData object. I fail to see how to handle this request on my backend though - doesn't Spring Boot expect the #RequestBody of the PUT request to be a JSON that resembles my Student entity?
Anyways, does anyone know how to achieve this?
I want to post with the Fetch API and call an action from my controller but the action is not being loaded like when I would do it with submitting a post form.
function postQuery() {
let query = document.getElementById("query").value;
fetch('/actionName', {
method: 'POST',
body: query,
headers:
{
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then(response => {
console.log(response);
})
.then(data => {
console.log('Success:', data);
})
}
/actionName is not being loaded, I am supposed to be directed to a different page.
When I would submit a form like that:
<form action="/actionName" method="post">
the public function actionName would be called but with fetch its not working.
When i try to see the $_POST with var_dump($_POST) inside of actionName, I am getting an empty array...I dont understand this
I see two questions here:
Why is the data not accessible to the server
Why is the brower not redirected to /actionName
Answer to #1:
Make sure the content type header matches the data you are sending, if it is raw json, you should use application/json rather then application/x-www-form-urlencoded. If you want to send a form using fetch API, you would need to either serialize to form to a URL encoded format, or use FormData, for example:
var fd = new FormData(document.getElementById('myForm'))
fetch('/actionName', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data;'
},
body: fd
})
Answer to #2:
Submitting HTML Forms will direct the browser to the forms action, so if I submit a form to /actionName, I will end up seeing the HTML that is returned by the server for that route. Using Fetch API to submit a form is a type of AJAX, which means that it is capable of communicating with the server without needing to load a new page.
With that in mind, you have a few options:
Use a regular form so that the desired default behavior happens
Manually redirect the user somewhere after the fetch promise resolves, something like:
fetch(/*..*/).then(data => {
console.log('Success:', data);
window.location.href = '/otherPage'
})
Render the response HTML without redirecting the user, something like:
fetch(/*..*/).then(data => {
console.log('Success:', data);
data.text().then(rawHTML => {
document.body.parentElement.innerHTML = rawHTML
})
})
My personal intuition would be to go with the first option, as it suits your requirements and is the simplest.
I'm using js fetch to call to an action method(in asp.net mvc),
but I need to pass parameters to the method.
How can I pass this data using fetch?
I'm trying to use this code but the data didn't pass:
fetch(url, {
data: { repositoryName: "dada" }
})
.then(() => {
console.log("test");
});
According to the documentation second parameter shouldn't contain data property.
I guess you need to use body property(you can use JSON string, FormData or URLSearchParams here basing on your needs, see docs):
fetch(url, {
method: "POST",
body: JSON.stringify({ repositoryName: "dada" })
}).then(() => { ... })
Also in this simple example it's possible to simply use query string like this:
fetch(url + '?repositoryName=dada').then(() => { ... })
Note that GET requests cannot have body so if your MVC action is GET action then you have to use query strings like in my second example.
I am developing an angular2+ app with typescript. I am trying to pull data for one of my Angular2 Kendo grid and making the following call to get results to populate the grid. In this web call I am sending a status ID , skip and take and a Sort array which contains the field I want to sort and the direction I want it sorted in.
Below is my typescript code which makes the web service call:
getUserRequests(statusId: number, skip: number, take: number, sort: SortDescriptor[]): Observable<GridResult> {
private getUserRequestsUrl = environment.serviceHostName + environment.serviceAppURL + '/api/Dashboard/GetUserRequestsByStatuses';
var headers = new Headers();
headers.append('Content-Type', 'application/json;');
return this.http.post(this.getUserRequestsUrl, JSON.stringify({ "Filter": { "Field": "StatusId", "Value": statusId, "Operator": "eq" },
"Skip": skip, "Take": take, "Sort": sort }), { headers: this.headers }).share()
.map((res: Response) => res.json())
.map(response => (<GridResult>{
data: response.Data ,
total: response.Count
}));
}
This is my service side code which never gets hit.
[HttpGet]
public HttpResponseMessage GetUserRequestsByStatuses([FromBody] DataRequest model)
{
DataResponse<AngKendoGridDashboard> response =
BusinessAccess.GetUserRequestsByStatuses(model);
return CreateHttpResponse(response);
}
Problem I am facing:
For some reason when make this web service call I get an error saying
"ERROR Response with status: 405 Method Not Allowed for URL:
http://localhost/Services/RequestService/api/Dashboard/GetUserRequestsByStatuses"
I checked the request object which is being sent and here is what is looks like
{"Filter":{"Field":"StatusId","Value":2,"Operator":"eq"},"Skip":0,"Take":5,"Sort":[{"field":"CreatedDate","dir":"desc"}]}
Also in the response body I see this message:
{"Message":"The requested resource does not support http method
'POST'."}
I been looking at this since Friday and could not come up with a solution. Any help is appreciated. I think it may be something to do with how I am sending my request object through typescript.
The error says the method POST is not supported yet the action has a HttpGet attribute.
You'll need to change the HttpGet to HttpPost.
[HttpPost]
public HttpResponseMessage GetUserRequestsByStatuses([FromBody] DataRequest model)
{
DataResponse<AngKendoGridDashboard> response =
BusinessAccess.GetUserRequestsByStatuses(model);
return CreateHttpResponse(response);
}
You could also lose the [FromBody] attribute too, it's the default given the parameter type.
I am trying to pass a JSON Object from a typescript POST call to a Web API method.
Fiddler shows that the object has been converted into JSON and the Content-Type is 'application/JSON'. But at the API controller, the parameter value displays null instead of JSON.
Typescript:
createPO(product: string): Promise<string> {
var headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });
return this._http.post(this._creatPOUrl, JSON.stringify(product), options)
.toPromise()
.then(response => <string>response.statusText)
.catch(this.handleError);
}
Web API:
[HttpPost]
public async Task CreatePOInMO([FromBody] string product)
{
return Ok();
}
product contains null.
If I pass the actual value inside product object from typescript(which is a JSON) , it works. But I cannot hard code like this.
I followed this post : Angular2 Service not passing JSON to WebAPI
But it looks like I am doing whatever is mentioned here.
In Angular 2, when posting JSON with the Http client, you should not call JSON.stringify:
this._http.post(this._creatPOUrl, product, options)