Moving from standard .NET rest to RestSharp - c#

For the most part, I have managed quite quickly to move my code from standard .NET code to using RestSharp. This has been simple enough for GET processes, but I'm stumped for POST processes
Consider the following
var request = System.Net.WebRequest.Create("https://mytestserver.com/api/usr") as System.Net.HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json;version=1";
request.Headers.Add("Content-Type", "application/json;version=1");
request.Headers.Add("Accepts", "application/json;version=1");
request.Headers.Add("Authorize", "key {key}");
using (var writer = new System.IO.StreamWriter(request.GetRequestStream())) {
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes("{\n \"firstName\": \"Dan\",\n \"lastName\": \"Eccles\",\n \"preferredNumber\": 1,\n \"email\" : \"testuser#example.com\",\n \"password\": \"you cant get the wood\"\n}");
request.ContentLength = byteArray.Length;
writer.Write(byteArray);
writer.Close();
}
string responseContent;
using (var response = request.GetResponse() as System.Net.HttpWebResponse) {
using (var reader = new System.IO.StreamReader(response.GetResponseStream())) {
responseContent = reader.ReadToEnd();
}
This is fairly straight forward to move across, except for the serialisation code. Is there a particular way this has to be done for RestSharp? I've tried creating an object and using
var json = JsonConvert.SerializeObject(user);
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddBody(json);
but the server still comes back with an error.
I'm also currently using JSON.NET for deserialization to an error object when the user passes in bad data. Is there a way I can deserialize to error object based on a single string using RestSharp?

You're close, but you don't need to worry about serialization with RestSharp.
var request = new RestRequest(...);
request.RequestFormat = DataFormat.Json;
request.AddBody(user); // user is of type User (NOT string)
By telling it that the format is JSON, then passing your already-serialized-as-JSON string, RestSharp is actually encoding it again as a string.
So you pass the string: {"firstName":"foo"} and it actually gets sent to the server as a JSON string object: "{\"firstName\":\"foo\"}" (note how your JSON is escaped as a string literal), which is why it's failing.
Note you can also use an anonymous object for the request:
var request = new RestRequest(...);
request.RequestFormat = DataFormat.Json;
request.AddBody(new{
firstName = "Dan",
lastName = "Eccles",
preferredNumber = 1,
// etc..
});
You use the same typed objects with the response (eg, RestSharp deserializes for you):
var response = client.Execute<UserResponse>(request);
// if successful, response.Data is of type UserResponse

Related

Calling a GraphQL API over HTTP

I was able to make a graphql POST from Postman by choosing "GraphQL" content type:
When I am trying to perform the POST from C#:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
myHttpWebRequest.Method = "POST";
myHttpWebRequest.ContentType = "application/graphql";
myHttpWebRequest.Headers.Add("Authorization", authToken);
var encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
myHttpWebRequest.ContentLength = byte1.Length;
var newStream = myHttpWebRequest.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
using (var response = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
using (var receiveStream = response.GetResponseStream())
{
using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
string strContent = readStream.ReadToEnd();
return strContent;
}
}
}
it looks the the content type is expected to be application/json even I specifically set content type to be "application/graphql" because the response I get is:
{"data":null,"errors":[{"message":"failed to recognize JSON request: 'invalid character 'q' looking for beginning of value'","path":null,"extensions":{"timestamp":"2021-05-19T16:04:23.091659509Z"}}]}
How can I rewrite this part as json?
query{
viewer{
accounts(filter: {accountTag: "accountTagHere"}){
ipFlows1mGroups(
limit:10
filter: {datetimeMinute_gt: "2021-05-19T16:00:00Z"}){
avg{bitsPerSecond}
}
}
}
}
This doens't work:
var postParams = #"{`query`:`viewer{accounts(filter: { accountTag: ...";
postParams = postParams.Replace("`", "\"");
If you use application/graphql, according to the original guidelines from Facebook here, the body of the POST should be the query and only the query, just as you've got in your Postman screenshot. You shouldn't need to encode it, just set the body using StringContent (assuming you're using HttpClient).
Another option though is to POST using application/json and then you need to post JSON of the form as shown on that page and below. (Note: make sure to use an operationName that matches the one in the query, or just not pass it if you've got only one and it's not named)
{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... }
}
Finally, why not use a library that makes this easier for you? There's options for GraphQL C# client's.
StrawberryShake - Generates typed clients from .graphql files and can have a store backing it (think redux) that caches/syncs data, supports reactive concepts, etc. More here. There's even a VS extension that gives you intellisense when writing your queries.
graphql-dotnet/graphql-client - A simple wrapper around HttpClient

