SignlaR not working with load balancing - c#

We already had a server with signalr hub where clients connect using signalr. We recently moved it to two nodes with a load balancer for scalability. But after moving it to load balancer now clients are unable to connect to the server using signalr. Clients first try using web sockets and it gives the following error on signalr trace.
fae26beb-a806-4957-b52a-39b80856e492 - Auto: Failed to connect to using transport webSockets. System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.Security._SslStream.EndRead(IAsyncResult asyncResult)
at System.Net.TlsStream.EndRead(IAsyncResult asyncResult)
at System.Net.PooledStream.EndRead(IAsyncResult asyncResult)
at System.Net.Connection.ReadCallback(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__21.MoveNext()
at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNet.SignalR.Client.Transports.WebSocketTransport.<PerformConnect>d__1.MoveNext()
But after couple of times trying to connect it manages to connect using SSE (Server Sent Events).
fae26beb-a806-4957-b52a-39b80856e492 - SSE: OnMessage(Data: {"C":"s-0,BA9F","S":1,"M":[]})
fae26beb-a806-4957-b52a-39b80856e492 - ChangeState(Connecting, Connected)
fae26beb-a806-4957-b52a-39b80856e492 - SSE: OnMessage(Data: {"C":"s-0,BAA0","M":[{"H":"PrintConnectorHub","M":"SignalRConnectedSuccessfully","A":[true]}]})
fae26beb-a806-4957-b52a-39b80856e492 - OnMessage({"R":false,"I":"3"})
But when the server tries to send a message back to the client, client does not receive the message. We have implemented SignalR scale out with SQL Server and following are the log traces in the server.
TRACE SignalR.SqlMessageBus Stream 0 : SqlReceiver last payload ID=47781, new payload ID=47782 (Microsoft.AspNet.SignalR.SqlServer.SqlReceiver.ProcessRecord)
TRACE SignalR.SqlMessageBus Stream 0 : Updated receive reader initial payload ID parameter=47782 (Microsoft.AspNet.SignalR.SqlServer.SqlReceiver.ProcessRecord)
TRACE SignalR.SqlMessageBus Stream 0 : Payload 47782 containing 1 message(s) received (Microsoft.AspNet.SignalR.SqlServer.SqlReceiver.ProcessRecord)
TRACE SignalR.SqlMessageBus Stream 0 : 1 records received (Microsoft.AspNet.SignalR.SqlServer.ObservableDbOperation.ExecuteReaderWithUpdates)
TRACE SignalR.SqlMessageBus Created DbCommand: CommandType=Text, CommandText=SELECT [PayloadId], [Payload], [InsertedOn] FROM [SignalR].[Messages_0] WHERE [PayloadId] > #PayloadId, Parameters= [Name=PayloadId, Value=47782] (Microsoft.AspNet.SignalR.SqlServer.DbOperation.TraceCommand)
Signalr initialization in clients
signalrHostUrl = "SignalR_Host";
try
{
hubConnection = new HubConnection(signalrHostUrl);
hubConnection.Error += ex =>
{
signalRlogger.Error(ex, "Exception from hubConnection");
};
hubConnection.ConnectionSlow += () => ConnectionSlow();
hubConnection.Closed += () => SignalrConnectionConnectionClosed();
hubConnection.StateChanged += signalRConnectionStateController.StateChanged;
hubConnection.Start().Wait();
}
catch (Exception ex)
{
signalRlogger.Error(ex, "initialzing hub connection");
}
Before moving to the load balancer the clients were perfectly able to connect via web sockets and communicate. But after moving to load balancer it completely fails to connect via web sockets. We even tried to open a web socket connection by this tool (https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo?hl=en) which also fails to open a connection. Although it manages to connect via SSE it still unable to communicate to clients. What are the complications when using web sockets in load balancing and in this situation why signalr fails to make a connection to the clients?

When the other machine tries to decrypt the connection token you got when negotiating the connection it can't and the request fails. You need to ensure that all machines you are using have the same machine key. This way all the machines will be able to decrypt connectionTokens created by other machines.
Are you able to enable stickyness on the load balancers? For example session based stickyness. This will make sure the clients connect to the same machine. The downside is that if a machine fails the client won't be able to reconnect.

Related

Getting "System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly." error while calling web api

In my application, there is a functionality to extract reports based on a date range. In the background, it is calling my Web API with authentication(A), which consists of api caller functionality using httpclient, which is calling another non-secured DMZ server API (B) and a DMZ API-caliing WCF service (C) to collect data from the database.
My problem is that whenever I select a large date range, I get the following error in my WebAPI (A).
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at LRAS.OrderServices.Core.Helpers.ApiCaller.d__4.MoveNext()
What I have tried: I have increased the httpclient timeout from 300 to 1000 seconds, but it is breaking nearly every minute.
You can try several methods:
1.Configure the service point security protocol and select the SecurityProtocolType that suits you (Tls12, Ssl3, Tls, Tls11).
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
C# System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send
2.Set the ConnectionClose property of HttpClient.
_client.DefaultRequestHeaders.ConnectionClose = true;
HttpClient throwing "An error occurred while sending the request."
3.Try to hold the request long enough for it to complete normally and receive a valid response.
_client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
_client.DefaultRequestHeaders.Add("Keep-Alive", "3600");
.NET HttpClient - An existing connection was forcibly closed by the remote host

DotNetCore SocketException "Cannot assign requested address" SmtpClient

I have an dotnet 5 service that sends emails using the SmtpClient. This service is deployed as a linux docker image running in AWS EKS (Kubernetes).
Running locally on my machine, everything works fine, but when it's deployed to our K8s environment, every SmtpClient.SentAsync call sits for around 10 minutes, before it finally crashes with the following exception:
System.Net.Mail.SmtpException: Failure sending mail.
---> System.Net.Sockets.SocketException (99): Cannot assign requested address
I've researched this error, and there is a lot of talk about using/not using localhost as a host name. In my case, I'm not using local host at all. I'm just trying to send outbound emails using SmtpClient, where the host is a 3rd party SMTP server.
I've tried running this as a linux docker container on my own dev machine, and it also works fine, so it seems to not like something about my EKS environment, yet I can't figure out what that is. Any ideas?
Update:
FYI, the pod can access the internet just fine, using the HttpClient for example. I can also make http calls to it's API on port 80. So it's binding just fine in that regard. It just seems to be an issue when using the SmtpClient.
Stack Track:
System.Net.Mail.SmtpException: Failure sending mail.
---> System.Net.Sockets.SocketException (99): Cannot assign requested address
at System.Net.Sockets.Socket.BeginConnectEx(EndPoint remoteEP, Boolean flowContext, AsyncCallback callback, Object state)
at System.Net.Sockets.Socket.UnsafeBeginConnect(EndPoint remoteEP, AsyncCallback callback, Object state, Boolean flowContext)
at System.Net.Sockets.Socket.PostOneBeginConnect(MultipleAddressConnectAsyncResult context)
--- End of stack trace from previous location ---
at System.Net.Sockets.Socket.DoMultipleAddressConnectCallback(Object result, MultipleAddressConnectAsyncResult context)
at System.Net.Sockets.Socket.MultipleAddressConnectCallback(IAsyncResult result)
--- End of stack trace from previous location ---
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.Sockets.TcpClient.EndConnect(IAsyncResult asyncResult)
at System.Net.Mail.SmtpConnection.ConnectAndHandshakeAsyncResult.InitializeConnectionCallback(IAsyncResult result)
--- End of stack trace from previous location ---
at System.Net.Mail.SmtpConnection.ConnectAndHandshakeAsyncResult.End(IAsyncResult result)
at System.Net.Mail.SmtpClient.ConnectCallback(IAsyncResult result)
...

Intermittent SocketException while trying to contact external web service from Azure web app

I'm encountering a situation on production that is difficult to debug.
Sometimes the connection to an external service can't be established with the following error:
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 93.39.196.220:443
at System.Net.Sockets.Socket.InternalEndConnect(IAsyncResult asyncResult)
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Sometimes it works without any problem. This is what I've tried:
Replacing the way I perform the connection (from Restsharp to HttpClient)
HttpClient is long lived as suggested by this post
Adjusting the timeout
Using async and sync code
Analyzing SNAT Port exhaustion
More info:
The IPs of my server are authorized by the external service (and if they weren't I would be receiving a different error)
While on production I'm having the problem I'm able to connect to the service from development or staging (so it shouldn't be a problem with the external service)
While I'm having trouble contacting this service I don't have trouble contacting a different (but similar) service
I'm on a Web App Service on Azure. I'm using the .NET framework 4.7.2
The same code sometimes works and sometimes it doesn't
This is (more or less) the current iteration
private async Task<ResultSet> SendRequestAsync(HttpClient client, RateRequestBody document){
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
var response = await client.PostAsXmlAsync(baseUrl + "/XMLServices", document);
if (response.IsSuccessStatusCode){
...
}else{
...
}
}
Any ideas on what I might have missed?
Thanks
The answer may lay here: Default SecurityProtocol in .NET 4.5
Assuming both servers are operating correctly, one works fine with your client code and the other gives you problems based on your 'More Info' section: "While I'm having trouble contacting this service I don't have trouble contacting a different (but similar) service"
I recommend removing or commenting out the following line and giving it a try:
//ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
...or replace it with:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Connecting to gmail with Mailkit ImapClient using TLS not SSL

I'm trying to poll a gmail account in C# code.
I am using the Mailkit libraries (https://github.com/jstedfast/MailKit).
I can connect successfully when I tell the client to use SSL:
using (var client = new ImapClient ())
{
client.Connect ("imap.friends.com", 993, true);
client.Authenticate ("joey", "password");
client.Disconnect (true);
}
But it's my understanding (possibly wrong) that SSL is insecure and we shouldn't be using it. So I'm trying to force a TLS connection:
using (var client = new ImapClient ())
{
client.Connect ("imap.friends.com", 993, SecureSocketOptions.StartTls);
client.Authenticate ("joey", "password");
client.Disconnect (true);
}
But this errors on the client.connect line:
Message: The IMAP Server has unexpectedly disconnected
Stack Trace:
at MailKit.Net.Imap.ImapStream.<ReadAheadAsync>d__54.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MailKit.Net.Imap.ImapStream.<ReadTokenAsync>d__69.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MailKit.Net.Imap.ImapEngine.<ConnectAsync>d__140.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at MailKit.Net.Imap.ImapClient.<ConnectAsync>d__81.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MailKit.Net.Imap.ImapClient.Connect(String host, Int32 port, SecureSocketOptions options, CancellationToken cancellationToken)
I'm running with the protocol logger, but that's not telling me much, it holds only 1 line:
Connected to imap://imap.gmail.com:993/?starttls=always
So I guess my questions are:
1) Should I be worried about using insecure SSL 3.0 to access gmail? I find it hard to believe that they are forcing me to use a deprecated security protocol.
2) If so, how can I force a TLS connection, so I can keep SSL3.0 turned off for clients on my application server?
MailKit has 2 different ways of doing SSL/TLS:
Use SSL/TLS immediately upon connecting to the remote server
Use the STARTTLS command to toggle into SSL/TLS mode after connecting and reading the greeting to check if the server supports it
You are trying to use the second mode but you are connecting to a port (993) which requires the first mode.
Which version of SSL vs TLS gets used with either of these modes is entirely dependent upon what the server supports (actually, technically, MailKit doesn't support any version of SSL by default, it only supports TLSv1.0, TLSv1.1, and TLSv1.2 - I removed SSLv3 by default a few years ago).
The way that you can change the supported SSL and/or TLS versions that you'd like to limit MailKit to can be done by setting the client.SslProtocols property.

System.Net.Sockets.SocketException Disaster

In our Winforms client app that is disconnected from the business layer and communicates via MVC web API, we get a nasty error. Are there any experts out there who can please explain!
What does all this mean?
---> (Inner Exception #0) System.Net.Http.Httprequestexception: An Error Occurred While Sending The Request.
---> System.Net.Webexception: The Underlying Connection Was Closed: An Unexpected Error Occurred On A Receive.
---> System.Io.Ioexception: Unable To Read Data From The Transport Connection: An Existing Connection Was Forcibly Closed By The Remote Host.
---> System.Net.Sockets.Socketexception: An Existing Connection Was Forcibly Closed By The Remote Host
At System.Net.Sockets.Socket.Endreceive(Iasyncresult Asyncresult)
At System.Net.Sockets.Networkstream.Endread(Iasyncresult Asyncresult)
--- End Of Inner Exception Stack Trace ---
At System.Net.Sockets.Networkstream.Endread(Iasyncresult Asyncresult)
At System.Net.Pooledstream.Endread(Iasyncresult Asyncresult)
At System.Net.Connection.Readcallback(Iasyncresult Asyncresult)
--- End Of Inner Exception Stack Trace ---
At System.Net.Httpwebrequest.Endgetresponse(Iasyncresult Asyncresult)
At System.Net.Http.Httpclienthandler.Getresponsecallback(Iasyncresult Ar)
--- End Of Inner Exception Stack Trace ---<---
Well, in general, this exception is very vexing, indeed. But what you have expected? You are working with the network. It lies down and gets up frequently. There are two main reasons of such a behaviour:
The quality of the network in which the code is executing.
Errors made by programmers if they implemented their own protocol of communication.
If these two reasons are not in place, then you should implement something like auto connection using timeouts. Also, the TCP-protocol implemetation internals will be very helpful!

Categories

Resources