I am testing a WebService on Postman v7.36.0 and I am getting the json without issue. So I copy the code that Postman gaves to use on C# but I am getting a different result a error response saying that I am not using a right input to obtain data (custom error from the source of the webservice).
¿Why I am getting diferent result if I just copied and pasted the code?
¿How can I debug this?
¿Could be a problem the space between the date and the hour?
¿How can I be sure if the inputs that I am sending on Postman are really the same on the RestSharp code?
The code used needs a token that I am getting without problem on another webservive that I have to invoke previously. I copied and pasted the code given on Postman as well and it worked.
To get the token:
var client = new RestClient("http://URL:port/api");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("user", "user");
request.AddParameter("pass", "pass");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
To get the list of people:
var client = new RestClient("http://URL:PORT/api/API");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + thetoken);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("startDate", "2020-10-01 00:00");
request.AddParameter("finishDate", "2020-10-31 23:59");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
EDIT: The webservice returns a json with a list of person with the cuantity of days worked between start and finish date.
EDIT 2: I think the issue is about the date format or the way the dates are sent. Using Fiddler I see with Postaman the raw request is:
GET http://URL:port/api/API HTTP/1.1
Authorization: Bearer thetokenxxxx
User-Agent: PostmanRuntime/7.26.8
Accept: */*
Cache-Control: no-cache
Postman-Token: b877f51b-550e-45ff-b4e4-50ca01412491
Host: URL:port
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 66
startDate=2020-10-01%2000%3A00&finishDate=2020-10-31%2023%3A59
But with RestSharp v105.2.3 the raw request is:
GET http://URL:port/api/API?startDate=2020-10-01%2000%3A00&finishDate=2020-10-31%2023%3A59 HTTP/1.1
Authorization: Bearer thetokenxxxx
Content-Type: application/x-www-form-urlencoded
Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml
User-Agent: RestSharp/105.1.0.0
Host: URL:port
Accept-Encoding: gzip, deflate
Related
We are using RestSharp to upload a base64 encoded file. The API requires a request format that looks like the following, but we are unable to produce this format using RestSharp. I think there must be a way?
FORMAT 1
POST https://www.myapiurl.com/api/v1/add HTTP/1.1
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------330780699366863579549053
Content-Length: 522
----------------------------330780699366863579549053
Content-Disposition: form-data; name="id"
7926456167
----------------------------330780699366863579549053
Content-Disposition: form-data; name="filename"
test2.txt
----------------------------330780699366863579549053
Content-Disposition: form-data; name="description"
----------------------------330780699366863579549053
Content-Disposition: form-data; name="attachment"
dGhpcyBpcyBhIHRlc3Q=
----------------------------330780699366863579549053--
Using RestSharp, we are only able to create a request that looks like...
FORMAT 2
POST https://www.myapiurl.com/api/v1/add HTTP/1.1
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------330780699366863579549053
Content-Length: 83
id=7926456167&filename=SQLSearch.exe&description=&attachment=dGhpcyBpcyBhIHRlc3Q=
For the API we are hitting, this works fine unless the "attachment" parameter is a larger file. We can manually compose/submit a request for larger files if we use FORMAT 1. FORMAT 2 fails, but that is all we can get out of RestSharp.
Here is the code we are using.
var client = new RestClient("http://myapiurl.com/api/v1/add");
var restRequest = new RestRequest(request, Method.POST);
restRequest.AddHeader("Content-Type", "multipart/form-data; boundary=--------------------------330780699366863579549053");
restRequest.AddParameter("id", "7926456167", "multipart/form-data", ParameterType.RequestBody);
restRequest.AddParameter("filename", "test2.txt", "multipart/form-data", ParameterType.RequestBody);
restRequest.AddParameter("description", "", "multipart/form-data", ParameterType.RequestBody);
restRequest.AddParameter("attachment", "dGhpcyBpcyBhIHRlc3Q=", "multipart/form-data", ParameterType.RequestBody);
How is this code changed to produce a request in FORMAT 1?
RestSharp can build a proper multipart/form-data request automatically, so you don't need to specify Content-Type header manually and you can remove multipart/form-data and ParameterType.RequestBody from parameters. Then you just need to set AlwaysMultipartFormData property to true so it will generate proper headers and body for you
var client = new RestClient("http://myapiurl.com/api/v1/add");
var restRequest = new RestRequest(request, Method.POST);
restRequest.AddParameter("id", "7926456167");
restRequest.AddParameter("filename", "test2.txt");
restRequest.AddParameter("description", "");
restRequest.AddParameter("attachment", "dGhpcyBpcyBhIHRlc3Q=");
restRequest.AlwaysMultipartFormData = true;
I am trying to create an attachment using the Support Bee API as documented here:
https://supportbee.com/api#create_attachment
I have written a service that uses an HttpClient to create and send the request using a filename.
If I test in in Postman, it succeeds. I am using form-data for the body and just selecting the file to upload from the UI:
It doesn't work when I try to upload it via my HttpClient Service:
public async Task<string> CreateAttachmentAsync(string fileName)
{
// "client" is HttpClient provided via D.I.
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StreamContent(new FileStream(fileName, FileMode.Open)), "files[]");
using (HttpResponseMessage response = await client.PostAsync(
"https://xxx.supportbee.com/attachments?auth_token=xxx",
content))
{
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
}
This results in a 500 Internal Server Error. Inspecting the MultipartFormDataContent object I can see that it's header values are automatically being set:
{
Content-Type: multipart/form-data; boundary="c9be3778-4de5-4460-9929-adcaa6bdda79"
Content-Length: 164
}
I have also tried reading the file to a byte array first and using ByteArrayContent instead of StreamContent to no avail. The response doesn't provide anything helpful, but since the request works in Postman I must have something wrong with my code, but I don't know what else to try.
Edit: I tested with Fiddler to compare the successful Postman request to my code. Here is the request with Postman:
POST
https://xxx.supportbee.com/attachments?auth_token=xxx
HTTP/1.1 User-Agent: PostmanRuntime/7.22.0 Accept: / Cache-Control:
no-cache Postman-Token: f84d22fa-b4b1-4bf5-b183-916a786c6385 Host:
xx.supportbee.com Content-Type: multipart/form-data;
boundary=--------------------------714700821471353664787346
Accept-Encoding: gzip, deflate, br Content-Length: 241 Connection:
close
----------------------------714700821471353664787346 Content-Disposition: form-data; name="files[]"; filename="sample.txt"
Content-Type: text/plain
This contains example text.
----------------------------714700821471353664787346--
And the failing request from my code:
POST
https://xxx.supportbee.com/attachments?auth_token=xxx
HTTP/1.1 Host: xxx.supportbee.com Accept: / Accept-Encoding:
gzip, deflate, br Connection: close Content-Type: multipart/form-data;
boundary="ea97cbc1-70ea-4cc4-9801-09f5feffc763" Content-Length: 206
--ea97cbc1-70ea-4cc4-9801-09f5feffc763 Content-Disposition: form-data; name="files[]"; filename=sample; filename*=utf-8''sample
This contains example text.
--ea97cbc1-70ea-4cc4-9801-09f5feffc763--
The difference I can see is that the individual part in Postman has its own Content-Type: text/plain header for the file, and mine doesn't. I'm unable to add this because if I try content.Headers.Add("Content-Type", "text/plain"); It fails with 'Cannot add value because header 'Content-Type' does not support multiple values.'
First, it's important to note that a 500 response is akin to an unhandled exception, i.e. it's a bug on their end and more or less impossible to know for sure what you did wrong. I would suggest reporting it to them and, although I'm not familiar with Support Bee, I would hope they have good support people who can help you troubleshoot. :)
But if you want to play the guessing game, I agree that subtle differences between your successful Postman call and your code are a good place to start. For that header, note that content is the MultipartFormDataContent. You actually want to set it on the StreamContent object.
Also, look at the request headers Postman is sending and see if Content-Disposition includes a filename. You might need to add that to your code too, if the API is expecting it.
Here's how to do both:
var fileContent = new StreamContent(File.OpenRead(path));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
content.Add(fileContent, "files[]", Path.GetFileName(path));
If that's not the problem, look at the "raw" version of the request body in Postman, as well as those 11 request headers, and see if you can spot anything else you might be missing.
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¶m2=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¶m2=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¶m2=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¶m2=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¶m2=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¶m2=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¶m2=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.
I'm using RestSharp to communication with an Web Service.
I use this code
public static object GetTagValue(string url, string tagname, out string resp)
{
object result = null;
resp = string.Empty;
string theReq = string.Format("tags/{0}", tagname);
var client = new RestClient(url);
var request = new RestRequest(theReq, Method.GET);
request.RequestFormat = DataFormat.Json;
IRestResponse response = client.Execute(request);
resp = response.Content;
if (!string.IsNullOrWhiteSpace(resp))
{
dynamic json = JValue.Parse(resp);
if (null != json.value)
{
result = json.value;
}
}
return result;
}
Call to the server
GET http://ame-hp/tags/int32 HTTP/1.1
Accept: application/json, application/xml, text/json, text/x-json,
text/javascript, text/xml
User-Agent: RestSharp/105.2.3.0
Host: ame-hp
Accept-Encoding: gzip, deflate
Response from the server for a working call:
HTTP/1.1 200 Ok
Server: Internet Pack HTTP Server
Connection: Close
Set-Cookie: SID=f11985564d;Expires=Fri, 27 Jan 2017 07:52:17
GMT;Path=/
Content-Type: application/json
Content-Length: 133
{"quality":"Good","description":"","name":"int32","value":0,"dataType":"int32","controllers":[],"initialValue":null,"readonly":false}
It's working but after two calls the service answers with this
{"Code":503,"Message":"Service Unavailable - Maximum number of active clients reached."}
Third call to server
GET http://ame-hp/tags/int32 HTTP/1.1
Accept: application/json, application/xml, text/json, text/x-json,
text/javascript, text/xml
User-Agent: RestSharp/105.2.3.0
Host: ame-hp
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Response from the server for all calls from now and until the server is restarted
HTTP/1.1 503 Service Unavailable - Maximum number of active clients
reached.
Server: Internet Pack HTTP Server
Connection: Keep-Alive
Content-Type: application/json
Content-Length: 88
{"Code":503,"Message":"Service Unavailable - Maximum number of active
clients reached."}
So I assume that the service has a limit of two clients.
But why do there exist two active clients?
Either the Server or RestSharp is not closing the connection, but which?
Is there something I can do in RestSharp to close the connection?
The problem was, as I assumed, that the server only allows 2 clients. On the first connection a Session Cookie is sent back and this has to be used for the rest of the calls.
In RestSharp you only need to add one line to make this happen
After creating the client (which by the way you need to reuse for all the calls). You add this line:
client.CookieContainer = new System.Net.CookieContainer();
The initialization of the client would be
client = new RestClient();
client.CookieContainer = new System.Net.CookieContainer();
Then you can use
client.BaseUrl = new Uri(url);
To set the url you want to call
I have a HTTP handler which receives a HTTP POST.
HTTP POST message with header is -
POST /ibe/example.com HTTP/1.1
Content-Length: 445
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: */*
Host: 202.177.46.142
charset=UTF-8¶m1=val1¶m2=val2
Handler in my code is -
var V1 = context.Request["param1"];
var V2 = context.Request["param2"];
But this didn't work.
I think you should be using:
var V1 = context.Request.Param["param1"];
var V2 = context.Request.Param["param2"];
Taken from this example here: http://forums.asp.net/t/1190337.aspx and here How to send data to httphandler