Call HTTP GET with JSON body content parameters - c#

How can I call HTTP GET using JSON parameters in content body?
I tried this:
HttpWebRequest.WebRequest.Create(_uri);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
httpWebRequest.Headers.Add("X-AUTH-TOKEN", _apiKey);
using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) {
string _json = "\"{\"filter\": {\"relation\": \"equals\", \"attribute\": \"state\", \"value\": \"CA\" }, \"insights\": {\"field\": \"family.behaviors\", \"calculations\": [\"fill_count\"]}}";
streamWriter.Write(_json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse();
using(var streamReader = new StreamReader(httpResponse.GetResponseStream())) {
var result = streamReader.ReadToEnd();
}
but it throws an exception:
"Cannot send a content-body with this verb-type."

If you use .NET core, the new HttpClient can handle this. Otherwise you can use System.Net.Http.WinHttpHandler package, but it has a ton of dependencies. See answer
https://stackoverflow.com/a/47902348/1030010
for how to use these two.
I can't use .NET core and I don't want to install System.Net.Http.WinHttpHandler.
I solved it by using reflection, to trick WebRequest that it is legal to send body with a GET request (which is according to latest RFC). What I do is to set ContentBodyNotAllowed to false for HTTP verb "GET".
var request = WebRequest.Create(requestUri);
request.ContentType = "application/json";
request.Method = "GET";
var type = request.GetType();
var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request);
var methodType = currentMethod.GetType();
methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write("<Json string here>");
}
var response = (HttpWebResponse)request.GetResponse();
Note, however, that the attribute ContentBodyNotAllowed belongs to a static field, so when its value changes, it remains in effect for the rest of the program. That's not a problem for my purposes.

It is entirely possible, but you have to use the newer HttpClient class: https://stackoverflow.com/a/47902348/70345

Even tho it is technically allowed to send a body with Get requests, Microsoft has decided for you that you cannot do that.
This can be seen in HttpWebRequest source code:
if (onRequestStream) {
// prevent someone from getting a request stream, if the protocol verb/method doesn't support it
throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
}
So you need to change your verb to Put or Post or have some other workaround.

GET will only receive it.
If you need to specify parameters, please include it in url.
Or you can send JSON BODY if POST or PUT.
HTTP request methods
HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. Although they can also be nouns, these request methods are sometimes referred as HTTP verbs. Each of them implements a different semantic, but some common features are shared by a group of them: e.g. a request method can be safe, idempotent, or cacheable.
GET
The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
HEAD
The HEAD method asks for a response identical to that of a GET request, but without the response body.
POST
The POST method is used to submit an entity to the specified resource, often causing a change in state or side effects on the server.
PUT
The PUT method replaces all current representations of the target resource with the request payload.
In Addition:
I found this. Long discussion has been held.
HTTP GET with request body
What this means is that it is possible to send BODY with GET, but sending a payload body on a GET request might cause some existing implementations to reject the request (such as Proxy in the middle of the route).
Please be sure to read this article carefully as there are many other points to pay attention to.
By the way, it seems that you can send GET with body using the -i option of cURL command.
Curl GET request with json parameter

Related

Creating and sending an HttpResponse message

Given either a url or a HttpResponse instance, I need to send back a HttpResponse (note Response not Request) with Status code 200. I've tried a generic HttpClient.PostAsync and GetAsync, but I can't configure the status code.
This is basically a handshake for subscribing to events for a remote service. I send a Request, get an OK back from the server and now it's expecting me to reply to the OK with my own OK.
Any ideas on how to go about this? I don't have an incoming request to respond to.
var resp = new HttpResponseMessage(HttpStatusCode.OK);
// need to sent this to the url. no content necessary.
Here's some things I cannot do:
var client = new HttpClient();
var resp = await client.GetAsync(url);
-------------------
var content = new ByteArrayContent(new byte[0]);
var client = new HttpClient();
var resp = await client.PostAsync(url, content);
When you invoke HttpClient calls you are creating HttpRequestMessages. There are a number of helper methods (like some PostAsync overloads or PostAsJsonAsync) which let you pass in a plain old C# object, which it then wraps for you. These values get set in the Content property of the HttpRequestMessage, wrapped by an instance of HttpContent. You're also perfectly free to create these request messages yourself, setting the status code and content to anything you like. HttpResponseMessage (note Response, not Request) is the type you'll get back from your client call, which you can use to read the response code or data sent back to you (stored in HttpResponseMessage.Content, not to be confused with HttpRequestMessage.Content, which you would have already set).
That said, you CAN set your request content to an instance of HttpResponseMessage, but that would be a little bit odd. Generally, the objects you use for your content should be simple objects which exist simply to define the shape of your requests' body (like JSON).
This article goes over the basics pretty well: Calling a Web API from a .Net Client
You should be able to set the status directly on the HttpResponse object
Something like this...
HttpResponse().StatusCode = 200;

