Difference between RestSharp methods AddParameter and AddQueryParameter using HttpGET - c#

I'm using RestSharp to call an external API.
This works:
var client = new RestClient(apiUrl);
var request = new RestRequest(myurl, Method.GET);
foreach (var param in parameters)
{
request.AddQueryParameter(param.Key, param.Value);
}
var response = client.Execute(request);
This doesn't:
var client = new RestClient(apiUrl);
var request = new RestRequest(myurl, Method.GET);
foreach (var param in parameters)
{
request.AddParameter(param.Key, param.Value);
}
var response = client.Execute(request);
Resulting in:
System.Exception: API Call MyWebAPIMethod GET: Failed with status code
0 - Unable to connect to the remote server
What's the difference between AddParameter and AddQueryParameter?
According to the documentation they should function the same when using HttpGET and according to Fiddler they seem to generate the same URL as well.

To answer your question
AddQueryParameter adds a parameter in the query string as ParameterType.QueryString whereas AddParameter(string, object) adds the parameter as ParameterType.GetOrPost
For more details on each parameter type, see:
GetOrPost: https://github.com/restsharp/RestSharp/wiki/ParameterTypes-for-RestRequest#getorpost
QueryString: https://github.com/restsharp/RestSharp/wiki/ParameterTypes-for-RestRequest#querystring
To solve your problem
It seems it is unrelated to the type of parameter, because the exception thrown seems to indicate you aren't even connecting to the remote server.
make sure you pass the same apiUrl / myUrl in both cases.

To answer the OP and anyone else who might have trouble with the concept.
It took me awhile to get around to the concept.
You probably need to visualise the RESTful standard of how to construct a GET request message in a url against constructing for a POST request message.
You will notice that for GET , the parameter(s) are attached to the URL header
whereas for the POST , the parameter(s) are placed in the body of the message.
RestSharp 's method AddQueryParameter() will only add the (Query) parameters in the header of the message, whereas the AddParameter() will only add the parameters to the mesasge body. As demonstrated below the GET has one query parameter with a value of "Flavours" . For the POST , the parameters contact_name and company_name are located in the bottom of the message body.
Eg:
GET message format :
GET http://www.consumerdiarydemo.cbrnetwork.test.au/api/ConsumerDiary/getSizesOrFlavours/Flavours HTTP/1.1
Host: www.consumerdiarydemo.cbrnetwork.test.au
Connection: keep-alive
Accept: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Referer: http://www.consumerdiarydemo.cbrnetwork.test.au/ConsumerDiaryPage2template
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
POST message format :
POST
http://localhost:1234567/api/customers HTTP/1.1
Accept: application/json, text/javascript, /; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
{"contact_name":"value_data1","company_name":"value_data2"}

AddParameter / Get or Post
GetOrPost behaves differently based on the method. If you execute a GET call, RestSharp will append the parameters to the Url in the form url?name1=value1&name2=value2.
On a POST or PUT Requests, it depends on whether you have files attached to a Request. If not, the Parameters will be sent as the body of the request in the form name1=value1&name2=value2.
Ref: https://restsharp.dev/usage.html#get-or-post
AddQueryParameter / Query String
QueryString works like GetOrPost, except that it always appends the parameters to the url in the form url?name1=value1&name2=value2, regardless of the request method.
Ref: https://restsharp.dev/usage.html#query-string

Related

