Skip to content

Commit b43a40d

Browse files
committed
Dogfood MAUI sample flow
1 parent 5346aed commit b43a40d

6 files changed

Lines changed: 147 additions & 33 deletions

File tree

samples/Exceptionless.SampleMaui/App.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ namespace Exceptionless.SampleMaui;
22

33
public sealed class App : Application {
44
private readonly ExceptionlessClient _exceptionlessClient;
5+
private readonly SampleDogfoodRunner _dogfoodRunner;
56
private readonly MainPage _mainPage;
67

7-
public App(MainPage mainPage, ExceptionlessClient exceptionlessClient) {
8+
public App(MainPage mainPage, ExceptionlessClient exceptionlessClient, SampleDogfoodRunner dogfoodRunner) {
89
_exceptionlessClient = exceptionlessClient;
10+
_dogfoodRunner = dogfoodRunner;
911
_mainPage = mainPage;
1012
}
1113

1214
protected override Window CreateWindow(IActivationState? activationState) {
13-
return new Window(_mainPage);
15+
var window = new Window(_mainPage);
16+
_ = _dogfoodRunner.RunIfRequestedAsync();
17+
18+
return window;
1419
}
1520

1621
protected override void OnSleep() {

samples/Exceptionless.SampleMaui/MainPage.cs

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
using Exceptionless.Logging;
21
using Microsoft.Maui.Controls.Shapes;
32

43
namespace Exceptionless.SampleMaui;
54

65
public sealed class MainPage : ContentPage {
76
private readonly ExceptionlessClient _exceptionlessClient;
7+
private readonly SampleEventService _sampleEvents;
88
private readonly Label _statusLabel;
99
private readonly Label _lastReferenceIdLabel;
10+
private readonly Label _configLabel;
1011
private readonly ActivityIndicator _activityIndicator;
1112

12-
public MainPage(ExceptionlessClient exceptionlessClient) {
13+
public MainPage(ExceptionlessClient exceptionlessClient, SampleEventService sampleEvents) {
1314
_exceptionlessClient = exceptionlessClient;
15+
_sampleEvents = sampleEvents;
1416

1517
Title = "Exceptionless";
1618
BackgroundColor = Color.FromArgb("#F6F8FA");
@@ -29,6 +31,13 @@ public MainPage(ExceptionlessClient exceptionlessClient) {
2931
LineBreakMode = LineBreakMode.TailTruncation
3032
};
3133

34+
_configLabel = new Label {
35+
Text = $"Config {SampleEventService.SampleConfigSettingKey}: not loaded",
36+
FontSize = 13,
37+
TextColor = Color.FromArgb("#576575"),
38+
LineBreakMode = LineBreakMode.TailTruncation
39+
};
40+
3241
_activityIndicator = new ActivityIndicator {
3342
IsVisible = false,
3443
Color = Color.FromArgb("#276749")
@@ -38,6 +47,7 @@ public MainPage(ExceptionlessClient exceptionlessClient) {
3847
}
3948

4049
private View BuildContent() {
50+
var refreshConfigButton = CreateActionButton("Refresh Config", OnRefreshConfigClicked);
4151
var sendExceptionButton = CreateActionButton("Send Handled Exception", OnSendExceptionClicked);
4252
var sendLogButton = CreateActionButton("Send Warning Log", OnSendLogClicked);
4353
var trackFeatureButton = CreateActionButton("Track Feature", OnTrackFeatureClicked);
@@ -88,22 +98,15 @@ private View BuildContent() {
8898
},
8999
_statusLabel,
90100
_lastReferenceIdLabel,
101+
_configLabel,
91102
_activityIndicator
92103
}
93104
}
94105
},
95-
new Grid {
96-
ColumnDefinitions = {
97-
new ColumnDefinition { Width = GridLength.Star },
98-
new ColumnDefinition { Width = GridLength.Star }
99-
},
100-
RowDefinitions = {
101-
new RowDefinition { Height = GridLength.Auto },
102-
new RowDefinition { Height = GridLength.Auto }
103-
},
104-
ColumnSpacing = 12,
105-
RowSpacing = 12,
106+
new VerticalStackLayout {
107+
Spacing = 12,
106108
Children = {
109+
refreshConfigButton,
107110
sendExceptionButton,
108111
sendLogButton,
109112
trackFeatureButton,
@@ -129,43 +132,37 @@ private static Button CreateActionButton(string text, EventHandler clicked) {
129132
return button;
130133
}
131134

135+
private async void OnRefreshConfigClicked(object? sender, EventArgs e) {
136+
await RunClientActionAsync("Configuration refreshed.", async () => {
137+
await _sampleEvents.RefreshProjectConfigurationAsync();
138+
SetConfigValue(_sampleEvents.GetSampleConfigValue());
139+
});
140+
}
141+
132142
private async void OnSendExceptionClicked(object? sender, EventArgs e) {
133143
await RunClientActionAsync("Handled exception queued.", () => {
134-
string referenceId = Guid.NewGuid().ToString("N");
135-
136-
try {
137-
throw new InvalidOperationException("Exceptionless MAUI sample handled exception.");
138-
} catch (Exception ex) {
139-
ex.ToExceptionless(_exceptionlessClient)
140-
.SetReferenceId(referenceId)
141-
.AddTags("handled")
142-
.SetProperty("Screen", nameof(MainPage))
143-
.Submit();
144-
}
145-
144+
string referenceId = _sampleEvents.SubmitHandledException();
146145
SetLastReferenceId(referenceId);
147146
return Task.CompletedTask;
148147
});
149148
}
150149

151150
private async void OnSendLogClicked(object? sender, EventArgs e) {
152151
await RunClientActionAsync("Warning log queued.", () => {
153-
_exceptionlessClient.SubmitLog("Exceptionless.SampleMaui.MainPage", "MAUI sample warning log.", LogLevel.Warn);
154-
SetLastReferenceId(_exceptionlessClient.GetLastReferenceId());
152+
SetLastReferenceId(_sampleEvents.SubmitWarningLog());
155153
return Task.CompletedTask;
156154
});
157155
}
158156

159157
private async void OnTrackFeatureClicked(object? sender, EventArgs e) {
160158
await RunClientActionAsync("Feature usage queued.", () => {
161-
_exceptionlessClient.SubmitFeatureUsage("MauiSample.TrackFeature");
162-
SetLastReferenceId(_exceptionlessClient.GetLastReferenceId());
159+
SetLastReferenceId(_sampleEvents.TrackFeatureUsage());
163160
return Task.CompletedTask;
164161
});
165162
}
166163

167164
private async void OnFlushClicked(object? sender, EventArgs e) {
168-
await RunClientActionAsync("Queue processed.", () => _exceptionlessClient.ProcessQueueAsync());
165+
await RunClientActionAsync("Queue processed.", () => _sampleEvents.FlushQueueAsync());
169166
}
170167

171168
private async Task RunClientActionAsync(string successMessage, Func<Task> action) {
@@ -177,7 +174,9 @@ private async Task RunClientActionAsync(string successMessage, Func<Task> action
177174
await action();
178175

179176
_statusLabel.Text = successMessage;
180-
} catch (Exception ex) {
177+
} catch (InvalidOperationException ex) {
178+
_statusLabel.Text = $"Error: {ex.Message}";
179+
} catch (TaskCanceledException ex) {
181180
_statusLabel.Text = $"Error: {ex.Message}";
182181
} finally {
183182
_activityIndicator.IsRunning = false;
@@ -190,4 +189,8 @@ private void SetLastReferenceId(string? referenceId) {
190189
? "Last reference id: none"
191190
: $"Last reference id: {referenceId}";
192191
}
192+
193+
private void SetConfigValue(string value) {
194+
_configLabel.Text = $"Config {SampleEventService.SampleConfigSettingKey}: {value}";
195+
}
193196
}

samples/Exceptionless.SampleMaui/MauiProgram.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public static MauiApp CreateMauiApp() {
1616
.UseMauiApp<App>();
1717

1818
builder.Services.AddSingleton(exceptionlessClient);
19+
builder.Services.AddSingleton<SampleEventService>();
20+
builder.Services.AddSingleton<SampleDogfoodRunner>();
1921
builder.Services.AddSingleton<MainPage>();
2022

2123
return builder.Build();

samples/Exceptionless.SampleMaui/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ export EXCEPTIONLESS_SERVER_URL="https://collector.exceptionless.io"
1818

1919
Events are queued under `FileSystem.Current.AppDataDirectory`, `IncludePrivateInformation` is disabled, and the sample has an explicit **Flush Queue** action. The app also asks the client to process the queue when the MAUI application goes to sleep.
2020

21+
Use **Refresh Config** to force a project configuration fetch. The page shows the `SampleMaui.ConfigValue` server setting after it is loaded.
22+
23+
For command-line dogfooding, set `EXCEPTIONLESS_SAMPLE_AUTORUN=true` and optionally `EXCEPTIONLESS_SAMPLE_AUTORUN_RESULT_PATH` before launching the app. Autorun refreshes project configuration, submits a handled exception, submits a warning log, tracks feature usage, flushes the queue, and writes a small result file when a result path is supplied.
24+
2125
## Run
2226

2327
Install the MAUI workload for the .NET SDK used by this repository, then run a target supported by your machine:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
namespace Exceptionless.SampleMaui;
2+
3+
public sealed class SampleDogfoodRunner {
4+
private readonly SampleEventService _sampleEvents;
5+
6+
public SampleDogfoodRunner(SampleEventService sampleEvents) {
7+
_sampleEvents = sampleEvents;
8+
}
9+
10+
public async Task RunIfRequestedAsync() {
11+
if (!String.Equals(Environment.GetEnvironmentVariable("EXCEPTIONLESS_SAMPLE_AUTORUN"), "true", StringComparison.OrdinalIgnoreCase))
12+
return;
13+
14+
string? resultPath = Environment.GetEnvironmentVariable("EXCEPTIONLESS_SAMPLE_AUTORUN_RESULT_PATH");
15+
16+
try {
17+
await _sampleEvents.RefreshProjectConfigurationAsync();
18+
string configValue = _sampleEvents.GetSampleConfigValue();
19+
string exceptionReferenceId = _sampleEvents.SubmitHandledException();
20+
string? logReferenceId = _sampleEvents.SubmitWarningLog();
21+
string? featureReferenceId = _sampleEvents.TrackFeatureUsage();
22+
await _sampleEvents.FlushQueueAsync();
23+
24+
WriteResult(resultPath,
25+
"status=completed",
26+
$"config.{SampleEventService.SampleConfigSettingKey}={configValue}",
27+
$"handledExceptionReferenceId={exceptionReferenceId}",
28+
$"logReferenceId={logReferenceId}",
29+
$"featureReferenceId={featureReferenceId}");
30+
} catch (InvalidOperationException ex) {
31+
WriteResult(resultPath, "status=failed", $"error={ex.Message}");
32+
} catch (TaskCanceledException ex) {
33+
WriteResult(resultPath, "status=failed", $"error={ex.Message}");
34+
}
35+
}
36+
37+
private static void WriteResult(string? path, params string[] lines) {
38+
if (String.IsNullOrWhiteSpace(path))
39+
return;
40+
41+
// Autorun should still exercise the client if a platform sandbox rejects the result path.
42+
try {
43+
File.WriteAllLines(path, lines);
44+
} catch (IOException) {
45+
} catch (UnauthorizedAccessException) {
46+
}
47+
}
48+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Exceptionless.Configuration;
2+
using Exceptionless.Logging;
3+
4+
namespace Exceptionless.SampleMaui;
5+
6+
public sealed class SampleEventService {
7+
public const string SampleConfigSettingKey = "SampleMaui.ConfigValue";
8+
9+
private readonly ExceptionlessClient _exceptionlessClient;
10+
11+
public SampleEventService(ExceptionlessClient exceptionlessClient) {
12+
_exceptionlessClient = exceptionlessClient;
13+
}
14+
15+
public string SubmitHandledException() {
16+
string referenceId = Guid.NewGuid().ToString("N");
17+
18+
try {
19+
throw new InvalidOperationException("Exceptionless MAUI sample handled exception.");
20+
} catch (InvalidOperationException ex) {
21+
ex.ToExceptionless(_exceptionlessClient)
22+
.SetReferenceId(referenceId)
23+
.AddTags("handled")
24+
.SetProperty("Screen", nameof(MainPage))
25+
.Submit();
26+
}
27+
28+
return referenceId;
29+
}
30+
31+
public string? SubmitWarningLog() {
32+
_exceptionlessClient.SubmitLog("Exceptionless.SampleMaui.MainPage", "MAUI sample warning log.", LogLevel.Warn);
33+
return _exceptionlessClient.GetLastReferenceId();
34+
}
35+
36+
public string? TrackFeatureUsage() {
37+
_exceptionlessClient.SubmitFeatureUsage("MauiSample.TrackFeature");
38+
return _exceptionlessClient.GetLastReferenceId();
39+
}
40+
41+
public async Task RefreshProjectConfigurationAsync() {
42+
await SettingsManager.UpdateSettingsAsync(_exceptionlessClient.Configuration, 0);
43+
}
44+
45+
public Task FlushQueueAsync() {
46+
return _exceptionlessClient.ProcessQueueAsync();
47+
}
48+
49+
public string GetSampleConfigValue() {
50+
return _exceptionlessClient.Configuration.Settings.GetString(SampleConfigSettingKey, "not loaded");
51+
}
52+
}

0 commit comments

Comments
 (0)