AsyncAwaitBestPractices 6.0.4

.NET Standard 1.0
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));
Product Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows
.NET Core netcoreapp1.0 netcoreapp1.1 netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1
.NET Standard netstandard1.0 netstandard1.1 netstandard1.2 netstandard1.3 netstandard1.4 netstandard1.5 netstandard1.6 netstandard2.0 netstandard2.1
.NET Framework net45 net451 net452 net46 net461 net462 net463 net47 net471 net472 net48
MonoAndroid monoandroid
MonoMac monomac
MonoTouch monotouch
Tizen tizen30 tizen40 tizen60
Universal Windows Platform uap uap10.0
Windows Phone wp8 wp81 wpa81
Windows Store netcore netcore45 netcore451
Xamarin.iOS xamarinios
Xamarin.Mac xamarinmac
Xamarin.TVOS xamarintvos
Xamarin.WatchOS xamarinwatchos
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 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

Xam.Shell.Badge

A small plugin to ease the use of badges on Shell Bottom Bars

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 64,722 11/23/2021
6.0.3 4,322 11/11/2021
6.0.2 10,846 10/12/2021
6.0.1 12,723 9/27/2021
6.0.0 26,571 7/3/2021
6.0.0-pre1 683 6/7/2021
5.1.0 65,775 3/13/2021
5.0.2 92,056 11/2/2020
5.0.0-pre2 1,560 9/17/2020
5.0.0-pre1 327 9/17/2020
4.3.0 24,141 9/15/2020
4.3.0-pre1 1,569 7/29/2020
4.2.0 35,303 7/13/2020
4.1.1 34,349 5/15/2020
4.1.1-pre1 2,182 4/1/2020
4.1.0 64,644 1/30/2020
4.1.0-pre2 1,012 1/7/2020
4.1.0-pre1 871 12/19/2019
4.0.1 87,788 12/13/2019
4.0.0-pre3 675 11/29/2019
4.0.0-pre1 406 11/7/2019
3.1.0 27,315 8/28/2019
3.1.0-pre5 694 8/20/2019
3.1.0-pre4 443 8/20/2019
3.1.0-pre3 499 8/14/2019
3.1.0-pre2 623 7/31/2019
3.1.0-pre1 478 7/31/2019
3.0.0 4,806 7/30/2019
3.0.0-pre4 548 7/14/2019
3.0.0-pre3 472 7/7/2019
3.0.0-pre2 537 7/2/2019
3.0.0-pre1 579 6/9/2019
2.1.1 16,690 4/17/2019
2.1.0 4,241 1/12/2019
2.1.0-pre1 862 12/27/2018
2.0.0 833 12/19/2018
1.2.1 690 12/17/2018
1.2.0 554 12/17/2018
1.1.0 679 12/16/2018
1.0.1 700 12/15/2018
1.0.0 666 11/30/2018
0.9.0 1,021 11/22/2018

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