httpclient Displays a negative answer - c#

First , a function that creates the token.
Then, calls GetClient(real token)
public static HttpClient GetClient(string token)
{
HttpClient client = new HttpClient();
HttpContent content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("ContentType", "application/json"), new KeyValuePair<string, string>("Authorization", "Bearer '" + token + "'") });
var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
string responseString = responseContent.ReadAsStringAsync().Result;
}
return client;
}
The error is:
{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{Paypal-Debug-Id: 5341e7ff8a884
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Date: Mon, 10 Feb 2020 05:36:37 GMT
Content-Length: 244
Content-Type: application/json
}}
What is the fix for such a thing??

There are two main parts of HTTP request that you have to understand to make this work:
Headers
Content
Headers is the first part of HTTP request which contains information about request like authorization, content length, content format, etc.
Second part is content. This is your actual data that you want to pass to the server. Content can be formatted in many different ways and your headers are supposed to inform server which type of formatting is used. Two of those formats that are referenced in your snippet are:
Form Url/Encoded - this data type is typicaly used with HTML forms. When you have something like
<form>
<input name="key1" value="value1"/>
<input name="key2" value="value2"/>
</form>
this form data is encoded as key1=value1&key2=value2.
Json - this is what you want to use for calling PayPal API, it's basically just Json structure appended as content with appropiate headers informing server that it should parse content as Json.
You are having problems because you are conflating headers with content and Form/UrlEncoded and Json content types. FormUrlEncodedContent constructor expects list of form key/value pairs, not headers and when you pass content-type and authorization to it, those key/value pairs are treated as data, not headers. This is where 401 error comes from as server is looking for authorization header not key/value pair in content. Try something like this:
public static HttpClient GetClient(string token)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var yourContent = new
{
key1 = "value1",
key2 = "value2"
};
var jsonContent = JsonConvert.SerializeObject(yourContent);
var content = new StringContent(jsonContent, Encoding.ASCII, "application/json");
var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
string responseString = responseContent.ReadAsStringAsync().Result;
}
return client;
}
First of all, I moved authentication from content to headers. You just need to create a new AuthenticationHeaderValue and pass "Bearer" as scheme (I haven't looked it up, but from your code I assume that API used Bearer authentication scheme).
Next, it seems that you want to use Json content-type. So you have to genereate Json as content. I perform that using anonymous data type and passing it to JsonConvert (you'll need Newtonsoft.Json package, if you copy this code Visual Studio should automaticaly suggest installing that package for you).
Finally, to add Json content to request you should use StringContent and pass both your generated Json string and content-type "application/json".
EDIT:
Tested your code, I assume your latest error was no longer 401, but rather 400 - Bad Request, caused by invalid content structure. Or it might have been 401 caused by invalid token parsing (maybe response length differs a bit?). Either way, updated code to correctly convert objects back and forth to JSON.
public class TokenResponse
{
[JsonProperty(PropertyName = "scope")]
public string Scope { get; set; }
[JsonProperty(PropertyName = "access_token")]
public string AccessToken { get; set; }
[JsonProperty(PropertyName = "token_type")]
public string TokenType { get; set; }
[JsonProperty(PropertyName = "app_id")]
public string AppId { get; set; }
[JsonProperty(PropertyName = "expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty(PropertyName = "nonce")]
public string Nonce { get; set; }
}
public class Amount
{
[JsonProperty(PropertyName = "currency_code")]
public string CurrencyCode { get; set; }
[JsonProperty(PropertyName = "value")]
public string Value { get; set; }
}
public class PurchaseUnit
{
[JsonProperty(PropertyName = "amount")]
public Amount Amount { get; set; }
}
public class OrdersRequest
{
[JsonProperty(PropertyName = "intent")]
public string Intent { get; set; }
[JsonProperty(PropertyName = "purchase_units")]
public PurchaseUnit[] PurchaseUnits { get; set; }
}
public static void CreateToken()
{
var client = new HttpClient();
byte[] authBytes = Encoding.ASCII.GetBytes("user:pass");
string base64Auth = Convert.ToBase64String(authBytes);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);
var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("grant_type", "client_credentials") });
var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v1/oauth2/token"), content).Result;
if (response.IsSuccessStatusCode)
{
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(response.Content.ReadAsStringAsync().Result);
GetClient(tokenResponse.AccessToken);
}
}
public static HttpClient GetClient(string token)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new OrdersRequest
{
Intent = "CAPTURE",
PurchaseUnits = new PurchaseUnit[] { new PurchaseUnit
{
Amount = new Amount
{
CurrencyCode = "USD",
Value = "100.0"
}
}
}
};
var jsonContent = JsonConvert.SerializeObject(request);
var content = new StringContent(jsonContent, Encoding.ASCII, "application/json");
var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
if (response.IsSuccessStatusCode)
{
var responseString = response.Content.ReadAsStringAsync().Result;
}
return client;
}

Related

C# Rest API Post