Connecting to PHP api from c# project

I have an api
http://cbastest.cadvilpos.com/module/posmodule/customapi
with parameters
{
"action":4,
"device_token": "3e8ea119a90ee6d2",
"key":"9475962085b3a1b8c475d52.95782804",
"shop":1,
"language":1
}
This is working fine in postman. But when I try to connect from c# project its showing an error {"success":0,"error":"Missing the action parameter."}. Please give a working C# code to get the json result.
The code I tried:
var request = (HttpWebRequest)WebRequest.Create("http://cbastest.cadvilpos.com/module/posmodule/customapi");
var postData = "{ 'action':'4', 'device_token':'3e8ea119a90ee6d2','key':'9475962085b3a1b8c475d52.95782804','shop':'1','language':'1'}";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response2 = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response2.GetResponseStream()).ReadToEnd();
You don't need to use a raw HttpWebRequest object to make an HTTP call. HttpClient was introduced in 2012 to allow easy asynchronous HTTP calls.
You could do something as simple as :
var content=new StringContent(postData,Encoding.UTF8, "application/json");
HttpResponseMessage response=await httpClient.PostAsync(url,content);
//Now process the response
if (response.IsSuccessCode)
{
var body=await response.Content.ReadAsStringAsync();
var responseDTO=JsonConvert.DeserializeObject<MyDTO>(body);
}
Instead of building a JSON string by hand you could use a strongly typed class or an anonymous object and serialize it to JSON with JSON.NET :
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var postData=JsonConvert.SerializeObject(data);
var content=new StringContent(postData,Encoding.UTF8, "application/json");
var response=await httpClient.PostAsync(url,content);
...
You can read a response body in one go as a string, using ReadAsStringAsync or you can get the response stream with ReadAsStreamAsync. You could copy the response data directly to another stream, eg a file or memory stream with HttpContent.CopyToAsync
Check Call a Web API from a .NET Client for more examples. Despite the title, the examples work to call any HTTP/REST API.
The Microsoft.AspNet.WebApi.Client package mentioned in that article is another thing that applies to any call, not just calls to ASP.NET Web API. The extension method PostAsJsonAsync for example, combines serializing and posting a request to a url. Using it, posting the action DTO could be reduced to a single line:
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var response=await httpClient.PostAsJsonAsync(url,data);
There is a button in Postman that will generate code for the currently defined request. The link is here:
And this is what the code looks like. You'll need to pull in RestSharp from Nuget

Wrong time while Deserialize json object

I am deserializing List of class "pushNotification" using JavaScriptSerializer but I am not getting time values properly in result. However it is returned properly from the server side. I am using web http call to wcf to get list of this class. below is my code I get 6:00AM in "itemValue.ScheduledTime" however from service it was returned like 11 AM.
Datetime string returned from the server in JSON is "1425535200000+0500" and in datebase its "2015-03-05 11:00:00.000"
// Restful service URL
string url = "http://localhost:4567/ClientService.svc/GetPendingNotification";
string strResult = string.Empty;
// declare httpwebrequet wrt url defined above
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
// set method as post
webrequest.Method = "GET";
// set content type
// declare & read response from service
HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
// set utf8 encoding
// read response stream from response object
StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream());
// read string from stream data
strResult = loResponseStream.ReadToEnd();
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<Dictionary<string, List<pushNotification>>>(strResult);
List<pushNotification> Notifications = new List<pushNotification>();
foreach (var itemValue in dict.Values.First())
{
Notifications.Add(new pushNotification { Message = itemValue.Message, toAndroid = itemValue.toAndroid , toiOS = itemValue.toiOS, ScheduledDate = Convert.ToDateTime(itemValue.ScheduledDate), ScheduledTime = Convert.ToDateTime(itemValue.ScheduledTime)});
}
JavaScriptSerializer doesn't understand timezone offset. Use DataContractJsonSerializer (https://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer%28v=vs.110%29.aspx) instead (you'll have to mark object you're serializing/properties with DataMember/DataContract attributes).

