AsyncAwaitBestPractices 6.0.4

Install-Package AsyncAwaitBestPractices -Version 6.0.4
dotnet add package AsyncAwaitBestPractices --version 6.0.4
<PackageReference Include="AsyncAwaitBestPractices" Version="6.0.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AsyncAwaitBestPractices --version 6.0.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: AsyncAwaitBestPractices, 6.0.4"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install AsyncAwaitBestPractices as a Cake Addin
#addin nuget:?package=AsyncAwaitBestPractices&version=6.0.4

// Install AsyncAwaitBestPractices as a Cake Tool
#tool nuget:?package=AsyncAwaitBestPractices&version=6.0.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

AsyncAwaitBestPractices

NuGet

Available on NuGet: https://www.nuget.org/packages/AsyncAwaitBestPractices/

  • SafeFireAndForget
    • An extension method to safely fire-and-forget a Task or a ValueTask
    • Ensures the Task will rethrow an Exception if an Exception is caught in IAsyncStateMachine.MoveNext()
  • WeakEventManager
    • Avoids memory leaks when events are not unsubscribed
    • Used by AsyncCommand, AsyncCommand<T>, AsyncValueCommand, AsyncValueCommand<T>
  • Usage instructions

Setup

Usage

SafeFireAndForget

An extension method to safely fire-and-forget a Task.

SafeFireAndForget allows a Task to safely run on a different thread while the calling thread does not wait for its completion.

public static async void SafeFireAndForget(this System.Threading.Tasks.Task task, System.Action<System.Exception>? onException = null, bool continueOnCapturedContext = false)
public static async void SafeFireAndForget(this System.Threading.Tasks.ValueTask task, System.Action<System.Exception>? onException = null, bool continueOnCapturedContext = false)
Basic Usage - Task
void HandleButtonTapped(object sender, EventArgs e)
{
    // Allows the async Task method to safely run on a different thread while the calling thread continues, not awaiting its completion
    // onException: If an Exception is thrown, print it to the Console
    ExampleAsyncMethod().SafeFireAndForget(onException: ex => Console.WriteLine(ex));

    // HandleButtonTapped continues execution here while `ExampleAsyncMethod()` is running on a different thread
    // ...
}

async Task ExampleAsyncMethod()
{
    await Task.Delay(1000);
}
Basic Usage - ValueTask

If you're new to ValueTask, check out this great write-up, Understanding the Whys, Whats, and Whens of ValueTask .

void HandleButtonTapped(object sender, EventArgs e)
{
    // Allows the async ValueTask method to safely run on a different thread while the calling thread continues, not awaiting its completion
    // onException: If an Exception is thrown, print it to the Console
    ExampleValueTaskMethod().SafeFireAndForget(onException: ex => Console.WriteLine(ex));

    // HandleButtonTapped continues execution here while `ExampleAsyncMethod()` is running on a different thread
    // ...
}

async ValueTask ExampleValueTaskMethod()
{
    var random = new Random();
    if (random.Next(10) > 9)
        await Task.Delay(1000);
}
Advanced Usage
void InitializeSafeFireAndForget()
{
    // Initialize SafeFireAndForget
    // Only use `shouldAlwaysRethrowException: true` when you want `.SafeFireAndForget()` to always rethrow every exception. This is not recommended, because there is no way to catch an Exception rethrown by `SafeFireAndForget()`; `shouldAlwaysRethrowException: true` should **not** be used in Production/Release builds.
    SafeFireAndForgetExtensions.Initialize(shouldAlwaysRethrowException: false);

    // SafeFireAndForget will print every exception to the Console
    SafeFireAndForgetExtensions.SetDefaultExceptionHandling(ex => Console.WriteLine(ex));
}

void UninitializeSafeFireAndForget()
{
    // Remove default exception handling
    SafeFireAndForgetExtensions.RemoveDefaultExceptionHandling()
}

void HandleButtonTapped(object sender, EventArgs e)
{
    // Allows the async Task method to safely run on a different thread while not awaiting its completion
    // onException: If a WebException is thrown, print its StatusCode to the Console. **Note**: If a non-WebException is thrown, it will not be handled by `onException`
    // Because we set `SetDefaultExceptionHandling` in `void InitializeSafeFireAndForget()`, the entire exception will also be printed to the Console
    ExampleAsyncMethod().SafeFireAndForget<WebException>(onException: ex =>
    {
        if(ex.Response is HttpWebResponse webResponse)
            Console.WriteLine($"Task Exception\n Status Code: {webResponse.StatusCode}");
    });
    
    ExampleValueTaskMethod().SafeFireAndForget<WebException>(onException: ex =>
    {
        if(ex.Response is HttpWebResponse webResponse)
            Console.WriteLine($"ValueTask Error\n Status Code: {webResponse.StatusCode}");
    });

    // HandleButtonTapped continues execution here while `ExampleAsyncMethod()` and `ExampleValueTaskMethod()` run in the background
}

async Task ExampleAsyncMethod()
{
    await Task.Delay(1000);
    throw new WebException();
}

async ValueTask ExampleValueTaskMethod()
{
    var random = new Random();
    if (random.Next(10) > 9)
        await Task.Delay(1000);
        
    throw new WebException();
}

WeakEventManager

An event implementation that enables the garbage collector to collect an object without needing to unsubscribe event handlers.

