What is the idiomatic way to make a get request using RestSharp? - c#

I'm trying to make a GET request to a REST api which returns a JSON. This is what I have right now:
RestClient client = new RestClient(BASE_URL);
var request = new RestRequest(CONTROLLER_PATH);
var response = await client.GetAsync<MyDtoClass[]>(request);
When this code executes, response is an array of MyDtoClass but the fields in each element of the array are null. If instead, I run this code (I removed the generic):
RestClient client = new RestClient(BASE_URL);
var request = new RestRequest(CONTROLLER_PATH);
var response = await client.GetAsync(request);
then response is a string represintation of the JSON that BASE_URL + CONTROLLER_PATH returns (nothing is null).
What is the idiomatic way to make a request to this REST api and convert the response into an array of MyDtoClass. Also, if anyone has suggestions for a library you think is better then RestSharp, please share.
Thank you in advance.

The issue was that MyDtoClass had fields instead of properties.

Related

C# How to put curly brackets in URL

I've been trying to get the data that I need from Facebook's graph api explorer but unfortunately, cant pass the fields necessary in URL via C#.
Here's what I've tried so far
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://graph.facebook.com");
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{id,created_time,permalink_url,message,link,type,full_picture}&access_token={textBox1.Text}").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
var jsonRes = JsonConvert.DeserializeObject<dynamic>(result);
var returned = jsonRes.ToString();
MessageBox.Show(returned);
}
What's needed to be done here for fetching data via API? :)
As it turns out, there is an issue because you're using string interpolation and also want curly braces in your string. You'll have to escape them by doubling them.
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{{id,created_time,permalink_url,message,link,type,full_picture}}&access_token={textBox1.Text}").Result;
Your approach is incorrect Because Those Variables You Are Trying To Add In Url Are Actually Getting On String, You must escape them to get their valueTherefore Change
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{id,created_time,permalink_url,message,link,type,full_picture}&access_token={textBox1.Text}").Result;
To
HttpResponseMessage response = client.GetAsync($"cocacola?fields="+posts{id,created_time,permalink_url,message,link,type,full_picture}+"&access_token="+{textBox1.Text}).Result;
But here to its incorrect cause i dont think {textBox1.Text} and posts{id,created_time,permalink_url,message,link,type,full_picture} Means Anything

Differences between using C# HttpClient API and the postman testing? Client call works on postman, but not C# httpClient getAsync

I am testing a REST API post, and it works well when I try it on Postman. However, in some scenario (related to the posting XML data) if I post with HttpClient API, I would receive the following error:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
But the same XML content works fine on Postman with status OK and proper response.
What is the differences between using the C# HttpClient API and the postman testing? How can I configure my API call to match with the behavior on postman?
Here I attached the source code, and the Postman screenshot
public void createLoan()
{
string baseCreateLoanUrl = #"https://serverhost/create?key=";
var strUCDExport = XDocument.Load(#"C:\CreateLoan_testcase.xml");
using (var client = new HttpClient())
{
var content = new StringContent(strUCDExport.ToString(), Encoding.UTF8, Mediatype);
string createLoanApi = string.Concat(baseCreateLoanUrl, APIKey);
try
{
var response = client.PostAsync(createLoanApi, content).Result;
}
catch (Exception ex)
{
MessageBox.Show("Error Happened here...");
throw;
}
if (response.IsSuccessStatusCode)
{
// Access variables from the returned JSON object
string responseString = response.Content.ReadAsStringAsync().Result;
JObject jObj = JObject.Parse(responseString);
if (jObj.SelectToken("failure") == null)
{
// First get the authToken
string LoanID = jObj["loanStatus"]["id"].ToString();
MessageBox.Show("Loan ID: " + LoanID);
}
else
{
string getTokenErrorMsg = string.Empty;
JArray errorOjbs = (JArray) jObj["failure"]["errors"];
foreach (var errorObj in errorOjbs)
{
getTokenErrorMsg += errorObj["message"].ToString() + Environment.NewLine;
}
getTokenErrorMsg.Dump();
}
}
}
Thanks for Nard's comment, after comparing the header, I found the issue my client header has this:
Expect: 100-continue
While postman doesn't has.
Once I removed this by using the ServicePointManager:
ServicePointManager.Expect100Continue = false;
Everything seems fine now. Thanks all the input!
My gut tells me it's something simple. First, we know the API works, so I'm thinking it's down to how you are using the HttpClient.
First things first, try as suggested by this SO answer, creating it as a singleton and drop the using statement altogether since the consensus is that HttpClient doesn't need to be disposed:
private static readonly HttpClient HttpClient = new HttpClient();
I would think it would be either there or an issue with your content encoding line that is causing issues with the API. Is there something you are missing that it doesn't like, I bet there is a difference in the requests in Postman vs here. Maybe try sending it as JSON ala:
var json = JsonConvert.SerializeObject(strUCDExport.ToString());
var content = new StringContent(json, Encoding.UTF8, Mediatype);
Maybe the header from Postman vs yours will show something missing, I think the real answer will be there. Have fiddler running in the background, send it via Postman, check it, then run your code and recheck. Pay close attention to all the attribute tags on the header from Postman, the API works so something is missing. Fiddler will tell you.
I was struggling with this for 2 days when I stumbled over Fiddler which lets you record the traffic to the service. After comparing the calls I saw that I had missed a header in my code.

Setting up a REST Client Application (Post) from a Web API

I've been having a few issues in trying to retrieve the results of a POST operation from a Web Service.
I have been using a chrome extension to test the API Services and they are working there. However I've been having problems on implementing it in code.
This is an example of usage of the chrome extension:
What I'm trying to retrieve on code, is the last part, the json array that the POST operation generates, where it says accessToken.
However, in the code that I've been using below, I've only had access to the status (200 OK) etc.
Here's a preview of the code I am using:
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(url.Text);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(header.Text));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url.Text);
request.Content = new StringContent(body.Text, Encoding.UTF8, header.Text);
client.SendAsync(request)
.ContinueWith(responseTask =>
{
MessageBox.Show(responseTask.Result.Content.Headers.ToString());
}
);
}
The Header.Text is exactly "application/json", the body.Text is body which has those various properties such as username and password (in string format) and url.Text contains the complete URL to call the Web service.
I'd like to know what I'm doing wrong with my code, and what can I do to obtain that json array that contains the accessToken
In your code you need to use ReadAsStringAsync method to convert your HttpContent object to string/json. For example:
client.SendAsync(request)
.ContinueWith(responseTask =>
{
var jsonString = responseTask.Result.Content.ReadAsStringAsync().Result;
MessageBox.Show(jsonString);
});
then you can convert you jsonString as you need.

