I know that await can’t be used in catch clause.
However I haven’t really faced a problem related to this, until now …
Basically I have a layer that is responsible for receiving incoming requests, processing them, building messages from them and pass the messages to another layer responsible to send the messages.
If something goes wrong during the sending of the message, a custom exception is thrown, and caught by the message sending layer. At this point, a failure record for this message should be inserted in DB (takes some time, so async), and the exception should be propagated to the upper layer which is in charge of sending an error response to the client that made the request.
Here is some very simplified code for illustration purpose below :
public async Task ProcessRequestAsync(Request req)
{
int statusCode = 0;
try
{
await SendMessageAsync(new Message(req));
}
catch(MyCustomException ex)
{
statusCode = ex.ErrorCode;
}
await SendReponseToClientAsync(req, statusCode);
}
public async Task SendMessageAsync(Message msg)
{
try
{
// Some async operations done here
}
catch (MyCustomException ex)
{
await InsertFailureForMessageInDbAsync(msg, ex.ErrorCode); // CAN'T DO THAT
throw;
}
}
Of course the request processing layer knows nothing about the DB, it is just in charge of building a message, passing the message to the message processing layer, and send a response to the client (positive or negative).
So I think it makes sense … If an exception happens, my “business” layer want to insert a failure record in DB and rethrow the exception so that the “request” processing layer can do what’s necessary (in this context, send a negative response back to the client).
Should exceptions not be used this way ? It seems clean to me but the fact that I can’t do this await in the catch clause makes me think there is maybe a code smell with the design (even if I the idea of handling the exception in one layer then rethrowing it for the upper layer to do some different handling as well sounds to me like it’s exactly what exceptions are made for).
Any idea arround this ?
Thanks !
I’ve run into this a couple of times as well.
As Rafael commented, you could just ignore the result of
InsertFailureForMessageInDbAsync:Note that any exceptions from
InsertFailureForMessageInDbAsyncwill be ignored by default.Your other option is more complex:
This will asynchronously handle the exception and return a
Taskthat has a realAggregateExption(containing both exceptions ifInsertFailureForMessageInDbAsyncdoes throw one).Unfortunately,
awaitwill ignore the second exception. If you really want all exceptions passed up, you can replace the last line (await Task.WhenAll...) with something like this:But that’s pretty complex, and not exactly the kind of pattern you want repeated. If possible, I’d just ignore the logging result as Rafael recommended.