Convert Working Postman Request to C# (HttpClient) - c#

Having a hard time converting a successful Postman request to a successful request in C#. Showing my code using HttpClient, but have also tried with PostSharp and HttpRequest. I am using a local pfx certificate file which has a password.
In Postman:
Added the PFX cert to Client Certificates
Authorization tab has username and password (Basic Auth)
Authorization header automatically generates based on above ("Basic <encoded username/password>")
Body is "{}"
Sends successfully (200).
Using HttpClient:
var host = #"https://thehost/service/verb?param1=blah&param2=1111111";
const string certName = #"C:\Key.pfx";
const string userName = "userName";
const string certPassword = "password1";
const string authPassword = "password2";
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
// tried many combinations here
handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 |
SslProtocols.Tls12 | SslProtocols.Tls13;
var cert = new X509Certificate2(certName, certPassword);
handler.ClientCertificates.Add(cert);
//not sure if this is needed
handler.ServerCertificateCustomValidationCallback += (message, certificate2, arg3, arg4) => true;
var client = new HttpClient(handler);
//not sure if these are needed
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
// added this to both the request and the client.
// Also tried "*/*" for both
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var request = new HttpRequestMessage();
request.RequestUri = new Uri(host);
request.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
request.Content = new StringContent("{}", Encoding.UTF8,
"application/json");
request.Method = HttpMethod.Post;
//basic auth header
var authenticationString = $"{userName}:{authPassword}";
var base64EncodedAuthenticationString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authenticationString));
var authHeader = new AuthenticationHeaderValue("Basic",
base64EncodedAuthenticationString);
request.Headers.Authorization = authHeader;
try
{
var httpResponseMessage = client.SendAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
}catch (Exception e){
Console.WriteLine(e);
throw;
}
This returns Unauthorized (401). The response text contains "Invalid user name or password."
Any thoughts on what might not be matching up between the two requests?

Have you tried using the Postman code snippets to auto-generate the code? It uses the RESTSharp REST API client library for C#.
Click on the </> icon and choose "C# - RestSharp" and it should give you code.
https://learning.postman.com/docs/sending-requests/generate-code-snippets/

Related

WebException: The request was aborted: Could not create SSL/TLS secure channel but working with POSTMAN

I am calling Power school API to fetch student data. Using the below code.
public Token GetAuthToken(string baseUrl, string authKey)
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
var client = new HttpClient();
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var values = new Dictionary<string, string> { { "grant_type", "client_credentials" } };
var content = new FormUrlEncodedContent(values);
client.DefaultRequestHeaders.Add("Authorization", $"Basic {authKey}");
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = content,
};
request.Headers.Add("Authorization", $"Basic {authKey}");
var response = client.PostAsync(baseUrl+ "/oauth/access_token", content).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
var token = JsonConvert.DeserializeObject<Token>(responseString);
return token;
}
catch (Exception e)
{
throw;
}
finally
{
}
}
This code was working fine 3 months ago but now started giving error WebException: The request was aborted: Could not create SSL/TLS secure channel.
I tried to post the same request from POSTMAN and it was able to connect and get data. Postman shows TLS 1.2. See the below Image
I also tried the code generated from the POSTMAN and it was giving the same error. Below is the code generated from POSTMAN
var client = new RestClient("<MY URL HERE>");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Basic <MY KEY HERE>");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
I am using these on Windows Server 2012 R2. POSTMAN is able to connect while C# (.Net Framework 4.8) is failing.
What could be the issue? I tried a combination of all TLS versions available from TLS to TLS13
EDIT
When I check event logs, I am getting below error

RestClient Digest Authentication C#

