im refactoring out some try catch blocks with a ExcecuteWithLogging method, but exception that occurs in restHandler.GetResultAsync() never get caught, why?
public async Task<Aaa> SearchByPersonnummerAsync(string personnummer)
{
var restHandler = new RestHandler();
GenericResult<Aaa> aaa= await ExcecuteWithLogging(async () =>
{
var res = await restHandler.GetResultAsync<Aaa>(
_configurationManager.GetSetting("api"),
"url");
return res;
});
return aaa.Result;
}
private T ExcecuteWithLogging<T>(Func<T> function)
{
try
{
function();
}
catch (Exception ex)
{
var message = ex.Message;
// Log
}
return default(T);
}
Here is my solution which is working as i prefered:
var aaa = null;
await ExcecuteWithLogging(async () =>
aaa = await Method());
public async Task<string> ExcecuteWithLogging(Func<Task> action)
{
try
{
await action();
}
catch (Exception ex)
{
// handle exception
return null;
}
return "ok";
}
I had a similar problem and here is my solution. In my case I couldn't be sure about the functions type, so I simply created an overload for async ones:
public static T CallAndLogErrors<T, TLog>(Func<T> method, ILogger<TLog> logger)
{
try
{
return method();
}
catch (Exception e)
{
LogError(e, logger);
throw;
}
}
public static async Task<T> CallAndLogErrors<T, TLog>(Func<Task<T>> method, ILogger<TLog> logger)
{
try
{
return await method();
}
catch (Exception e)
{
LogError(e, logger);
throw;
}
}
This makes it possible to call methods with T, Task<T> or async Task<T> return types like:
var result = CallAndLogErrors(() => Method(), logger);
var result = await CallAndLogErrors(() => Method(), logger);
And all exceptions are catched.
The problem is that you are not implementing an overload of ExecuteWithLogging that resolves specifically for Func<Task<T>>. Remember that lambda expressions can be converted into any compatible delegate, that is why your async lambda is assigned succesfully to your current ExecuteWithLogging method.
Before you read the rest of the answer pleas have a look to the following article, it helped me a lot when I came across with exactly the same problem that you are facing now. I am pretty much sure that after reading that article you will understand what is happening here, but for completness sake here you have some samples that will make things clarer. I have modified your methodos in the following way:
public static async void SearchByPersonnummerAsync(string personnummer)
{
var aaa = await ExcecuteWithLogging(async () =>
{
Console.WriteLine("Executing function");
var res = await Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine("Before crashing");
throw new Exception();
return 1;
});
Console.WriteLine("Finishing execution");
return res;
});
}
private static T ExcecuteWithLogging<T>(Func<T> function)
{
try
{
Console.WriteLine("Before calling function");
function();
Console.WriteLine("After calling function");
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
}
Console.WriteLine("Returning..");
return default(T);
}
This is just where you are now, I only added some console logging code, what is the output?
As you can see ExecutingWithLogging is returning when the async delegate has not even crashed!
Let's add an overload that accepts a Func<Task<T>>
private static async Task<T> ExcecuteWithLogging<T>(Func<Task<T>> function)
{
T result;
try
{
Console.WriteLine("Before calling function");
result = await function();
Console.WriteLine("After calling function");
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
return default(T);
}
Console.WriteLine("Returning..");
return result;
}
The compiler will pick this now, from the article mentioned above:
The compiler prefers the method call that expects a delegate that returns a Task. That’s good, because it’s the one you’d rather use. The compiler comes to this conclusion using the type inference rules about the return value of anonymous delegates. The “inferred return type” of any async anonymous function is assumed to be a Task. Knowing that the anonymous function represented by the lambda returns a Task, the overload of Task.Run() that has the Func argument is the better match.
Now the output is:
And you get your exeption catched. So what is the moral? Again, I quote the mentioned article:
First, avoid using async lambdas as arguments to methods that expect Action and don’t provide an overload that expects a Func. If you do that, you’ll create an async void lambda. The compiler will happily assume that’s what you want.
Second, if you author methods that take delegates as arguments,
consider whether programmers may wish to use an async lambda as that
argument. If so, create an overload that uses Func as the
argument in addition to Action. As a corollary, create an overload
that takes Func> in addition to Task for arguments that
return a value.
EDIT
As #Servy points out in the comments if you mantain only the original version of ExecuteWithLogging T is actually a Task<Aaa>... but the only way I can think of awaiting without the overload is:
private static async Task<T> ExcecuteWithLogging<T>(Func<T> function)
{
try
{
var result = function();
if (result is Task t)
{
return await t;
}
return result;
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
}
Console.WriteLine("Returning..");
return default(T);
}
But besides being ugly IMHO, it always fails since the call to function() runs synchronously and by the time you want to await the task has already ended or crashed. But the worst part of this approach is that it does not even compile, the compiler complains with: Can not implicitly convert type void to T
Related
I have an API endpoint:
[HttpGet("api/query")]
public async IAsyncEnumerable<dynamic> Query(string name)
{
await foreach(var item in _myService.CallSomethingReturningAsyncStream(name))
{
yield return item;
}
}
I would like to be able to in case of an ArgumentException return something like "Bad request" response.
If I try using try-catch block, I get error:
CS1626: Cannot yield a value in the body of a try block with a catch
clause
Please note that it is an API endpoint method, so error handling should ideally be in the same method, without need for making additional middlewares.
If needed, rough implementation of CallSomethingReturningAsyncStream method:
public async IAsyncEnumerable<dynamic> CallSomethingReturningAsyncStream(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name is missing", nameof(name));
(...)
foreach (var item in result)
{
yield return item;
}
}
You could install the System.Interactive.Async package, and do this:
[HttpGet("api/query")]
public IAsyncEnumerable<dynamic> Query(string name)
{
return AsyncEnumerableEx.Defer(() => _myService.CallSomethingReturningAsyncStream(name))
.Catch<dynamic, Exception>(ex =>
AsyncEnumerableEx.Return<dynamic>($"Bad request: {ex.Message}"));
}
The signature of the Defer operator:
// Returns an async-enumerable sequence that invokes the specified
// factory function whenever a new observer subscribes.
public static IAsyncEnumerable<TSource> Defer<TSource>(
Func<IAsyncEnumerable<TSource>> factory)
The signature of the Catch operator:
// Continues an async-enumerable sequence that is terminated by
// an exception of the specified type with the async-enumerable sequence
// produced by the handler.
public static IAsyncEnumerable<TSource> Catch<TSource, TException>(
this IAsyncEnumerable<TSource> source,
Func<TException, IAsyncEnumerable<TSource>> handler);
The signature of the Return operator:
// Returns an async-enumerable sequence that contains a single element.
public static IAsyncEnumerable<TValue> Return<TValue>(TValue value)
The Defer might seem superficial, but it is needed for the case that the _myService.CallSomethingReturningAsyncStream throws synchronously. In case this method is implemented as an async iterator, it will never throw synchronously, so you could omit the Defer.
You have to split method. Extract part which does async processing:
private async IAsyncEnumerable<dynamic> ProcessData(TypeOfYourData data)
{
await foreach(var item in data)
{
yield return item;
}
}
And then in API method do:
[HttpGet("api/query")]
public IActionResult Query(string name)
{
TypeOfYourData data;
try {
data = _myService.CallSomethingReturningAsyncStream(name);
}
catch (...) {
// do what you need
return BadRequest();
}
return Ok(ProcessData(data));
}
Or actually you can just move the whole thing into separate method:
[HttpGet("api/query")]
public IActionResult Query(string name)
{
try {
return Ok(TheMethodYouMovedYourCurrentCodeTo);
}
catch (...) {
// do what you need
return BadRequest();
}
}
It will of course only catch exceptions thrown before actual async enumeration starts, but that's fine for your use case as I understand. Returning bad request after async enumeration has started is not possible, because response is already being sent to client.
Update: you mentioned your service code is:
public async IAsyncEnumerable<dynamic> CallSomethingReturningAsyncStream(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name is missing", nameof(name));
foreach (var item in result)
{
yield return item;
}
}
It has the same problem as your current api method. It's generally a good practice to split such methods in two - first part performs validation, and then returns the second part. For example let's consider this code:
public class Program {
static void Main() {
try {
CallSomethingReturningAsyncStream(null);
}
catch (Exception ex) {
Console.WriteLine(ex);
}
}
public static async IAsyncEnumerable<string> CallSomethingReturningAsyncStream(string name) {
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name is missing", nameof(name));
await Task.Delay(100);
yield return "1";
}
}
It will complete without any exceptions, because the code inside CallSomethingReturningAsyncStream was converted by compiler into a state machine and will only execute when you enumerate the result, including part which validates arguments.
However, if you change your method like this:
public class Program {
static void Main() {
try {
CallSomethingReturningAsyncStream(null);
}
catch (Exception ex) {
Console.WriteLine(ex);
}
}
public static IAsyncEnumerable<string> CallSomethingReturningAsyncStream(string name) {
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name is missing", nameof(name));
return CallSomethingReturningAsyncStreamInternal(name);
}
// you can also put that inside method above,
// as local function
private static async IAsyncEnumerable<string> CallSomethingReturningAsyncStreamInternal(string name) {
await Task.Delay(100);
yield return "1";
}
}
It will do the same thing, BUT now method validates arguments synchronously, and then goes to async part. This code will throw argument exception which will be caught.
So I'd suggest to follow this best practice for your code, and that will also resolve your issue stated in question. There is no reason to delay throwing exception until enumeration occurs when it's clear right away that arguments are invalid and enumeration is not possible anyway.
I have many statements that can throw exceptions. Exceptions are not important.
My system accepts missing patient data fields.
patientData.PatientId = message.Find(...);
try
{
patientData.Gender = message.Find(...);
}
catch
{
// no gender, no problem
}
try
{
patientData.DateOfBirth = message.Find(...);
}
catch
{
// no DateOfBirth, no problem
}
// and many other try-catch blocks ...
What is the best way to write these statements that can throw exceptions but not critical?
In your example, you can create static TryFindMessage method in addition to Find. In case of exception just return false.
For example:
bool Message.TryFind(..., Message message, out string result).
But, if you wish some generic approach which you can use with anything, then you can take advantage of delegates and create some static helper.
You can use Action or Func in that case. Add another extension method which accepts Func if you need to return some value from executed function.
public static class SilentRunner
{
public static void Run(Action action, Action<Exception> onErrorHandler)
{
try
{
action();
}
catch (Exception e)
{
onErrorHandler(e);
}
}
public static T Run<T>(Func<T> func, Action<Exception> onErrorHandler)
{
try
{
return func();
}
catch (Exception e)
{
onErrorHandler(e);
}
return default(T);
}
}
And then use it so:
SilentRunner.Run(
() => DoSomething(someObject),
ex => DoSomethingElse(someObject, ex));
In case of Func, you can take result as well:
var result = SilentRunner.Run(
() => DoSomething(someObject),
ex => DoSomethingElse(someObject, ex));
I have many statements that can throw exceptions. Exceptions are not
important.
This can be dangerous, because exceptions can be thrown for different reasons, not only because of missing property.
I would advise instead of swallowing exception, modify code to return default value(null) when value is not found.
You can introduce new method in message class, for example FindOrDefault
// Pseudo code
public T FindOrDefault(string property)
{
return CanFind(property) ? Find(property) : default(T);
}
Usage of such method will be self explanatory
patientData.PatientId = message.Find(...); // Mandatory - must throw if not found
patientData.Gender = message.FindOrDefault(...);
patientData.DateOfBirth = message.FindOrDefault(...);
Updated code (as per comment): still doesn't work
I am trying to create an extension method on Task to call my async database calls (fire and forget), however I am getting a compilation error:
Error CS4010
Cannot convert async lambda expression to delegate type 'Func<T>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<T>'. AsyncTaskExtension
This is my code:
public static void ExecuteTask<T>(this Task<T> BackgroudJob, Action<T> UIJob, Action<Exception> OnError = null) where T : struct
{
Func<T> work = async () =>
{
T ret = default(T);
try
{
ret = await BackgroudJob;
UIJob(ret);
//throw new Exception("My exception !!!");
}
catch (Exception ex)
{
try
{
if (OnError != null)
{
OnError(ex);
}
System.Diagnostics.Debug.WriteLine(ex);
}
catch { }//eat exception
}
return ret;
};
work();
}
I am trying to create an extension method on Task to call my async database calls(fire and ferget)
OK, I have to say that this is a really, really bad idea!
"Fire and forget" means: "I don't care when this code completes. Or if it completes." Corollary: "I am perfectly OK with losing database writes during an appdomain recycle, process recycle, reboot, or pod replacement; and I am happy with not having any logs or other notifications about said data loss."
I cannot imagine how this would ever be acceptable for a database write operation. At most, fire-and-forget is sometimes used for things like updating caches. Some people think it's OK for emails, too, but I prefer a simple queue.
To make the method fire-and-forget, change the return type to void and the Func<T> to an Action:
public static void CreateFireAndForgetWork<T>(this Task<T> Job, Action<Exception> OnError = null) where T : struct
{
Action work = async () =>
{
try
{
await Job;
}
catch (Exception ex)
{
...
}
};
work();
}
This code does result in an async void lambda expression (since it is converted to an Action). Normally, this is a bad idea, but it's here because the code is doing fire-and-forget (which, as noted at the beginning of this post, is a bad idea IMO).
Ok finally it worked
public static void ExecuteTask<T>(this Task<T> BackgroudJob, Action<T> UIJob, Action<Exception> OnError = null) where T : struct
{
Action work = async () =>
{
T? ret = null;
try
{
ret = await BackgroudJob;
//throw new Exception("My exception !!!");
}
catch (Exception ex)
{
try
{
if (OnError != null)
{
OnError(ex);
}
System.Diagnostics.Debug.WriteLine(ex);
}
catch { }//eat exception
}
if (ret.HasValue)
{
UIJob(ret.Value);
}
};
work();
}
I have this method:
public object LongRunningTask()
{
return SomethingThatTakesTooLong();
}
I wrote the following code so I can transform a normal method in an async one and still get the Exception:
public async Task<object> LongRunningTaskAsync()
{
Exception ex = null;
object ret = await Task.Run(() =>
{
object r = null;
try
{
//The actual body of the method
r = SomethingThatTakesTooLong();
}
catch (Exception e)
{
ex = e;
}
return r;
});
if (ex == null)
return ret;
else
throw ex;
}
When I need to do this in several methods, I have to copy all this code and change only the middle.
Is there a way to do something like this?
[SomeAttributeThatDoesThatMagically]
public async Task<object> LongRunningTaskAsync()
{
return SomethingThatTakesTooLong();
}
Attributes are generally metadata though it is possible to define attributes that can be executed (such as security behaviours in WCF) however, something has to be looking for it first. Your attributes won't just magically run.
I suspect you might have to use a dynamic proxy.
Take a look at how WCF does things for ideas.
I have a very ugly piece of code that is scattered throughout a project. The only difference in this piece of code is one line where a different method is called. The method that's called always returns a bool.
I want to refactor this and extract it into its own method and pass the 1 liner into this method (if possible) from my understanding I can use a Func<> to do this.
Here is what I am trying to do. I have tried to keep things as clear as possible
public async Task<bool> SomeMethod()
{
//code removed for readability.
//IsCustomerComplete will return a bool
var process = await RepeatableMasterPiece(1, 2, _myRepo.IsCustomerComplete(someParameterRequired));
//do something with process result
return process;
}
private async Task<bool> RepeatableMasterPiece(int param1, int param2, Func<Task<bool>> method)
{
int retry = 0;
bool soapComplete = false;
string soapFault = "just a placeholder for example";
bool blackListStatus = false;
while (!soapComplete && retry <= 1)
{
try
{
if (soapFault != null)
{
//do some stuff with param1 & param2 here
}
if (!soapComplete)
{
return await method.Invoke();
}
}
catch (FaultException ex)
{
soapFault = ex.Message;
retry++;
if (retry > 1)
{
throw ex;
}
}
}
}
From the repo
public async Task<bool> IsCustomerComplete(int id)
{
...removed other code here
return true;
}
Does this make sense, am I on the right track, from the examples I have found they only show Funcs<> passing in a string or int which makes things look a whole lot simpler.
If I understand your goal, you're very close. The biggest thing you're missing is the conversion of your method to a Func<> delegate. In your question, you included the argument parentheses. You don't need these if you're not invoking the method.
So, basically, this is what you probably want.
var process = await RepeatableMasterPiece(1, 2, _myRepo.IsCustomerComplete);
Here is an example based on your provided details.
public async Task SomeMethod() {
//code in method.
var _myRepo = new repo();
var someParameterRequired = 1;
var process = await RepeatableMasterPiece(1, 2, () => _myRepo.IsCustomerComplete(someParameterRequired));
//do something with process result
}
private async Task<bool> RepeatableMasterPiece(int param1, int param2, Func<Task<bool>> method) {
int retry = 0;
bool soapComplete = false;
string soapFault = "just a placeholder for example";
bool blackListStatus = false;
while (!soapComplete && retry <= 1) {
try {
if (soapFault != null) {
//do some stuff with param1 & param2 here
}
if (!soapComplete && method != null) {
return await method();
}
} catch (FaultException ex) {
soapFault = ex.Message;
retry++;
if (retry > 1) {
throw ex;
}
}
}
return false;
}
The assumption here is that all the target methods will be returning Task<bool>
If the target function does not require any parameters then you can do as mentioned in other answer and just provide the function itself without the parenthesis.
I would checkout Action<T> and Func<T, TResult> delegates.
Use an Action<T> delegate when you wish to pass in an void anonymous method.
Use an Func<TResult> delegate when you need to pass in a anonymous method with a return type.
MSDN has some good examples:
Func Delegates MSDN
Action Delegates MSDN
I have used actions and function many times over my career. They come in handy when adding features to tightly coupled code that cannot be refactored.
However, their correct usage should be used when writing loosely coupled code. There are many times where I wanted to give the implementer the option to provide their own functionality.