I have a socket and I'd like to send messages and read from it.
When I read/write with the socket while the other side is offline, I get the same Exception: System.IO.IOException: Unable to read data from the transport connection: Operation on non-blocking socket would block.
How can I identify in which of the two it happened besides having two separate try-catch blocks? Can't I just get a Timeout Exception when the reading timeout is over?
example:
try
{
SendData("!GetLocation!");
string data = GetData();
}
catch (Exception ex)
{
if (ex is System.IO.IOException)
{
//How can I identify if the exception was raised at the read method or the write method?
}
}
Yeah, exception handling is heavy resource wise, but sometimes is not so bad.
If you stick to only one try-catch you can check the error message.
Note: I have also added a second try-catch for generic (non IO) errors
try
{
SendData("!GetLocation!");
string data = GetData();
}
catch (System.IO.IOException ex)
{
if (ex.Message.IndexOf("Unable to read") != -1)
{
// GetData error
}
else if (ex.Message.IndexOf("Unable to write") != -1)
{
// SendData error
}
else
{
//Other IO errors
}
}
catch(Exception exc)
{
// Unspected errors
}
you could also set a boolean variable and check its value to know where it
broke your code.
bool sendCalled = false;
try
{
SendData("!GetLocation!");
sendCalled = true;
string data = GetData();
}
catch (System.IO.IOException ex)
{
if (sendCalled)
{
// GetData error
}
else
{
// SendData error
}
}
Not that I endorse either of these solutions, but an answer is an answer: you can either
analyze the stack trace of the exception to find out which call failed (e.g. name of the method at the top of the stack frame
set a flag after the write, and do logic based on that flag
Neither of these is as straight forward as wrapping each method call. In fact, wrapping each call conveys your intent. In the catch of your first call, you can return/break/skip the read call, which explicitly tells the reader you're bailing out fast.
Related
In SignalR v2, I used code like this (below) to handle exceptions that happened when my connections failed. What is the equivalent in SignalR v3? Does SendAsync or SendAsyncCore throw some exception should connections fail or serialization fail?
private async void ManagerOnUserRemoved(UserDto userDto)
{
try
{
await Context.Clients.All.MyFunc(userDto);
}
catch (InvalidOperationException) { }
catch (AggregateException) { }
}
I didn't see any exceptions listed here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.signalr.client.hubconnectionextensions.sendasync?view=aspnetcore-3.0
Update: I have the same question for the calls from the client-side (to InvokeCoreAsync et al).
In SignalR V3 use HubException to capture exceptions that contain sensitive information, such as connection information.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.signalr.hubexception?view=aspnetcore-3.1
private async void ManagerOnUserRemoved(UserDto userDto)
{
try
{
await Context.Clients.All.MyFunc(userDto);
}
catch(Exception ex) {
//Now check exceptions what you want by exception message or exception code
}
}
With this code you can handle all exceptions, or you can do this:
hubConnection.Error += ex => Console.WriteLine("Error: {0}", ex.Message);
I think it will be help
I'm incorporating telemetry into my product on all service requests, unfortunately that includes exceptions. A problem I'm having is I surround my requests with a try-catch and if it's successful I log the request and if there's a catch I log the exception than throw the exception so that it still gets propagated up so that it can be debugged. A problem I'm having is that with try-catch I lose all the original data from the original exception caught by my try-catch, which I think would be nice to propagate back up.
public void someFunction(object data)
{
try
{
var response = await request(data);
LogInformation(request: data, response: response);
}
catch (Exception e)
{
throw HandleAndLogException(data, e);
}
}
private HttpResponseException HandleAndLogException(object data, Exception e)
{
LogException(data: data, response: e.Message);
var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) {
Content = new StringContent(e.Message)
};
return new HttpResponseException(resp);
}
So as you can see I create a new HttpResponseException and just append the message to it, but I'd rather propagate back up the exception thrown in it's entirety.
If you want to do something clever/evil, you can use the when keyword to introduce logging without breaking the stack trace on your exception.
See when contextual keyword in the C# reference on MSDN. It's supposed to be used as a filter (the method returns true or false, indicating whether that catch block should be used) but you can do whatever you want with
I think this is what you'd want, although I haven't tested it:
public void someFunction(object data)
{
try
{
var response = await request(data);
LogInformation(request: data, response: response);
}
catch (Exception e) when (HandleAndLogException(data, e))
{
throw;
}
}
private bool HandleAndLogException(object data, Exception e)
{
LogException(data: data, response: e.Message);
return true;
}
What is the difference between code like this:
string path = #"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
and this:
string path = #"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
if (file != null)
{
file.Close();
}
Is really finally block necessary in this construction. Why Microsoft provided such construction? It seems to be redundant. Isn't it?
Imagine if some other exception occurred that you haven't handled, e.g. an ArgumentOutOfRangeException, or if you want to rethrow the exception or throw a wrapped exception from your catch block:
The first block would ensure that the file is closed regardless of whether or not an exception occurred.
The second block would only close the file if either no exception occurred or an IOException occurred. It does not handle any other cases.
The first block will close the file even if there is an uncaught exception.
The second block will close the file only if there are no exceptions, or any thrown exceptions are caught.
The first will also ensure that the file is closed if the try has a break, goto, return, continue, or any other jump construct that would cause the execution to move outside of the try block. The second doesn't, and as such it could result in the resource not being closed.
In your example, if your code throws an exception other than System.IO.IOException, your cleanup code is not guaranteed to run. With the finally block, the code within it will run no matter what type of exception is thrown.
In that case it's redundant.
It's usefull if you for example will rethrow an exception and still want some code to run after the block:
try {
// do something dangerous
} catch(...) {
// log the error or something
throw; // let the exception bubble up to the caller
} finally {
// this always runs
}
// this only runs if there was no exception
Another example is if the catch may throw an exception for a different reason:
try {
// do something dangerous
} catch(...) {
// handle the error
// log the error, which may cause a different exception
} finally {
// this runs even if the catch crashed
}
// this only runs if there was no exception, or the code in the catch worked
Simply, as code might crash for plenty of reasons you might not even know about, it's useful to put the cleanup in a finally block just to be sure that it runs whatever happens.
Imagine there was an exception inside catch{}, code inside finally would still run but if (file != null){} block will not.
I have to process items off a queue.
Deleting items off the queue is a manual call to Queue.DeleteMessage. This needs to occurs regardless of whether or not the processing succeeds.
var queueMessage = Queue.GetMessage();
try
{
pipeline.Process(queueMessage);
}
catch (Exception ex)
{
try
{
Logger.LogException(ex);
}
catch { }
}
finally
{
Queue.DeleteMessage(queueMessage);
}
Problem:
On failure, I log the error to some data store. If this logging fails (perhaps the data store is not available), I still need the message to be deleted from the queue.
I have wrapped the LogException call in another try catch. Is this the correct way or performing thing?
Following code is enough. finally blocks execute even when exception is thrown in catch block.
var queueMessage = Queue.GetMessage();
try
{
pipeline.Process(queueMessage);
}
catch (Exception ex)
{
Logger.LogException(ex);
}
finally
{
Queue.DeleteMessage(queueMessage);//Will be executed for sure*
}
The finally block always executes, even if it throws an unhandled error (unless it end the app). So yes.
I'm attempting to extend this answer on SO to make a WCF client retry on transient network failures and handle other situations that require a retry such as authentication expiration.
Question:
What are the WCF exceptions that need to be handled, and what is the correct way to handle them?
Here are a few sample techniques that I'm hoping to see instead of or in addition to proxy.abort():
Delay X seconds prior to retry
Close and recreate a New() WCF client. Dispose the old one.
Don't retry and rethrow this error
Retry N times, then throw
Since it's unlikely one person knows all the exceptions or ways to resolve them, do share what you know. I'll aggregate the answers and approaches in the code sample below.
// USAGE SAMPLE
//int newOrderId = 0; // need a value for definite assignment
//Service<IOrderService>.Use(orderService=>
//{
// newOrderId = orderService.PlaceOrder(request);
//}
/// <summary>
/// A safe WCF Proxy suitable when sessionmode=false
/// </summary>
/// <param name="codeBlock"></param>
public static void Use(UseServiceDelegateVoid<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
catch (CommunicationObjectAbortedException e)
{
// Object should be discarded if this is reached.
// Debugging discovered the following exception here:
// "Connection can not be established because it has been aborted"
throw e;
}
catch (CommunicationObjectFaultedException e)
{
throw e;
}
catch (MessageSecurityException e)
{
throw e;
}
catch (ChannelTerminatedException)
{
proxy.Abort(); // Possibly retry?
}
catch (ServerTooBusyException)
{
proxy.Abort(); // Possibly retry?
}
catch (EndpointNotFoundException)
{
proxy.Abort(); // Possibly retry?
}
catch (FaultException)
{
proxy.Abort();
}
catch (CommunicationException)
{
proxy.Abort();
}
catch (TimeoutException)
{
// Sample error found during debug:
// The message could not be transferred within the allotted timeout of
// 00:01:00. There was no space available in the reliable channel's
// transfer window. The time allotted to this operation may have been a
// portion of a longer timeout.
proxy.Abort();
}
catch (ObjectDisposedException )
{
//todo: handle this duplex callback exception. Occurs when client disappears.
// Source: https://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
EDIT: There seems to be some inefficiencies with closing and reopening the client multiple times. I'm exploring solutions here and will update & expand this code if one is found. (or if David Khaykin posts an answer I'll mark it as accepted)
After tinkering around with this for a few years, the code below is my preferred strategy (after seeing this blog posting from the wayback machine) for dealing with WCF retries and handling exceptions.
I investigated every exception, what I would want to do with that exception, and noticed a common trait; every exception that needed a "retry" inherited from a common base class. I also noticed that every permFail exception that put the client into an invalid state also came from a shared base class.
The following example traps every WCF exception a client could through, and is extensible for your own custom channel errors.
Sample WCF Client Usage
Once you generate your client side proxy, this is all you need to implement it.
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
}
ServiceDelegate.cs
Add this file to your solution. No changes are needed to this file, unless you want to alter the number of retries or what exceptions you want to handle.
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = null;
bool success = false;
Exception mostRecentEx = null;
int millsecondsToSleep = 1000;
for(int i=0; i<5; i++) // Attempt a maximum of 5 times
{
// Proxy cann't be reused
proxy = (IClientChannel)_channelFactory.CreateChannel();
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
break;
}
catch (FaultException customFaultEx)
{
mostRecentEx = customFaultEx;
proxy.Abort();
// Custom resolution for this app-level exception
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
catch (ChannelTerminatedException cte)
{
mostRecentEx = cte;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following is thrown when a remote endpoint could not be found or reached. The endpoint may not be found or
// reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
catch (EndpointNotFoundException enfe)
{
mostRecentEx = enfe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
// The following exception that is thrown when a server is too busy to accept a message.
catch (ServerTooBusyException stbe)
{
mostRecentEx = stbe;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (TimeoutException timeoutEx)
{
mostRecentEx = timeoutEx;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch (CommunicationException comException)
{
mostRecentEx = comException;
proxy.Abort();
// delay (backoff) and retry
Thread.Sleep(millsecondsToSleep * (i + 1));
}
catch(Exception e)
{
// rethrow any other exception not defined here
// You may want to define a custom Exception class to pass information such as failure count, and failure type
proxy.Abort();
throw e;
}
}
if (success == false && mostRecentEx != null)
{
proxy.Abort();
throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
}
}
}
I started a project on Codeplex that has the following features
Allows efficient reuse of the client proxy
Cleans up all resources, including EventHandlers
Operates on Duplex channels
Operates on Per-call services
Supports config constructor, or by factory
http://smartwcfclient.codeplex.com/
It is a work in progress, and is very heavily commented. I'll appreciate any feedback regarding improving it.
Sample usage when in instance mode:
var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);
reusableSW.Reuse(client =>
{
client.CheckIn(count.ToString());
});
reusableSW.Dispose();
we have a WCF client that deal with almost any type of failure at the server. The Catch list is very long but does not have to be. If you look closely, you will see that many exceptions are child definitions of the Exception Class (and a few other classes).
Thus you can simplify things a lot if you want to. That said, here are some typical errors that we catch:
Server timeout
Server too busy
Server unavailable.
Below links may help to handle WCF Exceptions:
http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx
http://msdn.microsoft.com/en-us/library/cc949036.aspx