-1

In constructor I want to call one method type :

private async Task OnLoadPrometDanKorisnikDatum

and I want to wait that method while its finish, and I have more method(3) like this and I want to call this 3 methods in background thread and don't wait him to finish, just want to wait first method. And I want to them executing parallel. I have methods async Task,and in constructor of view model I call like this

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, 
    DatumVrednost).Wait();
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).Wait();

if I don't place .Wait() on the end, program doesn't work. I see in debug mode they run asynchronly, but time spent tell me that they sub(one method time + second method time + ....). Can someone help me, this is for me very stuf...

RMPR
  • 3,368
  • 4
  • 19
  • 31
  • 9
    https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html – Sebastian Schumann Mar 10 '20 at 08:46
  • 1
    why does it have to be in the constructor? btw. You should post the constructor to give us the context where the code is situated – Mong Zhu Mar 10 '20 at 08:50
  • 3
    Calling `Wait()` on a task is a big no-no in many scenarios; if the scenario here has a sync-context (and I suspect it does), it is entirely possible that you will deadlock by doing that. Basically: **don't do that** (or access `.Result`); can you not simply `await` here? – Marc Gravell Mar 10 '20 at 08:51
  • @Sebastian Schumann i try to implemented but dont success. I implemented interface public interface IAsyncInitialization { Task Initialization { get; } }---------------------------------public PrometPageViewModel(INavigationService navigationService, IPrometDanService servicePrometDan,IEventAggregator eventAggregator, Prism.Services.IPageDialogService pageDialogService, IAsyncInitialization asc) : base(navigationService)//,IEventAggregator ea {...Initialization = MyMethodAsync();}public Task Initialization { get; private set; } – Fon Projekat Mar 10 '20 at 10:37
  • 1
    Sorry - but this code is unreadable. Please post it so something like https://dotnetfiddle.net/ or whatever. What are your problems? You only told me that you don't have any success but I don't see what problem do you have. – Sebastian Schumann Mar 10 '20 at 12:15
  • Short,I have 4 mehtod which from api get data from database.Method type are private async Task,and in construktor i go NameOfMethod.Wait(); For me ideal solution and i want to get first method to wait for data.and rest 3 to work paralel in the background and dont wait their result.How to do that? – Fon Projekat Mar 12 '20 at 09:59
  • For the rest 3 method, you can put it in the Android background service. it will not affect the First method. – Leon Mar 13 '20 at 06:00
  • This is code for iOS,Android and UWP.I dont work only for one platform.And i want to learn...I try to async Task subbstitution with async void but app dont work then. – Fon Projekat Mar 13 '20 at 10:28

1 Answers1

-2

Answer

The best way to handle your scenario is to use async void.

I recommend first reading the Explanation section below to fully understand the best practices around async void.

public MyConstructor()
{
    ExecuteAsyncMethods();
}

async void ExecuteAsyncMethods()
{ 
    try
    {
        await OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost);
        await OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja);
    }
    catch(Exception e)
    {
        //Handle Exception
    }
}

Explanation

Many C# devs are taught "Never use async void", but this is one of the few use-cases for it.

Yes async void can be dangerous and here's why:

  • Cannot await an async avoid method
  • Can lead to race conditions
  • Difficult to catch an Exception thrown by async void methods
    • E.g. the following try/catch block will not catch the Exception thrown here:
public MyConstructor()
{
    try
    {
        //Cannot await `async void`
        AsyncVoidMethodWithException();
    }
    catch(Exception e)
    {
        //Will never catch the `Exception` thrown in  `AsyncVoidMethodWithException` because `AsyncVoidMethodWithException` cannot be awaited
    }

    //code here will be executing by the time `AsyncVoidMethodWithException` throws the exception
}

async void AsyncVoidMethodWithException()
{
    await Task.Delay(2000);
    throw new Exception();
}

That being said, as long as we wrap the contents of our entire async void in a try/catch block, we will be able to catch the exception, like so:

public MyConstructor()
{
    AsyncVoidMethodWithException();
}

