return await Method.Invoke() - c#

I am a big fan of DRY coding, and I like to avoid boiler plate code as much as possible. Hence I have refactored all of my WCF channel faff into an AOP class, which deals with the lifecycle of the WCF channel.
I also am a big fan of async-await, especially with WCF, as it would in theory free up a thread that would normally be sleep-waiting for the response.
So I created an interceptor in the fluentAOP lib
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var ret = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
However, when thinking a little about the solution I noted that in the case of a WCF contract of the form
[ServiceContract]
public interface IFoo
{
[OperationContract]
Task<int> GetInt();
}
GetInt would have unexpected results. Firstly the catch FaultException would do nothing. Secondly I would be closing the channel before the request returns. I could in theory switch to another code path if the return type is of Task. But I can't figure out how to await the results of a Task<> and then return an awaitable.
This of course is especially difficult since with runtime AOP I would not have access be able to use generics of the return type (without the whole bodge of reflection).
Any ideas how to implement this function as an awaitable, which closes the channel on complete and catches/marshals exceptions to the calling thread?

To do async injection, you'll have to replace your returned task. For code readability, I recommend replacing it with an async method instead of using ContinueWith.
I'm not familiar with fluentAOP, but I've done async injection with Castle DynamicProxy.
If you want to use reflection, what you'll want to do is first determine if it's an async call (i.e., if the return type is a subclass of or is equal to typeof(Task). If it's an async call, then you will need to use reflection to pull the T out of Task<T> and apply it to your own async method:
private static MethodInfo handleAsync = ...; // point this to HandleAsync<T>
// Only called if the return type is Task/Task<T>
private static object InvokeAsyncOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var task = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments) as Task;
object ret;
if (task.GetType() == typeof(Task))
ret = HandleAsync(task, channel);
else
ret = handleAsync.MakeGenericMethod(task.GetType().GetGenericParameters()).Invoke(this, task, channel);
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task HandleAsync(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> HandleAsync<T>(Task task, IChannel channel)
{
try
{
var ret = await (Task<T>)task;
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
An alternative is to use dynamic:
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
dynamic result = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
return Handle(result, channel);
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task Handle(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> Handle<T>(Task<T> task, IChannel channel)
{
await Handle((Task)task, channel);
return await task;
}
private static T Handle<T>(T result, IChannel channel)
{
channel.Close();
return result;
}

Related

How to handle exception in AWS Lambda in C# for reprocessing

I am a beginner in AWS and at present, I am sending data from DyanmoDB leveraging on TTL to AWS Lambda and then to an End Point. My manager wants me to handle a situation where Lambda throws some exception thus fails to deliver the events to an endpoint.
In case of exception from Lambda he wants me to send the entry back to the DynamoDB table. I am sure it should be doable by using Put-Item command. But I want to know is there any out of the box solution that Lambda provides with which I can handle the failure condition and reprocess that received event data, and thus not lose the entries from DyanmoDB Stream during an exception. By doing this I won't have to send the data back to DynamoDB.
Below is working code for AWS Lambda
public class Function
{
private JsonSerializer _jsonSerializer = new JsonSerializer();
private readonly IQueueClient client;
public async Task FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)
{
try
{
foreach (var record in dynamoEvent.Records)
{
try
{
if (record.EventName == OperationType.REMOVE)
{
context.Logger.LogLine("Calling SerializeStreamRecord function");
string streamRecordJson = SerializeStreamRecord(record.Dynamodb);
Debug.Write(streamRecordJson);
await SendAsync(streamRecordJson, context);
context.Logger.LogLine("Data Sent");
}
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
context.Logger.LogLine("Exception Occurred" + ex.Message);
}
context.Logger.LogLine("Stream processing complete.");
}
private async Task SendAsync(string stream, ILambdaContext context)
{
try
{
var message = new Message(Encoding.UTF8.GetBytes(stream));
await client.SendAsync(message); // SEND MESSAGE
}
catch (Exception ex)
{
throw ex;
}
}
private string SerializeStreamRecord(StreamRecord streamRecord)
{
try
{
using (var writer = new StringWriter())
{
_jsonSerializer.Serialize(writer, streamRecord);
return writer.ToString();
}
}
catch (Exception ex)
{
throw ex;
}
}
}

Error handling in the repository (API REST)

I have this situation (method in Repository):
public string Get(string name)
{
string response;
try
{
using (var context = new MyDB())
{
var row = context.TblSomething.FirstOrDefault();
response = row.GetType().GetProperty(name).GetValue(row, null).ToString();
}
return response;
}
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
}
When there is content other than the Property in the name field, it throws an exception
The method is called in the Controller
public IActionResult Get(string name)
{
string response;
try
{
response = _module.MyRepository().Get(name);
}
catch (ValidationException e)
{
return BadRequest(new { error = new { message = e.Message, value = e.Value } });
}
return Ok(response);
}
How to make it not return a 500 error to the user but should be BadRequest?
The way to make it return 400 instead of 500 is to actually catch the exception. You already have a catch block that returns BadRequest, so the only assumption that can be made is that ValidationException is not what's being thrown. Catch the actual exception being thrown and you're good.
That said, absolute do not catch an exception merely to throw the same exception. All you're doing is slowing down your app. You should also never catch Exception, unless you're simply trying to generally log all exceptions and then rethrow. If you don't have a specific handler for an exception type, then don't catch it. In other words, remove these lines:
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
If you're not going to handle any exceptions as your repo code does, then don't use a try block at all.
It's also worth mentioning that you shouldn't rely on exceptions unless you have to. Throwing exceptions is a drain on performance. In a situation like this, you should simply return null, instead of throwing an exception when there's no matching property. Then, you can do a null check to verify instead of a try/catch.
You could create your own Exception Handling Middleware to catch 500 error and return your custom error status code and message.
1.Create the middleware:
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context )
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
string message = "Something is wrong!";
httpStatusCode = HttpStatusCode.BadRequest; // Or whatever status code you want to return
message = exception.Message; // Or whatever message you want to return
string result = JsonConvert.SerializeObject(new
{
error = message,
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
return context.Response.WriteAsync(result);
}
}
2.Add it into the middleware pipeline after app.UseDeveloperExceptionPage();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMiddleware(typeof(ExceptionHandlingMiddleware));
}

How to await an async delegate correctly?

While in sync world, I have a TryExecute function to wrap try/catch/log logic for reuse, like this:
TryExecute(() => SyncFunction());
private static void TryExecute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
I don't understand how to rewrite it into async/await pattern.
As what I understand, I have five valid ways to rewrite it into async/await (ignore any other Visual Studio has warning).
Using original sync TryExecute() with async delegate:
(1) TryExecute(async () => await AsyncFunction());
It seems not waiting anymore, the TryExecute() passes without waiting AsyncFunction() to finished.
Rewrite to a new sync TryExecuteTask() returns Task, call it with or without async delegate:
(2) await TryExecuteTask(() => AsyncFunction());
(3) await TryExecuteTask(async () => await AsyncFunction());
private static Task TryExecuteTask(Func<Task> asyncAction)
{
try
{
return asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
Or rewrite to a new async TryExecuteAsync(), call it with or without async delegate:
(4) await TryExecuteAsync(() => AsyncFunction());
(5) await TryExecuteAsync(async () => await AsyncFunction());
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
But if I throw Exception from inside AsyncFunction(), then none of above five ways can catch Exception. All stopped with unhandled exception. Only catch without delegate works:
(0) try
{
await AsyncFunction();
}
catch (Exception ex)
{
Log(ex);
}
That means I can't use any forms of TryExecute() from (1) to (5) to reuse the try/catch/log logic, I can only repeating try/catch/log everywhere like (0).
My whole Console code is following:
class Program
{
async static Task Main(string[] args)
{
// Original sync way
TryExecute(() => SyncFunction());
Console.WriteLine("0");
try
{
await AsyncFunction();
}
catch (Exception ex)
{
Log(ex);
}
////Console.WriteLine("1");
////TryExecute(async () => await AsyncFunction());
////Console.WriteLine("2");
////await TryExecuteTask(() => AsyncFunction());
////Console.WriteLine("3");
////await TryExecuteTask(async () => await AsyncFunction());
////Console.WriteLine("4");
////await TryExecuteAsync(() => AsyncFunction());
////Console.WriteLine("5");
////await TryExecuteAsync(async () => await AsyncFunction());
Console.WriteLine("Finished without unhandled exception.");
}
private static void SyncFunction()
{
Console.WriteLine("SyncFunction starting");
Thread.Sleep(500);
Console.WriteLine("SyncFunction starting");
throw new Exception();
}
private async static Task AsyncFunction()
{
Console.WriteLine("AsyncFunction starting");
await Task.Run(() =>
{
Console.WriteLine("Sleep starting");
Thread.Sleep(500);
Console.WriteLine("Sleep end");
throw new Exception();
});
Console.WriteLine("AsyncFunction end");
}
private static void TryExecute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Log(ex);
}
}
private static Task TryExecuteTask(Func<Task> asyncAction)
{
try
{
return asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private static void Log(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Because of the unhandled exception, I can only comment out all pieces but one in Main() to test every case.
Calling await TryExecuteAsync(AsyncFunction) works like you would expect:
class Program
{
async static Task Main(string[] args)
{
await TryExecuteAsync(AsyncFunction);
Console.WriteLine("Finished without unhandled exception.");
}
private async static Task AsyncFunction()
{
Console.WriteLine("AsyncFunction starting");
await Task.Run(() =>
{
Console.WriteLine("Sleep starting");
Thread.Sleep(3000);
Console.WriteLine("Sleep end");
throw new Exception();
});
Console.WriteLine("AsyncFunction end");
}
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private static void Log(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
AsyncFunction() raises an exception that is logged and then rethrown in TryExecuteAsync. If you want to catch the rethrown exception, you should put a try/catch around the call to TryExecuteAsync:
async static Task Main(string[] args)
{
try
{
await TryExecuteAsync(AsyncFunction);
Console.WriteLine("Finished without unhandled exception.");
}
catch (Exception ex)
{
Console.WriteLine("Failed to execute: " + ex.Message);
}
}
I don't understand how to rewrite it into async/await pattern.
When converting to async, the first step is to convert what your method calls. In this case, the delegate should be converted to an async-compatible delegate first.
Action is a delegate that takes no parameters and has no return value, like void Method(). An asynchronous method that takes no parameters and has no return value looks like async Task Method(), so its delegate type would be Func<Task>.
Side note: it's especially important when dealing with delegates to remember that async void is unnatural and should be avoided.
Once you change your delegate type from Action to Func<Task>, you can await its return value, which causes your TryExecute method to be changed to async Task, as such:
private static async Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
none of above five ways can catch Exception. All stopped with unhandled exception.
That's actually just a side effect of running the code in the debugger. With asynchronous code, you do sometimes see "unhandled" exceptions that are not actually unhandled. This is because it's the compiler-generated code that is catching the exception and placing it on the task, where it will later be re-raised when your code awaits it and then your code will catch it. The debugger gets a bit freaked out when the original exception caught by something other than your code (it's caught by the compiler generated code), and it has no way of knowing that this is perfectly normal.
So if you just continue past the debugger's "unhandled" exception, you'll see it works just fine.

async Exception not being caught

I have a windows service that references the following code. My code that uses the below method contains a try..catch block but it doesn't seem to catch RefereshTokenException that is thrown in the below method. Obviously my understanding of async is not correct.
private async void RefreshTokens()
{
try
{
var cognito = new CognitoApi();
var response = cognito.TokenRefresh(_refreshToken);
if (response.HttpStatusCode == HttpStatusCode.OK)
{
_idToken = new AwsToken(response.AuthenticationResult.IdToken);
_accessToken = new AwsToken(response.AuthenticationResult.AccessToken);
}
else
{
await _signIn(_credentials.SiteId, _credentials.LocationId, null);
}
}
catch (NotAuthorizedException)
{
await _signIn(_credentials.SiteId, _credentials.LocationId, null);
}
catch (Exception ex)
{
throw new RefreshTokenException("Failed refreshing tokens.", ex);
}
}
This is the code that calls RefreshTokens
public async void Process(QueueMessage queueMessage, Action<QueueMessage> retryAction)
{
_processingCounter.Increment();
try
{
......
IAwsToken idToken = authenticationService.Tokens.IdToken; //This is the code that calls "RefreshTokens" method
........
}
catch (Exception ex)
{
//Code never reaches here...
_logger.Error("Error in ProcessMessage", ex);
}
_processingCounter.Decrement();
}
This is an async void. One of the main reasons to avoid async void methods is that you cannot handle the exceptions they throw.
Make it an async Task and await it in the caller.
Note that you then have the same issue in that caller, async void Process(...)
Make that an async Task as well and work your way up. async/await should form a chain, from your GUI or Controller down to an async I/O call.

A good solution for await in try/catch/finally?

I need to call an async method in a catch block before throwing again the exception (with its stack trace) like this :
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
But unfortunately you can't use await in a catch or finally block. I learned it's because the compiler doesn't have any way to go back in a catch block to execute what is after your await instruction or something like that...
I tried to use Task.Wait() to replace await and I got a deadlock. I searched on the Web how I could avoid this and found this site.
Since I can't change the async methods nor do I know if they use ConfigureAwait(false), I created these methods which take a Func<Task> that starts an async method once we are on a different thread (to avoid a deadlock) and waits for its completion:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
So my questions is: Do you think this code is okay?
Of course, if you have some enhancements or know a better approach, I'm listening! :)
You can move the logic outside of the catch block and rethrow the exception after, if needed, by using ExceptionDispatchInfo.
static async Task f()
{
ExceptionDispatchInfo capturedException = null;
try
{
await TaskThatFails();
}
catch (MyException ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null)
{
await ExceptionHandler();
capturedException.Throw();
}
}
This way, when the caller inspects the exception's StackTrace property, it still records where inside TaskThatFails it was thrown.
You should know that since C# 6.0, it's possible to use await in catch and finally blocks, so you could in fact do this:
try
{
// Do something
}
catch (Exception ex)
{
await DoCleanupAsync();
throw;
}
The new C# 6.0 features, including the one I just mentioned are listed here or as a video here.
If you need to use async error handlers, I'd recommend something like this:
Exception exception = null;
try
{
...
}
catch (Exception ex)
{
exception = ex;
}
if (exception != null)
{
...
}
The problem with synchronously blocking on async code (regardless of what thread it's running on) is that you're synchronously blocking. In most scenarios, it's better to use await.
Update: Since you need to rethrow, you can use ExceptionDispatchInfo.
We extracted hvd's great answer to the following reusable utility class in our project:
public static class TryWithAwaitInCatch
{
public static async Task ExecuteAndHandleErrorAsync(Func<Task> actionAsync,
Func<Exception, Task<bool>> errorHandlerAsync)
{
ExceptionDispatchInfo capturedException = null;
try
{
await actionAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null)
{
bool needsThrow = await errorHandlerAsync(capturedException.SourceException).ConfigureAwait(false);
if (needsThrow)
{
capturedException.Throw();
}
}
}
}
One would use it as follows:
public async Task OnDoSomething()
{
await TryWithAwaitInCatch.ExecuteAndHandleErrorAsync(
async () => await DoSomethingAsync(),
async (ex) => { await ShowMessageAsync("Error: " + ex.Message); return false; }
);
}
Feel free to improve the naming, we kept it intentionally verbose. Note that there is no need to capture the context inside the wrapper as it is already captured in the call site, hence ConfigureAwait(false).

Categories

Resources