I have a custom class contained in a standard .net class library which makes a request to an external public facing api using the HttpClient.
When I instantiate the class and call the method via a standard .net console app, the expected result is returned.
However, executing the same code via a Xunit test produces the following exception:
'The underlying connection was closed: An unexpected error occurred on a send.'
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Both the test project and class library project framework are .Net Standard 4.8.
Most examples online make use of the WebApplicationFactory, documented here.
In my case I am not using ASP Core and I cannot use this class.
I am not that experienced in xunit and there is not much detail in the error message as to why this is occuring.
To try isolate the issue I tried running this piece of code directly in the test method and the same error occurrs.
Any suggestions/work arounds are much appreciated.
using (HttpClient httpClient = new HttpClient())
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = endpoint
};
request.Headers.Add("api-key", key);
using (HttpResponseMessage response = httpClient.SendAsync(request).Result)
{
var rawResponse = response.Content.ReadAsStringAsync().Result;
var response = JsonConvert.DeserializeObject<CustomResponse>(rawResponse);
}
}
I resolved the issue thanks to this post
Adding TLS 1.1 and 1.2 before the request was made worked
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Related
I have a problem calling my ASP.NET Web API from a client application. Many questions regarding this topic were asked here but none of the answers solved my issue.
Problem:
When I try to call my API I get the following exception:
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
Info:
Both projects (cleint and API) are based on .NET 4.5.2
In my test environment client and API are running on the same VM
Everything worked fine wihtout https
I created a selfsigned certificate for testing purposes but no browser shows a warning so it seems to be fine
Code:
HttpClient client = new HttpClient();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
client.BaseAddress = new Uri(apiBaseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync("call/CreateNew", call);
I tried several solutions provided in the answers of similar questions, but none of these worked so far:
Using .NET Framework 4.6 instread of 4.5.2
Specified the protocol with ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Tried ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; (just to be sure)
In another question someone suggested using Wireshark to further analyze the problem. I gave it a try but I have to admit that I did not really know what I was doing.
Anyway I found segments that said "ACKed segment that wasn't captured" and "Previous segment(s) not captured" of which the second contained data I actually tried to send to my API.
Can you give me some advice what to try next or how to fix this error?
I wrote a simple .Net Core 3.0 API using Swashbuckle Swagger and generated an api client via NSwag Studio, then I put a generated Api Client to a .Net Standard 2.0 project.
I have a Universal Windows Platform application, which is meant to be connecting to the Web Api and send/receive data etc.
I put a simple code in MainPage.xaml.cs class with System.Net.Http.HttpClient inside
public MainPage()
{
this.InitializeComponent();
var httpClient = new HttpClient();
var apiClient = new ApiClient(ProjectConstants.API_URL, httpClient);
var deviceService = new DeviceService(apiClient);
}
When API is called later in deviceService my program throws an exception on SendAsync method in generated Api Client
"An error occurred while sending the request."
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
I tested API Client and HttpClient on .Net Core console app and it worked fine.
I read about Http Client for UWP https://learn.microsoft.com/en-us/windows/uwp/networking/httpclient but it seems UWP should support System.Net.Http.HttpClient too, which I would love to stick to.
Is this a Universal Windows Platform bug or do I forgot about adding something necessary to a project?
The System.Net.Http.HttpClient API can be used across platforms, but we do recommend using APIs from Windows.Web.Http.HttpClient NameSpace which is easy to use. So you could use Windows.Web.Http.HttpClient API in UWP,and use GetAsync(PostAsync) to send a request, for example:
Uri requestUri = new Uri("http://www.contoso.com");
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
Windows.Web.Http.HttpResponseMessage httpResponse = new Windows.Web.Http.HttpResponseMessage();
httpResponse = await httpClient.GetAsync(requestUri);
For more information about the differences between Windows.Web.Http and System.Net.Http.HttpClient, you can refer to this article
Does it have the same api as the portable HttpClient?
I'm creating a WebAPI in .NetCore 1.1 which needs to call an external service. When I run it with dotnet run it works perfectly, but when I use Docker I get an
One or more errors occurred. (An error occurred while sending the
request.)
This is my Post method:
public static string Post(string url, string jsonObject, string serviceName)
{
// opening a connection to the microservice
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = client.PostAsync(url, new StringContent(jsonObject, Encoding.UTF8, "application/json")).Result)
{
LogWrapper.SafeInfo(LoggingEvents.SERVICECALLER_GETSERVICESRESPONSE, "Let's test if we get an OK response from " + serviceName);
// we'll throw an exception in case status code is different from 200
response.EnsureSuccessStatusCode();
LogWrapper.SafeInfo(LoggingEvents.SERVICECALLER_GETSERVICESRESPONSE, "We got an OK response from " + serviceName);
using (HttpContent responseContent = response.Content)
{
return responseContent.ReadAsStringAsync().Result;
}
}
}
The error is thrown in line client.PostAsync. The same error occurs in the GET method.
I already check the URL and the parameters.
What makes it even more intriguing is that it only happens when I run my application inside a docker container. When I run my application without Docker it works very well.
Thanks for your help.
Sorry for the lack of details, but after some reading and Googling I finally discovered the problem.
I had two containers running on localhost so I was requesting a service from the container A to the container B.
I used the http://127.0.0.1:356/api/LogIn address, but the problem is that localhost in this case does not point to my machine, but to the container A itself. That's why I could make it work with dotnet run but not with Docker.
As a matter of fact, this answer made me see my mistake.
We've just launched a new service, which we're having trouble connecting to from a very basic c# console app when targeting the .Net 4.5 framework.
We first found the problem in an ASP MVC site, but have broken it down into the simplest of simple console apps to help isolate the problem
Code snippet (there isn't anything else):
string myURL = #"https://<myurl>.com/<myurl>";
using (var httpClient = new HttpClient())
{
var request = (HttpWebRequest)WebRequest.Create(myURL);
request.Method = "GET";
request.ContentLength = 0;
request.ContentType = "text/xml";
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
{
...
}
else
{
...
}
}
}
What happens
Web Exception - Underlying Connection Closed.
Thrown on the call to GetRequest
Service Information
HTTPS service
SHA-256.
Other differences
Examining the request variable in the intermediate window before it is sent shows no difference.
Examining the request variable after the call has been attempted shows one difference - System.Net.HttpWebRequest.Pipelined is true in the successful attempt, false in the failed attempt.
Setup Essentials
Load balancer, balancing between two API's hosted in IIS.
Has it ever worked?
Yes!
If the URL is dropped into a browser - it works.
If I recompile this code targeting the .net 4.6 framework - it works.
If I connect directly to the site in IIS (over http) it works.
What am I asking
What could be causing this problem?
Have you seen similar and have suggestions for possible remedies?
What further steps would you take to help debug / solve the issue.
How would changing .Net framework version to 4.6 affect the HttpClient or the HttpWebRequest?"
Thanks,
Al.
This is usually caused by the server using TLS v1.2. I think Net4.5 defaults to TLS v1.1, so you must add this to your code:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
As far as I can tell, there seems to be a big limitation in .NET in that there is no way using C# and .NET to make an TLS connection that uses Server Name Indication (SNI). Have I missed something or is my understanding correct?
Does anybody know if and how I could make an SNI connection using OpenSSL.NET, libcurl.NET or some other 3rd party .NET library? Some sample code would be very much appreciated.
In my .Net 4.5 project the following fails for a server using SNI:
var url = "https://www.somesite.com";
System.Net.WebClient client = new System.Net.WebClient();
client.Encoding = Encoding.UTF8;
var data = client.DownloadString(url);
But it works if explicitly specifying TLS1.2 by prefixing it with:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
The same applies to webrequest:
WebRequest request = WebRequest.Create("https://www.somesite.com");
and HttpRequestMessage:
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
They all need the protocol explicitly set to TLS 1.2 to work with an SNI server (this may have changed in newer .Net versions)
This is a fairly old post but still this answer might help some people, at least it cost me some days.
.NET Framework does support the Server Name Indication by default. (Tested on 4.5.1 but I guess it's same at least for .NET 4.5+)
A short example:
HttpResponseMessage response;
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
var handler = new HttpClientHandler
{
CookieContainer = new CookieContainer()
};
using (var client = new HttpClient(handler))
{
response = client.SendAsync(httpRequestMessage).Result;
}
This is a very standard way to create a GET request within C#. You will see, this example does run using, in my case, TLS 1.2 with SNI. If you use Wireshark to see the actual packages which are sent, you will see a Client Hello with the Server Name Indication set to www.google.com.
An issue we ran into: The SNI tag is set by the .NET Framework (or Schannel by Windows, not sure) based on the URL passed in the constructor of HttpRequestMessage. If you know initialize the request based on some URL (for example https://www.google.com) and later on you switch the RequestUri OR the Host header, the SNI tag will still be created based on the original url URL. This might be the case for example if you pass through a request and you remap all original headers to the newly created request.