Inspired by Xamarin.Forms.WeakEventManager.

Using EventHandler
readonly WeakEventManager _canExecuteChangedEventManager = new WeakEventManager();

public event EventHandler CanExecuteChanged
{
    add => _canExecuteChangedEventManager.AddEventHandler(value);
    remove => _canExecuteChangedEventManager.RemoveEventHandler(value);
}

void OnCanExecuteChanged() => _canExecuteChangedEventManager.RaiseEvent(this, EventArgs.Empty, nameof(CanExecuteChanged));
Using Delegate
readonly WeakEventManager _propertyChangedEventManager = new WeakEventManager();

public event PropertyChangedEventHandler PropertyChanged
{
    add => _propertyChangedEventManager.AddEventHandler(value);
    remove => _propertyChangedEventManager.RemoveEventHandler(value);
}

void OnPropertyChanged([CallerMemberName]string propertyName = "") => _propertyChangedEventManager.RaiseEvent(this, new PropertyChangedEventArgs(propertyName), nameof(PropertyChanged));
Using Action
readonly WeakEventManager _weakActionEventManager = new WeakEventManager();

public event Action ActionEvent
{
    add => _weakActionEventManager.AddEventHandler(value);
    remove => _weakActionEventManager.RemoveEventHandler(value);
}

void OnActionEvent(string message) => _weakActionEventManager.RaiseEvent(message, nameof(ActionEvent));

WeakEventManager<T>

An event implementation that enables the garbage collector to collect an object without needing to unsubscribe event handlers.

Inspired by Xamarin.Forms.WeakEventManager.

Using EventHandler<T>
readonly WeakEventManager<string> _errorOcurredEventManager = new WeakEventManager<string>();

public event EventHandler<string> ErrorOcurred
{
    add => _errorOcurredEventManager.AddEventHandler(value);
    remove => _errorOcurredEventManager.RemoveEventHandler(value);
}

void OnErrorOcurred(string message) => _errorOcurredEventManager.RaiseEvent(this, message, nameof(ErrorOcurred));
Using Action<T>
readonly WeakEventManager<string> _weakActionEventManager = new WeakEventManager<string>();

public event Action<string> ActionEvent
{
    add => _weakActionEventManager.AddEventHandler(value);
    remove => _weakActionEventManager.RemoveEventHandler(value);
}

void OnActionEvent(string message) => _weakActionEventManager.RaiseEvent(message, nameof(ActionEvent));

NuGet packages (4)

Showing the top 4 NuGet packages that depend on AsyncAwaitBestPractices:

Package Downloads
AsyncAwaitBestPractices.MVVM

Async Extensions for ICommand Includes AsyncCommand and IAsyncCommand which allows ICommand to safely be used asynchronously with Task. Includes AsyncValueCommand and IAsyncValueCommand which allows ICommand to safely be used asynchronously with ValueTask

HB.FullStack.Common

Package Description

ImageHive

Cross platform plugin

ImageHive.Forms

Cross platform Xamarin plugin

GitHub repositories (4)

Showing the top 4 popular GitHub repositories that depend on AsyncAwaitBestPractices:

Repository Stars
beeradmoore/dlss-swapper
Azure/Industrial-IoT
Azure Industrial IoT Platform
xamarin/dev-days-labs
Goz3rr/SatisfactorySaveEditor
Version Downloads Last updated
6.0.4 344 11/23/2021
6.0.3 1,789 11/11/2021
6.0.2 4,419 10/12/2021
6.0.1 3,184 9/27/2021
6.0.0 18,369 7/3/2021
6.0.0-pre1 641 6/7/2021
5.1.0 42,484 3/13/2021
5.0.2 74,393 11/2/2020
5.0.0-pre2 1,507 9/17/2020
5.0.0-pre1 274 9/17/2020
4.3.0 20,986 9/15/2020
4.3.0-pre1 1,495 7/29/2020
4.2.0 30,126 7/13/2020
4.1.1 27,748 5/15/2020
4.1.1-pre1 2,144 4/1/2020
4.1.0 56,313 1/30/2020
4.1.0-pre2 957 1/7/2020
4.1.0-pre1 808 12/19/2019
4.0.1 85,684 12/13/2019
4.0.0-pre3 631 11/29/2019
4.0.0-pre1 348 11/7/2019
3.1.0 26,296 8/28/2019
3.1.0-pre5 646 8/20/2019
3.1.0-pre4 398 8/20/2019
3.1.0-pre3 451 8/14/2019
3.1.0-pre2 532 7/31/2019
3.1.0-pre1 388 7/31/2019
3.0.0 4,680 7/30/2019
3.0.0-pre4 501 7/14/2019
3.0.0-pre3 420 7/7/2019
3.0.0-pre2 487 7/2/2019
3.0.0-pre1 493 6/9/2019
2.1.1 15,320 4/17/2019
2.1.0 4,145 1/12/2019
2.1.0-pre1 794 12/27/2018
2.0.0 752 12/19/2018
1.2.1 584 12/17/2018
1.2.0 471 12/17/2018
1.1.0 595 12/16/2018
1.0.1 600 12/15/2018
1.0.0 590 11/30/2018
0.9.0 901 11/22/2018

New In This Release:
- Mark internal classes as abstract
- Update AssemblyFileVersion
- Add NuGet README
- Improve Nullablitiy