![]() |
VOOZH | about |
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" />Directory.Packages.props
<PackageReference Include="Sharpnado.TaskMonitor" />Project file
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.0Install as a Cake Addin
#tool nuget:?package=Sharpnado.TaskMonitor&version=1.1.0Install as a Cake Tool
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:
async void scenarios and non awaited TaskNow 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.
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);
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();
}
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()));
}
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
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 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
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.Tabs.Maui
Pure MAUI Tabs (No handlers, no renderers, no effects): * Fixed tabs (android tabs style) * Scrollable tabs * Vertical tabs * Material design tabs (top and leading icon) * Support for SVG images * Segmented tabs * 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 * Ripple touch effect for all platforms |
|
|
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); |
Showing the top 5 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 frame component supporting blur, acrylic, dark mode. Implemented with RealtimeBlurView on Android (custom blurview) and UIVisualEffectView on iOS.
|
|
|
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