async void AsyncVoidMethodWithException()
{
    try
    {
        await Task.Delay(2000);
        throw new Exception();
    }
    catch(Exception e)
    {
        //Exception will be caught and successfully handled 
    }
}

SafeFireAndForget

I created a library to help with this and its additional benefit is that it avoids writing async void code that could be potentially misused by future devs.

It's open source and also available on NuGet:

SafeFireAndForget

SafeFireAndForget allows us to safely execute a Task whilst not blocking the calling thread and without waiting for it to finish before moving to the next line of code.

Below is a simplified version of SafeFireAndForget that you can add to your project.

However, I recommend copy/pasting its complete source code or adding its NuGet Package to your library to get a more robust implementation

public static async void SafeFireAndForget<TException>(this Task task, Action<TException> onException = null, bool continueOnCapturedContext = false) where TException : Exception
{
    try
    {
        await task.ConfigureAwait(continueOnCapturedContext);
    }
    catch (TException ex) when (onException != null)
    {
        onException(ex);
    }
}

Using SafeFireAndForget

To use SafeFireAndForget, append it to your method call like so:

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost).SafeFireAndForget();
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).SafeFireAndForget();

To handle any Exception thrown by that Task, use onException. Here's an example that prints the Exception to the Debug Console:

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost).SafeFireAndForget(ex => Debug.WriteLine(ex));
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).SafeFireAndForget(ex => Debug.WriteLine(ex));
Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
  • I think that the simplified version of `SafeFireAndForget` will crash the application in case that `onException` is `null`. To male it truly safe you must include an unconditional `catch` in the block. – Theodor Zoulias Mar 11 '20 at 22:10
  • @TheodorZoulias You are correct, and that's one of my objectives with this library: to surface an `Exception` in the `Task`. If a `Task` is called without `await`, and an `Exception` is thrown inside that `Task`, the `Exception` will disappear forever. I've seen too many devs call a `Task` without `await`ing it and then wonder why their code got into an unexpected state. – Brandon Minnick Mar 11 '20 at 22:18
  • In that case, if crashing the application is intentional, then I don't think that the name `HandleSafeFireAndForget` is appropriate for this method. I suggest that you make the `onException` argument mandatory, and add another method named for example `OnExceptionThrowUnhandled` that communicates clearly what is going to happen in case of an exception in the task! – Theodor Zoulias Mar 11 '20 at 22:31
  • To be clear, SafeFireAndForget doesn’t crash your code. Rather, non-handled exceptions in poorly written code crash the code. SafeFireAndForget ensures that all exceptions are rethrown by the compiler-generated IAsyncStateMachine. – Brandon Minnick Mar 12 '20 at 02:01
  • Then in what aspect is "safe" the `SafeFireAndForget` method? And how am I supposed to "forget" something that can crash my application at any moment? It makes no sense to me. Besides that, if I really wanted my application to crash on any faulted task that I didn't `await`, I could simply configure the application with `` in App.config, instead of chaining a misleadingly named method to all of my tasks. – Theodor Zoulias Mar 12 '20 at 02:56
  • 1
    A relevant quote from an old Stephen Cleary's answer: *Avoid async void. It has tricky semantics around error handling; I know some people call it "fire and forget" but I usually use the phrase "fire and crash".* [citation](https://stackoverflow.com/questions/12803012/fire-and-forget-with-async-vs-old-async-delegate/12804036#12804036) – Theodor Zoulias Mar 15 '20 at 02:37
  • And another one: *Regarding "fire and forget": I personally never use this phrase for async void methods. For one thing, the error handling semantics most certainly do not fit in with the phrase "fire and forget"; I half-jokingly refer to async void methods as "fire and crash".* [citation](https://stackoverflow.com/questions/17659603/async-void-asp-net-and-count-of-outstanding-operations/17660475#17660475) – Theodor Zoulias Mar 15 '20 at 02:38
  • 1
    I had to downvote as while `async void` will do the trick it is strictly recommended to use this only in exceptional situations (event handlers) exactly because that's not safe. – Ivan Ičin Mar 15 '20 at 20:14