Sharpnado.TaskMonitor
1.1.0
dotnet add package Sharpnado.TaskMonitor --version 1.1.0
NuGet\Install-Package Sharpnado.TaskMonitor -Version 1.1.0
<PackageReference Include="Sharpnado.TaskMonitor" Version="1.1.0" />
<PackageVersion Include="Sharpnado.TaskMonitor" Version="1.1.0" />
<PackageReference Include="Sharpnado.TaskMonitor" />
paket add Sharpnado.TaskMonitor --version 1.1.0
#r "nuget: Sharpnado.TaskMonitor, 1.1.0"
#:package Sharpnado.TaskMonitor@1.1.0
#addin nuget:?package=Sharpnado.TaskMonitor&version=1.1.0
#tool nuget:?package=Sharpnado.TaskMonitor&version=1.1.0
Sharpnado.TaskMonitor
TaskMonitor
is a task wrapper component helping you to deal with "fire and forget" Task
(non awaited task) by implementing async/await best practices.
It offers:
- Safe execution of all your async tasks: taylor-made for
async void
scenarios and non awaitedTask
- Callbacks for any states (canceled, success, completed, failure)
- Default or custom error handler
- Default or custom task statistics logger
Free yourself from async void!
Now let's say you have an evil async void in your code:
public async void InitializeAsync()
{
try
{
await InitializeMonkeyAsync();
}
catch (Exception exception)
{
// handle error
}
}
private async Task InitializeMonkeyAsync()
{
Monkey = await _monkeyService.GetMonkeyAsync();
}
You can get rid of async void and simply use the TaskMonitor
:
public void InitializeAsync()
{
TaskMonitor.Create(InitializeMonkeyAsync);
}
If an error occurs, it will call the default error handler which will Trace
the exception, so that it won't crash (async void) or fail silently (non awaited task).
TaskMonitor|ERROR|013|Error in wrapped task
Exception:System.Exception: Fault
at Sharpnado.Tasks.Tests.TaskMonitorTest.DelayFaultAsync() in D:\Dev\Sharpnado\src\TaskMonitor\Sharpnado.TaskMonitor.Tests\TaskMonitorTest.cs:line 243
at Sharpnado.Tasks.TaskMonitorBase.MonitorTaskAsync(Task task) in D:\Dev\Sharpnado\src\TaskMonitor\Sharpnado.TaskMonitor\TaskMonitorBase.cs:line 186
But you can also setup globally your own error handler with the TaskMonitorConfiguration
static class:
TaskMonitorConfiguration.ErrorHandler = (message, exception) =>
{
// Do custom stuff for exception handling;
};
Now careful: if you are in a MVVM scenario, I strongly encourage you to read my Free Yourself From IsBusy post. The ViewModelLoader
or the NotifyTask
would be better to handle the ViewModel
loading states.
Features summary
Delegates for all states of the ran task:
// Here task is "hot", it runs as soon as Create is called
TaskMonitor.Create(
() => DoSomethingAsync(cts.Token),
t => isCompleted = true,
t => isFaulted = true,
t => isSuccessfullyCompleted = true);
Builder for more elegant construction and deferred execution:
var monitor = new TaskMonitor.Builder(() => DoSomethingAsync(cts.Token))
.WithWhenCanceled(t => isCanceled = true)
.WithWhenFaulted(t => isFaulted = true)
.WithWhenSuccessfullyCompleted(t => isSuccess = true)
.Build();
// explicit task start
monitor.Start();
Support for task with result, Task<T>
:
var monitor = TaskMonitor<List<string>>.Create(
DelayListAsync,
t => isCompleted = true,
t => isFaulted = true,
(task, result) =>
{
isSuccessfullyCompleted = true;
Assert.Equal(3, result.Count);
});
private async Task<List<string>> DelayListAsync()
{
await Task.Delay(200);
return new List<string> {"1", "2", "3"};
}
Default handling of errors and statistics, and naming of the monitor:
TaskMonitorConfiguration.LogStatistics = true;
TaskMonitor.Create(
DelayFaultAsync,
name: "NominalFaultTestTask");
Output:
TaskMonitor|ERROR|013|Error in wrapped task
Exception:System.Exception: Fault
at Sharpnado.Tasks.Tests.TaskMonitorTest.DelayFaultAsync() in D:\Dev\Sharpnado\src\TaskMonitor\Sharpnado.TaskMonitor.Tests\TaskMonitorTest.cs:line 262
at Sharpnado.Tasks.TaskMonitorBase.MonitorTaskAsync(Task task) in D:\Dev\Sharpnado\src\TaskMonitor\Sharpnado.TaskMonitor\TaskMonitorBase.cs:line 186
TaskMonitor|STATS|013|NominalFaultTestTask => Status: IsFaulted, Executed in 246,55870000000002 ms
Global configuration for statistics and errors handlers:
TaskMonitorConfiguration.LogStatistics = true;
TaskMonitorConfiguration.StatisticsHandler = (taskMonitor, timeSpan) =>
{
statsHandlerCalled = true;
Assert.True(timeSpan.TotalMilliseconds > 0);
};
TaskMonitorConfiguration.ErrorHandler = (taskMonitor, message, exception) =>
{
errorHandlerCalled = true;
};
Run the wrapped Task
in a new Task
:
int threadId = Thread.CurrentThread.ManagedThreadId;
var monitor = TaskMonitor<int>.Create(
DelayThreadIdAsync,
inNewTask: true);
await monitor.TaskCompleted;
Assert.NotEqual(threadId, monitor.Result);
Await the task monitor without failures. Awaiting on the TaskCompleted
property will never fail:
// Will always succeed wether the task is canceled, successful or faulted
await monitor.TaskCompleted;
Consider globally or locally the cancel state as faulted to simplify your workflow:
// Local configuration
var cts = new CancellationTokenSource();
bool isFaulted = false;
bool isCanceled = false;
var monitor = new TaskMonitor.Builder(() => DelayCanceledAsync(cts.Token))
.WithWhenCanceled(t => isCanceled = true)
.WithWhenFaulted(t => isFaulted = true)
.WithConsiderCanceledAsFaulted(true)
.Build();
cts.Cancel();
monitor.Start();
await monitor.TaskCompleted;
Assert.True(!isCanceled && monitor.IsCanceled);
Assert.True(isFaulted && monitor.IsFaulted);
// Global configuration
var cts = new CancellationTokenSource();
TaskMonitorConfiguration.ConsiderCanceledAsFaulted = true;
bool isFaulted = false;
bool isCanceled = false;
bool isSuccess = false;
var monitor = new TaskMonitor.Builder(() => DelayCanceledAsync(cts.Token))
.WithWhenCanceled(t => isCanceled = true)
.WithWhenFaulted(t => isFaulted = true)
.Build();
cts.Cancel();
monitor.Start();
await monitor.TaskCompleted;
Assert.True(!isCanceled && monitor.IsCanceled);
Assert.True(isFaulted && monitor.IsFaulted);
Other common scenarios
Good with events or messages
If you are subscribing to an event/message and want to make async stuff when the event is raised, it will also be a perfect candidate.
public Constructor(IMonkeyService monkeyService)
{
monkeyService.MonkeyChanged += OnMonkeyChanged;
// same as messageService.Subscribe("MonkeyChangedMessage", OnMonkeyChanged)
}
private void OnMonkeyChanged(MonkeyChangedEventArgs eventArgs)
{
TaskMonitor.Create(() => DoSomethingAsync(eventArgs.Monkey));
}
private Task DoSomethingAsync(Monkey monkey)
{
await CrazyAsyncStuff(monkey);
await SomeOtherCrazyAction();
}
Good with non awaited task and ContinueWith
Previously you maybe used the ContinueWith
task method to create a new task and deal with fire and forget scenarios.
public void DoSomethingAsync()
{
// Task will not be awaited and you are still handling the exception: hooray!
Task.Run(() => InitializeMonkey())
.ContinueWith(
t => HandleException(t.InnerException),
TaskContinuationOptions.OnlyOnFaulted);
}
private void InitializeMonkey()
{
...
}
You can achieve the same behaviour with the TaskMonitor
in a cleaner way:
public void DoSomethingAsync()
{
TaskMonitor.Create(Task.Run(() => InitializeMonkey()));
}
Can be used as a simple decorator for statistics and error handling
You can specify global error handler and statistics logger:
TaskMonitorConfiguration.LogStatistics = true;
TaskMonitorConfiguration.StatisticsHandler = (taskMonitor, timeSpan) =>
{
// My global statistics logger
};
TaskMonitorConfiguration.ErrorHandler = (taskMonitor, message, exception) =>
{
// My global error logger
};
Then use TaskMonitor
as a simple task logging decorator:
try
{
await TaskMonitor.Create(DelayFaultAsync, name: "UseMonitorAsDecoratedFaultTest").Task;
}
catch(Exception exception)
{
// handle exception
}
But you can also let the default handlers Trace
the errors and the statistics.
Output with default handlers:
TaskMonitor|ERROR|013|Error in wrapped task
Exception:System.Exception: Fault
at Sharpnado.Tasks.Tests.TaskMonitorTest.DelayFaultAsync() in D:\Dev\Sharpnado\src\TaskMonitor\Sharpnado.TaskMonitor.Tests\TaskMonitorTest.cs:line 262
at Xunit.Assert.RecordExceptionAsync(Func`1 testCode) in C:\Dev\xunit\xunit\src\xunit.assert\Asserts\Record.cs:line 82
TaskMonitor|STATS|013|UseMonitorAsDecoratedFaultTest => Status: IsFaulted, Executed in 334,27070000000003 ms
Origins
The TaskMonitor
was inspired by Stephen Cleary's NotifyTask
. It's a task wrapper dealing with non-awaited, or fire and forget if you prefer, Task.
The difference is that NotifyTask
is made for UI scenarios (MVVM), where you want to bind the result or the state of the task to a view property. For this it implements INotifyPropertyChanged
.
See this: https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Whereas TaskMonitor
is designed to be used in any kind of scenarios (server, business layer, UI, etc...).
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages (15)
Showing the top 5 NuGet packages that depend on Sharpnado.TaskMonitor:
Package | Downloads |
---|---|
Sharpnado.Presentation.Forms
Collection of Xamarin.Forms components. IMPORTANT: On platform projects, call SharpnadoInitializer.Initialize() after Xamarin.Forms.Forms.Init() and before LoadApplication(new App()). Pure Xamarin.Forms tabs: * Fixed tabs (android tabs style) * Scrollable tabs * Segmented tabs * Custom shadows (neumorphism ready) * Circle button in tab bar * Bottom bar tabs (ios tabs style) * Custom tabs (be creative just implement TabItem) * Independent ViewSwitcher Sharpnado.Shadows: * Add as many custom shadows as you like to any view (Android, iOS, UWP) * You can specify each shadow Color, Opacity, BlurRadius, and Offset * Simply implement Neumorphism * You can add one shadow, 3 shadows, 99 shadows, to any Xamarin.Forms element * Animate any of these property and make the shadows dance around your elements MaterialFrame: * AcrylicBlur mode * 3 Blur styles: Light, ExtraLight, Dark (UIVisualEffectView styles) * Acrylic mode * Dark mode * Light mode * Change modes dynamically * Performance (CALayer on ios, LayerDrawable on android) * Android: RealtimeBlurView from Tu Yimin (mmin18) The TaskLoaderView 2.0 handles all your task loading states: * Handles error with custom messages and icons * Handles empty states * Show snackbar errors for refresh scenarios (if data is already shown) * Handles retry with button * Support Xamarin.Forms.Skeleton * Can override any state views with your own custom ones HorizontalListView for Xamarin.Forms (close to a CollectionView): * Carousel layout * Column count * Snapping on first or middle element * Padding and item spacing * Handles NotifyCollectionChangedAction Add Remove and Reset actions * View recycling * RecyclerView on Android * UICollectionView on iOS Grid ListView (HorizontalListView with ListLayout set to Grid): * Column count * Drag And Drop * RefreshView support * Padding and item spacing * Handles NotifyCollectionChangedAction Add Remove and Reset actions * View recycling |
|
Sharpnado.TaskLoaderView
Free yourself from IsBusy=true! The `TaskLoaderView` and the `TemplatedTaskLoader` are UI components that handle all your UI loading state (Loading, Error, Result, Notification), and removes all the pain of async loading from your view models (try catch / async void / IsBusy / HasErrors / base view models / ...) thanks to its brother the `TaskLoaderNotifier`. Featuring: * Default views for all loading states (Loading, Error, Success, Notification, Refresh) * Snackbar component * Compose notifiers with CompositeTaskLoaderNotifier * Stylable views including fonts, accent color, error images, ... * Any states are overridable with user custom views and easily positionned with AbsoluteLayout properties * Support for Xamarin.Forms.Skeleton nuget package * Support for refresh scenarios, and error while refreshing with the ErrorNotificationView * Supports Async mvvm ICommand through TaskLoaderCommand * Supports loading task on demand with the NotStarted state * TaskLoaderNotifier for the ViewModel side taking care of all the error handling and the IsBusy nonsense |
|
Sharpnado.Forms.HorizontalListView
* Horizontal, Grid, Carousel or Vertical layout * Reveal custom animations * Drag and Drop feature * Column count * Infinite loading with Paginator component * Snapping on first or middle element * Padding and item spacing * Handles NotifyCollectionChangedAction Add, Remove and Reset actions * View recycling * RecyclerView on Android * UICollectionView on iOS Initialization: * On core project call Sharpnado.HorizontalListView.Initializer.Initialize(true, false) in App.xaml.cs after InitializeComponent(). * On platform projects (ios/android), call SharpnadoInitializer.Initialize() before Xamarin.Forms.Forms.Init() and LoadApplication(new App()). Warning: the MaterialFrame is no longer included in the package, you have to install it manually: Sharpnado.MaterialFrame. |
|
Sharpnado.Tabs
Pure Xamarin.Forms tabs: * Fixed tabs (android tabs style) * Scrollable tabs * Vertical tabs * Material design tabs (top and leading icon) * Support for SVG images * Segmented tabs * Custom shadows (neumorphism ready) * Badges on tabs * Circle button in tab bar * Bottom bar tabs (ios tabs style) * Custom tabs (be creative just implement TabItem) * Independent ViewSwitcher * Bindable with ItemsSource -------------- Installation -------------- * In Core project, in `App.xaml.cs`: public App() { InitializeComponent(); Sharpnado.Tabs.Initializer.Initialize(loggerEnable: false); ... } * In iOS project: Xamarin.Forms.Forms.Init(); Sharpnado.Tabs.iOS.Preserver.Preserve(); * In UWP project: var rendererAssemblies = new[] { typeof(UWPShadowsRenderer).GetTypeInfo().Assembly, typeof(UwpTintableImageEffect).GetTypeInfo().Assembly, }; Xamarin.Forms.Forms.Init(e, rendererAssemblies); |
|
Sharpnado.Tabs.Maui
Pure MAUI Tabs: * Fixed tabs (android tabs style) * Scrollable tabs * Vertical tabs * Material design tabs (top and leading icon) * Support for SVG images * Segmented tabs * Custom shadows (neumorphism ready) * Badges on tabs * Circle button in tab bar * Bottom bar tabs (ios tabs style) * Custom tabs (be creative just implement TabItem) * Independent ViewSwitcher * Bindable with ItemsSource ## Installation * In Core project, in `MauiProgram.cs`: ```csharp public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseSharpnadoTabs(loggerEnabled: false); } ``` |
GitHub repositories (6)
Showing the top 6 popular GitHub repositories that depend on Sharpnado.TaskMonitor:
Repository | Stars |
---|---|
roubachof/Sharpnado.Tabs
Pure MAUI and Xamarin.Forms Tabs, including fixed tabs, scrollable tabs, bottom tabs, badge, segmented control, custom tabs, button tabs, bendable tabs...
|
|
roubachof/Sharpnado.MaterialFrame
A modern MAUI (and XF) Frame component supporting blur, acrylic, dark mode. Implemented with RealtimeBlurView on Android (custom blurview) and UIVisualEffectView on iOS.
|
|
roubachof/Sharpnado.Shadows
Add as many custom shadows (Color, Offset, Blur, Neumorphism) as you like to any Xamarin.Forms view (Android, iOS, UWP).
|
|
roubachof/Xamarin-Forms-Practices
Collection of good practices for Xamarin forms developement
|
|
roubachof/Sharpnado.CollectionView
A performant list view supporting: grid, horizontal and vertical layout, drag and drop, and reveal animations.
|
|
roubachof/Sharpnado.TaskLoaderView
Free yourself from IsBusy=true! The `TaskLoaderView` is a UI component that handles all your UI loading state (Loading, Error, Result, Notification), and removes all the pain of async loading from your view models (try catch / async void / IsBusy / HasErrors / base view models / ...) thanks to its brother the `TaskLoaderNotifier`.
|
Upgrade to .Net 9