POST json to another url

I've a problem as I need to send some json to a url. When I send all my json and token to the page.
Then there will be no content JSON value into the system.
I have checked up on whether there is some content and it is there, but it sends just do not like json values.
string apiKeyToken = model.reepaytoken; // TOKEN HERE.
string URLLink = APIClassPay.HelperPay.CreateCustomerURL;//URL to send it json to.
WebClient client = new WebClient();
//JSON coming here!
var JSONCustomer = APIClassPay.HelperPay.CreateCustomer(model.Brugernavn, model.Adresse, model.Byen, model.Postnr.ToString(), model.Mobil.ToString(), model.Fornavn, model.Efternavn);
client.Headers.Add("text/json", JSONCustomer);
client.Headers.Set("X-Auth-Token", apiKeyToken);
string reply = client.DownloadString(URLLink);
When I blow my json looks like this.
[HttpPost]
public ActionResult information(BuyMedlemskabViewModel model)
{
DataLinqDB db = new DataLinqDB();
var Pric = db.PriceValues.FirstOrDefault(i => i.id == model.HiddenIdMedlemskab);
if (Pric != null)
{
string _OrderValue = DateTime.Now.Year + Helper.Settings.PlanValue();
Session[HelperTextClass.HelperText.SessionName.OrderId] = _OrderValue;
Session[HelperTextClass.HelperText.SessionName.FakturaId] = model.HiddenIdMedlemskab;
Session[HelperTextClass.HelperText.SessionName.fornavn] = model.Fornavn;
Session[HelperTextClass.HelperText.SessionName.efternavn] = model.Efternavn;
Session[HelperTextClass.HelperText.SessionName.Adresse] = model.Adresse;
Session[HelperTextClass.HelperText.SessionName.Post] = model.Postnr;
Session[HelperTextClass.HelperText.SessionName.Byen] = model.Byen;
Session[HelperTextClass.HelperText.SessionName.Mobil] = model.Mobil;
string apiKeyToken = model.reepaytoken;.
string URLLink = APIClassPay.HelperPay.CreateCustomerURL;//URL to send it json to.
WebClient client = new WebClient();
//JSON coming here!
var JSONCustomer = APIClassPay.HelperPay.CreateCustomer(model.Brugernavn, model.Adresse, model.Byen, model.Postnr.ToString(), model.Mobil.ToString(), model.Fornavn, model.Efternavn);
client.Headers.Add("text/json", JSONCustomer);
client.Headers.Set("X-Auth-Token", apiKeyToken);
string reply = client.DownloadString(URLLink);
}
return RedirectToAction("information");
}
EDIT - Update (ERROR HERE):
ReePay API reference: https://docs.reepay.com/api/
I think there are a few things, you'll have to fix:
First of all you're obviously trying to create a ressource (usually a POST or PUT, speaking in REST-words but you're using WebClient's DownloadString-method which performs a GET. So I think you should probably use a POST or PUT instead but which one to chose exactly depends on the web service you're contacting.
Then you seem to have mistaken the Content-Type-header and tried to pack the payload in there. The payload - your customer JSON - will have to be put into the request's body.
Based on your previous questions I assume the service you're trying to contact is either PayPal or QuickPay. To further help you with this question, it'd be helpful if you could specify which one you use.
If it's QuickPay, please notice that there's an official .NET client which you could use instead of using WebClient on you own.
But anyway for making HTTP requests I'd suggest you to use HttpClient in favor of WebClient. You'd generally do it in a way like this:
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post,
APIClassPay.HelperPay.CreateCustomerURL);
request.Headers.Add("X-Auth-Token", apiKeyToken);
request.Headers.Add("Content-Type", "application/json");
request.Content = new StringContent(JSONCustomer);
var response = await httpClient.SendAsync(request);
}
EDIT:
As you clarified in a comment, the service you're using is Reepay. If you take a look at the documentation of the create customer method, you can see, that the necessary HTTP method is POST. So the code snippet above should generally fit.
Regarding the compilation error you faced, I updated the code-snipped above. There was a mistake in the variable names I chose. Please note, that you dropped the keyword await as I can see from your screenshot. Please re-enter it. If the compiler complains about it, it's very likely that the .NET framework version of your project is less than 4.5 which is necessary to use async/await.
So you should update your project's .NET framework version at best to version 4.6.1 as Microsoft recently announced that support for 4.5 and others is discontinued. Have a look here on how to do that.