I am trying to get a REST API to feed into https://www.scheduleit.com/faq/10640/is-there-a-rest-api-or-webhooks
I have the get working, put the post I always get
"{"status": "error", "status_code": "404", "message": "Not Found - Invalid End Point for Method POST"}"
Code is
var client = new RestClient("https://www.scheduleit.com/api/");
var request = new RestRequest(this.TokenEndPoint, Method.POST);
//client.Authenticator = new HttpBasicAuthenticator(userName, password);
request.AddHeader("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxx");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("Cache-Control", "no-cache");
request.AddParameter("title", "Title Test");
request.AddParameter("owner", "813");
request.AddParameter("date_start", "2022-12-05");
request.AddParameter("date_end", "2022-12-06");
IRestResponse response = client.Execute(request);
Any suggestions
Have tried various ways of coding
The endpoint you specified doesn't exist. You need to include the resource target;
/api/groups
/api/resources
/api/events
/api/labels
/api/reports
You also need to pass arguments in a JSON Body, not as query parameters.
This is how it should look;
public class RequestBody {
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("owner")]
public string Owner { get; set; }
[JsonPropertyName("date_start")]
public DateTime DateStart { get; set; }
[JsonPropertyName("date_end")]
public DateTime DateEnd { get; set; }
}
var body = new RequestBody {
Title = "Title Test",
Owner = "813",
DateStart = Date.Now(),
DateEnd = Date.Now()
};
var client = new RestClient("https://www.scheduleit.com/api/events");
var request = new RestRequest().AddJsonBody(body);
var response = await client.PostAsync(request, CancellationToken.None);

HTTP Client Patch method with Asp.net core 2.1, bad request

Using HttpClient to perform a PATCH method request is getting an bad request error
var patchDoc = new JsonPatchDocument<ClientOrganisationRequestArgs>();
patchDoc.Replace(e => e.Name, clientOrganisationRequestArgs.Name);
var serializedDoc = JsonConvert.SerializeObject(patchDoc);
var requestContent = new StringContent(serializedDoc, Encoding.UTF8, "application/json-patch+json");
var httpResponseMessage = await _httpClient.PatchAsync(
$"api/orgs/{clientOrganisationRequestArgs.ClientRefId}", requestContent);
Model
public class ClientOrganisationRequestArgs
{
public int ClientRefId { get; set; }
public string Name { get; set; }
public string DefaultTimezone => "AUSTRALIA/SYDNEY";
public string CustomStylePath { get; set; }
}
Getting 400 with bad request
Postman also show an 500 internal server error with body as raw
Authorization and accept header
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.yellowfin.api-v1.3+json");
_authorizationHeader =
$"{_authorizationHeader}, token={accessToken.SecurityToken}";
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation(
HeaderNames.Authorization, _authorizationHeader);
You have application/json-patch+json as content type
//...
var requestContent = new StringContent(serializedDoc, Encoding.UTF8, "application/json-patch+json");
//...
But based on the docs shown it is expecting simple application/json content type header
var requestContent = new StringContent(serializedDoc, Encoding.UTF8, "application/json");
Also based on the example in the shown doc, the payload is a plain JSON document and does not really appear to be following the JSON Patch document format. This may result in the API not recognizing the request content.
I suggest serializing the payload to match the example given
string serializedDoc = JsonConvert.SerializeObject(clientOrganisationRequestArgs);
StringContent requestContent = new StringContent(serializedDoc, Encoding.UTF8, "application/json");
string url = $"api/orgs/{clientOrganisationRequestArgs.ClientRefId}";
var httpResponseMessage = await _httpClient.PatchAsync(url, requestContent);
assuming
public class ClientOrganisationRequestArgs {
[JsonProperty("clientRefId")]
public int ClientRefId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("defaultTimezone")]
public string DefaultTimezone => "AUSTRALIA/SYDNEY";
[JsonProperty("customStylePath")]
public string CustomStylePath { get; set; }
}

"HTTP 406 Not Acceptable" When trying to send PDF converted to base64. C# xamarin

I'm doing a POST method to an end point with a PDF that is converted to base64 but I'm receiving a HTTP 406 CODE. I included in the body the application/pdf for mime type and I included the necessary header to accept my POST request but still I'm receiving the 406 code. Does the json body has any connection on receiving the 406 code or am I having a problems on my header? Please see attached image for the details of the end point and json body.
public class MyFile
{
[JsonProperty("mime")]
public string MimeType { get; set; }
[JsonProperty("data")]
public string Base64Data { get; set; }
}
public class PdfFile
{
[JsonProperty("file")]
public MyFile myFile { get; set; }
}
string pdfBase64;
const string pdfFileName = "file.pdf";
using (var pdfStream = await FileSystem.OpenAppPackageFileAsync(pdfFileName))
{
using (var pdfReader = new StreamReader(pdfStream))
{
var fileContents = await pdfReader.ReadToEndAsync();
pdfBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(fileContents));
}
}
var file = new MyFile();
var pdf = new PdfFile();
file.MimeType = "application/pdf";
file.Base64Data = "base64-data=" + pdfBase64;
pdf.myFile = file;
var jsonContent = JsonConvert.SerializeObject(pdf.myFile);
string baseUrl = "https://goodmorning-axa-dev.azure-api.net/upload";
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders
.Accept
.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, baseUrl);
requestMessage.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
requestMessage.Headers.Add("x-axa-api-key", apiKey);
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
string responseAsString = await responseMessage.Content.ReadAsStringAsync();
if (responseAsString != null)
{
Console.WriteLine(responseAsString);
}

