Log.LogError
isn't going to terminate your app unless it also throws an exception. You didn't post all the code in that function so it is hard to say what is going on here. It seems like your code is handling all the errors, although I don't know that this is a good idea. What you need to look at is what exception is actually causing the app to crash. If you're running in the debugger then it'll show you the actual line crashing your app.
As for your code, I think you can simplify it down quite a bit. It is unclear to me why you're handling very specific exceptions and logging them but generating a different log for everything else. If you really need this behavior then consider creating an exception filter instead. This would make it very easy to add new exceptions while keeping the code small.
try
{
...
} catch (Exception error) when (IsSpecialError(e))
{
//Log special exceptions here
} catch (Exception error)
{
//Everything else lands here
};
private static bool IsSpecialError ( Exception error )
{
//Nothing special...
return false;
}
Looking at what could cause the issue I see the following things that raise some concerns:
- Creating a new
TcpClient
each time can be wasteful. If you are talking to the same client then create theTcpClient
once and reuse it. Otherwise wrap it in ausing
statement otherwise you are leaking aTcpClient
every time your code throws an exception. - You are setting the
ReadTimeout
to 250ms. That is pretty fast. Interestingly the first error you log is related to the timeout of the read. Unless you have specific requirements then don't set the read timeout from its default value. - You should never handle exceptions unless you can do something about them. This, of course, excludes logging the exception and then rethrowing. In your case you're handling exceptions that should crash your app as they are true error cases. Referencing a disposed object indicates a lifetime issue. Argument exception indicates bad code, etc. Only handle exceptions that you can do something about. In all other cases log the exception and rethrow it. Maybe the caller can better handle the error. This also plays into what you're going to return if an error does occur.
Here is a first pass at how I might rewrite your code.
private string SendReceive(string message, string clientAddress, int id)
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, Port
// combination.
if (clientAddress.Equals("localhost"))
clientAddress = "127.0.0.1";
byte[] data = Encoding.ASCII.GetBytes(message);
try
{
using var client = new TcpClient(clientAddress, Port);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Log.LogInfo("Sent for note: " + id + " with " + message);
data = new byte[256];
// Read the first batch of the TcpServer response bytes.
int bytes = stream.Read(data, 0, data.Length);
string responseData = Encoding.ASCII.GetString(data, 0, bytes);
Log.LogInfo("Note: " + id + " reply from server " + responseData);
responseData = responseData.ToUpper();
return responseData;
} catch (IOException e)
{
Log.LogError(MethodBase.GetCurrentMethod().Name, e.Message, e);
return "IO ERROR";
} catch (SocketException e)
{
Log.LogError(MethodBase.GetCurrentMethod().Name, e.Message, e);
return e.Message;
} catch (Exception ex)
{
Log.LogError(MethodBase.GetCurrentMethod().Name, "Exception in ESPComm.SendReceive: {0}", ex);
Log.LogInfo("Exception returned: " + ex.Message);
//Nothing to do here so fail
throw;
}
//Will never get here...
}
I would probably go even further and refactor the read/write into separate functions if they are more complex than what is shown here.