HTTP persistent connection in C# - c#

I have to make an HTTP persistent connection to a chinese security camera so I can obtain certain thermographic information. The manufacturer told me that they implemented HTTP persistent connection (I have never made persistent connections before).
This is the code I have right now:
var uri = new Uri($"http://<cam's IPv4>/ISAPI/Thermal/channels/2/thermometry/realTimethermometry/rules?format=json");
var credentialCache = new CredentialCache();
credentialCache.Add(uri, "Digest", new NetworkCredential("test", "test"));
using (var handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
Credentials = credentialCache
})
{
using (var httpClient = new HttpClient(handler))
{
httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
var response = await httpClient.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return null;
}
}
}
The thing is I'm not getting any response at all. How can I transform this code to HTTP 1.1 or make a persistent connection with this?.
For what I have been reading, there should only be an initial request and then I would keep receiving responses. Or at least that is what tbe manufacturer is telling me:
if you already called GET
/ISAPI/Thermal/channels/2/thermometry/realTimethermometry/rules?format=json
and established a connection, just receive alarms from the connection,
please do not call GET
/ISAPI/Thermal/channels/2/thermometry/realTimethermometry/rules?format=json
again

Related

C# - AWS EC2 Outgoing Traffic Does Not Initiate

we are using Cloudinary and AWS S3 Bucket as CDN for our application.
At my local development machine, the Cloudinary.NET and AWS SDK works as expected and can upload files. However when I publish the application to the EC2 instance, it never even initiates the HTTP(s) connection. I can see that through WireShark and Microsoft Network Monitor tools. No TCP requests are made, and the code never reaches the lines after the network calls (the SDKs' methods).
To test things out, I even tried implement the API calls using C#'s HttpClient to no avail. Somehow the calls to the HTTP protocol from C# are not processed at all with no exception. It acts like an infinite timeout.
Since I get no errors at all, I have no idea what I am supposed to do.
NOTE
The EC2 instance's Security Group allows ALL outgoing traffic by the way. And it also allows incoming traffic for Ephimeral ports (whatever that is).
Any directions are appreciated.
Here is the code snippet for HttpClient:
using (HttpClient c = new HttpClient())
{
var fileBytes = new byte[model.FileStream.Length];
_logger.LogInformation("Reading bytes from incoming file stream...");
await model.FileStream.ReadAsync(fileBytes, 0, fileBytes.Length);
model.FileStream.Close();
_logger.LogInformation("Read bytes from incoming file stream...");
MultipartFormDataContent form = new MultipartFormDataContent();
// Also tried including an actual file as ByteArrayContent
//form.Add(new ByteArrayContent(fileBytes, 0, fileBytes.Length), "file");
form.Add(new StringContent("SOME_PUBLICLY_ACCESSABLE_URL"), "file");
form.Add(new StringContent(_cloudinarySettings.ApiKey), "api_key");
form.Add(new StringContent(timestamp.ToString()), "timestamp");
form.Add(new StringContent(signature), "signature");
HttpResponseMessage response = await c.PostAsync(
$"https://api.cloudinary.com/v1_1/{_cloudinarySettings.Cloud}/image/upload",
form);
_logger.LogInformation("RESPONSE: {0}", await response.Content.ReadAsStringAsync());
return null;
}
For Cloudinary:
var uploadParams = new ImageUploadParams()
{
File = new FileDescription(fileName, model.FileStream),
PublicId = publicId,
Overwrite = true,
// TODO:
NotificationUrl = model.CallbackUrl
};
_logger.LogInformation("Trying to upload to CDN");
var uploadResult = await _cloudinary.UploadAsync(uploadParams);
_logger.LogInformation("Uploaded image to CDN");
var url = _cloudinary.Api.UrlImgUp
.Format(uploadResult.Format)
.Transform(new Transformation().FetchFormat("auto"))
.BuildUrl(uploadResult.PublicId);
AWS SDK:
var fileTransferUtility =
new TransferUtility(_amazonS3Client);
var objectId = $"{folder}/{fileName}";
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
BucketName = _awsS3Settings.BucketName,
InputStream = model.FileStream,
StorageClass = S3StorageClass.Standard,
PartSize = 6291456, // 6 MB.
Key = objectId,
CannedACL = S3CannedACL.PublicRead
};
fileTransferUtilityRequest.Metadata.Add("X-FileExtension", Path.GetExtension(model.FileName));
fileTransferUtilityRequest.Metadata.Add("X-OriginalFileName", model.FileName);
fileTransferUtilityRequest.Metadata.Add("X-GeneratedFileId", fileId.ToString());
fileTransferUtilityRequest.Metadata.Add("X-GeneratedFileName", fileName);
await fileTransferUtility.UploadAsync(fileTransferUtilityRequest);
BONUS
I even included a simple GET call to google.com with no success again at the
using (HttpClient c = new HttpClient())
{
_logger.LogInformation("Sending request to google...");
c.Timeout = TimeSpan.FromSeconds(2);
HttpResponseMessage response = await c.GetAsync(
$"https://google.com");
_logger.LogInformation("RESPONSE: {0}", await response.Content.ReadAsStringAsync());
return null;
}
This is weird but it seems like the default HttpClient somehow uses system level default proxy or something?
The answer to the question Web request from HttpClient stuck is kind of correct. The solution I came up with was forking the CloudinaryDotNet repository, inject a new HttpClientHandler with Proxy explicitly set to null and UseProxy explicitly set to false. This behaviour is not supported because the library internally creates a new HttpClient once at ApiShared.Proxy.cs and it internally decides based on target framework whether to use the HttpClientHandler or not.
For reference, this is the code change that makes it work:
ApiShared.Proxy.cs Line 17
Remove
public HttpClient Client = new HttpClient();
Add
public HttpClient Client = new HttpClient(new HttpClientHandler
{
UseProxy = false,
Proxy = null
});
Obviously this will not work for everyone and is not an ideal solution. The ideal solution would probably involve digging deeper on how EC2 uses default proxies, maybe somehow including the proxy options the SDKs. But I'm posting anyway in case someone else has a similar problem.