problem when trying to redeem the token for user information in the microsoft graph api

once the user logs in with his microsoft account in the web application, a redirection is made to a method which aims to extract the user code and exchange it for the token, finally when I try to use the token with the api , when making the http request through the get method, it fails, here I show the code, it was make on C#:
var EmailRequest = "https://graph.microsoft.com/v1.0/me/?$select=displayName";
var Request = WebRequest.Create(EmailRequest);
Request.Headers.Add("Authorization", "Bearer " + accessToken );
var Response = (HttpWebResponse)Request.GetResponse();
Seems you are trying to get User displayName once the user login into web application.
Its depends how are you getting token, If you are getting token using
Client_Credentialprotocol you wouldn't get displayName using
query parameters like this. You have to use ROPC if you
want to get like this.
You could try following way:
Token And API Request
string tokenUrl = $"https://login.microsoftonline.com/YourTenent/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["client_id"] = "b603c7be-a866_client_id_6921e61f925",
["client_secret"] = "Vxf1SluKb_client_secret_eZ8wL/Yp8ns4sc=",
["resource"] = "https://graph.microsoft.com",
["username"] = "Login_User_Name.onmicrosoft.com",
["password"] = "User_Password"
});
dynamic json;
dynamic results;
HttpClient client = new HttpClient();
var tokenResponse = await client.SendAsync(tokenRequest);
json = await tokenResponse.Content.ReadAsStringAsync();
results = JsonConvert.DeserializeObject<AccessTokenClass>(json);
//New Block For Accessing Data from Microsoft Graph API
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/?$select=displayName");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", results.access_token);
HttpResponseMessage response = await client.SendAsync(request);
dynamic selectUserDisplayName = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
Class Used
public class AccessTokenClass
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string resource { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
}
You could refer to this Official Document
Hope this would help you.

How to get data in Xamarin C# url with body form-data

Hy Guys,
I'm trying to download data from a url by logging in with a php Web Service but I don't know how to do it.
If I make a POST request via postman inserting in BODY -> form-data the email and password, it gives me this:
{"Users": [{"email": "email#test.it", "nickname": "nickname", "image": "http: \ / \ / localhost \ / MyWebService \ / images \ /test_img.png "}]}
So I created a class in cs like this:
public class Users
{
[JsonProperty("users", NullValueHandling = NullValueHandling.Ignore)]
public User[] UsersUsers { get; set; }
}
public class User
{
[JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)]
public string email { get; set; }
[JsonProperty("nickname", NullValueHandling = NullValueHandling.Ignore)]
public string nickname { get; set; }
[JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)]
public string password { get; set; }
[JsonProperty("image", NullValueHandling = NullValueHandling.Ignore)]
public Uri image { get; set; }
}
Instead in the botton function I tried to write this code to contact the Service and make the call :
async private void login(Object sender, EventArgs e)
{
string email = lbl_email.Text;
string password = lbl_password.Text;
string url = "http://192.168.178.77/TestLoginURL/api/login.php";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("email", email),
new KeyValuePair<string, string>("password", password),
});
string contentType = "application/json";
JObject json = new JObject
{
{ "email", email},
{ "password", password }
};
HttpClient client = new HttpClient();
var response = await client.PostAsync(url, new StringContent(json.ToString(), Encoding.UTF8, contentType));
var data = await response.Content.ReadAsStringAsync();
var users = JsonConvert.DeserializeObject<Users>(data);
}
Obviously it is crushed and the error that gives me back is this:
Newtonsoft.Json.JsonReaderException
Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
So, someone can help me?
Where am I wrong?
Thanks
Solved in this way :
async private void login(Object sender, EventArgs e)
{
string email = lbl_email.Text;
string password = lbl_password.Text;
string url = "http://192.168.178.77/TestLoginURL/api/login.php";
Users users = new Users();
FormUrlEncodedContent formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("email", email),
new KeyValuePair<string, string>("password", password),
});
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
try
{
CancellationTokenSource cts = new CancellationTokenSource();
var responseMessage = client.PostAsync(url, formContent).Result;
var data = await responseMessage.Content.ReadAsStringAsync();
users = JsonConvert.DeserializeObject<Users>(data);
lbl_nickname.Text = users.UsersUsers[0].nickname;
}
catch (Exception ex)
{
ex.Message.ToString();
throw;
}
}
The way in which I passed the parameters to the url was practically wrong and consequently it gave me error by not recognizing the email and password I sent.

Categories

Resources