Making a web request with SSL Certificate and SOAP on C# - c#

I am facing an issue while making a request to an external web service from a C# code with SSL certificate authentication. Currently I am getting error code 500 Internal Server Error from that web service as response.
C# code to make request object and call it:
public class ERCOTWebRequest
{
string action = #"https://testmisapi.ercot.com/2007-08/Nodal/eEDS/EWS?MarketInfo";
public bool GetReports()
{
try
{
// WebRequestHelper.
var request = CreateSOAPWebRequest();
XmlDocument SOAPReqBody = new XmlDocument();
//SOAP Body Request
string nodalXml = File.ReadAllText(#"C:\Users\test\source\repos\WebRequestHelper\ERCOTWebServiceHelper\XMLFile1.xml");
SOAPReqBody.LoadXml(nodalXml);
using (Stream stream = request.GetRequestStream())
{
SOAPReqBody.Save(stream);
}
//Geting response from request
using (WebResponse Serviceres = request.GetResponse())
{
using (StreamReader rd = new StreamReader(Serviceres.GetResponseStream()))
{
//reading stream
var ServiceResult = rd.ReadToEnd();
//writting stream result on console
Console.WriteLine(ServiceResult);
Console.ReadLine();
}
}
return true;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public HttpWebRequest CreateSOAPWebRequest()
{
string host = #"https://testmisapi.ercot.com/2007-08/Nodal/eEDS/EWS/";
string certName = #"C:\Users\Test\Downloads\ERCOT_TEST_CA\TestAPI123.pfx";
string password = #"password";
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
X509Certificate2Collection certificates = new X509Certificate2Collection();
certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
req.AllowAutoRedirect = true;
req.ClientCertificates = certificates;
req.ContentType = "text/xml;charset=\"utf-8\"";
req.Accept = "text/xml";
req.Headers.Add("SOAPAction", action);
req.Proxy = WebRequest.GetSystemWebProxy();
//HTTP method
req.Method = "POST";
return req;
}
}
Currently I am getting an error(Error 500: Internal Server error) while trying to make SOAP request. Someone please help.

Related

HttpWebRequest Post synchronous call - TimeOut not working

My webrequest timeout does not seem to be working. The URL that host has some TLS setting issue. But even in cases of exceptions, is it not expected to respect the timeout?
The hostname has the domain name and not IP.Please let me know what I am missing for the timeout to work at 30secs immaterial of success/exception scenarios.
Find the code below - we have currently kept the timeout to be 30s but recieving the response after 1.15mins or more.
public string CallJsonService(string JsonString, string ServiceURL, string strLogUser, string RandomValue, string strAPIToCall)
{
string displayvalue = "";
try
{
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => { return true; };
ServicePointManager.Expect100Continue = false;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
byte[] bytestream = Encoding.UTF8.GetBytes(JsonString);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(ServiceURL);
req.Method = "POST";
req.ContentType = "application/json; charset=utf-8";
req.ContentLength = bytestream.LongLength;
req.Timeout = 30000;
req.ReadWriteTimeout = 30000;
req.KeepAlive = true;
String ProxyValue = objCommon.GetParamValue("ProxyValueForInstant");
req.Proxy = new System.Net.WebProxy(ProxyValue, true);
req.Headers.Add("vRanKey", Convert.ToString(RandomValue));
req.Accept = "application/json";
using (Stream stream = req.GetRequestStream())
{
stream.Write(bytestream, 0, bytestream.Length);
stream.Flush();
}
using (WebResponse responserequest = req.GetResponse())
{
Stream ResponseStream = responserequest.GetResponseStream();
displayvalue = HttpUtility.HtmlDecode((new StreamReader(ResponseStream)).ReadToEnd());
}
}
catch (WebException e)
{
using (WebResponse response = e.Response)
{
HttpWebResponse httpResponse = (HttpWebResponse)response;
if (response != null)
{
using (Stream data = response.GetResponseStream())
{
using (var reader = new StreamReader(data))
{
displayvalue = reader.ReadToEnd();
}
}
}
else
{
throw e;
}
}
}
catch (Exception ex)
{
throw ex;
}
return displayvalue;
}

HttpWebRequest The remote server returned an error: (401) Unauthorized

I am trying to make web request to a website that does not require any credentials.
I used postman utility with the cookie and it works fine. I took cookie from chrome browser.
. However, I tried setting cookie, TLS, use default credentials, but nothing is helping.
Main website: https://www.nseindia.com/option-chain On this website I go to developer tools and copy the cookie value.
Web Request URL: https://www.nseindia.com/api/option-chain-equities?symbol=APOLLOHOSP
Code:
void DOSomething()
{
try
{
string html = string.Empty;
string url = #"https://www.nseindia.com/api/option-chain-equities?symbol=APOLLOHOSP";
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = new CookieContainer();
string cook = System.Net.WebUtility.UrlEncode(txtCookie.Text.Trim());
Uri target = new Uri(url);
request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
request.UseDefaultCredentials = true;
request.PreAuthenticate = true;
request.Credentials = CredentialCache.DefaultCredentials;
request.CookieContainer.Add(new System.Net.Cookie("cookie",cook) { Domain = "nseindia.com" });
request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
Console.WriteLine(html);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Please help.

Bad Request when updating api in HttpWebRequest

I have used Cin 7 Endpoints to Update Order. Here is the link: Cin7 Update Order
and then when calling a api I will have Bad Request error. Here is the code
public string UpdateData(string endpoint, Dispatched saleOrder)
{
string xmlStringResult = string.Empty;
try
{
var req = (HttpWebRequest)WebRequest.Create(endpoint);
req.Method = "PUT";
req.ContentType = "application/json";
req.Credentials = GetCredential(endpoint);
var json = JsonConvert.SerializeObject(saleOrder);
if (!String.IsNullOrEmpty(json))
{
using (var ms = new MemoryStream())
{
using (var writer = new StreamWriter(req.GetRequestStream()))
{
writer.Write(json);
writer.Close();
}
}
}
using (var resp = (HttpWebResponse)req.GetResponse())
{
return resp.StatusDescription + resp.StatusCode;
}
}
catch (Exception ex)
{
AppendError(string.Format("UpdateData catch exception: {0}", ex.Message), LogType.System);
}
return xmlStringResult;
}
Extracting credential
private CredentialCache GetCredential(string url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var credentialCache = new CredentialCache();
credentialCache.Add(new Uri(url), "Basic", new NetworkCredential(_cred.Username, _cred.Key));
return credentialCache;
}
Here is the json data to update
{"id":2631912,"dispatchedDate":"2018-05-10T11:49:41.6238207+08:00","trackingCode":"6J7010926112","reference":"255552"}
Please help and thank you in advance.

http get works in browser and postman but get a 401 using c# httpwebrequest

I have a web app hosted in azure. When I use postman to make the request I get a
json result, which is the correcet response. When I try to make the same request via C# using the same token I receive a errpr - The remote server returned an error: (401) Unauthorized.
here is the code I use to make the request.
public string RequestData(string queryString, string token)
{
var request = (HttpWebRequest)WebRequest.Create(queryString);
request.Proxy = GetProxy();
request.Credentials = CredentialCache.DefaultCredentials;
request.PreAuthenticate = true;
request.UseDefaultCredentials = true;
request.Method = "GET";
request.ContentType = "application/json";
request.ContentLength = 0;
request.CookieContainer = new CookieContainer();
request.Headers.Add("authorization", "Bearer " + token);
using (var webresponse = request.GetResponse())
{
if (webresponse.GetResponseStream() == Stream.Null)
{
throw new Exception("Response stream is empty");
}
var response = (HttpWebResponse)webresponse;
if (response.StatusCode != HttpStatusCode.OK)
{
return response.StatusCode.ToString();
}
else
{
return response.StatusCode.ToString();
}
}
}
I have double checked the token to ensure it is correct and it is.
Another point I wanted to mention is that it did not work initially in
Postman without enabling Interceptor. This goes for Advanced Rest Client.
The request did not work until I enabled "XHR" and installed ARC cookie exchange.
I have checked the request headers in Fiddler and noticed there are no additional headers except for the authorization one (which I add as well).
UPDATE:
I got a successfull response in Postman (https://www.getpostman.com/)
and ran the code it generated for c# using RestSharp. In the response
the error thrown was
"You do not have permission to view this directory or page."
Which points to the token not being correct. Which is confusing since it works
in Postman and Advanced Rest Client. Also I must mention I retrieve the token
on each call using the clientid and secret using the following code:
public async static Task<AzureAccessToken> CreateOAuthAuthorizationToken(string clientId, string clientSecret, string resourceId, string tenantId)
{
AzureAccessToken token = null;
var oauthUrl=string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
var reqBody = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}",clientId, clientSecret);
var client = new HttpClient();
HttpContent content = new StringContent(reqBody);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content))
{
if (response.IsSuccessStatusCode)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken));
Stream json = await response.Content.ReadAsStreamAsync();
token = (AzureAccessToken)serializer.ReadObject(json);
return token;
}
return null;
}
}
after checking the log in azure, I saw the following error message:
JWT validation failed: IDX10214: Audience validation failed. Audiences: '00000002-0000-0000-c000-000000000000'. Did not match: validationParameters.ValidAudience: 'f50a9d02-b8f4-408f-aaf8-0046e6cbf7a6' or validationParameters.ValidAudiences: 'null'.
I resolved the issue by adding '00000002-0000-0000-c000-000000000000' to the "Allowed Token Audiences" under Azure Active Directory Settings.
I have called third party API. When I use postman to make the request I get a json result, which is the correct response. When I try to make the same request via C# using the same token I receive a error - The remote server returned an error: (401) Unauthorized. Finally I got the solution.
When I make the login request some cookies will send by the server and that cookie will store in postman. If you see code snippet you will see information about request that is raised by postman.
When I call the Login method I stored the cookies like below:
public ResponseData OnGetResponseFromAPI(string URL, string Method, string PostData = null, Dictionary<string, string> Headers = null, string body = null, string ContentType = "application/json")
{
ResponseData response = new ResponseData();
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
var webRequest = (HttpWebRequest)WebRequest.Create(URL);
CookieContainer cookieJar = new CookieContainer();
webRequest.CookieContainer = cookieJar;
webRequest.Method = Method;
webRequest.ContentType = ContentType;
if (Method == "GET")
{
var type = webRequest.GetType();
var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(webRequest);
var methodType = currentMethod.GetType();
methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);
}
if (Headers == null)
Headers = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> header in Headers)
{
webRequest.Headers.Add(header.Key, header.Value);
}
if (!string.IsNullOrEmpty(PostData))
{
var RequestStream = new StreamWriter(webRequest.GetRequestStream());
RequestStream.Write(PostData);
RequestStream.Close();
}
if (!string.IsNullOrEmpty(body))
{
byte[] byteArray = Encoding.UTF8.GetBytes(body);
webRequest.ContentLength = byteArray.Length;
Stream dataStream = webRequest.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
var ResponseStream = new StreamReader(webRequest.GetResponse().GetResponseStream());
string cookie = string.Empty;
CookieCollection allCookies = cookieJar.GetCookies(webRequest.RequestUri);
foreach (Cookie c in allCookies)
{
cookie = cookie + c.Name + "=" + c.Value+";";
}
cookie = cookie.Substring(0, cookie.LastIndexOf(';'));
var ResponseData = ResponseStream.ReadToEnd();
response.response=ResponseData.ToString();
response.cookie=cookie;
return response;
}
catch (WebException webException)
{
if (webException == null || webException.Response == null)
return null;
var responseStream = webException.Response.GetResponseStream() as MemoryStream;
if (responseStream == null)
return null;
var responseBytes = responseStream.ToArray();
var responseString = Encoding.UTF8.GetString(responseBytes);
response.response = responseString;
return response;
}
}
Whenever I am calling any api method I am sending token and cookie in header like below:
public string DownLoadDocument( string FilePath, string FileName, string token,string cookie)
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
HttpWebRequest webRequest;
webRequest = (HttpWebRequest)WebRequest.Create(URL);
webRequest.Method = "GET";
webRequest.ContentType = "application/octet-stream;charset=UTF-8";
webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1";
webRequest.Headers.Add("Cookie", cookie);
webRequest.Headers.Add("Authentication", "Bearer "+token);
webRequest.Headers.Add("Content-Disposition", "attachment");
Stream responseReader = webRequest.GetResponse().GetResponseStream();
using (var fs = new FileStream(FilePath, FileMode.Create))
{
responseReader.CopyTo(fs);
}
}
catch (Exception ex)
{
throw;
}
return FilePath;
}

