From ede39a253b5cc2ba856ba3788a1eb7080e64d50c Mon Sep 17 00:00:00 2001 From: Yaser Moradi Date: Tue, 29 Oct 2024 19:53:58 +0100 Subject: [PATCH] feat(templates): add telemetry context to boilerplate #9054 (#9055) --- .../Components/AppComponentBase.cs | 2 +- .../Components/AppInitializer.cs | 17 +++++--- .../Components/Layout/IdentityHeader.razor.cs | 4 +- .../Components/Layout/RootLayout.razor.cs | 4 +- .../Components/Layout/UserMenu.razor.cs | 4 +- .../Pages/Identity/SignIn/SignInPage.razor.cs | 3 +- .../IClientCoreServiceCollectionExtensions.cs | 12 +++--- .../Services/AppPlatform.cs | 3 -- .../Services/AppTelemetryContext.cs | 18 +++++++++ .../Services/Contracts/ICultureService.cs | 6 --- .../Services/Contracts/IPubSubService.cs | 10 ----- .../Services/Contracts/ITelemetryContext.cs | 39 +++++++++++++++++++ .../Services/Contracts/IThemeService.cs | 8 ---- .../Services/CultureService.cs | 4 +- .../Services/ExceptionHandlerBase.cs | 14 ++++++- .../Services/MessageBoxService.cs | 2 +- .../Services/PubSubService.cs | 4 +- .../Services/SnackBarService.cs | 2 +- .../Services/ThemeService.cs | 4 +- .../Components/Pages/AboutPage.razor.cs | 15 +++---- .../MauiProgram.Services.cs | 1 + .../Boilerplate.Client.Maui/MauiProgram.cs | 4 +- .../Services/MauiTelemetryContext.cs | 18 +++++++++ .../Services/MauiTelemetryInitializer.cs | 18 +++++---- .../Components/Pages/AboutPage.razor.cs | 6 ++- .../MainWindow.xaml.cs | 2 +- .../Program.Services.cs | 1 + .../Services/WindowsTelemetryContext.cs | 6 +++ .../Services/WindowsTelemetryInitializer.cs | 15 ++++--- .../Extensions/ClaimsPrincipalExtensions.cs | 3 ++ 30 files changed, 165 insertions(+), 84 deletions(-) create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppTelemetryContext.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ICultureService.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPubSubService.cs create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ITelemetryContext.cs delete mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IThemeService.cs create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryContext.cs create mode 100644 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryContext.cs 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 cdf63beadb..c55f0867af 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 @@ -22,7 +22,7 @@ public partial class AppComponentBase : ComponentBase, IAsyncDisposable /// /// /// - [AutoInject] protected IPubSubService PubSubService = default!; + [AutoInject] protected PubSubService PubSubService = default!; [AutoInject] protected IConfiguration Configuration = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppInitializer.cs index 6dff25ac30..5e5fe8e0e9 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppInitializer.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/AppInitializer.cs @@ -14,14 +14,15 @@ public partial class AppInitializer : AppComponentBase //#if (notification == true) [AutoInject] private IPushNotificationService pushNotificationService = default!; //#endif - [AutoInject] private SnackBarService snackBarService = default!; - [AutoInject] private AuthenticationManager authManager = default!; [AutoInject] private IJSRuntime jsRuntime = default!; - [AutoInject] private IBitDeviceCoordinator bitDeviceCoordinator = default!; + [AutoInject] private Bit.Butil.Console console = default!; [AutoInject] private IStorageService storageService = default!; - [AutoInject] private CultureInfoManager cultureInfoManager = default!; + [AutoInject] private SnackBarService snackBarService = default!; + [AutoInject] private AuthenticationManager authManager = default!; + [AutoInject] private ITelemetryContext telemetryContext = default!; [AutoInject] private NavigationManager navigationManager = default!; - [AutoInject] private Bit.Butil.Console console = default!; + [AutoInject] private CultureInfoManager cultureInfoManager = default!; + [AutoInject] private IBitDeviceCoordinator bitDeviceCoordinator = default!; protected async override Task OnInitAsync() { @@ -52,7 +53,7 @@ protected override async Task OnAfterFirstRenderAsync() if (AppPlatform.IsBlazorHybrid is false) { - AppPlatform.OSDescription = await jsRuntime.GetBrowserPlatform(); + telemetryContext.OS = await jsRuntime.GetBrowserPlatform(); } } @@ -60,6 +61,10 @@ private async void AuthenticationStateChanged(Task task) { try { + var user = (await task).User; + telemetryContext.UserId = user.IsAuthenticated() ? user.GetUserId() : null; + telemetryContext.UserSessionId = user.IsAuthenticated() ? user.GetSessionId() : null; + //#if (signalr == true) if (InPrerenderSession is false) { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/IdentityHeader.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/IdentityHeader.razor.cs index 3b9b370dc1..94e763cb98 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/IdentityHeader.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/IdentityHeader.razor.cs @@ -7,8 +7,8 @@ public partial class IdentityHeader : AppComponentBase, IDisposable private Action unsubscribeUpdateBackLink = default!; - [AutoInject] private IThemeService themeService = default!; - [AutoInject] private ICultureService cultureService = default!; + [AutoInject] private ThemeService themeService = default!; + [AutoInject] private CultureService cultureService = default!; [CascadingParameter] private BitDir? currentDir { get; set; } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/RootLayout.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/RootLayout.razor.cs index ae9b6759db..8af2b5a449 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/RootLayout.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/RootLayout.razor.cs @@ -15,8 +15,8 @@ public partial class RootLayout : IDisposable private Action unsubscribeRouteDataUpdated = default!; - [AutoInject] private IThemeService themeService = default!; - [AutoInject] private IPubSubService pubSubService = default!; + [AutoInject] private ThemeService themeService = default!; + [AutoInject] private PubSubService pubSubService = default!; [AutoInject] private AuthenticationManager authManager = default!; [AutoInject] private IExceptionHandler exceptionHandler = default!; [AutoInject] private NavigationManager navigationManager = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/UserMenu.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/UserMenu.razor.cs index a2fdeeefcd..43dde27760 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/UserMenu.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/UserMenu.razor.cs @@ -14,8 +14,8 @@ public partial class UserMenu [AutoInject] private Cookie cookie = default!; [AutoInject] private CultureInfoManager cultureInfoManager = default!; - [AutoInject] private IThemeService themeService { get; set; } = default!; - [AutoInject] private ICultureService cultureService { get; set; } = default!; + [AutoInject] private ThemeService themeService { get; set; } = default!; + [AutoInject] private CultureService cultureService { get; set; } = default!; [CascadingParameter] private BitDir? currentDir { get; set; } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs index 06f8b50d56..eba2644f2c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor.cs @@ -26,6 +26,7 @@ public partial class SignInPage : IDisposable [AutoInject] private ILocalHttpServer localHttpServer = default!; + [AutoInject] private ITelemetryContext telemetryContext = default!; [AutoInject] private IIdentityController identityController = default!; [AutoInject] private IExternalNavigationService externalNavigationService = default!; @@ -48,7 +49,7 @@ protected override async Task OnInitAsync() model.UserName = UserNameQueryString; model.Email = EmailQueryString; model.PhoneNumber = PhoneNumberQueryString; - model.DeviceInfo = AppPlatform.OSDescription; + model.DeviceInfo = telemetryContext.OS; if (string.IsNullOrEmpty(OtpQueryString) is false) { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs index 81df0f17e2..7aaeb978ab 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs @@ -29,15 +29,17 @@ public static IServiceCollection AddClientCoreProjectServices(this IServiceColle services.AddSingleton(sp => configuration.Get()!); - services.AddSessioned(); - services.AddSessioned(); + services.AddSessioned(); services.AddSessioned(); + services.AddSessioned(); + services.AddSessioned(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppPlatform.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppPlatform.cs index 4368df6e3a..4c451e99bc 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppPlatform.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppPlatform.cs @@ -1,5 +1,4 @@ using System.Runtime.Versioning; -using System.Runtime.InteropServices; namespace Boilerplate.Client.Core.Services; @@ -29,6 +28,4 @@ public static partial class AppPlatform [SupportedOSPlatformGuard("ios")] public static bool IsIosOnMacOS { get; set; } - - public static string OSDescription { get; set; } = RuntimeInformation.OSDescription; } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppTelemetryContext.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppTelemetryContext.cs new file mode 100644 index 0000000000..4b7085ebdf --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppTelemetryContext.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace Boilerplate.Client.Core.Services; + +public class AppTelemetryContext : ITelemetryContext +{ + public virtual Guid? UserId { get; set; } + + public virtual Guid? UserSessionId { get; set; } + + public Guid AppSessionId { get; set; } = Guid.NewGuid(); + + public virtual string? OS { get; set; } = RuntimeInformation.OSDescription; + + public virtual string? AppVersion { get; set; } = typeof(AppTelemetryContext).Assembly.GetName().Version?.ToString(); + + public virtual string? WebView { get; set; } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ICultureService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ICultureService.cs deleted file mode 100644 index 2208e1b0af..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ICultureService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Boilerplate.Client.Core.Services.Contracts; - -public interface ICultureService -{ - Task ChangeCulture(string? cultureName); -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPubSubService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPubSubService.cs deleted file mode 100644 index ca04272c37..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPubSubService.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Boilerplate.Client.Core.Services.Contracts; - -/// -/// Contract for Publish/Subscribe pattern. -/// -public interface IPubSubService -{ - void Publish(string message, object? payload = null); - Action Subscribe(string message, Func handler); -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ITelemetryContext.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ITelemetryContext.cs new file mode 100644 index 0000000000..1994fa7260 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/ITelemetryContext.cs @@ -0,0 +1,39 @@ +namespace Boilerplate.Client.Core.Services.Contracts; + +public interface ITelemetryContext +{ + private static ITelemetryContext? _current; + + public static ITelemetryContext? Current + { + get + { + if (AppPlatform.IsBlazorHybridOrBrowser is false) + throw new InvalidOperationException("ITelemetryContext.Current is only available in Blazor Hybrid or web assembly apps."); + + return _current; + } + set + { + if (AppPlatform.IsBlazorHybridOrBrowser is false) + throw new InvalidOperationException("ITelemetryContext.Current is only available in Blazor Hybrid or web assembly apps."); + + _current = value; + } + } + + public Guid? UserId { get; set; } + + /// + /// Stored in Users table's Sessions column and is identified after the user sign-in. + /// + public Guid? UserSessionId { get; set; } + + public Guid AppSessionId { get; set; } + + public string? OS { get; set; } + + public string? AppVersion { get; set; } + + public string? WebView { get; set; } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IThemeService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IThemeService.cs deleted file mode 100644 index 0c8aa3a70e..0000000000 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IThemeService.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Boilerplate.Client.Core.Services.Contracts; - -public interface IThemeService -{ - Task GetCurrentTheme(); - - Task ToggleTheme(); -} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/CultureService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/CultureService.cs index 9950a80c62..b36c260cae 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/CultureService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/CultureService.cs @@ -1,9 +1,9 @@ namespace Boilerplate.Client.Core.Services; -public partial class CultureService : ICultureService +public partial class CultureService { [AutoInject] private Cookie cookie = default!; - [AutoInject] private IPubSubService pubSubService = default!; + [AutoInject] private PubSubService pubSubService = default!; [AutoInject] private IStorageService storageService = default!; [AutoInject] private NavigationManager navigationManager = default!; [AutoInject] private CultureInfoManager cultureInfoManager = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ExceptionHandlerBase.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ExceptionHandlerBase.cs index 745076872f..4c3b4a4880 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ExceptionHandlerBase.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ExceptionHandlerBase.cs @@ -7,10 +7,11 @@ namespace Boilerplate.Client.Core.Services; public abstract partial class ExceptionHandlerBase : IExceptionHandler { - [AutoInject] protected readonly IStringLocalizer Localizer = default!; - [AutoInject] protected readonly MessageBoxService MessageBoxService = default!; [AutoInject] protected Bit.Butil.Console Console = default!; + [AutoInject] protected ITelemetryContext TelemetryContext = default!; [AutoInject] protected ILogger Logger = default!; + [AutoInject] protected readonly MessageBoxService MessageBoxService = default!; + [AutoInject] protected readonly IStringLocalizer Localizer = default!; public void Handle(Exception exp, Dictionary? parameters = null, @@ -26,6 +27,15 @@ public void Handle(Exception exp, parameters[nameof(filePath)] = filePath; parameters[nameof(memberName)] = memberName; parameters[nameof(lineNumber)] = lineNumber; + parameters[nameof(TelemetryContext.UserId)] = TelemetryContext.UserId; + parameters[nameof(TelemetryContext.UserSessionId)] = TelemetryContext.UserSessionId; + parameters[nameof(TelemetryContext.AppSessionId)] = TelemetryContext.AppSessionId; + parameters[nameof(TelemetryContext.AppVersion)] = TelemetryContext.AppVersion; + parameters[nameof(TelemetryContext.OS)] = TelemetryContext.OS; + if (AppPlatform.IsBlazorHybrid) + { + parameters[nameof(TelemetryContext.WebView)] = TelemetryContext.WebView; + } Handle(exp, parameters.ToDictionary(i => i.Key, i => i.Value ?? string.Empty)); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/MessageBoxService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/MessageBoxService.cs index d6c5f6bd53..6a98fcaf86 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/MessageBoxService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/MessageBoxService.cs @@ -6,7 +6,7 @@ public partial class MessageBoxService private readonly ConcurrentQueue queue = new(); - [AutoInject] private readonly IPubSubService pubSubService = default!; + [AutoInject] private readonly PubSubService pubSubService = default!; public Task Show(string message, string title = "") diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubService.cs index b944b830de..efc74ca411 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubService.cs @@ -1,9 +1,9 @@ namespace Boilerplate.Client.Core.Services; /// -/// For more information docs. +/// Service for Publish/Subscribe pattern. /// -public partial class PubSubService : IPubSubService +public partial class PubSubService { private readonly ConcurrentDictionary>> handlers = new(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SnackBarService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SnackBarService.cs index 7a7cfa8b89..c846675704 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SnackBarService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SnackBarService.cs @@ -2,7 +2,7 @@ public partial class SnackBarService { - [AutoInject] private readonly IPubSubService pubSubService = default!; + [AutoInject] private readonly PubSubService pubSubService = default!; public void Show(string title, string body = "", BitColor color = BitColor.Info) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ThemeService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ThemeService.cs index 58c211a0f5..b381594140 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ThemeService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ThemeService.cs @@ -1,9 +1,9 @@ namespace Boilerplate.Client.Core.Services; -public partial class ThemeService : IThemeService +public partial class ThemeService { [AutoInject] private Cookie cookie = default!; - [AutoInject] private IPubSubService pubSubService = default!; + [AutoInject] private PubSubService pubSubService = default!; [AutoInject] private BitThemeManager bitThemeManager = default!; [AutoInject] private IBitDeviceCoordinator bitDeviceCoordinator = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Components/Pages/AboutPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Components/Pages/AboutPage.razor.cs index 4614775014..55dd11e9da 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Components/Pages/AboutPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Components/Pages/AboutPage.razor.cs @@ -4,6 +4,8 @@ namespace Boilerplate.Client.Maui.Components.Pages; public partial class AboutPage { + [AutoInject] private ITelemetryContext telemetryContext = default!; + protected override string? Title => Localizer[nameof(AppStrings.AboutTitle)]; protected override string? Subtitle => string.Empty; @@ -16,18 +18,13 @@ public partial class AboutPage protected async override Task OnInitAsync() { - appName = AppInfo.Name; - appVersion = AppInfo.Version.ToString(); - processId = Environment.ProcessId.ToString(); - os = $"{DeviceInfo.Current.Platform} {DeviceInfo.Current.VersionString}"; -#if Android // You have direct access to the Android, iOS, macOS, and Windows SDK features along with the ability to // call third-party Java, Kotlin, Swift, and Objective-C libraries. // https://stackoverflow.com/a/2941199/2720104 - os += $" {Android.Webkit.WebView.CurrentWebViewPackage?.PackageName}: {Android.Webkit.WebView.CurrentWebViewPackage?.VersionName}"; -#elif Windows - os += $" EdgeWebView2: {Microsoft.Web.WebView2.Core.CoreWebView2Environment.GetAvailableBrowserVersionString()}"; -#endif + appName = AppInfo.Name; + appVersion = telemetryContext.AppVersion!; + os = $"{telemetryContext.OS} {telemetryContext.WebView}"; + processId = Environment.ProcessId.ToString(); oem = DeviceInfo.Current.Manufacturer; await base.OnInitAsync(); 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 76dc55d493..e64287e89a 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 @@ -75,6 +75,7 @@ public static void ConfigureServices(this MauiAppBuilder builder) //-:cnd:noEmit services.AddTransient(); + services.AddSingleton(ITelemetryContext.Current = new MauiTelemetryContext()); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs index 1678b96d6a..0e0180bb46 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs @@ -7,6 +7,7 @@ //#endif //-:cnd:noEmit using Boilerplate.Client.Core.Styles; +using Boilerplate.Client.Maui.Services; #if iOS || Mac using UIKit; using WebKit; @@ -33,9 +34,6 @@ public static MauiApp CreateMauiApp() #if iOS AppPlatform.IsIosOnMacOS = NSProcessInfo.ProcessInfo.IsiOSApplicationOnMac; #endif - - AppPlatform.OSDescription = $"{DeviceInfo.Current.Manufacturer} {(AppPlatform.IsIosOnMacOS ? DevicePlatform.macOS : DeviceInfo.Current.Platform)} {DeviceInfo.Current.Version}"; - var builder = MauiApp.CreateBuilder(); builder diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryContext.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryContext.cs new file mode 100644 index 0000000000..a47ca63a89 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryContext.cs @@ -0,0 +1,18 @@ +namespace Boilerplate.Client.Maui.Services; + +public class MauiTelemetryContext : AppTelemetryContext +{ + public override string? OS { get; set; } = $"{DeviceInfo.Current.Manufacturer} {(AppPlatform.IsIosOnMacOS ? DevicePlatform.macOS : DeviceInfo.Current.Platform)} {DeviceInfo.Current.Version}"; + + public override string? AppVersion { get; set; } = VersionTracking.CurrentVersion; + + //-:cnd:noEmit + public override string? WebView { get; set; } = +#if Android + $"{Android.Webkit.WebView.CurrentWebViewPackage?.PackageName} {Android.Webkit.WebView.CurrentWebViewPackage?.VersionName}"; +#elif Windows + $"EdgeWebView2 {Microsoft.Web.WebView2.Core.CoreWebView2Environment.GetAvailableBrowserVersionString()}"; +#else + null; +#endif +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryInitializer.cs index 3d4e08b875..f09f13cb75 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryInitializer.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Services/MauiTelemetryInitializer.cs @@ -5,19 +5,23 @@ namespace Boilerplate.Client.Maui.Services; public partial class MauiTelemetryInitializer : ITelemetryInitializer { - private string sessionId { get; } = Guid.NewGuid().ToString(); - public void Initialize(ITelemetry telemetry) { - telemetry.Context.Session.Id = sessionId; - telemetry.Context.Session.IsFirst = VersionTracking.IsFirstLaunchEver; + 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.OS; + telemetry.Context.User.Id = ITelemetryContext.Current.UserId?.ToString(); - telemetry.Context.Device.OperatingSystem = DeviceInfo.Current.Platform.ToString(); + telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); + telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; + } + + telemetry.Context.Session.IsFirst = VersionTracking.IsFirstLaunchEver; telemetry.Context.Device.OemName = DeviceInfo.Current.Manufacturer; telemetry.Context.Device.Model = DeviceInfo.Current.Model; - telemetry.Context.Component.Version = AppInfo.Current.VersionString; - if (AppPlatform.IsIosOnMacOS) { telemetry.Context.GlobalProperties["IsiOSApplicationOnMac"] = "true"; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Components/Pages/AboutPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Components/Pages/AboutPage.razor.cs index b80a3ed8f0..de6c17b215 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Components/Pages/AboutPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Components/Pages/AboutPage.razor.cs @@ -4,6 +4,8 @@ namespace Boilerplate.Client.Windows.Components.Pages; public partial class AboutPage { + [AutoInject] private ITelemetryContext telemetryContext = default!; + protected override string? Title => Localizer[nameof(AppStrings.AboutTitle)]; protected override string? Subtitle => string.Empty; @@ -18,8 +20,8 @@ protected override async Task OnInitAsync() { var asm = typeof(AboutPage).Assembly; appName = asm.GetCustomAttribute()!.Title; - appVersion = asm.GetName().Version!.ToString(); - os = $"{AppPlatform.OSDescription} EdgeWebView2: {Microsoft.Web.WebView2.Core.CoreWebView2Environment.GetAvailableBrowserVersionString()}"; + appVersion = telemetryContext.AppVersion!; + os = $"{telemetryContext.OS} {telemetryContext.WebView}"; processId = Environment.ProcessId.ToString(); await base.OnInitAsync(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/MainWindow.xaml.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/MainWindow.xaml.cs index bc390c3fa6..b707a1aef4 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/MainWindow.xaml.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/MainWindow.xaml.cs @@ -33,7 +33,7 @@ public MainWindow() App.Current.Properties["Culture"]?.ToString() ?? // 1- User settings CultureInfo.CurrentUICulture.Name); // 2- OS Settings } - AppWebView.Services.GetRequiredService().Subscribe(PubSubMessages.CULTURE_CHANGED, async culture => + AppWebView.Services.GetRequiredService().Subscribe(PubSubMessages.CULTURE_CHANGED, async culture => { App.Current.Shutdown(); Application.Restart(); 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 fb81ecc008..0efb0154f1 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 @@ -32,6 +32,7 @@ public static void AddClientWindowsProjectServices(this IServiceCollection servi services.AddBlazorWebViewDeveloperTools(); } + services.AddSingleton(ITelemetryContext.Current = new WindowsTelemetryContext()); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryContext.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryContext.cs new file mode 100644 index 0000000000..247e2119b4 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryContext.cs @@ -0,0 +1,6 @@ +namespace Boilerplate.Client.Windows.Services; + +public class WindowsTelemetryContext : AppTelemetryContext +{ + public override string? WebView { get; set; } = $"EdgeWebView2 {Microsoft.Web.WebView2.Core.CoreWebView2Environment.GetAvailableBrowserVersionString()}"; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryInitializer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryInitializer.cs index cfa96c82f7..49cf1b2731 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryInitializer.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Services/WindowsTelemetryInitializer.cs @@ -5,14 +5,17 @@ namespace Boilerplate.Client.Windows.Services; public partial class WindowsTelemetryInitializer : ITelemetryInitializer { - private string sessionId { get; } = Guid.NewGuid().ToString(); - public void Initialize(ITelemetry telemetry) { - telemetry.Context.Session.Id = sessionId; - - telemetry.Context.Device.OperatingSystem = AppPlatform.OSDescription; + 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.OS; + telemetry.Context.User.Id = ITelemetryContext.Current.UserId?.ToString(); - telemetry.Context.Component.Version = typeof(WindowsTelemetryInitializer).Assembly.GetName().Version!.ToString(); + telemetry.Context.GlobalProperties[nameof(ITelemetryContext.UserSessionId)] = ITelemetryContext.Current.UserSessionId?.ToString(); + telemetry.Context.GlobalProperties[nameof(ITelemetryContext.WebView)] = ITelemetryContext.Current.WebView; + } } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ClaimsPrincipalExtensions.cs index 4955b5f13b..993787b4a4 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ClaimsPrincipalExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -27,6 +27,9 @@ public static string GetDisplayName(this ClaimsPrincipal claimsPrincipal) return claimsPrincipal.GetEmail() ?? claimsPrincipal.GetUserName(); } + /// + /// Returns the user session id stored in sessions column of user table after user sign in. + /// public static Guid? GetSessionId(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.IsAuthenticated()