I am trying to make a post request using RestClient with Digest Authentication .
But I keep getting error :
Cannot load all required data from authenticateHeader. Data: Realm="api domain"&Nonce="7fe0990c20aaa812c5a0a725e3a01423"&Qop="""
My code
var client = new RestClient("ApiUrlPath");
client.Authenticator = new DigestAuthenticator("username","Password");
client.UseUtf8Json();
client.Timeout = -1;
var request = new RestRequest();
request.AlwaysMultipartFormData = true;
request.AddParameter("id", "2");
var response = client.Execute(request);
The request works in postman

How to post a Multipart/mixed:boundary=”MIME-Boundary” with two different document types and HMAC signature in C# [Open Invoice]

As part of an integration to Open Invoice the API is requiring a legacy Multipart/mixed:boundary=”MIME-Boundary” request header. There is very minimal documentation on utilizing this Header for C# across the internet including Microsoft documentation.
The two documents in the POST request include a UTF-8 XML string and a Base64 pdf string. The outbound request requires Content-Type headers (one for each document) which HTTPRequestMessage does not support natively as it assumes you will be delivering a "text/plain" request.
Headers.Add() //throws an exception when setting Content-Type
Headers.TryAddWithoutValidation() //does not fix the problem
Additionally the request needs to be signed with an HMAC hash of the request body.
How do I build this request in C#?
Build the client
X509Certificate2 cert = new X509Certificate2(certificateName, certPassword);
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(cert);
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(openInvoiceURL);
Build The Request
//Starting from byte[] for both files
var xmlString = System.Text.Encoding.UTF8.GetString(xmlBytes);
string pdf64 = Convert.ToBase64String(pdfBytes);
string url = "/docp/supply-chain/v1/invoices";
var multiPartContent = new MultipartContent("mixed", "_MIME-Boundary");
var xmlHttpContent = new StringContent(xmlString);
xmlHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
multiPartContent.Add(xmlHttpContent);
var pdfHttpContent = new StringContent(pdf64);
pdfHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
pdfHttpContent.Headers.Add("content-transfer-encoding", "base64");
pdfHttpContent.Headers.Add("Content-ID", pdfName);
multiPartContent.Add(pdfHttpContent);
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Content = multiPartContent;
request = AttachHMAC(request, secretKey);
var response = client.SendAsync(request).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
Sign the Request Body (only on POST)
private HttpRequestMessage AttachHMAC(HttpRequestMessage request, string secretKey)
{
var payload = string.Empty;
if(request != null && request.Content != null)
{
payload = request.Content.ReadAsStringAsync().Result;
}
var hashMaker = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
var payloadByteArray = Encoding.UTF8.GetBytes(payload);
byte[] hash = hashMaker.ComputeHash(payloadByteArray);
var base64Hash = Convert.ToBase64String(hash);
request.Headers.Add("mac", base64Hash);
return request;
}

SharePoint 2010 ListData.svc REST API Randomly returns error: 'uriString' parameter represents an absolute URI from HTTPClient

I'm experiencing an intermittent problem with our SharePoint 2010 REST API. I have a .Net Core Console application that makes a series of calls to SharePoint List Endpoints to get a JSON response. My problem is that at random times, the API response is an error page:
A relative URI cannot be created because the 'uriString' parameter
represents an absolute URI.http://www.example.com/somefolder/file.svc
Is there a problem with my HTTPClient configuration? Is there a configuration setting that I can toggle in SharePoint to prevent the error or more reliable?
var uri = new Uri("http://www.example.com/");
var credential = new NetworkCredential("username", "password", "domain");
var credentialsCache = new CredentialCache { { uri, "NTLM", credential } };
var handler = new HttpClientHandler { Credentials = credentialsCache };
HttpClient Client = new HttpClient(handler);
Client.BaseAddress = new Uri("http://www.example.com/sharepoint/path/ListData.svc/");
// Make the list request
var result = await Client.GetAsync("MySharePointList");
To get the list items, the REST API URI like below.
http://sp2010/_vti_bin/ListData.svc/listname
Modify the code as below.
var siteUrl = "http://www.example.com/";
var listName = "MySharePointList";
var uri = new Uri(siteUrl);
var credential = new NetworkCredential("username", "password", "domain");
var credentialsCache = new CredentialCache { { uri, "NTLM", credential } };
var handler = new HttpClientHandler { Credentials = credentialsCache };
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(uri, "/_vti_bin/ListData.svc");
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
client.DefaultRequestHeaders.Add("ContentType", "application/json;odata=verbose");
var requestURL = siteUrl + "/_vti_bin/ListData.svc/" + listName;
// Make the list request
var result = client.GetAsync(requestURL).Result;
var items= result.Content.ReadAsStringAsync();

facebook error An active access token must be used to query information about the current user

I am using Facebook C# SDK with RestClient and RestRequest Classes, in order to connect to facebook.
But every few calls I am getting the following error from facebook:
An active access token must be used to query information about the
current user
this is my code:
var client = new RestClient { Authority = "https://graph.facebook.com/v2.1/oauth/" };
var request = new RestRequest { Path = "access_token" };
request.AddParameter("client_id", Storage.FacebookClientId);
request.AddParameter("redirect_uri", CallbackUrl);
request.AddParameter("client_secret", Storage.FacebookApplicationSecret);
request.AddParameter("code", code);
RestResponse response = client.Request(request);
// A little helper to parse the querystrings.
StringDictionary result = ParseQueryString(response.Content);
sAccessToken = result["access_token"];
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
var client = new RestClient { Authority = "https://graph.facebook.com/v2.1/" };
var request = new RestRequest { Path = "me" };
request.AddParameter("access_token", sAccessToken);
RestResponse response = client.Request(request);
Dictionary<string, object> result = _serializerService.Deserialize(response.Content);
Any Ideas please?

Categories