One is encouraged to re-use HttpClient rather than making a new one for each api call.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
My client program has a single connection that remains open.
However, if somebody stops IIS then the connection can't remain open.
In this case I get an exception that kills my client program even though I have a catch for it. (see code)
Is there some way to make the exception handler handle the exception without crashing the program?
Alternatively, is there some property of HttpClient that indicates that the server has closed it?
try
{
return await m_Client.GetAsync(AppVars.Instance.ServerAddress + method);
}
catch (Exception ex)
{
// getting 'An existing connection was forcibly closed by the remote host' kills the
// application
// getting 'No connection could be made because the target machine actively refused it'
// does not kill the application - i.e. catch behaves as expected
}
I have discovered that this is caused by Visual Studio. I am debugging both the client and the server from one solution (multiple startup projects). When I close IIS Express, Visual Studio kills the client next time it tries to use the connection. If I launch a separate instance of Visual Studio and debug the client from there then the client does not get killed when I try to re-use the closed connection, i.e. the exception handling works as expected. (so I can make a new connection and retry)
Hopefully this will help anyone who experiences the same issue.
Related
We have written several C# web services that have a connection to our internal Firebird 2.5.5 database.
Unfortunately the exception "Error reading data from the connection" is thrown more and more often and we don't know how to fix it.
We tried to disable pooling but this did not have the desired effect.
We also wrote a try catch block that reconnects and re-executes the SQL, but this does not seem to us to be the right solution.
Is there another option?
Here are some environment informations:
C# 7.0
.NET 4.5
Firebird Version 2.5.5
Firebird Driver 5.5.0
The Firebird log does not show any error messages at that time
The error happens from time to time with any sql statement
The problem is relatively simple: the network connection between client and server is interrupted or broken for some reason, but the State of the client connection remains Open - even though you cannot use that connection anymore. Unfortunately Firebird decided to not update this status to Broken automatically, which would make a lot more sense if you ask me.
You already figured out that reopening the connection "somewhat fixes" the problem, and we have discussed that you could do this only when FbException.ErrorCode is 335544726.
Unfortunately this does mean that any open transaction is also lost, and you cannot commit any data from it anymore. The only way I could think of to reliably recover from this situation is to rethrow the exception:
try
{
// ...
}
catch (FbException ex)
{
if (ex.ErrorCode == 335544726)
{
// close the connection (reopen depending on your application)
}
throw;
}
This way, you can catch this exception at a higher level in your application, and deal with it however is appropriate at that point - ie. retrying the entire transaction, or letting the user choose what to do.
I am currently working with a server application we have designed to communicate with a Xamarin mobile app. We are using an old messaging library that makes a connection with a TcpClient and keeps the connection open (with a heartbeat message every 3 seconds). We added SSL to the library by wrapping the TcpClient stream with an SslStream. We have run the server application on Windows and it works well, but our ultimate target is Mono on a BeagleBoneBlack.
However, when we close the stream and the client on the mobile app side and then attempt to re-initiate a new connection, the SslStream.AuthenticateAsServer(...) will not complete on the server. However, if I completely close the mobile app, the server will throw an exception. At that point, I re-open the app, and can reconnect without any issue.
So it seems something low level is not being closed on either the app or the server side. What is odd is that I run the exact same code on both when the server is running on windows and I don't have an issue.
Here is my code that closes/disposes the stream
public async Task Disconnect()
{
if (!UseAsync)
{
semaphore.Wait();
}
try
{
if (UseSSL)
{
SslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch (Exception ex) // Assuming we had an exception from trying to close the sslstream
{
logger.Error(ex, "Did not close/dispose correctly: {0}", ex.ToString());
}
finally
{
SslStream = null;
Client = null;
if (!UseAsync)
{
semaphore.Release();
}
}
}
Edit: It shouldn't be significant since the issue seems to lie at the server somewhere, and the client and server ssl code is almost identical, but in case someone asks, here is the client disconnect code
public async Task Disconnect()
{
try
{
if (UseSSL)
{
_sslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch // Assuming we had an exception from trying to close the sslstream
{
// Ignore exceptions since we've already closed them
}
finally
{
_sslStream = null;
Client = null;
}
}
Edit 2
It should also be noted that I've found at least one bug report that looks like it's the same issue I'm dealing with. It doesn't appear from this bug report that it has ever been resolved, but I found other reports that seemed to reflect a similar issue in the mono framework and it was resolved. Additionally, I have added code to send some "dummy" data from the client after the connect ant it seems to have no affect.
Edit 3: I ultimately receive this exception on the client side
System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00360] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:533
Well... I almost feel silly answering this, but I feel others could end up in my situation out of equal ignorance, so hopefully this helps someone out with a similar architecture.
What happened is that I created a self signed certificate and had it in my project folder, so the same certificate was being used on all of my "server" instances. What was happening is that, due to some internal caching of the SSL session cache, after connecting to one device, it would cache its information and then re-use that information when connecting the next time. The result would be that, since the self-signed certificate used the same host name for all devices, once it tried to reconnect to device B after being connected to device A, it would attempt to re-use device A's cached information (as far as I can tell) The reason this didn't initially make sense is that I could connect and disconnect to multiple different Windows servers over and over again, but only when connecting to Mono servers did I see this issue. As a result, it still seems to be a bug in either Windows or Mono's SSLStream implementation (since, in a perfect world, they are identical), but unfortunately I don't have the time to dig through the de-compiled source code to find it. And frankly, it probably doesn't matter because what I was doing was breaking the whole notion of an SSL connection anyways.
Ultimately, I created a function to programmatically generate a unique certificate for each device using Mono.Security and then provide a mechanism to provide the client with the unique hostname (even though the client is connecting directly to an IP address).
I use an C# Console Application to put and read messages of the MQ..
When the application starts, it connect once with the MQ and then the connection should be always upholded.
The program runs every 30 sec and check if new messages are in the queue or a database(to put them on the queue) and check the isConnected-variable if its true.
But what happen if an exception(2009 - connection broke) in the Put/Get occur? Will the isConnected automatically set to false?
Is the connection automatically disconnected or do I have to call Disconnect() in the error handling?
Thanks!
To answer your exact question, for a basic .net application (non XMS) using MQQueue for put/get, if you get CERTAIN bad return codes from the underlying API call which indicates a connection issue, MQ will attempt an MQBACK and an MQDISC for you and will result in the connection handle being invalidated (IsConnected would return false) and an exception being thrown. However if an exception occurs outside those return codes then no attempt is made to do anything with the connection.
Basically you should not code an application relying on this behaviour, when the most simple answer is to always disconnect if you get an exception which relates to the quality of the connection or queue manager. For example, a no message available etc type exception doesnt mean you need to disconnect but a connection broken obviously does. There is no harm in calling disconnect on an already disconnected connection.
When I try to access (open a connection to) an offline sql server instance (service turned off) from my web service, no exception is thrown, just a brief 5 sec timeout followed by return (I put the breakpoint way out in my controller, not sure what the connection object returns yet during the call to open).
I'm trying to simulate a scenario where the DB is not available to the webservice, and figured an exception would be thrown and I could just log the error.
Any suggestions on how to properly detect DB connection issues (I'm guessing I need to look to see what the connection object returns when calling open). It'd be nice to just have an exception bubble up though.
Thanks.
A connection timeout will be thrown for sure unless your thread is being aborted before that by a web server timeout. Placing a try/catch in your controller would certainly catch the DB connection timeout.
You should post code, as SqlConnection.Open() definitely would throw an exception but if you're using some other call/code to open the connection and it's getting swallowed then it is obviously difficult to determine a root cause.
My guess is that you are getting back a Connection object that is not connected, to check if it's connected:
if (conn.State == ConnectionState.Closed)
{
...
}
I cannot re-connect to my Redis DB doing the following:
Create a new RedisConnection called "connection"
Open the connection connection.Open().Wait();
Close the connection connection.Close(true);
Now when I attempt to connection.Open().Wait(); an error is thrown "Connection is closed".
I am aware the connection was closed but why I cannot re-open it?
The same happens if I instead of close the connection, shut down the Redis server, let the client raise the Closed event, re-start the server, and then attempt to open the connection with connection.Open().Wait(); again. "Connection is closed" error is thrown.
What is wrong with my approach? I do not seem to be able to manage connection states properly with Booksleeve.
Thanks
It is not the expected usage that you open and close a BookSleeve connection.
since it is a multiplexer, it is expected that it is opened once and then used by multiple callers concurrently (it is thread-safe etc)
opening involves various handshakes (at both network and protocol levels) to ensure correct operation - this is best avoided (it isn't insanely expensive, note)
no ongoing state would be viable once closed; you night as well just use a brand new connection if you really want to close it
Personally I'd only close it if I was reconfiguring the system at runtime, or the connection broke.