diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md index 7c57baf63d..e0bb95449c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.docs/15- Logging, OpenTelemetry and Health Checks.md @@ -251,29 +251,12 @@ The project is **pre-configured** for easy integration with popular logging prov ### How It Works -The OpenTelemetry configuration automatically exports to Application Insights if a connection string is provided: +1- The OpenTelemetry configuration automatically exports to Application Insights if a connection string is provided: -From [`src/Server/Boilerplate.Server.Shared/Extensions/WebApplicationBuilderExtensions.cs`](/src/Server/Boilerplate.Server.Shared/Extensions/WebApplicationBuilderExtensions.cs): - -```csharp -private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) - where TBuilder : IHostApplicationBuilder -{ - var appInsightsConnectionString = string.IsNullOrWhiteSpace(builder.Configuration["ApplicationInsights:ConnectionString"]) is false - ? builder.Configuration["ApplicationInsights:ConnectionString"] - : null; +From [`src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs`](/src/Server/Boilerplate.Server.Shared/Extensions/IOpenTelemetryExtensions.cs): - if (appInsightsConnectionString is not null) - { - builder.Services.AddOpenTelemetry().UseAzureMonitor(options => - { - builder.Configuration.Bind("ApplicationInsights", options); - }).AddAzureMonitorProfiler(); - } - - return builder; -} -``` +2- The Azure Application Insights JavaScript SDK added by `BlazorApplicationInsights` nuget in Client.Core project would collect JavaScript errors and more from +Browser and Blazor Hybrid's WebView ### OpenTelemetry Configuration diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs index c742d48f90..8487cbc34b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppComponentBase.cs @@ -255,7 +255,7 @@ protected async Task Abort() using var currentCts = cts; cts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } public async ValueTask DisposeAsync() @@ -264,7 +264,7 @@ public async ValueTask DisposeAsync() { using var currentCts = cts; cts = null; - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } await DisposeAsync(true); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs index e64287f88e..311f1b8a4b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.cs @@ -143,7 +143,7 @@ private async Task SetCurrentUser(Task task) using var currentCts = getCurrentUserCts; getCurrentUserCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); if (authUser.IsAuthenticated() is false) { @@ -196,7 +196,7 @@ public async ValueTask DisposeAsync() { if (getCurrentUserCts is not null) { - await getCurrentUserCts.CancelAsync(); + await getCurrentUserCts.TryCancel(); getCurrentUserCts.Dispose(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs index 4472dab439..824dd81c10 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/RolesPage.razor.cs @@ -97,7 +97,7 @@ private async Task HandleOnSelectRole(BitNavItem? item) using var currentCts = loadRoleDataCts; loadRoleDataCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } loadRoleDataCts = new(); @@ -398,7 +398,7 @@ protected override async ValueTask DisposeAsync(bool disposing) { if (loadRoleDataCts is not null) { - await loadRoleDataCts.CancelAsync(); + await loadRoleDataCts.TryCancel(); loadRoleDataCts.Dispose(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs index fd73144fdf..aa74af576a 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Management/UsersPage.razor.cs @@ -110,7 +110,7 @@ private async Task HandleOnSelectUser(BitNavItem? item) using var currentCts = loadRoleDataCts; loadRoleDataCts = new(); - await currentCts.CancelAsync(); + await currentCts.TryCancel(); } loadRoleDataCts = new(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj index acaa1a8750..7c1aa01248 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj @@ -1,4 +1,4 @@ - + net10.0-android;net10.0-ios;net10.0-maccatalyst @@ -167,12 +167,12 @@ - - + + - + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs index bcb80b1cb0..aad1cd0cbc 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.Services.cs @@ -1,5 +1,9 @@ -using Microsoft.Extensions.Logging; +//+:cnd:noEmit +using Microsoft.Extensions.Logging; using Boilerplate.Client.Maui.Services; +//#if (appInsights == true) +using Azure.Monitor.OpenTelemetry.Exporter; +//#endif using Boilerplate.Client.Core.Services.HttpMessageHandlers; namespace Boilerplate.Client.Maui; @@ -52,23 +56,26 @@ public static void ConfigureServices(this MauiAppBuilder builder) builder.Logging.AddEventSourceLogger(); - if (AppPlatform.IsWindows) - { - builder.Logging.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); - } - - //+:cnd:noEmit //#if (appInsights == true) - if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) + builder.Logging.AddOpenTelemetry(options => { - builder.Logging.AddApplicationInsights(config => + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + + if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) { - config.TelemetryInitializers.Add(new MauiAppInsightsTelemetryInitializer()); - configuration.GetRequiredSection("ApplicationInsights").Bind(config); - }, options => configuration.GetRequiredSection("Logging:ApplicationInsights").Bind(options)); - } + options.AddAzureMonitorLogExporter(o => + { + o.ConnectionString = settings.ApplicationInsights.ConnectionString; + }); + } + }); //#endif - //-:cnd:noEmit + + if (AppPlatform.IsWindows) + { + builder.Logging.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); + } services.AddOptions() .Bind(configuration) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs deleted file mode 100644 index c730f6089c..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiAppInsightsTelemetryInitializer.cs +++ /dev/null @@ -1,35 +0,0 @@ -//+:cnd:noEmit -using Microsoft.ApplicationInsights.Channel; -using Microsoft.ApplicationInsights.Extensibility; - -namespace Boilerplate.Client.Maui.Services; - -public partial class MauiAppInsightsTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - if (ITelemetryContext.Current is not null) - { - telemetry.Context.Session.Id = ITelemetryContext.Current.AppSessionId.ToString(); - telemetry.Context.Component.Version = ITelemetryContext.Current.AppVersion; - telemetry.Context.Device.OperatingSystem = ITelemetryContext.Current.Platform; - telemetry.Context.User.AuthenticatedUserId = ITelemetryContext.Current.UserId?.ToString(); - - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.TimeZone)] = ITelemetryContext.Current.TimeZone; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.Culture)] = ITelemetryContext.Current.Culture; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.IsOnline)] = ITelemetryContext.Current.IsOnline?.ToString().ToLowerInvariant(); - } - - telemetry.Context.Session.IsFirst = VersionTracking.IsFirstLaunchEver; - telemetry.Context.Device.OemName = DeviceInfo.Current.Manufacturer; - telemetry.Context.Device.Model = DeviceInfo.Current.Model; - telemetry.Context.Device.Type = DeviceInfo.Idiom.ToString(); - - if (AppPlatform.IsIosOnMacOS) - { - telemetry.Context.GlobalProperties["IsiOSApplicationOnMac"] = "true"; - } - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj index f4babaa16a..9f7f20303b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj @@ -37,14 +37,16 @@ + + - + PreserveNewest diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs index 0f5a4d90f8..0c6d0ca8f5 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cs @@ -1,6 +1,10 @@ //+:cnd:noEmit +using OpenTelemetry.Logs; using Microsoft.Extensions.Logging; using Boilerplate.Client.Windows.Services; +//#if (appInsights == true) +using Azure.Monitor.OpenTelemetry.Exporter; +//#endif using Boilerplate.Client.Core.Services.HttpMessageHandlers; namespace Boilerplate.Client.Windows; @@ -54,17 +58,29 @@ public static void AddClientWindowsProjectServices(this IServiceCollection servi loggingBuilder.ConfigureLoggers(configuration); loggingBuilder.AddEventSourceLogger(); - loggingBuilder.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); - //#if (appInsights == true) - if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) + loggingBuilder.AddOpenTelemetry(options => { - loggingBuilder.AddApplicationInsights(config => + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + + //#if (appInsights == true) + if (string.IsNullOrEmpty(settings.ApplicationInsights?.ConnectionString) is false) { - config.TelemetryInitializers.Add(new WindowsAppInsightsTelemetryInitializer()); - configuration.GetRequiredSection("ApplicationInsights").Bind(config); - }, options => configuration.GetRequiredSection("Logging:ApplicationInsights").Bind(options)); - } - //#endif + options.AddAzureMonitorLogExporter(o => + { + o.ConnectionString = settings.ApplicationInsights.ConnectionString; + }); + } + //#endif + + var useOtlpExporter = string.IsNullOrWhiteSpace(configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]) is false; + if (useOtlpExporter) + { + options.AddOtlpExporter(); + } + }); + + loggingBuilder.AddEventLog(options => configuration.GetRequiredSection("Logging:EventLog").Bind(options)); }); services.AddOptions() diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs index f0d64de004..4ee5a0bfe7 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.cs @@ -25,7 +25,11 @@ public static void Main(string[] args) Application.SetColorMode(SystemColorMode.System); - var configuration = new ConfigurationBuilder().AddClientConfigurations(clientEntryAssemblyName: "Boilerplate.Client.Windows").Build(); + var configuration = new ConfigurationBuilder() + .AddClientConfigurations(clientEntryAssemblyName: "Boilerplate.Client.Windows") + .AddEnvironmentVariables() + .Build(); + var services = new ServiceCollection(); services.AddClientWindowsProjectServices(configuration); Services = services.BuildServiceProvider(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs deleted file mode 100644 index 1bba6b420c..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsAppInsightsTelemetryInitializer.cs +++ /dev/null @@ -1,25 +0,0 @@ -//+:cnd:noEmit -using Microsoft.ApplicationInsights.Channel; -using Microsoft.ApplicationInsights.Extensibility; - -namespace Boilerplate.Client.Windows.Services; - -public partial class WindowsAppInsightsTelemetryInitializer : ITelemetryInitializer -{ - public void Initialize(ITelemetry telemetry) - { - if (ITelemetryContext.Current is not null) - { - telemetry.Context.Session.Id = ITelemetryContext.Current.AppSessionId.ToString(); - telemetry.Context.Component.Version = ITelemetryContext.Current.AppVersion; - telemetry.Context.Device.OperatingSystem = ITelemetryContext.Current.Platform; - telemetry.Context.User.AuthenticatedUserId = ITelemetryContext.Current.UserId?.ToString(); - - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.TimeZone)] = ITelemetryContext.Current.TimeZone; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.Culture)] = ITelemetryContext.Current.Culture; - telemetry.Context.GlobalProperties[nameof(ITelemetryContext.IsOnline)] = ITelemetryContext.Current.IsOnline?.ToString().ToLowerInvariant(); - } - } -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props index 6173130d89..333922a27c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props @@ -26,6 +26,7 @@ + @@ -54,6 +55,7 @@ + @@ -74,9 +76,9 @@ - - - + + + @@ -91,7 +93,7 @@ - + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs index ff7881ae61..ac70a50c86 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppChatbot.cs @@ -27,7 +27,7 @@ public partial class AppChatbot [AutoInject] private ILogger logger = default!; [AutoInject] private IServiceProvider serviceProvider = default!; - private string? variables; + private string? variablesPrompt; private string? supportSystemPrompt; private List chatMessages = []; @@ -66,7 +66,7 @@ public async Task StartChat( }, token: cancellationToken); - variables = @$" + variablesPrompt = @$" ### Variables: {{{{UserCulture}}}}: ""{culture?.NativeName ?? "English"}"" {{{{DeviceInfo}}}}: ""{request.DeviceInfo ?? "Generic Device"}"" @@ -107,7 +107,7 @@ public async Task ProcessNewMessage( var chatOptions = CreateChatOptions(serverApiAddress, cancellationToken); await foreach (var response in chatClient.GetStreamingResponseAsync([ - new (ChatRole.System, variables), + new (ChatRole.System, variablesPrompt), new (ChatRole.System, supportSystemPrompt), .. chatMessages, new (ChatRole.User, incomingMessage) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs index 50d9e78344..1728bf75d4 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs @@ -43,7 +43,7 @@ async Task ReadIncomingMessages() await foreach (var incomingMessage in incomingMessages) { if (messageSpecificCancellationTokenSrc is not null) - await messageSpecificCancellationTokenSrc.CancelAsync(); + await messageSpecificCancellationTokenSrc.TryCancel(); messageSpecificCancellationTokenSrc = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); _ = chatbotService.ProcessNewMessage( diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj index 2e71657350..78d83f8b11 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Boilerplate.Server.AppHost.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs index 0b6e78e48d..ebb9ee9541 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.AppHost/Program.cs @@ -111,10 +111,6 @@ serverWebProject.WithReference(mailpit); //#endif - // Blazor Hybrid Windows project. - builder.AddProject("clientwindows", "../../Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj") - .WithExplicitStart(); - //#if (api == "Standalone") builder.AddDevTunnel("api-dev-tunnel") .WithAnonymousAccess() @@ -124,6 +120,55 @@ var tunnel = builder.AddDevTunnel("web-dev-tunnel") .WithAnonymousAccess() .WithReference(serverWebProject.WithHttpEndpoint(name: "devTunnel").GetEndpoint("devTunnel")); + + if (OperatingSystem.IsWindows()) + { + // Blazor Hybrid Windows project. + builder.AddProject("clientwindows", "../../Client/Boilerplate.Client.Windows/Boilerplate.Client.Windows.csproj") + .WithExplicitStart(); + } + + // Blazor Hybrid MAUI project. + var mauiapp = builder.AddMauiProject("mauiapp", @"../../Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj"); + + if (OperatingSystem.IsWindows()) + { + mauiapp.AddWindowsDevice() + .WithExplicitStart() + .WithReference(serverWebProject); + } + + if (OperatingSystem.IsMacOS()) + { + mauiapp.AddMacCatalystDevice() + .WithExplicitStart() + .WithReference(serverWebProject); + } + + if (OperatingSystem.IsMacOS()) + { + // Windows supports iOS Simulator and Physical devices if there's a mac connected to network, but the following runners only work on macOS for now. + + mauiapp.AddiOSDevice() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + + mauiapp.AddiOSSimulator() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + } + + mauiapp.AddAndroidDevice() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); + + mauiapp.AddAndroidEmulator() + .WithExplicitStart() + .WithOtlpDevTunnel() // Required for OpenTelemetry data collection + .WithReference(serverWebProject, tunnel); } await builder diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs new file mode 100644 index 0000000000..263a12d9ff --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/CancellationTokenSourceExtensions.cs @@ -0,0 +1,20 @@ +namespace System.Threading; + +public static class CancellationTokenSourceExtensions +{ + /// + /// Tries to cancel the without throwing an exception if it has already been disposed. + /// + public static async Task TryCancel(this CancellationTokenSource source) + { + try + { + await source.CancelAsync(); + return true; + } + catch (ObjectDisposedException) + { + return false; + } + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json index b9d220a6b3..c4e9bb7cfd 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/appsettings.json @@ -36,6 +36,7 @@ "Comment2": "Integrates Sentry across both backend and frontend projects", "Dsn": "", "SendDefaultPii": true, + "TracesSampleRate": 1.0, "EnableScopeSync": true, "LogLevel": { "Default": "Warning",