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 790 11/23/2021
6.0.3 1,908 11/11/2021
6.0.2 4,613 10/12/2021
6.0.1 3,291 9/27/2021
6.0.0 18,648 7/3/2021
6.0.0-pre1 642 6/7/2021
5.1.0 43,033 3/13/2021
5.0.2 74,951 11/2/2020
5.0.0-pre2 1,508 9/17/2020
5.0.0-pre1 275 9/17/2020
4.3.0 21,067 9/15/2020
4.3.0-pre1 1,496 7/29/2020
4.2.0 30,228 7/13/2020
4.1.1 27,863 5/15/2020
4.1.1-pre1 2,145 4/1/2020
4.1.0 56,562 1/30/2020
4.1.0-pre2 958 1/7/2020
4.1.0-pre1 809 12/19/2019
4.0.1 85,799 12/13/2019
4.0.0-pre3 632 11/29/2019
4.0.0-pre1 349 11/7/2019
3.1.0 26,319 8/28/2019
3.1.0-pre5 647 8/20/2019
3.1.0-pre4 399 8/20/2019
3.1.0-pre3 452 8/14/2019
3.1.0-pre2 533 7/31/2019
3.1.0-pre1 389 7/31/2019
3.0.0 4,681 7/30/2019
3.0.0-pre4 502 7/14/2019
3.0.0-pre3 421 7/7/2019
3.0.0-pre2 488 7/2/2019
3.0.0-pre1 494 6/9/2019
2.1.1 15,347 4/17/2019
2.1.0 4,146 1/12/2019
2.1.0-pre1 795 12/27/2018
2.0.0 753 12/19/2018
1.2.1 586 12/17/2018
1.2.0 472 12/17/2018
1.1.0 596 12/16/2018
1.0.1 601 12/15/2018
1.0.0 591 11/30/2018
0.9.0 902 11/22/2018

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