Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Exceptionless.Net.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Project Path="samples/Exceptionless.SampleHosting/Exceptionless.SampleHosting.csproj" />
<Project Path="samples/Exceptionless.SampleLambda/Exceptionless.SampleLambda.csproj" />
<Project Path="samples/Exceptionless.SampleLambdaAspNetCore/Exceptionless.SampleLambdaAspNetCore.csproj" />
<Project Path="samples/Exceptionless.SampleMaui/Exceptionless.SampleMaui.csproj" />
<Project Path="samples/Exceptionless.SampleMvc/Exceptionless.SampleMvc.csproj">
<BuildDependency Project="src/Exceptionless/Exceptionless.csproj" />
<BuildDependency Project="src/Platforms/Exceptionless.Mvc/Exceptionless.Mvc.csproj" />
Expand Down
25 changes: 25 additions & 0 deletions samples/Exceptionless.SampleMaui/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Exceptionless.SampleMaui;

public sealed class App : Application {
private readonly ExceptionlessClient _exceptionlessClient;
private readonly SampleDogfoodRunner _dogfoodRunner;
private readonly MainPage _mainPage;

public App(MainPage mainPage, ExceptionlessClient exceptionlessClient, SampleDogfoodRunner dogfoodRunner) {
_exceptionlessClient = exceptionlessClient;
_dogfoodRunner = dogfoodRunner;
_mainPage = mainPage;
}

protected override Window CreateWindow(IActivationState? activationState) {
var window = new Window(_mainPage);
_ = _dogfoodRunner.RunIfRequestedAsync();

return window;
}

protected override void OnSleep() {
_ = _exceptionlessClient.ProcessQueueAsync();
base.OnSleep();
}
}
40 changes: 40 additions & 0 deletions samples/Exceptionless.SampleMaui/Exceptionless.SampleMaui.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net10.0-android</TargetFrameworks>
<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('linux'))">$(TargetFrameworks);net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net10.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>Exceptionless.SampleMaui</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<ApplicationTitle>Exceptionless MAUI Sample</ApplicationTitle>
<ApplicationId>com.exceptionless.samplemaui</ApplicationId>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<WindowsPackageType>None</WindowsPackageType>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
</PropertyGroup>

<ItemGroup>
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#3A6EA5" />
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#3A6EA5" BaseSize="128,128" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Exceptionless\Exceptionless.csproj" SetTargetFramework="TargetFramework=netstandard2.0" />
</ItemGroup>

</Project>
196 changes: 196 additions & 0 deletions samples/Exceptionless.SampleMaui/MainPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using Microsoft.Maui.Controls.Shapes;

namespace Exceptionless.SampleMaui;

