Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ObservableTaskBuilder.cs
1using System;
2using System.Linq;
3using System.Threading;
4using System.Threading.Tasks;
5using CommunityToolkit.Mvvm.Input;
9
11{
12 public class ObservableTaskBuilder<TProgress>
13 {
14 private readonly ObservableTaskOptions options = new();
15 private Func<TaskContext<TProgress>, Task>? factory;
16
17 public ObservableTaskBuilder<TProgress> Named(string name) { this.options.Name = name; return this; }
18 public ObservableTaskBuilder<TProgress> AutoStart(bool value = true) { this.options.AutoStart = value; return this; }
19 public ObservableTaskBuilder<TProgress> UseTaskRun(bool value = true) { this.options.UseTaskRun = value; return this; }
20 public ObservableTaskBuilder<TProgress> WithPolicy(IAsyncPolicy policy) { this.options.Policies.Add(policy); return this; }
21 public ObservableTaskBuilder<TProgress> WithTelemetry(IObservableTaskTelemetry telemetry) { this.options.Telemetry = telemetry; return this; }
22 public ObservableTaskBuilder<TProgress> WithDispatcher(IDispatcherAdapter dispatcher) { this.options.Dispatcher = dispatcher; return this; }
23 public ObservableTaskBuilder<TProgress> Run(Func<TaskContext<TProgress>, Task> op) { this.factory = op; return this; }
24
25 public ObservableTask<TProgress> Build(params IRelayCommand[] notify)
26 {
27 if (this.factory is null)
28 throw new InvalidOperationException("Factory not set.");
29
30 Func<TaskContext<TProgress>, Task> Wrapped = async ctx =>
31 {
32 System.Diagnostics.Stopwatch Sw = System.Diagnostics.Stopwatch.StartNew();
33 try
34 {
35 // Build policy pipeline outer -> inner
36 Func<CancellationToken, Task> Core =
37 ct => this.factory(new TaskContext<TProgress>(ctx.IsRefreshing, ct, ctx.Progress));
38
39 Func<CancellationToken, Task> Pipeline = Core;
40
41 foreach (IAsyncPolicy? Policy in Enumerable.Reverse(this.options.Policies))
42 {
43 Func<CancellationToken, Task> Next = Pipeline;
44 Pipeline = ct => Policy.ExecuteAsync(Next, ct);
45 }
46
47 await Pipeline(ctx.CancellationToken);
48 this.options.Telemetry?.OnEvent(new(this.options.Name, ObservableTaskStatus.Succeeded, Sw.Elapsed, null, ctx.IsRefreshing));
49 }
50 catch (OperationCanceledException oce) when (ctx.CancellationToken.IsCancellationRequested)
51 {
52 this.options.Telemetry?.OnEvent(new(this.options.Name, ObservableTaskStatus.Canceled, Sw.Elapsed, oce, ctx.IsRefreshing));
53 throw;
54 }
55 catch (Exception ex)
56 {
57 this.options.Telemetry?.OnEvent(new(this.options.Name, ObservableTaskStatus.Failed, Sw.Elapsed, ex, ctx.IsRefreshing));
58 throw;
59 }
60 };
61
62 // Create the task here so the builder doesn't own a disposable field (fixes CA1001).
64 {
65 UseTaskRun = this.options.UseTaskRun,
66 Dispatcher = this.options.Dispatcher ?? UiDispatcher.Instance
67 };
68
69 Task.Configure(Wrapped, notify);
70
71 // Attach disposable policies for cleanup when the task is disposed
72 foreach (IAsyncPolicy Policy in this.options.Policies)
73 {
74 if (Policy is IDisposable d)
75 Task.AttachDisposable(d);
76 }
77
78 if (this.options.AutoStart)
79 Task.Run();
80
81 return Task;
82 }
83 }
84
86 {
87 }
88}
Provides a data-binding friendly mechanism to manage and report the status of asynchronous operations...
void Configure(Func< TaskContext< TProgress >, Task > task, params IRelayCommand[] notifyCommands)
Store the factory and optional commands without starting the task. Use Run or RunRefresh to start lat...
ObservableTaskStatus
UI-friendly status for an observable async operation. (Renamed to avoid collision with System....
class TaskContext< TProgress >(bool IsRefreshing, CancellationToken CancellationToken, IProgress< TProgress > Progress)
Represents the context for an asynchronous task execution.
Definition: TaskContext.cs:9