WebRequest: Query string data vs x-www-form-urlencoded content

I am trying to call Google's OAuth2 authentication service as per these instructions: https://developers.google.com/accounts/docs/OAuth2ForDevices
I put all of the required parameters into the query string and sent the request. This worked for the "Obtaining a user code" section but not for the "Obtaining Access and Refresh Tokens" section.
After much playing around and getting 400 Bad Request errors, I found that, instead of putting the data in the query string, you can create a request with a FormUrlEncodedContent and send the data through as content with application\x-www-form-urlencoded Content-Type.
Here is the code before:
var requestMessage = new HttpRequestMessage();
requestMessage.Method = "POST";
requestMessage.RequestUri = new Uri(fullUrl);
Where fullUrl is something like:
https://accounts.google.com/o/oauth2/device/code?client_id=812741506391-h38jh0j4fv0ce1krdkiq0hfvt6n5amrf.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile
And the new code is:
var requestMessage = new HttpRequestMessage();
requestMessage.Method = "POST";
requestMessage.RequestUri = new Uri(url);
requestMessage.Content = new FormUrlEncodedContent(CreateDictionary(queryStringNames, queryStringValues));
Where url is:
https://accounts.google.com/o/oauth2/device/code
and queryStringNames and queryStringValues are string arrays of the names and values of the required parameters.
What is the difference between these two methods? Is it safe to assume that all POST calls can use the URL Encoded Content requests instead of putting the data in the query string?
In general, POST requests do not need query string but it is still subjected to Server's logic implementation. In case of OAuth which is quite known standard and they do follow good practice, it is safe to use form encoded data unless mentioned explicitly in API to send Parameter as query string.
Query String & Post data are two different set of parameters. If server is expecting Query string then you must send query string only. It all depends on how server side logic is implemented. You can not use them alternatively. Most API documentation specify clearly what are they expecting.

POST or GET method?

