I am trying to set up a small ASP.NET Web API projects so I can post data to the database from a small React.JS project. I tried alot of sollutions but the results made no sense and I have no idea how to fix it anymore.
I have this very simple model:
public class Hour
{
public int WeekID { get; set; }
}
And this is my controller
[HttpPost]
public IHttpActionResult AddHour(Hour hour)
{
return Ok();
}
This is the method that I use to POST my data
export const SaveWeek = weekData=> {
const headers = new Headers();
headers.append("Content-Type", "application/json");
const Week= {
method: "POST",
headers,
mode: "cors",
body: weekData
};
console.log("Hours:");
// Returns {"WeekID": 1}
console.log(Hours.body);
return axios.post("http://localhost:52350/api/REST/AddHour", {
Week
});
};
The way I call this SaveWeek method in React is:
// The JSON parameter is for testing hard coded to: {"WeekID": 1}
handleSave = async json => {
const data = await SaveWeek(json);
console.log(data);
this.closeModal();
};
I know that the axios POST request works, the way I tested that is by changing the method to not use any parameters and looking at the result that where received:
[HttpPost]
public IHttpActionResult AddHour(Hour hour)
{
// This returns a string in which the data that I sent
// can be found.
string body = Request.Content.ReadAsStringAsync().Result;
return Ok();
}
The weird thing is that the body will be filled with data when the method does not contain any parameters, but when I provide the method with the Hour object parameter the body will be an empty string (""). And also the Hour object parameter wont be filled with the values that I provide it.
What am I doing wrong here?
According to https://github.com/axios/axios#axiosposturl-data-config axios.post has following signature
axios.post(url[, data[, config]])
So you just need to change your request to
export const SaveWeek = weekData => {
//headers should be simple object, not Headers
const headers = {
"Content-Type": "application/json"
};
//removed body, because we pass data as second parameter
//removed method, because 'axios.post' implies using "post" method
const Config = {
headers,
mode: "cors"
};
const url = "http://localhost:52350/api/REST/AddHour";
return axios.post(url, weekData, Config);
}
An incoming request to the ASP.Net Web API pipeline is read as a forward-only stream for super speed. Once it has been read it cannot be read again.
[HttpPost]
public IHttpActionResult AddHour(Hour hour)
{
// With model binding
// use hour.WeekID
}
In this first example model binding is already done and once it has been read it cannot be read again. Hence, Request.Content will be empty after that.
[HttpPost]
public IHttpActionResult AddHour()
{
// Without model binding
// use Request.Content
}
In second example it does not use model binding therefore still has the Request.Content property populated.
Use one or the other, not both, do not mix with MVC model binding which works differently.
A better explanation is available in this blog post
http://www.hackered.co.uk/articles/asp-net-web-api-why-is-the-request-Content-empty-when-the-model-is-populated
Related
Trying to get a basic model of my functions working.
Frontend (Angular): the body data will be JSON of this class:
class BackendParams {
listValues: any;
constructor( netList: any ) {
this.listValues = netList;
}
}
Then a function creates the class object:
const params = new BackendParams(list);
then calls a (still in the front-end) Angular function to send it to the backend:
onClickTest(params: any) {
const A = 1;
const B = 2;
const NameString = 'test';
const formData = new FormData();
formData.append('NetworkList', JSON.stringify(params));
let url = `${this.url}/CalibrationModel/1/2/SampleTest/TestModel`;
this.http.post(url, formData).subscribe(
(data) => {
console.log(data);
});
}
BACKEND:
class BackendParams
{
List<Constituent> listNetworkConstituents;
}
The following is image of the source code so you can see the syntax red underlines
I don't think the two are related (or are they?) but referencing the body parameters is of course essential.
And, of course, let me know anything else you see that might be a problem.
Thanks for your help. I learn a lot from you guys.
Yogi
If your method were marked as async then returning a bool would work. So public async Task<bool>..., but that isn't the case. However, as #JohnD91 said, if you're not using await in your method, it doesn't need to be async and it also doesn't need to return a Task.
The other problem is that parmsJSON is misspelled, because it's defined in the method signature as paramsJSON. You're missing the other a.
I try to update the identity of a worker on my project, I use HttpClient with a put, working in Angular 6 project and web API 2 on .NET Core. You can see here the request on the front-end side:
updateWorkerIdentity(worker: WorkerRead) : Observable<WorkerRead> {
const url = 'workerinfo/activeContractId=' + worker.activeContract.id;
return this.httpClient.put<WorkerRead>(url , JSON.stringify(worker) );
}
And at the API side:
[HttpPut("{activeContractId}")]
public async Task<IActionResult> Put([FromRoute] string activeContractId, [FromBody] WorkerRead worker)
{
var companyId = GetCompanyId();
var period = GetPeriod();
var language = GetLanguage();
var workerInfo = await _workerInfoService.UpdateWorkerIdentity(companyId, activeContractId, language, worker);
return Ok(workerInfo);
}
the activeContractId coming from the [FromRoute] is well sent but the worker is still null.
The worker sent from the body is well sent as you can see here in the payload:
and the Content-Type of the header is well application/JSON.
Anyone has an idea?
Everything on the server side looks OK for a simple endpoint.
However, based on the [HttpPut("{activeContractId}")] route template the request on the client side should be refactored to match the expected template
updateWorkerIdentity(worker: WorkerRead) : Observable<WorkerRead> {
const url = 'workerinfo/' + worker.activeContract.id;
return this.httpClient.put<WorkerRead>(url , worker);
}
I suspect that the httpClient will internally stringify the payload before sending.
The above code assumes the controller is defined
[Route("[controller]")]
public class WorkerInfoController : Controller {
//...
//PUT workerinfo/123456
[HttpPut("{activeContractId}")]
public async Task<IActionResult> Put([FromRoute] string activeContractId, [FromBody] WorkerRead worker) {
var companyId = GetCompanyId();
var period = GetPeriod();
var language = GetLanguage();
var workerInfo = await _workerInfoService.UpdateWorkerIdentity(companyId, activeContractId, language, worker);
return Ok(workerInfo);
}
}
Good Evening Community,
I am having problems to post data to a C# Api from Angular 2 POST methods. Practically I need to send a JSON object to the API. Below is the API POST method that is the endpoint.
[HttpPost]
public Boolean Update(BoRole role, Guid accessToken)
{
CheckUserSuperadmin(accessToken);
string JsonContent = Request.Content.ReadAsStringAsync().Result;
var roleEntity = BaseDependencies.RoleManager.GetRoleById(role.Id);
roleEntity.Name = role.Name;
roleEntity.AuthorizedThreshold = role.AuthorizedThreshold;
BaseDependencies.RoleManager.UpdateRole(roleEntity);
return true;
}
The following is my Angular 2 service, with the POST method.
// Update the Role
updateRole(role: Role, accessToken: string): any {
const body: any = JSON.stringify(role);
const headers = new Headers({'Content-Type': 'application/json'});
const options = new RequestOptions({ headers: headers });
const url = this.serverUrl + '/api/Role/Update?role=' + body + '&accessToken=' + accessToken;
return this.http.post(url, body, options).map((res: Response) => res.json());
}
To explain better, I am trying to send a JSON object to this API, but whenever I try to POST to the API the role object remains null, never tried to POST data this way. Is it possible?
Thanks
Change the Api to get only one get one body
[HttpPost("Add")]
public async Task<IActionResult> Post([FromBody]AddRequest value)
In my case the class
AddRequest
Have all the body structure that I need, in your case create one class that C# can automap (same names) and the rest is history in C#
At Angular
const url = this.serverUrl + '/api/Role/Update?role=' + body +
'&accessToken=' + accessToken;
change it for
const url = this.serverUrl + '/api/CONTROLLERNAME';
C# will detect that is a Post Request and map it to the right Http Call
I have been testing all the Get,Create,Update methods with Postman in which the Get passes in nothing. The Create and Update passes in raw json with Activity object with several properties that do match up with the C# class
So this signature for Create and Update works fine
[HttpPost]
public IHttpActionResult UpdateActivity(Activity activity)
Above works with Postman passing in JSON content type with all the properties. I have done this on OTHER projects.
HOWEVER
I'm trying to simply pass in a string and it is null no matter what
public IHttpActionResult DeleteActivity([FromBody]string Id)
{
// delete
var del = ActivityService.DeleteActivity(Id);
return Ok(del);
}
Postman I tried MANY ways
http://localhost:49810/api/activityapi/deleteactivity
I have tried MANY many ways based on blogs and google search one such example
{ "Id" = "5808786fa3e9ec79546b3c71" }
I know this is an older question but I wanted to help those who might have a similar problem as I was able to get this working.
In WebAPI Controller my method is setup as
[HttpPost]
public IHttpActionResult Create([FromBody] int eventId)
{
....
}
In order to get this to test properly in Postman you have to: In body, set to raw, make sure JSON (application/json) is set and then just add value like 2 that's it.. not like { "eventId":2 } which is proper JSON just the value and then it will work.
So in original poster's case, in Postman, if you set Body to raw, JSON (application/json) then "5808786fa3e9ec79546b3c71" as value it will work.
In Postman ensure the body is set to raw and select json and in the body just write "your string" in quotes. Do not use {} to surround it because that is to make a complex object
Try the following in the body, with the content-type as application/json
{ "5808786fa3e9ec79546b3c71" }
As when you specify it like so, it will attempt to de-serialize into a complex type with a property of Id
{ "Id" : "5808786fa3e9ec79546b3c71" }
Old question, but for those still wondering, I would recommend sending your string as a query parameter. Take a method like this for example:
[AllowAnonymous]
[HttpGet("resendEmailConfirmtionLink")]
public async Task<IActionResult> ResendEmailConfirmationLink(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null) return Unauthorized();
var origin = Request.Headers["origin"];
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
var verifyUrl = $"{origin}/verifyEmail?token={token}&email={user.Email}";
var message = $"<p>Please click the below link to verify your email address:</p><p><a href='{verifyUrl}'>Click to verify email</a></p>";
await _emailSender.SendEmailAsync(user.Email, "Please verify email", message);
return Ok("Email verification link resent");
}
This method expects a key value pair of a string called email. You can send your request like "http://localhost:5000/api/account/verifyEmail?email=myemail#test.com" or, in Postman, add it as a parameter like this:
postman query params
Your payload is not valid.
Change-->
{ "Id" = "5808786fa3e9ec79546b3c71" }
To-->
{ "Id" : "5808786fa3e9ec79546b3c71" }
[HttpPost]
public IHttpActionResult Create(int eventId)
{
....
}
Use form-data instead of raw-json
Key - eventId
Value - "5808786fa3e9ec79546b3c71"
This worked for me.
We're working on developing an application that uses Plivo for sending and receiving SMS messages. For every request that Plivo sends, they also send a signature in the HTTP header so that we can verify the request came from Plivo and not from a random user.
https://www.plivo.com/docs/xml/request/#validation
To do this validation, we require the POST content as a query string (eg: To=15555555555&From=11234567890&TotalRate=0&Units=1&Text=Text!&TotalAmount=0&Type=sms&MessageUUID=2be622bc-79f8-11e6-8dc0-06435fceaad7).
Current solution
This is what we have so far:
private bool VerifyPlivo(object thing, HttpRequestMessage Request)
{
if (Request.Headers.Contains("X-Plivo-Signature"))
{
Dictionary<string, string> reqParams = (from x in thing.GetType().GetProperties() select x).ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(thing, null) == null ? "" : x.GetGetMethod().Invoke(thing, null).ToString()));
IEnumerable<string> headerValues = Request.Headers.GetValues("X-Plivo-Signature");
string signature = headerValues.FirstOrDefault();
return XPlivoSignature.Verify(Request.RequestUri.ToString(), reqParams, signature, plivoToken);
}
else
{
return false;
}
}
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
if (!VerifyPlivo(req, Request))
{
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}
... // do actual work here
}
This works by using the object that it maps to PlivoRecieveSMS and doing some reflection to get the properties and values, and sticking them in a Dictionary. This works well especially given our lack of the preferred solution...
Preferred solution
Right now, we require a model (PlivoRecieveSMS) to map the data, and then do introspection to find the key/values. We would like to move the logic to an extension of System.Web.Http.AuthorizeAttribute, so that we can do something as simple as:
[AuthorizedPlivoApi]
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
... // do actual work here
}
The actual authorization is done in AuthorizedPlivoApi - if it's not valid, the request never reaches the controller. But we cannot do this at the moment because we can't map it to a specific object inside of AuthorizedPlivoApi.
I would like to access the POST key's / values directly, or perhaps map it to a dynamic object that isn't pre-defined before hand. If I can do that, we can then achieve our preferred solution.
tl;dr: is there any way to push application/x-www-form-urlencoded data from a POST request into a Dictionary<string,string>() without using a specific model?