I have a situation I just don't understand.
I have a c# class library application that works perfectly when I step through it in debug mode within VS2017.
When I compile it in "Debug" mode and call it from a console app it fails when calling a https API endpoint and does not report any error.
This is how I am calling the "CreateOrder":
// send the order to DNAGenotek
DNAGenotek.Model.Order.CreateResponse.CreateOrderResponse orderResponse = await DNAGenotek.Orders.CreateOrder(DNAGenotekAPIKey, DNAGenotekOrder);
This is how I am calling the "CallAPIString" function:
public static async Task<Model.Order.CreateResponse.CreateOrderResponse> CreateOrder(string APIKey, Model.Order.Create.Order order)
{
// convert the object to a string
string orderAsString = JsonConvert.SerializeObject(order);
// create the order
string result = await Helpers.CallAPIString(APIKey, "https://sofia-stage.dnagenotek.com/api/v2/orders", "POST", orderAsString);
DNAGenotek.Model.Order.CreateResponse.CreateOrderResponse orderResponse = JsonConvert.DeserializeObject<Model.Order.CreateResponse.CreateOrderResponse>(result);
return orderResponse;
}
I have attached to the running console .exe and stepped through and it fails on this line when doing a POST
WebResponse httpResponseGETDELETE = await httpWebRequest.GetResponseAsync();
In the following code:
public static async Task<string> CallAPIString(string APIKey, string url, string method, string bodyContent = null)
{
try
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.Method = method;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add("Authorization", "Basic " + APIKey);
switch (method)
{
case "GET":
case "DELETE":
WebResponse httpResponseGETDELETE = await httpWebRequest.GetResponseAsync();
using (StreamReader streamReader = new StreamReader(httpResponseGETDELETE.GetResponseStream()))
{
string result = await streamReader.ReadToEndAsync();
return result;
}
case "POST":
case "PUT":
case "PATCH":
using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
await streamWriter.WriteLineAsync(bodyContent);
await streamWriter.FlushAsync();
streamWriter.Close();
WebResponse httpResponsePOSTPUT = await httpWebRequest.GetResponseAsync();
using (StreamReader streamReader = new StreamReader(httpResponsePOSTPUT.GetResponseStream()))
{
string result = await streamReader.ReadToEndAsync();
return result;
}
}
default:
return "Method Not Found!";
}
}
catch (Exception e)
{
return e.Message;
}
}
It doesn't even bubble up to the catch line. It just closes the app.
When I watch the network traffic in Fiddler I can see it attempting to open the https connection but it then stalls.
This is what I see in Fiddler:
I am complete stumped how to get to the root cause without an error message?
UPDATE
I have now rewritten my code using the HttpClient and it now fails at the line:
HttpResponseMessage response = await client.PostAsync(url, content);
in this code:
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Basic " + APIKey);
StringContent content = new StringContent(bodyContent, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
return await response.Content.ReadAsStringAsync();
}
OK - this was my fault.
In the console application I was using :
SyncEngine.Functions.Sync("APIKey1", "APIKey2");
When I should have been using:
SyncEngine.Functions.Sync("APIKey1", "APIKey2").GetAwaiter().GetResult();
Sorry guys
Related
I have a form on my website that makes a basic Get request to an API (managed by the client). It was working for years, until suddenly, it started throwing the error:
The underlying connection was closed: An unexpected error occurred on a send
I've had the client looking into the API, and aren't aware of anything that has changed on their server. Our code hasn't changed either. However, there must be something in the code that is affecting its ability to connect with the server, because I am able to make the Get request in the browser, through postman, and in a brand new console app that we created for testing. Both the website and console app are targeting .Net 4.6.2
Here is the complete code of the console app, which is exactly the same as what's being used within the form submission in my website (with the exception of that I hardcoded the querystring for testing):
internal class Program{
static void Main(string[] args){
url = "https://apiurl.com/api/UserSearch";
string webServiceUrl = url + "?email=test#yopmail.com";
var response = ServiceHelper.GetHttpWebRequest(webServiceUrl);
using (Stream stream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(stream);
var jsonResponse = reader.ReadToEnd();
Console.WriteLine(jsonResponse);
}
}
}
public static class ServiceHelper
{
public static HttpWebResponse GetHttpWebRequest(string requestUrl, NameValueCollection requestHeaders = null)
{
var request = (HttpWebRequest)WebRequest.Create(requestUrl);
if (requestHeaders != null)
{
request.Headers.Add(requestHeaders);
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException wex)
{
Log.Error("ServiceHelper: Error getting Response Stream. "
+ Environment.NewLine + "RequestUrl = " + requestUrl
+ Environment.NewLine + GetWebExceptionDetails(wex), typeof(ServiceHelper));
throw;
}
string logMessage = "ServiceHelper: Called " + requestUrl;
if (response.StatusCode != HttpStatusCode.OK)
{
logMessage += " Response Status Code:" + response.StatusCode;
}
Log.Info(logMessage, typeof(ServiceHelper));
return response;
}
}
Since the basic code for the web request works in the console app, there must be something in the website configuration that's messing with the settings, but I'm not sure where to start looking.
EDIT: Alternate code that uses httpclient instead. This also works in console, fails in the website. Rather than immediately throwing an error, it just seems to hang in the async request indefinitely.
public static class httpclient
{
// uses asynchronous operations and await
public static async Task<string> Post(string url, string json)
{
// Encode the json data for HTTP
StringContent data = new StringContent(json, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsync(url, data);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
public static async Task<string> Get(string url, string querystring)
{
var builder = new UriBuilder(url);
builder.Query = querystring;
var uri = builder.ToString();
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(uri);
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
}
internal class Program{
static void Main(string[] args){
string webServiceUrl = "https://apiurl.com/api/UserSearch";;
var querystring = "?email=" + email;
var result = httpclient.Get(webServiceUrl, querystring).GetAwaiter().GetResult();
console.log(results);
}
}
I'm trying to develop an API suite so I can call it by passing some parameters. I successfully made the part about GET method.
POST seems a bit more complicated and I didn't find any source so I can understand how to make it. My plan is to call in POST with a body as parameter
I didn't develop the API I'm going to POST but it's not even a public one but inside the project development. Using .NET core 5.0. The scope is to call some APIs as regression tests before any deploy from the dev team and some of them might return a data that will be used as body param in the next API so I'm developing a console app that check if everything is OK.
This is the GET request I developed, could you help me understand how to make it using POST method?:
static void Main(string[] args)
{
string url = ConfigurationManager.AppSettings["url"];
string jsonBody = "";
string method = "GET";
string result = CallApi(url, method, jsonBody);
}
public static string CallApi(string url, string method, string bodyInput)
{
string bodyOutput = null;
HttpClient client = new();
Uri uri = new(url);
switch (method)
{
case "GET":
Task<HttpResponseMessage> response = client.GetAsync(uri);
HttpResponseMessage result = response.Result;
HttpContent content = result.Content;
bodyOutput = content.ReadAsStringAsync().Result;
break;
case "POST":
//bodyInput
break;
case "PUT":
break;
case "DELETE":
break;
default:
break;
}
return bodyOutput;
}
}
Thanks
Hi your code should look like this:
static async Task Main(string[] args)
{
string baseAddress = ConfigurationManager.AppSettings["baseAddress"];
string path = ConfigurationManager.AppSettings["path"];
string jsonBody = "";
HttpMethod method = HttpMethod.Get;
string result = await CallApi(baseAddress, path, method, jsonBody);
}
public static async Task<string> CallApi(string baseAddress, string path, HttpMethod method, string body)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = null;
switch (method)
{
case HttpMethod.Get:
response = await client.GetAsync(path);
break;
case HttpMethod.Post:
response = await client.PostAsJsonAsync(path, body);
break;
case HttpMethod.Put:
response = await client.PutAsJsonAsync(path, body);
break;
case HttpMethod.Delete:
response = await client.DeleteAsync(path);
break;
default:
throw new NotImplementedException();
}
// Throw an exception if the response code is not successful
response.EnsureSuccessStatusCode();
// Read the response
string bodyOutput = await response.Content.ReadAsStringAsync();
return bodyOutput;
}
}
You can see a more detailed example here:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
call this function using await , unlike what your doing in your function.
Post :
static async Task<string> Postfunc()
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new object obj());
var data = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
var response = await client.PostAsync(url, data);
string result = await response.Content.ReadAsStringAsync();
return result;
}
I am trying to make a program that requests my website with a username, password, hardware ID and a key in POST.
I have this code here that should send a POST request to my website with that form data, but when it sends, my webserver reports back that it didn't receive the POST data
try
{
string poststring = String.Format("username={0}&password={1}&key={2}&hwid={3}", Username, Password, "272453745345934756392485764589", GetHardwareID());
HttpWebRequest httpRequest =
(HttpWebRequest)WebRequest.Create("mywebsite");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
byte[] bytedata = Encoding.UTF8.GetBytes(poststring);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse httpWebResponse =
(HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = httpWebResponse.GetResponseStream();
StringBuilder sb = new StringBuilder();
using (StreamReader reader =
new StreamReader(responseStream, System.Text.Encoding.UTF8))
{
string line;
while ((line = reader.ReadLine()) != null)
{
sb.Append(line);
}
}
return sb.ToString();
}
catch (Exception Error)
{
return Error.ToString();
}
If someone could help me, I would really appreciate it.
As per HttpWebRequest documentation
We don't recommend that you use HttpWebRequest for new development. Instead, use the System.Net.Http.HttpClient class.
HttpClient contains only asynchronous API because Web requests needs awaiting. That's not good to freeze entire Application while it's pending response.
Thus, here's some async function to make POST request with HttpClient and send there some data.
First of all, create HttpClient seperately because
HttpClient is intended to be instantiated once per application, rather than per-use.
private static readonly HttpClient client = new HttpClient();
Then implement the method.
private async Task<string> PostHTTPRequestAsync(string url, Dictionary<string, string> data)
{
using (HttpContent formContent = new FormUrlEncodedContent(data))
{
using (HttpResponseMessage response = await client.PostAsync(url, formContent).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
Or C# 8.0
private async Task<string> PostHTTPRequestAsync(string url, Dictionary<string, string> data)
{
using HttpContent formContent = new FormUrlEncodedContent(data);
using HttpResponseMessage response = await client.PostAsync(url, formContent).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
Looks easier than your code, right?
Caller async method will look like
private async Task MyMethodAsync()
{
Dictionary<string, string> postData = new Dictionary<string, string>();
postData.Add("message", "Hello World!");
try
{
string result = await PostHTTPRequestAsync("http://example.org", postData);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
If you're not familiar with async/await, it's time to say Hello.
i'm very new to C#, let alone Windows Phone development :)
I'm trying to send a request, get the JSON response, but if there is an error (such as 401), be able to tell the user such. Here is my code:
async Task<string> AccessTheWebAsync()
{
//builds the credentials for the web request
var credentials = new NetworkCredential(globalvars.username, globalvars.password);
var handler = new HttpClientHandler { Credentials = credentials };
//calls the web request, stores and returns JSON content
HttpClient client = new HttpClient(handler);
Task<string> getStringTask = client.GetStringAsync("https://www.bla.com/content");
String urlContents = await getStringTask;
return urlContents;
}
I know it must be something I'm doing wrong in the way that I send the request and store the response...but i'm just not sure what.
If there is an error, I get a general:
net_http_message_not_success_statuscode
Thank you!
You could use te GetAsync() method instead of the GetStringAsync().
HttpResponseMessage response = await client.GetAsync("https://www.bla.com/content");
if(!response.IsSuccessStatusCode)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
do something...
}
}
String urlContents = await response.Content.ReadAsStringAsync();
This way you can make use of the HttpStatusCode enumerable to check the returned status code.
Instead of using an HttpClient use a plain good old HttpWebRequest :)
async Task<string> AccessTheWebAsync()
{
HttpWebRequest req = WebRequest.CreateHttp("http://example.com/nodocument.html");
req.Method = "GET";
req.Timeout = 10000;
req.KeepAlive = true;
string content = null;
HttpStatusCode code = HttpStatusCode.OK;
try
{
using (HttpWebResponse response = (HttpWebResponse)await req.GetResponseAsync())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
content = await sr.ReadToEndAsync();
code = response.StatusCode;
}
}
catch (WebException ex)
{
using (HttpWebResponse response = (HttpWebResponse)ex.Response)
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
content = sr.ReadToEnd();
code = response.StatusCode;
}
}
//Here you have now content and code.
return content;
}
I am trying to access to some rest services of a specific web server for my WP8 app and I canĀ“t do it well. For example, this is the code that I use when I try to login the user. I have to pass a string that represents a Json object ("parameters") with the username and the password and the response will be a json object too. I can't find the way to pass this pasameters in the rest request.
This is the code;
public void login(string user, string passwrd)
{
mLoginData.setUserName(user);
mLoginData.setPasswd(passwrd);
string serviceURL = mBaseURL + "/service/user/login/";
string parameters = "{\"username\":\"" + mLoginData.getUserName() + "\",\"password\":\"" + mLoginData.getPasswd() + "\"}";
//MessageBox.Show(parameters);
//MessageBox.Show(serviceURL);
//build the REST request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceURL);
request.ContentType = "application/json";
request.Method = "POST";
//async request launchs "Gotresponse(...) when it has finished.
request.BeginGetResponse(new AsyncCallback(GotResponse), request);
}
private void GotResponse(IAsyncResult ar)
{
try
{
string data;
// State of request is asynchronous
HttpWebRequest myHttpWebRequest = (HttpWebRequest)ar.AsyncState;
using (HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(ar))
{
// Read the response into a Stream object.
Stream responseStream = response.GetResponseStream();
using (var reader = new StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
}
}
catch (Exception e)
{
string exception = e.ToString();
throw;
}
}
I tried too with the webClient and the httpClient classes too but without any result.
Thanks and sorry for my bad english.
I solved it with the HttpClient class. This is the code.
public async void login(string user, string passwrd)
{
string serviceURL = "";
string parameters = "";
HttpClient restClient = new HttpClient();
restClient.BaseAddress = new Uri(mBaseURL);
restClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, serviceURL);
req.Content = new StringContent(parameters, Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
string responseBodyAsText = "";
try
{
response = await restClient.SendAsync(req);
response.EnsureSuccessStatusCode();
responseBodyAsText = await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException e)
{
string ex = e.Message;
}
if (response.IsSuccessStatusCode==true)
{
dynamic data = JObject.Parse(responseBodyAsText);
}
else
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
MessageBox.Show("User or password were incorrect");
}
else
{
MessageBox.Show("NNetwork connection error");
}
}
}
I wasn't setting the header values of the request correctly.
I hope this can help someone.