We have a service provider that allows us to connect to his payment page for payments, however the code he uses is php but we would like to do it in asp.net.
Problem is I don't really understand what the method should be, POST or GET, basically we need to redirect to the client with underlying parameters(not query strings) and then our current page that calls the request must be redirected to the client page with the parameters as well.
I do get the response witch is basically markup, but that's not what I want, I want it to redirect to the payment page, can someone please tell me what I do wrong.Thanks
Here is my code I use for the POST Method:
string query = string.Format("description={0}&amount={1}&merchantIdent={2}&email={3}&transaction={4}&merchantKey={5}",
description.ToString(), amount.ToString(), merchantIdent.ToString(), email.ToString(), id.ToString(), merchantKey.ToString());
// Create the request back
string url = "https://www.webcash.co.za/pay";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.AllowAutoRedirect = true;
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = query.Length;
req.AllowAutoRedirect = true;
StreamWriter stOut = new StreamWriter(req.GetRequestStream(),System.Text.Encoding.ASCII);
stOut.Write(query);
stOut.Close();
// Do the request
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
string response = stIn.ReadToEnd();
stIn.Close();
Not sure I totally understand your question, but as your title goes, here is the difference between POST and GET:
The GET method passes variables through the url. This can be practical or impractical (for instance if you plan to pass sensitive material to another page)
The POST method does not pass variables through the url, it passes the variables behind the scenes.
You'll need to decide which better fits your situation.
Normally GETs are idempotent (meaning they don't change data). Use a GET if you want to be able to issue a request and not change anything. Use a POST if you're performing some sort of update/processing/etc.

Is there any C# equivalent to the Perl's LWP::UserAgent?

In a project I'm invovled in, there is a requirment that the price of certain
stocks will be queryed from some web interface and be displayed in some way.
I know the "query" part of the requirment can be easily implemented using a Perl module like LWP::UserAgent. But for some reason, C# has been chosen as the language to implement the Display part. I don't want to add any IPC (like socket, or indirectly by database) into this tiny project, so my question is there any C# equivalent to the Perl's LWP::UserAgent?
You can use the System.Net.HttpWebRequest object.
It looks something like this:
// Setup the HTTP request.
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com");
// This is optional, I'm just demoing this because of the comments receaved.
httpWebRequest.UserAgent = "My Web Crawler";
// Send the HTTP request and get the response.
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
if (httpWebResponse.StatusCode == HttpStatusCode.OK)
{
// Get the HTML from the httpWebResponse...
Stream responseStream = httpWebResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string html = reader.ReadToEnd();
}
I'm not sure, but are you simply trying to make an HTTP Request? If so, you can use the HttpWebRequest class. Here's an example http://www.csharp-station.com/HowTo/HttpWebFetch.aspx
If you want to simply fetch data from the web, you could use the WebClient class. It seems to be quite good for quick requests.

HTTP Post in C# console app doesn't return the same thing as a browser request

I have a C# console app (.NET 2.0 framework) that does an HTTP post using the following code:
StringBuilder postData = new StringBuilder(100);
postData.Append("post.php?");
postData.Append("Key1=");
postData.Append(val1);
postData.Append("&Key2=");
postData.Append(val2);
byte[] dataArray = Encoding.UTF8.GetBytes(postData.ToString());
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("http://example.com/");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = dataArray.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(dataArray, 0, dataArray.Length);
requestStream.Flush();
requestStream.Close();
HttpWebResponse webResponse = (HttpWebResponse)httpRequest.GetResponse();
if (httpRequest.HaveResponse == true) {
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8);
String responseString = responseReader.ReadToEnd();
}
The outputs from this are:
webResponse.ContentLength = -1
webResponse.ContentType = text/html
webResponse.ContentEncoding is blank
The responseString is HTML with a title and body.
However, if I post the same URL into a browser (http://example.com/post.php?Key1=some_value&Key2=some_other_value), I get a small XML snippet like:
<?xml version="1.0" ?>
<RESPONSE RESULT="SUCCESS"/>
with none of the same HTML as in the application. Why are the responses so different? I need to parse the returned result which I am not getting in the HTML. Do I have to change how I do the post in the application? I don't have control over the server side code that accepts the post.
If you are indeed supposed to use the POST HTTP method, you have a couple things wrong. First, this line:
postData.Append("post.php?");
is incorrect. You want to post to post.php, you don't want post the value "post.php?" to the page. Just remove this line entirely.
This piece:
... WebRequest.Create("http://example.com/");
needs post.php added to it, so...
... WebRequest.Create("http://example.com/post.php");
Again this is assuming you are actually supposed to be POSTing to the specified page instead of GETing. If you are supposed to be using GET, then the other answers already supplied apply.
You'll want to get an HTTP sniffer tool like Fiddler and compare the headers that are being sent from your app to the ones being sent by the browser. There will be something different that is causing the server to return a different response. When you tweak your app to send the same thing browser is sending you should get the same response. (It could be user-agent, cookies, anything, but something is surely different.)
I've seen this in the past.
When you run from a browser, the "User-Agent" in the header is "Mozilla ...".
When you run from a program, it's different and generally specific to the language used.
I think you need to use a GET request, instead of POST. If the url you're using has querystring values (like ?Key1=some_value&Key2=some_other_value) then it's expecting a GET. Instead of adding post values to your webrequest, just put this data in the querystring.
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("http://example.com/?val1=" + val1 + "&val2=" + val2);
httpRequest.Method = "GET";
httpRequest.ContentType = "application/x-www-form-urlencoded";
....
So, the result you're getting is different when you POST the data from your app because the server-side code has a different output when it can't read the data it's expecting in the querystring.
In your code you a specify the POST method which sends the data to the PHP file without putting the data in the web address. When you put the information in the address bar, that is not the POST method, that is the GET method. The name may be confusing, but GET just means that the data is being sent to the PHP file through the web address, instead of behind the scenes, not that it is supposed to get any information. When you put the address in the browser it is using a GET.
Create a simple html form and specify POST as the method and your url as the action. You will see that the information is sent without appearing in the address bar.
Then do the same thing but specify GET. You will see the information you sent in the address bar.
I believe the problem has something to do with the way your headers are set up for the WebRequest.
I have seen strange cases where attempting to simulate a browser by changing headers in the request makes a difference to the server.
The short answer is that your console application is not a web browser and the web server of example.com is expecting to interact with a browser.
You might also consider changing the ContentType to be "multipart/form-data".
What I find odd is that you are essentially posting nothing. The work is being done by the query string. Therefore, you probably should be using a GET instead of a POST.
Is the form expecting a cookie? That is another possible reason why it works in the browser and not from the console app.

Categories

Resources