RestSharp - Retrieving Authorization token from POSTed response

I am trying to pass username and password to the following URL :
https://maxcvservices.dnb.com/rest/Authentication
According to the documentation the user_id and password must be passed as headers with the keys: x-dnb-user, x-dnb-pwd respectively.
I thus far have the following code which seems to work but I am unable to retrieve the auth token returned by the response object:
public static void Main (string[] args)
{
var client = new RestClient ("https://maxcvservices.dnb.com/rest/Authentication");
var request = new RestRequest (Method.POST);
request.AddHeader("x-dnb-user", myEmail);
request.AddHeader("x-dnb-pwd", myPassword);
IRestResponse resp = client.Execute(request);
var content = resp.Content;
Console.WriteLine (resp.StatusDescription);
Console.WriteLine (resp.StatusCode);
}
When I try printing the content I get a blank line but what I am actually expecting is the auth token that is returned by the service. A couple of things I think I am doing in the code (but not sure), is passing the userid and password as headers in the POST request which is what is required. The token is returned as the value of the 'Authorization' field in the response object. I was wondering how I might print the token. Also the statusDescription,statusCode both print OK which tells me I have the correct request but am unable to locate the auth token in the response. Any help would be much appreciated in guiding me on how to access the auth token in the Authorization field of the returned POST response.
So you're trying to get the HttpHeader values for Authorization from the IRestResponse object?
You could use e.g. use LINQ for that:
var authroizationHeaderFromResponse = resp.Headers.FirstOrDefault(h => h.Name == "Authorization");
if (authroizationHeaderFromResponse != null)
{
Console.WriteLine(authroizationHeaderFromResponse.Value);
}
Which yields
INVALID CREDENTIALS
You assume that if the response status code is 200 - OK, then there must be a response body accompanying it.
Does the documentation specifically state that you should expect a token in the response body in return?
The D&B developers could send a 200 - OK response with no response body if they want, or they can add their serialized token (JSON, XML etc) elsewhere, e.g. in a header field.
An example of this can be seen in this code from an ASP.NET Web API returning a response from a successful PUT
if (result.Success)
{
var dto = Mapper.Map<TEntity, TDto>(result.Data as TEntity);
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
var uri = Url.Link("DefaultApi", new {id = dto.Id});
response.Headers.Location = new Uri(uri);
return response;
}
This would return a 200 - OK with a serialized object (result.Data) in the response body, but there's nothing wrong with me changing the following
var response = Request.CreateResponse(HttpStatusCode.Created, dto);
To something like
var response = Request.CreateResponse(HttpStatusCode.Created);
That way you would still get a 200 - OK response, but without a response body. This of course is against the recommendations of the HTTP/1.1 Standard for PUT verbs, but it would still work.
I could even do this for giggles
throw new HttpResponseException(HttpStatusCode.Created);
And you would still get a 200 - OK response. Somewhat evil, but possible.
I would suggest trying to fetching data from another resource with the x-dnb-user and x-dnb-pwd header fields set, and check if a response body is returned then. Perhaps D&B was inspired by Basic Authentication when implementing these header fields, and as such require them to be present in every request?
It's worth a try.
Let me know how that works out.
Look in the Headers collection of IRestResponse. It will probably be there rather than the content.
Hth
Oli
It could be that the AUTHTOKEN comes back with the cookies, as this is a common approach.
In this case, you'll need to attach a CookieContanier to your IRestClient, then this container will store the cookies. Provided you use the same client for subsequent requests, that auth cookie will let you in.
private CookieContainer _cookieJar;
...
_cookieJar = new CookieContainer();
_client.CookieContainer = _cookieJar;
You can then inspect the container after a request
_client.PostAsync(MyRequest, (r, h) =>
{
r.Cookies... // inspect em

Categories

Resources