public sealed class MainPage : ContentPage {
private readonly ExceptionlessClient _exceptionlessClient;
private readonly SampleEventService _sampleEvents;
private readonly Label _statusLabel;
private readonly Label _lastReferenceIdLabel;
private readonly Label _configLabel;
private readonly ActivityIndicator _activityIndicator;

public MainPage(ExceptionlessClient exceptionlessClient, SampleEventService sampleEvents) {
_exceptionlessClient = exceptionlessClient;
_sampleEvents = sampleEvents;

Title = "Exceptionless";
BackgroundColor = Color.FromArgb("#F6F8FA");

_statusLabel = new Label {
Text = "Ready",
FontSize = 14,
TextColor = Color.FromArgb("#314256"),
LineBreakMode = LineBreakMode.WordWrap
};

_lastReferenceIdLabel = new Label {
Text = "Last reference id: none",
FontSize = 13,
TextColor = Color.FromArgb("#576575"),
LineBreakMode = LineBreakMode.TailTruncation
};

_configLabel = new Label {
Text = $"Config {SampleEventService.SampleConfigSettingKey}: not loaded",
FontSize = 13,
TextColor = Color.FromArgb("#576575"),
LineBreakMode = LineBreakMode.TailTruncation
};

_activityIndicator = new ActivityIndicator {
IsVisible = false,
Color = Color.FromArgb("#276749")
};

Content = BuildContent();
}

private View BuildContent() {
var refreshConfigButton = CreateActionButton("Refresh Config", OnRefreshConfigClicked);
var sendExceptionButton = CreateActionButton("Send Handled Exception", OnSendExceptionClicked);
var sendLogButton = CreateActionButton("Send Warning Log", OnSendLogClicked);
var trackFeatureButton = CreateActionButton("Track Feature", OnTrackFeatureClicked);
var flushButton = CreateActionButton("Flush Queue", OnFlushClicked);

return new ScrollView {
Content = new VerticalStackLayout {
Padding = new Thickness(24, 28),
Spacing = 18,
Children = {
new Label {
Text = "Exceptionless MAUI Sample",
FontSize = 26,
FontAttributes = FontAttributes.Bold,
TextColor = Color.FromArgb("#1D2733")
},
Comment thread
niemyjski marked this conversation as resolved.
new Label {
Text = "Submit sample events through the core Exceptionless client.",
FontSize = 15,
TextColor = Color.FromArgb("#576575"),
LineBreakMode = LineBreakMode.WordWrap
},
Comment thread
niemyjski marked this conversation as resolved.
new Border {
Stroke = Color.FromArgb("#D8DEE6"),
StrokeThickness = 1,
BackgroundColor = Colors.White,
StrokeShape = new RoundRectangle { CornerRadius = 8 },
Padding = new Thickness(18),
Content = new VerticalStackLayout {
Spacing = 12,
Children = {
new Label {
Text = "Client",
FontSize = 18,
FontAttributes = FontAttributes.Bold,
TextColor = Color.FromArgb("#1D2733")
},
Comment thread
niemyjski marked this conversation as resolved.
new Label {
Text = $"Server: {_exceptionlessClient.Configuration.ServerUrl}",
FontSize = 13,
TextColor = Color.FromArgb("#576575"),
LineBreakMode = LineBreakMode.TailTruncation
},
Comment thread
niemyjski marked this conversation as resolved.
new Label {
Text = $"Private information: {_exceptionlessClient.Configuration.IncludePrivateInformation}",
FontSize = 13,
TextColor = Color.FromArgb("#576575")
},
Comment thread
niemyjski marked this conversation as resolved.
_statusLabel,
_lastReferenceIdLabel,
_configLabel,
_activityIndicator
}
}
},
new VerticalStackLayout {
Spacing = 12,
Children = {
refreshConfigButton,
sendExceptionButton,
sendLogButton,
trackFeatureButton,
flushButton
Comment thread
niemyjski marked this conversation as resolved.
}
}
}
}
};
}

private static Button CreateActionButton(string text, EventHandler clicked) {
var button = new Button {
Text = text,
BackgroundColor = Color.FromArgb("#285A84"),
TextColor = Colors.White,
CornerRadius = 8,
FontAttributes = FontAttributes.Bold,
MinimumHeightRequest = 48
};

button.Clicked += clicked;
return button;
}

private async void OnRefreshConfigClicked(object? sender, EventArgs e) {
await RunClientActionAsync("Configuration refreshed.", async () => {
await _sampleEvents.RefreshProjectConfigurationAsync();
SetConfigValue(_sampleEvents.GetSampleConfigValue());
});
}

private async void OnSendExceptionClicked(object? sender, EventArgs e) {
await RunClientActionAsync("Handled exception queued.", () => {
string referenceId = _sampleEvents.SubmitHandledException();
SetLastReferenceId(referenceId);
return Task.CompletedTask;
});
}

private async void OnSendLogClicked(object? sender, EventArgs e) {
await RunClientActionAsync("Warning log queued.", () => {
SetLastReferenceId(_sampleEvents.SubmitWarningLog());
return Task.CompletedTask;
});
}

private async void OnTrackFeatureClicked(object? sender, EventArgs e) {
await RunClientActionAsync("Feature usage queued.", () => {
SetLastReferenceId(_sampleEvents.TrackFeatureUsage());
return Task.CompletedTask;
});
}

private async void OnFlushClicked(object? sender, EventArgs e) {
await RunClientActionAsync("Queue processed.", () => _sampleEvents.FlushQueueAsync());
}

private async Task RunClientActionAsync(string successMessage, Func<Task> action) {
try {
_activityIndicator.IsVisible = true;
_activityIndicator.IsRunning = true;
_statusLabel.Text = "Working...";

await action();

_statusLabel.Text = successMessage;
} catch (InvalidOperationException ex) {
_statusLabel.Text = $"Error: {ex.Message}";
} catch (TaskCanceledException ex) {
_statusLabel.Text = $"Error: {ex.Message}";
} finally {
_activityIndicator.IsRunning = false;
_activityIndicator.IsVisible = false;
}
}

private void SetLastReferenceId(string? referenceId) {
_lastReferenceIdLabel.Text = String.IsNullOrEmpty(referenceId)
? "Last reference id: none"
: $"Last reference id: {referenceId}";
}

private void SetConfigValue(string value) {
_configLabel.Text = $"Config {SampleEventService.SampleConfigSettingKey}: {value}";
}
}
45 changes: 45 additions & 0 deletions samples/Exceptionless.SampleMaui/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Exceptionless.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Storage;