C# Getting proxy settings from Internet Explorer

i have a problem in certain company in germany. They use proxy in their network and my program cant communicate with server.
IE works with this settings:
It means:
Automatically detect settings
This is the code:
public static bool CompleteValidation(string regKey)
{
string uri = "***";
int c = 1;
if (Counter < 5) c = 6 - Counter;
string response = "";
try
{
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.AllowWriteStreamBuffering = true;
request.Method = "POST";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
request.Headers.Add(HttpRequestHeader.AcceptLanguage, "pl,en-us;q=0.7,en;q=0.3");
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
request.Headers.Add(HttpRequestHeader.AcceptCharset, "ISO-8859-2,utf-8;q=0.7,*;q=0.7");
request.KeepAlive = true;
//proxy settings
string exepath = Path.GetDirectoryName(Application.ExecutablePath);
string proxySettings = exepath + #"\proxy.ini";
WebProxy wp = new WebProxy();
if (File.Exists(proxySettings)) {
request.Proxy = WebRequest.DefaultWebProxy;
IniFile ini = new IniFile(proxySettings);
string user = ini.IniReadValue("Proxy", "User");
string pass = ini.IniReadValue("Proxy", "Password");
string domain = ini.IniReadValue("Proxy", "Domain");
string ip = ini.IniReadValue("Proxy", "IP");
string port_s = ini.IniReadValue("Proxy", "Port");
int port = 0;
if (!string.IsNullOrEmpty(ip))
{
if (!string.IsNullOrEmpty(port_s))
{
try
{
port = Convert.ToInt32(port_s);
}
catch (Exception e)
{
ErrorLog.AddToLog("Problem with conversion of port:");
ErrorLog.AddToLog(e.Message);
ErrorLog.ShowLogWindow();
}
wp = new WebProxy(ip, port);
} else {
wp = new WebProxy(ip);
}
}
if (string.IsNullOrEmpty(domain))
wp.Credentials = new NetworkCredential(user, pass);
else
wp.Credentials = new NetworkCredential(user, pass, domain);
request.Proxy = wp;
}
string post = "***";
request.ContentLength = post.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = null;
try
{
writer = new StreamWriter(request.GetRequestStream()); // Here is the WebException thrown
writer.Write(post);
writer.Close();
}
catch (Exception e)
{
ErrorLog.AddToLog("Problem with request sending:");
ErrorLog.AddToLog(e.Message);
ErrorLog.ShowLogWindow();
}
HttpWebResponse Response = null;
try
{
Response = (HttpWebResponse)request.GetResponse();
}
catch (Exception e)
{
ErrorLog.AddToLog("Problem with response:");
ErrorLog.AddToLog(e.Message);
ErrorLog.ShowLogWindow();
}
//Request.Proxy = WebProxy.GetDefaultProxy();
//Request.Proxy.Credentials = CredentialCache.DefaultCredentials;
string sResponseHeader = Response.ContentEncoding; // get response header
if (!string.IsNullOrEmpty(sResponseHeader))
{
if (sResponseHeader.ToLower().Contains("gzip"))
{
byte[] b = DecompressGzip(Response.GetResponseStream());
response = System.Text.Encoding.GetEncoding(Response.ContentEncoding).GetString(b);
}
else if (sResponseHeader.ToLower().Contains("deflate"))
{
byte[] b = DecompressDeflate(Response.GetResponseStream());
response = System.Text.Encoding.GetEncoding(Response.ContentEncoding).GetString(b);
}
}
// uncompressed, standard response
else
{
StreamReader ResponseReader = new StreamReader(Response.GetResponseStream());
response = ResponseReader.ReadToEnd();
ResponseReader.Close();
}
}
catch (Exception e)
{
ErrorLog.AddToLog("Problem with comunication:");
ErrorLog.AddToLog(e.Message);
ErrorLog.ShowLogWindow();
}
if (response == "***")
{
SaveKeyFiles();
WriteRegKey(regKey);
RenewCounter();
return true;
}
else
{
return false;
}
}
My program logs it as:
[09:13:18] Searching for hardware ID
[09:13:56] Problem with response:
[09:13:56] The remote server returned an error: (407) Proxy Authentication Required.
[09:15:04] problem with comunication:
[09:15:04] Object reference not set to an object instance.
If they write user and pass into proxy.ini file, program works. But the problem is they cant do that. And somehow IE works without it. Is there any way to get those settings from IE or system?
Use GetSystemWebProxy to return what the system default proxy is.
WebRequest.DefaultProxy = WebRequest.GetSystemWebProxy();
But every HttpWebRequest should automatically be filled out with this information by default. For example, the following snippet in a standalone console application should print the correct information on a system with a PAC file configured.
HttpWebRequest myWebRequest=(HttpWebRequest)WebRequest.Create("http://www.microsoft.com");
// Obtain the 'Proxy' of the Default browser.
IWebProxy proxy = myWebRequest.Proxy;
// Print the Proxy Url to the console.
if (proxy != null)
{
Console.WriteLine("Proxy: {0}", proxy.GetProxy(myWebRequest.RequestUri));
}
else
{
Console.WriteLine("Proxy is null; no proxy will be used");
}
Use DefaultNetworkCredentials to return system proxy credentials.
request.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

Categories

Resources