I'm consuming a Web API of an internal system in the company.
It's getting a payload in JSON format and returning a response with data in JSON format.
When sending the request with Postman, it returns the expected response (StatusCode=200 + a response text in JSON format). That means that everything is OK with the web service.
Now I have to develop an application in C# to send this HTTP request.
The problem is, that I receive as response content "OK" and not the expected JSON response gotten with Postman.
public HttpWebResponse SendRequest(string url, string checkOutFolder, string drawingNo, string login, string password)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
request.Accept = "application/json";
string payload = GeneratePayLoad(checkOutFolder, drawingNo);
string header = CreateAuthorization(login, password);
request.Headers[HttpRequestHeader.Authorization] = header;
request.ServicePoint.Expect100Continue = false;
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(payload);
}
// Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string responseContent = rd.ReadToEnd();
Console.WriteLine(responseContent);
}
return response;
}
Has anyone already experiences something similar.
Can you help me?
EDIT
Following your suggestions
1) Changed the method to POST -> result is still the same
2) Used Postman's code generator and RestSharp -> result is still the same
public void Request(string url, string checkOutFolder, string drawingNo, string login, string password)
{
var client = new RestClient(url);
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic **********");
var body = GeneratePayLoad(checkOutFolder, drawingNo);
request.AddParameter("application/json", body, ParameterType.RequestBody);
var response = client.Execute(request);
Console.WriteLine(response.Content);
}
Changed to HttpClient -> result still the same
using (var client = new HttpClient())
{
string uri = "******************";
string path = "destinationpath";
var endpoint = new Uri(uri);
string payload = GeneratePayLoad(path, "100-0000947591");
//FormUrlEncodedContent form = new FormUrlEncodedContent(payload);
var stringContent = new StringContent(payload);
var payload2 = new StringContent(payload, Encoding.UTF8, "application/json");
var byteArray = Encoding.ASCII.GetBytes("*******");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(client.DefaultRequestHeaders.Authorization.ToString()));
var result = client.PostAsync(endpoint, stringContent).Result.Content.ReadAsStringAsync().Result;
Console.WriteLine("test");
}
Wrote a Python code using requests Package -> delivers the same as Postman. So the problem is in the C# code.
Does anyone have an idea what is going on?
SOLVED
The issue was on the payload generation!
The request needs to be an HTTP POST and not HTTP GET because it contains JSON payload.
request.Method = "GET"; should be request.Method = "POST";
That would be one of the issue(s). I am not sure if there is something else that is wrong, but try changing the request method to POST and try again.
Related
I've got a section of code to do a call to an external webapi using WebRequest. I'm trying to update it to use RestSharp instead. What am I missing here to make the conversion? The closest question here to give any sort of idea what might be going on is found in Calling webapi method gives 404. The "answer" was a missing accepted content type. I've verified through the RestClient the types are present (and appear valid).
Common request JSON
var statusRequest = #"
{
""auth"": {
""type"": ""basic""
},
""requestId"": ""15"",
""method"": {
""name"": ""getStatus"",
""params"": {
""showAllStatus"": ""0""
}
}
}
";
WebRequest code
var webRequest = WebRequest.Create("https://service.url/api/status") as HttpWebRequest;
webRequest.Method = "POST";
var username = "user";
var password = "pass";
var encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")
.GetBytes(username + ":" + password));
webRequest.Headers.Add("Authorization", "Basic " + encoded);
var requestWriter = new StreamWriter(webRequest.GetRequestStream());
webRequest.ContentType = "APPLICATION/JSON; CHARSET=UTF-8";
requestWriter.Write(statusRequest);
requestWriter.Close();
var responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
var responseData = responseReader.ReadToEnd();
responseReader.Close();
Should convert to RestSharp as
var client = new RestClient("https://service.url");
client.Authenticator = new HttpBasicAuthenticator("user", "pass");
var request = new RestRequest("api/status", Method.Post);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(statusRequest);
client.BuildUri(request);
var response = await client.GetAsync(request);
EDIT: Make the RestRequest a POST
Please read the docs.
Also, you are calling GetAsync. Even if you set the request method to Method.Post, calling GetAsync will override it.
This will work:
var request = new RestRequest("api/status")
.AddStringBody(statusRequest, DataFormat.Json);
var response = await client.PostAsync(request);
I try to convert HttpWebRequest to HttpClient but without success.
Can anybody help me?
It is my simple code with HttpWebRequest:
string url = "https://www.somesite.com/Service";
string postData = "text to send";
var data = Encoding.ASCII.GetBytes(postData);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "POST";
request.Proxy = null;
request.AllowAutoRedirect = false;
request.UserAgent = "Mozilla/5.0";
request.ContentType = "text/x-gwt-rpc; charset=UTF-8";
request.Headers.Add("Cookie", SetCookie);//get it after login
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseText = reader.ReadToEnd();
I think you can convert you HttpWebRequest based code to HttpClient based like this:
string url = "https://www.somesite.com/Service";
string postData = "text to send";
var data = Encoding.ASCII.GetBytes(postData);
var content = new ByteArrayContent(data);
using var httpHandler = new HttpClientHandler { UseCookies = false, AllowAutoRedirect = false };
using var client = new HttpClient(httpHandler);
client.DefaultRequestHeaders.Add("UserAgent","Mozilla/5.0");
client.DefaultRequestHeaders.Add("ContentType", "text/x-gwt-rpc; charset=UTF-8");
client.DefaultRequestHeaders.Add("Cookie", SetCookie);
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, url) { Content = content };
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
Remarks:
Instead of writing the Request's Stream manually you can use the ByteArrayContent abstraction for this. (Related SO topic)
In order to set the cookie(s) manually you have to turn-off the default behaviour. You can do this via the HttpClientHandler's UseCookies. (Related SO topic)
To set the headers manually you can use the HttpClient's DefaultRequestHeaders (Related SO topic)
The counterpart of GetResponse is the SendAsync
Instead of reading the Response's Stream manually you can use the HttpContent's ReadAsStringAsync (Related SO topic)
UPDATE: Include OP's amended code
var content = new StringContent(postData, Encoding.UTF8, "text/x-gwt-rpc");
So, instead of ByteArrayContent StringContent is being used.
I want to make Post request to "https://sslecal2.forexprostools.com/ajax.php". So there is my code:
string URI = "https://sslecal2.forexprostools.com/ajax.php";
string requestBody = String.Format("{{\"dateFrom\": \"{0}\", \"dateTo\": \"{1}\", \"timeZone\": {2}, \"action\": \"{3}\"}}",
"2018-12-24", "2018-12-24", 18, "filter"); //json format
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URI); //make request
request.Method = "POST";
request.UserAgent = "";
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(requestBody); //write your request payload
}
WebResponse response = request.GetResponse();
string jsonData = String.Empty;
using (var reader = new StreamReader(response.GetResponseStream()))
{
jsonData = reader.ReadToEnd();
}
response.Close();
I made something not correct in "requestBody" in string " string requestBody = String.Format("{{\"dateFrom\"..." because I get 200 and empty html answer.
And I attach the screens of the same request in postman with html code in answer. This request in postman processes well.
What the difference between this Post webrequest and request in Postman?
With postman you posting different format data. To get same thing in code you need to change request body format and set content type of request:
string URI = "https://sslecal2.forexprostools.com/ajax.php";
string requestBody = String.Format("dateFrom={0}&dateTo={1}&timeZone={2}&action={3}",
"2018-12-24", "2018-12-24", 18, "filter"); //<-- Change this
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URI);
request.Method = "POST";
request.UserAgent = "";
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
request.ContentType = "application/x-www-form-urlencoded"; //<-- Add this
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(requestBody);
}
WebResponse response = request.GetResponse();
string jsonData = String.Empty;
using (var reader = new StreamReader(response.GetResponseStream()))
{
jsonData = reader.ReadToEnd();
}
response.Close();
In PostMan, if you click the "Code" in the top right, under the send button, you can choose C# (RestSharp).. If you're not using RestSharp, there's a small amount of work to do to convert it to something else, but the basics are all there.
Here's the autogen output for your case (RestSharp):
var client = new RestClient("https://sslecal2.forexprostools.com/ajax.php");
var request = new RestRequest(Method.POST);
request.AddHeader("Postman-Token", "bfd1a3b3-983f-4160-a091-6f0962413e58");
request.AddHeader("Cache-Control", "no-cache");
request.AddHeader("X-Requested-With", "XMLHttpRequest");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("undefined", "dateFrom=2018-01-24&dateTo=2018-01-24&timeZone=18&action=filter", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Converting it to HttpWebRequest requires:
AddHeader -> Headers.Add
Specify method
Body data is set differently - take PostMan's string and write it to the request stream
Or install RestSharp free from NuGet
I am having a problem when I try using a rest web service in C#.
When I try via Fiddler it works Ok.
When I try via HTML/Ajax, it works Ok, as well.
When I try via C# (Console Application) I get an error.
This image is captured in fiddler. It is what I get when I try via ajax
this image is also captured in fiddler. It is what I get when I try via C#
As you can see, the JSON field is empty.
This is my C# code
string json = JsonConvert.SerializeObject(abc);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("MyURL"); //==> I am filling it correctly
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.PostAsJsonAsync("MyMethod", json).Result; //==> I am filling my method correctly
But I have tried several others and always getting the same problem. (the code bellow is another one I tried)
var requisicaoWeb = WebRequest.CreateHttp("MyURL");
requisicaoWeb.Method = "POST";
requisicaoWeb.ContentType = "application/json";
requisicaoWeb.ContentLength = dados.Length;
requisicaoWeb.UserAgent = "Console app";
requisicaoWeb.Accept = "Accept:application/json,text/javascript,*/*;q=0.01";
//precisamos escrever os dados post para o stream
using (var stream = requisicaoWeb.GetRequestStream())
{
stream.Write(MyJson, 0, dados.Length);
stream.Close();
}
//ler e exibir a resposta
using (var resposta = requisicaoWeb.GetResponse())
{
var streamDados = resposta.GetResponseStream();
StreamReader reader = new StreamReader(streamDados);
object objResponse = reader.ReadToEnd();
var post = objResponse.ToString();//JsonConvert.DeserializeObject<Post>(objResponse.ToString());
streamDados.Close();
resposta.Close();
}
Everything I try in C#, the JSON field on Fiddler is always empty and the "syntax View" description is always "Request Invalid".
Try it's;
public static string HttpPost(string URI, string Parameters)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
req.ContentType = "application/json; charset=utf-8";
req.Method = "POST";
req.Timeout = 600000;
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(Parameters);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
os.Close();
System.Net.WebResponse resp = req.GetResponse();
if (resp == null)
return null;
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();
}
I have just figure it out.
If anybody else has the same problem, here is the answer
string json = JsonConvert.SerializeObject(abc);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("MyURL"); //==> I am filling it correctly
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var stringContent = new StringContent(JsonConvert.SerializeObject(abc), Encoding.UTF8, "application/json");
var response = client.PostAsync("MyURL", stringContent).Result; //==> I am filling my method correctly
Here is the code that I am using:
public static void FetchXML()
{
_url = new Uri("http://api.tumblr.com/v2/blog/" + _username + ".tumblr.com/likes?api_key=REc3Z6l4ZYss11a8lX6KKje0X8Hsi9U77SyaPbQrOBBCGJGA6D");
var client = new RestClient();
client.Authority = _url.ToString();
var request = new RestRequest();
request.AddParameter("limit", "20");
request.AddParameter("offset", _offset.ToString());
var response = client.Request(request);
var content = response.Content.ToString();
var parsedResponse = JsonParser.FromJson(content);
}
If I take the Uri value and paste it into my browser (using a valid Tumblr username) I'm getting the correct Json, but in my application the content of response is:
"{\"meta\":{\"status\":401,\"msg\":\"Unauthorized\"},\"response\":[]}"
Anyone have any idea why this is? According to the Tumblr API
retrieving likes should only need the API key, which I am providing.
Hi you can use the below code to get the response.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "GET";
request.ContentType = "Application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream receive = response.GetResponseStream();
StreamReader reader = new StreamReader(receive, Encoding.UTF8);
string respond = reader.ReadToEnd();