namespace Exceptionless.SampleMaui;

public static class MauiProgram {
private const string DefaultApiKey = "LhhP1C9gijpSKCslHHCvwdSIz298twx271nTest";
private const string DefaultServerUrl = "https://ex.dev.localhost:7111";

public static MauiApp CreateMauiApp() {
var builder = MauiApp.CreateBuilder();
var exceptionlessClient = CreateExceptionlessClient();

builder
.UseMauiApp<App>();

builder.Services.AddSingleton(exceptionlessClient);
builder.Services.AddSingleton<SampleEventService>();
builder.Services.AddSingleton<SampleDogfoodRunner>();
builder.Services.AddSingleton<MainPage>();

return builder.Build();
}

private static ExceptionlessClient CreateExceptionlessClient() {
string appDataDirectory = FileSystem.Current.AppDataDirectory;

var client = new ExceptionlessClient(config => {
config.ApiKey = Environment.GetEnvironmentVariable("EXCEPTIONLESS_API_KEY") ?? DefaultApiKey;
config.ServerUrl = Environment.GetEnvironmentVariable("EXCEPTIONLESS_SERVER_URL") ?? DefaultServerUrl;
config.IncludePrivateInformation = false;
config.DefaultTags.Add("maui");
config.DefaultTags.Add("sample");
config.DefaultData["Platform"] = DeviceInfo.Current.Platform.ToString();
config.DefaultData["DeviceIdiom"] = DeviceInfo.Current.Idiom.ToString();
config.SetVersion(AppInfo.Current.VersionString);
config.UseFolderStorage(Path.Combine(appDataDirectory, "exceptionless-queue"));
Comment thread
github-code-quality[bot] marked this conversation as resolved.
Fixed
config.UseFileLogger(Path.Combine(appDataDirectory, "exceptionless-client.log"), LogLevel.Info);
Comment thread
github-code-quality[bot] marked this conversation as resolved.
Fixed
});

client.Startup();
return client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Android.App;
using Android.Content.PM;

namespace Exceptionless.SampleMaui;

[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Android.App;
using Android.Runtime;

namespace Exceptionless.SampleMaui;

[Application]
public class MainApplication : MauiApplication {
public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) {
}

protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Foundation;

namespace Exceptionless.SampleMaui;

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate {
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
31 changes: 31 additions & 0 deletions samples/Exceptionless.SampleMaui/Platforms/MacCatalyst/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDeviceFamily</key>
<array>
<integer>2</integer>
</array>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
Loading
Loading