PayPal Pay Operation - error 81002

I'm not sure why this PayPal Pay operation is giving me this error even though I seem to have covered all the required fields:
Error Code: 81002 Severity: Error Message: Unspecified Method (Method Specified is not Supported)"
string postData = JsonConvert.SerializeObject(request);
value of postData:
"actionType=PAY
&currencyCode=USD
&cancelUrl=https%3a%2f%2fexample.com%2fcancel
&returnUrl=https%3a%2f%2fexample.com%2freturn
&requestenvelope.errorLanguage=en_US
&receiverList.receiver(0).email=recipientemail%40gmail.com
&receiverList.receiver(0).amount=0.05
&VERSION=94.0
&USER=bizemail-facilitator_api1.gmail.com
&PWD=xxxxx
&SIGNATURE=xxxxxxxxx"
Here's how I do the post:
SendRequest("https://api-3t.sandbox.paypal.com/nvp", postData);
public string SendRequest(string url, string postData)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var encoding = new UTF8Encoding();
var requestData = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.Timeout = (300*1000); //TODO: Move timeout to config
request.ContentLength = requestData.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(requestData, 0, requestData.Length);
}
var response = request.GetResponse();
string result;
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII)) {
result = reader.ReadToEnd();
}
return result;
}
The method PAY doesn't exist on the NVP api. Full list of methods supported by that API is found here.
The PAY method, however, is defined in the Adaptive Payments API. Depending on your needs, you have two options:
Change the endpoint to https://svcs.paypal.com/AdaptivePayments/PAY and modify your values
Use another method, like DoDirectPayment, but I'm not sure it does what you want to.
I assume the value of postData is before you serialize it to a JSON string, instead of after as you say, since it is clearly not a JSON string.
If so, then it is already x-www-form-urlencoded, and you do not need to serialize it to a JSON string at all.
Or if you do after all, then change just this: request.ContentType = "application/json";

Simple REST request c# - error

I am trying write simple request to REST service.Follow to documentation from REST Service provider:
I should use in header Content-Type: application/json.
Response return in json format
For authorization proccess I have to send two headers one with APIKey and second with APISign
Controller PING in REST service to test code.
I use .net 2.0
string sha1String = APIKey + "/rest/ping" + APISecret;
string XRestApiSign = SHA1HashStringForUTF8String(sha1String);
string data = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(restServer);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("X-Rest-ApiSign", XRestApiSign);
request.Headers.Add("X-Rest-ApiKey", APIKey);
request.ContentLength = data.Length;
StreamWriter requestWriter;
Stream webStream = request.GetRequestStream();
using (requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII)) ;
{
requestWriter.Write(data);
}
request.BeginGetResponse((x) =>
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(response.GetResponseStream().ToString());
}
}, null);
I should get response string PONG but I get below message
Unexpected character encountered while parsing value: S. Path '', line 0, position 0
Is code OK ? Why I get this message?
This is mostly the case because the script that generates the JSON on the server side adds the byte order mark to the response.
In your case, however, you're trying to convert the stream to JSON, not the content of the stream. You need to read all text from the stream and deserialize the object from that. You need to call one of the methods on the stream that reads the content.
I modified my code with yours suggestion and it works. Now I have problem with send data :)
Subscription user1 = new Subscription
{
Email = "kubaIt#test.com.pl",
List = "xfct2bjcdv",
};
List<Subscription> user = new List<Subscription>();
user.Add(user1);
string json = JsonConvert.SerializeObject(user);
string data = json;
I added above. Other code is the same. I got error :The request was aborted: The request was canceled."
json = [{\"email\":\"kubaIt#test.com.pl\",\"list\":\"xfct2bjcdv\"}] //value from debuger

Categories