into HttpRequestMessage OR IHttpClientFactory set or connect proxy

I am beginner. Take it easy on me.
I want to set or connect proxy on that piece of code
var requestMsg = new HttpRequestMessage(GetHttpMethod(method), url);
if (method != APIMethod.GET)
{
var serializedContent = JsonConvert.SerializeObject(request);
requestMsg.Content = new StringContent(serializedContent, Encoding.UTF8, "application/json");
}
WebProxy myproxy = new WebProxy("xxx.xx.xx.xx", 8080);
requestMsg.Proxy = myproxy; <------ error
HttpResponseMessage task = await httpClientFactory.CreateClient().SendAsync(requestMsg);
please help me set proxy hard code
i read these but i cant understand
Proxy with HTTP Requests
C# Connecting Through Proxy
You can try to use HttpClient.DefaultProxy to set the global Http proxy.
HttpClient.DefaultProxy = new WebProxy("xxx.xx.xx.xx", 8080);

Request throwing An existing connection was forcibly closed by the remote host only on C# request

I'm having a hard time trying to consume a REST service from Cielo (credit/debit card gateway company). If I use postman it works:
POST /1/sales/ HTTP/1.1
Host: apisandbox.cieloecommerce.cielo.com.br
MerchantKey: my_key
Content-Type: application/json
MerchantId: merc_id
Cache-Control: no-cache
Postman-Token: 6643cc5a-173a-f5db-8924-85ea8b7bbb55
{"MerchantId":"00000000-0000-0000-0000-000000000000","MerchantKey":null,"RequestId":"00000000-0000-0000-0000-000000000000","MerchantOrderId":"1223","Customer":{"Name":"Emerson Fitchy"},"Payment":{"PaymentId":"00000000-0000-0000-0000-000000000000","Type":"CreditCard","Amount":15700,"Installments":1,"Provider":null,"ProofOfSale":null,"Tid":null,"AuthorizationCode":null,"SoftDescriptor":null,"ECI":null,"Status":0,"ReturnCode":null,"ReturnMessage":null,"CreditCard":{"CardNumber":"0000000000000001","Holder":"Emerson Fitchy Santis","ExpirationDate":"12/2022","SecurityCode":"154","Brand":"Visa"}}}
And this is the C# code (at the moment, I tried also with RestSharp and HttpClient with the same results):
var webrequest = (HttpWebRequest)WebRequest.Create(Constants.Cielo.GetSalesUrl());
webrequest.ContentType = "application/json";
webrequest.Method = "POST";
webrequest.Headers.Add("MerchantId", Constants.Cielo.Sandbox.MerchantId.ToString());
webrequest.Headers.Add("MerchantKey", Constants.Cielo.Sandbox.MerchantKey);
using (var streamWriter = new StreamWriter(webrequest.GetRequestStream()))
{
var json = JsonConvert.SerializeObject(sale);
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)webrequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
var x = result;
}
Any ideas on what am I doing wrong? I tried using Fiddler 4 but it's not picking up this request (I don't know why) and WireShark picks it up, but doesn't show the information the way Fiddler does (Maybe it's because I'm using https?).
Any ideas?
Thanks!
EDIT
Response/Exception
I just had the same issue where I suddenly was unable to make calls to a specific website from a Windows Server where I was running a console application on .NET 4.7.2. I was able to make the call in Postman from the same machine, but started getting the An existing connection was forcibly closed by the remote host.
It turns out that the sever had TLS 1.2 disabled. I was able to resolve it following the steps in this answer. I still am not sure if this setting was changed on the server or if the website started enforcing it, but it resolved the issue for me.
Try this client and see if it you get a different result:
var client = new HttpClient();
using (HttpRequestMessage request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(Constants.Cielo.GetSalesUrl(), UriKind.Absolute);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestContent = JsonConvert.SerializeObject(sale);
request.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
request.Headers.Add("MerchantId", Constants.Cielo.Sandbox.MerchantId.ToString());
request.Headers.Add("MerchantKey", Constants.Cielo.Sandbox.MerchantKey);
using (HttpResponseMessage response = await client.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
if (response.Content != null)
{
var rawJson = await response.Content.ReadAsStringAsync();
// do stuff - map to type, etc.
}
}
return something;
}
}

