Reading the post body directly - c#

I am using Google's re-captcha v2 and Google's Javascript at run time generates a form parameter, with the key g-recaptcha-response, dynamically. The markup is this:
<form method="post">
<div class="g-recaptcha" data-sitekey="6LcXjGYUAAAAA...g1UKiZ"></div>
<input type="submit" id="submit" value="Enter" />
</form>
<script src='https://www.google.com/recaptcha/api.js'></script>
You will notice that there is no <input> element with name g-recaptcha-response as it is generated by the Javascript dynamically. (Note: the above won't work for you as-is as the page url must match what has been configured at Google using data-sitekey.)
Upon clicking Submit, the request body is like this:
g-recaptcha-response=03AEMEkE....nLXmlhwEE&__RequestVerificationToken=CfDJ8Oe....93pb
I don't know how to use a model for such a scenario. So I am trying to read the request body directly using the following code:
public async Task<IActionResult> OnPostAsync()
{
String result;
using (StreamReader reader = new StreamReader(Request.Body)) {
result = await reader.ReadToEndAsync();
return RedirectToPage("/test");
}
}
The result is always an empty string, even though I can see that there is data from inspecting the Http stream. Are there any errors in the above code? It compiles and runs without error.
Or is there a built-in class or method that can return the post data in, say, Json?

...is there a built-in class or method that can return the post data in, say, Json?
Your example is posting form url encoded data. The built-in [FromForm] attribute can bind that to a Dictionary<string, string> model. Newtonsoft can convert that model to JSON for server side use, and a JsonResult can convert that model to JSON for client-side use.
[HttpPost]
public IActionResult Post([FromForm] Dictionary<string,string> model)
{
// convert to JSON
var json = Newtonsoft.Json.JsonConvert
.SerializeObject(model, Newtonsoft.Json.Formatting.Indented);
Console.WriteLine(json);
// return JSON
return new JsonResult(model);
}
If we receive a post like this...
POST http://localhost:5000/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:5000
Content-Length: 85
Content-Type: application/x-www-form-urlencoded
g-recaptcha-response=03AEMEkE....nLXmlhwEE&__RequestVerificationToken=CfDJ8Oe....93pb
...we will then see the following console output.
{
"g-recaptcha-response": "03AEMEkE....nLXmlhwEE",
"__RequestVerificationToken": "CfDJ8Oe....93pb"
}

Related

HttpClient POST with data

I got a form where user will insert data and save it to the database. After save, it will do a post with data to the URL(RequestURL) given. This RequestURL will analyze the data and pass back the result to the different URL(ResponseURL). Below is the simple code for it.
public class RequestSender
{
private static HttpClient _client;
public RequestSender()
{
if (_client== null)
{
_client= new HttpClient();
_client.BaseAddress = new Uri("https://example.com/api/");
}
}
[HttpPost]
public async Task<string> SaveData()
{
// get data from the form
// save the data
// Save data is easy, already done it
// Here is the problem
// after save the data, it will send a post to the default URL
var response = await _client.PostAsync(path);
return "OK";
}
}
I'm using httpclient, but the problem is I only get the response of the post. What I want is, it will post data and redirect to the URL like an action attribute in the form below. So, the URL will handle the data and pass back to the ResponseURL. Appreciate your help.
<form action="https://example.com/api/" method="post">
Actually I try to integrate the payment gateway. Here is the flow:
User submit form, save to the database.
After form save success, will have another post from backend to the URL (Payment site).
Payment site will handling the post data and send back to the ResponseURL.
Here I will read the response and handling it based on the response.
Actually, this can be done by submitting another form from client side, but instead of doing that, i try to post within the first form (save data).
You can return RedirectResult from action
[HttpPost]
public async Task<string> SaveData()
{
// some code
var response = await _client.PostAsync(path);
return Redirect("https://example.com/api/");
}
If you want HttpClient.PostAsync() with the data , you could try the below code :
[HttpPost]
public async Task<string> SaveData()
{
//Since the API will need the new data in JSON format
//therefore I am serializing the data into JSON and then converting it to a StringContent object
StringContent content=new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json" );
//The StringContent object is then added to the API request by adding it to the 2nd parameter of the PostAsync() method.
var response = await _client.PostAsync(path ,content);
var content= response.Content.ReadAsStringAsync().Result;
return "OK";
}
Reference : https://www.yogihosting.com/aspnet-core-consume-api/
This part you have it already
1- User submit a form, save to the database.
2/3- After form save success, will have another post from the backend to the URL (Payment site). Payment site will be handling the post data and send back to the ResponseURL.
This can be done in 2 different ways, you do that using an HttpClient as #Alexander suggested
var response = await _client.PostAsync(paymentUrl);
var responseModel = JsonConvert.DeserializeObject<ResponseModelDto>(json)
var returnUrl = responseModel.ReturnUrl
Or you need to do it from your front end, doing an async post to the PaymentPage and process the response (ResponseUrl) via javascript.
4 - Here I will read the response and handling it, based on the response.
With the response, you can redirect you can do anything you need
var returnUrl = responseModel.ReturnUrl;
return Redirect(returnUrl);
But there are some integrations with payment websites, that you normally redirect the user passing parameters via a post or a get. The website handles the request as part of the querystring or as part of the body from your post, you should send as well a returnUrl, where they will send any information(Dto) back to be processed it from your side. But that will depend on your specific scenario.
Hope this clarifies your doubts

AspNetCore Mvc always returns a JSON object

I faced out with an issue in Asp Net Core.
I can not return a file as blob data, but not as JSON object with encoded content to base64.
Here my code in C#:
[Route("DownloadExcel")]
[HttpPost]
public async Task<FileContentResult> DownloadExcel([FromBody] Queries.In.Pages.Users.ExportToExcel.InModel model)
{
//some logic to retrieve an array of bytes.
var filename = $"myFile_{DateTime.Now:yyyyMMdd_hh_mm}.xlsx";
return File(byteArray, "octet/stream", filename);
}
In Angular 6 side:
this.httpClient.post(url, model, {headers: headers, responseType: 'blob'} )
.subscribe(res => {
let blob = new Blob(["\ufeff", response], {type: 'octet/stream'});
saveAs(blob, '111.xlsx');
})
What's the result I see in my browser response tab?
and the headers:
Whats wrong in my project and how to modify it to retrieve a blob but not JSON?
Thanks in advance!
In ASP.NET Core, you need to be using an IActionResult if you are sending a custom response. All other responses will be serialized (JSON by default) and sent as response body.
Refer to the answer at File Streaming in ASP.NET Core

string value is Empty when using FromBody in asp.net web api

I am using asp.net core web api. below is my simple post function which is having a single string parameter. The problem is when I use [FromBody] the string stays null. I am using PostMan to test my service. I want raw data to pass from client to my controller. In Postman I am selecting body type RAW and
I set the header Content-Type text/plain. The Raw Body contains Just "Hello World" string.
[HttpPost]
[Route("hosted-services/tokenize-card")]
public IActionResult Test([FromRoute]decimal businessKey,[FromBody] string body)
{
var data = businessKey;
return new JsonResult("Hello World");
}
Like the doc says :
When a parameter has [FromBody], Web API uses the Content-Type header
to select a formatter.
Only XML and JSON content-types are supported by default. So you need to use application/xml, application/json or register a custom IInputFormatter.
Next, you need to send a content that match the selected content-type.
For json, if the parameter is int send a number. If it's a class, send a json object. If it's a string, send a json string. Etc.
int => 14
string => "azerty"
class => { "propName" : "value" }
Array => []
... => ...
In your case you should send application/json content-type and as content :
"Hello string"
And not just
Hello string
Aspnet core json input formatter implementation
Aspnet core xml input formatter implementation
Example: Creating a CSV Media Formatter
I did make it work by passing as row data in PostMan. Do not forget to add "="
sign as prefix in to the values.
public string Post([FromBody]string value)
{
return value;
}
Frombody means that get body directly.it is not necessary to use variable and value pairs.
For Example:
Your controller is like this.
[HttpPost]
public IActionResult GetStringFromBody([FromBody] string token)
{
...
}
False:
True:

No parameterless constructor defined when POST request in JSON Content Type with ASMX Web Service

As title,
When I use fiddler to test the page -
http://localhost:59583/JSONtest.asmx/Test
Content-Type: application/json; charset=utf-8
and my request body is
{"header":{"sig":"abcdefg","timestamp":"2016-03-25T04:25:09.8395853Z"}}
It will response back to this error message:
No parameterless constructor defined for type of \u0027System.String\u0027
But if I put the JSON format with backslashes:
{"header":"{\"sig\":\"abcdefg\",\"timestamp\":\"2016-03-25T04:25:09.8395853Z\"}"}
The response will show the result I want which is correct.
How do I insert without backslashes JSON format?
This is my asmx code.
[WebMethod]
[ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json)]
public string Test(string header)
{
return header;
}
That is because "header" in your first snippet is a class with properties, not a single string as in your code. The error message is just confusing in my opinion.
The second snippet does have just one string as value for "header", so that would be fine. If you really want "header" to be an object, you have to make a separate class for it in order to get it serialized right.
before sending the Ajax post request You can wrap both header object and it's value inside JSON.stringify()
var myHeader = {"header":JSON.stringify(headerValue)};
var myParams = JSON.stringify(myHeader);
then you can send the myParams variable as the data parameter into the ajax request
$.ajax('url',data:myParams .....

Content negotiation to return HTML

After reading this blog post on how to return HTML from Web API 2 using IHttpActionResult, I wanted to somehow "wire-up" this IHttpActionResult to my ApiController based on the Accept header that is sent with request.
Given controller actions that have signature similar to this:
public MyObject Get(int id)
{
return new MyObject();
}
If the request specifies the Accept: text/html, this IHttpActionResult should be used to return HTML. Is that possible? In addition, some insight on how this content negotiation pipeline works for json or xml (that have built-in support) would be greatly appreciated.
If we keep the discussion of IHttpActionResult aside for a momment, Content-negotiation process in Web API is driven through formatters. So you would need to create a new formatter for handling the media type text/html.
Web API exposes the default algorithm it uses for content-negotiation called DefaultContentNegotiator which is an implementation of the service IContentNegotiator.
Now this negotiation algorithm can be run either by Web API automatically for you like in the following cases:
Usage # 1:
public MyObject Get(int id)
{
return new MyObject();
}
OR
you can manually run the negotiation yourself like in the following:
Usage #2 :
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage();
IContentNegotiator defaultNegotiator = this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult negotationResult = defaultNegotiator.Negotiate(typeof(string), this.Request, this.Configuration.Formatters);
response.Content = new ObjectContent<string>("Hello", negotationResult.Formatter, negotationResult.MediaType);
return response;
}
Regarding IHttpActionResults:
In the following scenario, Ok<> is a shortcut method for generating an instance of type
OkNegotiatedContentResult<>.
public IHttpActionResult Get()
{
return Ok<string>("Hello");
}
The thing is this OkNegotiatedContentResult<> type does similar thing as in Usage # 2 scenario above. i.e they run the negotiator internally.
So to conclude, if you plan to support text/html media type then you need to write a custom formatter and add it to Web API's formatter collection and then when you use Ok<string>("Hello") with an Accept header of text/html, you should see the response in text/html. Hope this helps.

Categories

Resources