Return Unauthorized (401) only when calling from code (c#)

UPDATE
As #Alexandru Clonțea suggested, I checked the fiddler log and found:
In both success or fail cases, there are actually 2 requests being sent. The first request are mostly the same for both cases, it's something like:
GET http://myservice.com/handler?param1=something&param2=somethingelse HTTP/1.1
Authorization: Basic xxxxxx
Accept: application/json, application/xml, text/json, text/x-json,
text/javascript, text/xml
User-Agent: RestSharp/100.0.0.0
Host: myservice.com
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
The response for them are the same, which is:
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=utf-8
Location: /handler/?param1=something&param2=somethingelse
Date: Sat, 08 Sep 2018 01:50:16 GMT
Content-Length: 115
Moved Permanently.
I have noticed that it always try to redirect the call to /handler/?param1=something&param2=somethingelse, and that's because of the setup of the server code. it's actually working as expected. The difference is in the second request. The second request of the failure case (which is the c# code) doesn't have the authorization header and that's why it failed. Now, my question will be, why does the second request miss the authorization header? How can I fix it? Below is an example of the failed request:
GET http://myservice.com/handler/?param1=something&param2=somethingelse HTTP/1.1
Accept: application/json, application/xml, text/json, text/x-json,
text/javascript, text/xml
User-Agent: RestSharp/100.0.0.0
Accept-Encoding: gzip, deflate
Host: myservice.com
Backgroud:
I have a service written in GO deployed on a server. It requires a basic authentication. For example, I can call it successfully with the following request:
GET /handler/?
param1=something&param2=somethingelse HTTP/1.1
> Host: myservice.com
> Authorization: Basic xxxxxx
> User-Agent: RestClient/5.16.6
> Accept: */*
The request above is made by a rest api client tool (like postman), and it's working fine. It's also working fine if I call it from a browser.
Problem:
Now, I try to make the same call to the same service using c# code, and I have it as:
// pass cert validation
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
HttpClient client = new HttpClient();
var byteArray = Encoding.ASCII.GetBytes(username + ":" + password);
var auth = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = auth;
var response = client.SendAsync(request).Result; // don't need async
But in this case, I am getting Unauthorized (401) back. I have checked into the actually request that was sent by the code, it had exactly the same authorization header as the one shows above (Authorization: Basic xxxxxx, and the xxxxxx is the same as above) and same uri as well. Actually, everything it sent looks the same as when I used the rest api client tool, but it was just failed in code.
when I check the log on the server side, I see the log below when it returns 401:
[GIN-debug] redirecting request 301: /handler --> /hanlder/?param1=something&param2=somethingelse
but I don't see this log when the call is from the rest api client tool (or browser)
As you may know from the log, the server-side code is using the go gin framework. But since it works fine in other cases, I don't think it's a problem with the server-side code.
Back to the C# code, I have tried to use the HttpWebRequest with NetworkCredential instead of the HttpClient, and I also try to use client.DefaultRequestHeaders.Authorization = auth, but I was still getting the same error.
I am wondering if someone has seen this before or could help? It will be really appreciated.
As a workaround, I can modify the request to be http://myservice.com/handler/?param1=something&param2=somethingelse so that no redirection is needed. Thus, it will be correctly authorized.
But still, haven't figure out how to make the second request to be sent with the authorize header yet.

Processing a POST request in controller with a Parameter and encoded XML file

I was wondering if I could get some help with this. A service is sending a POST request to my controller and I am trying to get the encoded URL so I can store the information in my database. Unfortnately I dont know exaclty what type of object it is I can use in order to refer to this encoded XML
This is the feed that is being sent by the service to my controller method:
POST https://localhost:44300/efile/GeneratingXMLFormResponse HTTP/1.1
Host: localhost:44300
Connection: keep-alive
Content-Length: 563
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: https://togatest.efiletexas.gov
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: https://togatest.efiletexas.gov/epayments/webs/EPaymentConfirmation.aspx
Accept-Encoding: gzip, deflate
Accept-Language: es,en-US;q=0.8,en;q=0.6
Cookie: _jsuid=1589536271; _okdetect=%7B%22token%22%3A%2214383525196380%22%2C%22proto%22%3A%22https%3A%22%2C%22host%22%3A%22localhost%3A44300%22%7D; _ok=9593-948-10-2895; .AspNet.ApplicationCookie=5vYkwGx8d4ALu7qNAHeDHrhm7VIfQXZ_xMqp8ns4Xt9UlklBWBcqjuRy_hv5hRtaTM8ZD08EXrvzusa4qooq_svaxPJC41PAx3mGPsLHR3cYbW0QpK0PNX5vNi0fNMlS7vKRcGDIpRjr2DSCBWY8XWBFihko2EBWxOdKrt-LK5-z6jauQrfrwWyGeHIsab9BHYr30iAfeOxrkvIVj9vguw7R6Gd9YPEpjgso3TdGc7tyQLv4FF0WB2dKzmv-5LkVIYp39QcGDyyXAJ79Z93JK1WYeF0flnI9gKYljyrvJaDfCFBBipanV2kY8h11RRqkPuI4KK3uXFjQbR4sh7zQHcCSLX37tAkwMLZUcVAm7V_KHPQhpEIH5F68tHivbE2zFk-uRq0_eASb9QMnxxIs8y2XL9ThRew4Z5DXToZrB4lUCFim0T1LGyOq7z5XvII-_N_jKic-M1X3O_pYN-heQWhwxlJN-QMEzdo7w4n_9t2PwL5Dzf9gtn01nqw2dV9oXAxhi_arkZ9vvjbe0WYYJg; _okac=5ad74dff9c0fd7f739a94f0c8e47f538; _okla=1; _okbk=cd5%3Davailable%2Ccd4%3Dtrue%2Cvi5%3D0%2Cvi4%3D1438875502265%2Cvi3%3Dactive%2Cvi2%3Dfalse%2Cvi1%3Dfalse%2Ccd8%3Dchat%2Ccd6%3D0%2Ccd3%3Dfalse%2Ccd2%3D0%2Ccd1%3D0%2C; heatmaps_g2g_100855693=no; _ga=GA1.1.845327345.1433349177; _gat=1; _oklv=1438876103374%2Ca8VFkRUOPj95wlmt5R2JW7AJFUNQE0Ib; calltrk_referrer=direct; calltrk_landing=https%3A//localhost%3A44300/Efile; calltrk_session_swap_numbers_215746334=5123841992%3D8775996483; clicky_olark=9593-948-10-2895,W23FqlSrwPRFNA555R2JW1Z3JUQ0EHN1,a8VFkRUOPj95wlmt5R2JW7AJFUNQE0Ib; _first_pageview=1; calltrk_session_id_215746334=acab75bc-fb76-4073-bc6a-1d4b5115975c; olfsk=olfsk03380024363286793; wcsid=a8VFkRUOPj95wlmt5R2JW7AJFUNQE0Ib; hblid=W23FqlSrwPRFNA555R2JW1Z3JUQ0EHN1
ResponseXML=%3CPaymentResponse%3E%3CClientKey%3ECJOFSTEXFILE%3C%2FClientKey%3E%3CTransactionID%3E44077405%3C%2FTransactionID%3E%3CAmount%3E-1.00%3C%2FAmount%3E%3CReferenceNumber%3E%3C%2FReferenceNumber%3E%3CPayorToken%3E54230445%3C%2FPayorToken%3E%3CPayorName%3EMarco+A+Lostaunau%3C%2FPayorName%3E%3CTenderDescription%3EDISCOVER+XXXXXXXXXXXX0000%3C%2FTenderDescription%3E%3CExpirationMonth%3E5%3C%2FExpirationMonth%3E%3CExpirationYear%3E2018%3C%2FExpirationYear%3E%3CPaymentTimestamp%3E8%2F6%2F2015+10%3A49%3A17+AM%3C%2FPaymentTimestamp%3E%3C%2FPaymentResponse%3E
As you can see the ResponseXML parameter is set to an encoded XML. I need to extract this information from this parameter decoded, deserialize it and take some of the nodes.
This is my controller method:
public ActionResult GeneratingXMLFormResponse(XmlDocument xmlResponse)
{
var form = xmlResponse;
return View("EfileView");
}
The xmlResponse does not have the information that I need.
What object can I use in order to refer to the parameter ResponseXML?
Hey guys I figured out how to do this.
If your parameter and XML are coming in the body of your resposen you can receive it in your controller method as a string. After receiving the string you can transform that string into an XML like so:
[HttpPost, ValidateInput(false)]
public string GeneratingXMLFormResponse(string responseXML)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(responseXML);
}

WebView NavigateWithHttpRequestMessage Post is not delivered to the webserver

This is a follow-up question to the suggestion of user #Kiewic to make a post request using a webview: Post data with a request in a Windows Store app WebView - using C#
So I am using this code
// defined before: string uri, User user
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));
request.Content = new HttpStringContent(
String.Format(
"language={0}&session_id={1}&user_id={2}",
Text.GetLanguage(),
user.session_id,
user.user_id.ToString()
),
Windows.Storage.Streams.UnicodeEncoding.Utf8,
"application/x-www-form-urlencoded"
);
webView.NavigateWithHttpRequestMessage(request); // webView defined in xaml
Fiddler shows me this request:
POST http://mobile.mysite.com/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US,en;q=0.8,de-CH;q=0.5,de;q=0.3
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; SMJB; WebView/2.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: mobile.mysyte.com
Content-Length: 101
Connection: Keep-Alive
Pragma: no-cache
Cookie: _ga=GA1.2.769009833.1387593479; PHPSESSID=nk6b04rb7d7vu4vmm2ish7l0o4
language=en&session_id=fhihferihguiegierewfrefghxrfer&user_id=1
The webserver technology is PHP, so I used this code to print the post content
<?php
var_dump($_POST);
?>
But the result is an empty array. So where is my mistake?
According to a Microsoft employee there is a bug with setting the headers of the request content. This should mean that nothing is wrong with my code in the first post:
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/7deaf4ba-611f-4957-af3c-9b2b2e1e1b8b/webviewnavigatewithhttprequestmessage-set-contenttype?forum=winappswithcsharp
This means you cannot really use NavigateWithHttpRequest and you should use another approach to post data. User #Kiewic made a suggestion which works on Windows 8 too:
Post data with a request in a Windows Store app WebView - using C#

Passing post parameters to action methods in asp.net mvc?

I'm new to asp.net mvc. I'm having some trouble getting the values of parameters in my Action methods.
I have the following code:
[HttpPost]
public ActionResult ToggleRecommend(string mode)
{
byte[] requestContent = new byte[Request.ContentLength];
Request.InputStream.Read(requestContent, 0, Request.ContentLength);
string content = Encoding.ASCII.GetString(requestContent);
return EmptyResult();
}
I access this method using an Ajax request. The request has these headers:
Accept application/json
Accept-Encoding gzip, deflate
Accept-Language en-gb,en;q=0.5
Connection keep-alive
Content-Length 8
Content-Type text/plain; charset=UTF-8
Host localhost:62718
Referer http://localhost:62718/microsite
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1
X-Request JSON
X-Requested-With XMLHttpRequest
and this body:
mode=off
My problem is that the mode parameter of ToggleRecommend is not being populated with the value from the request - instead, it is null.
The request is reaching my server correctly: the variable content in the method has the value mode=off and Request.ContentLength is 8 as expected. Also, Request.RequestType is "POST", as is intended. However, Request.Form is empty: it has no keys or values. (I don't know if that is relevant).
What is going wrong here? How do I get the value of my mode parameter to go into my action method?
The problem must be to do with post: If I remove the HttpPost attribute and do a request to the Url localhost:62718/microsite/toggleRecommend/?mode=off the mode parameter gets the value off as is intended.
Edit:
The request is being made with javascript using the Mootools library. I've included that part of the code below:
var req = new Request.JSON({ method: "post",
url: "/microsite/toggleRecommend/" ,
autoCancel: true, urlEncoded: false, secure: false,
onFailure: recommendFail, onException: recommendFail,
onSuccess: recommendSuccess
});
req.send({ data: { mode: 'on'} });
Using firebug, I can see the exact format of the request (and that looks fine) so hopefully the specifics of the javascript code doesn't matter.
Your ajax call content/type is text/html, you need to specify to your controller that you are sending application/json information, otherwise he receives the info, but doesn't know how to distribute it to it's params

How to set Accept and Accept-Language header fields?

I can set Request.Content-Type = ... , Request.Content-Length = ...
How to set Accept and Accept-Language?
I want to upload a file (RFC 1867) and need to create a request like this:
POST /test-upload.php.xml HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 5.2; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: tr-tr,tr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-9,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------21724139663430
Content-Length: 56048
Take a look at Accept property:
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create(myUri);
myHttpWebRequest.Accept="image/*";
HttpWebResponse myHttpWebResponse=
(HttpWebResponse)myHttpWebRequest.GetResponse();
This MSDN article shows how to add custom headers to your request:
//Get the headers associated with the request.
WebHeaderCollection myWebHeaderCollection = myHttpWebRequest.Headers;
//Add the Accept-Language header (for Danish) in the request.
myWebHeaderCollection.Add("Accept-Language:da");
//Include English in the Accept-Langauge header.
myWebHeaderCollection.Add("Accept-Language","en;q=0.8");
When you want to set the Accept type and content type, just cast the webrequest to HttpwebRequest
var webreq= (HttpWebRequest)WebRequest.Create(requestUri);
webreq.Method = "POST";
webreq.Accept = "application/json";
webreq.ContentType = "application/json";
You need to be sure that you type cast the request to (HttpWebRequest), where the accept header property is available.
In the old WebRequest class, the Accept header is not accessible.
I have to confirm after several annoying attempts to use the headers that the
myWebHeaderCollection.Add("foo","bar"); solution works perfectly.
if you want to set the Language.
myWebHeaderCollection.Add("AcceptCharset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
myWebHeaderCollection.Add("TransferEncoding", "gzip,deflate");
Does not set the values however. Which may seem like a logical conclusion given the first one works.
If you are using HttpRequestMessage, set the header using Headers.Add method. In your case :
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
In a case where I have the pleasure of maintaining 15 year old vb.NET 3.5 code, this workaround was successful for me:
webReq = WebRequest.Create(apiHost)
CType(webReq, HttpWebRequest).Accept = "application/json"

Categories

Resources