Concur V3 Api not working for Users

I configured a Concur Sandbox and played around with the api. Since the User api is not supported by the .Net SDK I wrote following code.
Issue is that code for Expenses work (returns 200 with valida result), but code for users returns 401 Unauthorized.
Expenses
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("OAuth", oauthAccessToken);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var requestUri = "https://www.concursolutions.com/api/v3.0/expense/receiptimages";
var respone = await httpClient.GetAsync(requestUri);
if (respone.IsSuccessStatusCode)
{
var result = respone.Content.ReadAsStringAsync();
//throw new InvalidUriException(string.Format("Invalid uri: {0}", requestUri));
}
}
Ideally this should also work as the previous code works,
Users
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("OAuth", oauthAccessToken);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var requestUri = "http://www.concursolutions.com/api/v3.0/common/users?user=user1%40company.net";
var respone = await httpClient.GetAsync(requestUri);
if (!respone.IsSuccessStatusCode)
{
//throw new InvalidUriException(string.Format("Invalid uri: {0}", requestUri));
}
}
}
I thought it's a permission issue, but I given allowed enough permission.
Here is the Administration->Webservice app configuration,
Issue is that the User Api call needs to be https.

ASP.Net Web API Request URI Error

I have an ASP.Net Web API that generally works fine. I have a Winforms client application that does GET requests. The client application runs on our corporate network (the API is hosted as an Azure Website). Occasionally, and inconsistently, the HttpClient calls I make add what seem to be corporate URLs in front of my GET call.
Example: I try to call send an HttpClient request to the following URL: 'http://xyzxyz.azurewebsites.net/api/user/1'
but the actual request made is:
'http://usgaabc1iru01/B0000D0000N0001F0000S0000R0004/http://xyzxyz.azurewebsites.net/api/user/1'
This obviously causes an error.
I've asked our IT department what may be happening and they are at a loss. Hoping someone could point me in the right direction.
Edit:
Here's the code I use. First I have a static method I call everything I make a call to the API to get the HttpClient (is this awkward/bad perhaps):
public static HttpClient GetHttpClient()
{
var credentials = new NetworkCredential(GlobalVariables.CurrentUser.UserName, GlobalVariables.CurrentUser.Password);
HttpClientHandler handler = new HttpClientHandler();
handler.UseDefaultCredentials = false;
handler.Credentials = credentials;
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(PublicClasses.GlobalVariables.BaseUriString);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
GlobalVariables.CredentialedHttpClient = client;
}
return GlobalVariables.CredentialedHttpClient;
}
}
Here's a simple GET call I use:
public static List<Project> GetAllProjects()
{
try
{
HttpClient client = GetHttpClient();
HttpResponseMessage response = client.GetAsync("api/project").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
var projects = response.Content.ReadAsAsync<IEnumerable<Project>>().Result;
return (List<Project>)projects;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
catch (Exception)
{
throw;
}
}
I don't have an answer for why is this happening but I came across similar issue in a web form (not a win forms client). That is solved by using base meta tag.I am not sure if that solves your problem, but you can give a try.
You can use base address with HttpClient like this (if you are not already doing this):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://xyzxyz.azurewebsites.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/user/1");
if (response.IsSuccessStatusCode)
{
//add your code
}
}

Categories