From 653554ea5e4798f4c3364d8bd48deb41f99c92d2 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Wed, 1 Jan 2025 20:37:45 +0100 Subject: [PATCH 01/10] Build/NR: Run all unit test and show test summary (#67) * Build/NR: simplify unit test run * Build/NR: show unit test summary --- .github/workflows/NewsReader.CI.yml | 11 +++-------- src/NewsReader/Directory.Build.props | 1 + src/NewsReader/Directory.Packages.props | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/NewsReader.CI.yml b/.github/workflows/NewsReader.CI.yml index 74662117..ee902489 100644 --- a/.github/workflows/NewsReader.CI.yml +++ b/.github/workflows/NewsReader.CI.yml @@ -95,12 +95,7 @@ jobs: - name: 🔖 Check-out uses: actions/checkout@v4 - - name: 🕵️ Test - Domain.Test + - name: 🕵️ Test run: | - cd src/NewsReader/NewsReader.Domain.Test - dotnet test -c:Release -p:Version=${{ needs.GetVersion.outputs.version }} - - - name: 🕵️ Test - Presentation.Test - run: | - cd src/NewsReader/NewsReader.Presentation.Test - dotnet test -c:Release -p:Version=${{ needs.GetVersion.outputs.version }} + echo "## 🕵️ Test Results" >> $Env:GITHUB_STEP_SUMMARY + dotnet test ./src/NewsReader/NewsReader.sln -c:Release -p:Version=${{ needs.GetVersion.outputs.version }} --logger GitHubActions diff --git a/src/NewsReader/Directory.Build.props b/src/NewsReader/Directory.Build.props index 0dea3e8d..565f222c 100644 --- a/src/NewsReader/Directory.Build.props +++ b/src/NewsReader/Directory.Build.props @@ -17,6 +17,7 @@ $(MSBuildThisFileDirectory)CodeCoverage.runsettings + diff --git a/src/NewsReader/Directory.Packages.props b/src/NewsReader/Directory.Packages.props index c886d900..07ce125f 100644 --- a/src/NewsReader/Directory.Packages.props +++ b/src/NewsReader/Directory.Packages.props @@ -18,6 +18,7 @@ + From 5174eef9cf57efd163359bd3708a2f28380b65d7 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Mon, 6 Jan 2025 15:59:46 +0100 Subject: [PATCH 02/10] WAF: ThrottledAction: improve performance --- .../Foundation/ThrottledAction.cs | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs index eb8747b6..dfcf9fba 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/ThrottledAction.cs @@ -23,7 +23,6 @@ public enum ThrottledActionMode public class ThrottledAction { private readonly TaskScheduler taskScheduler; - private readonly object cancellationTokenSourceLock = new object(); private readonly Action action; private readonly ThrottledActionMode mode; private readonly TimeSpan delayTime; @@ -44,50 +43,42 @@ public ThrottledAction(Action action) /// The argument action must not be null. public ThrottledAction(Action action, ThrottledActionMode mode, TimeSpan delayTime) { - taskScheduler = SynchronizationContext.Current != null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default; + taskScheduler = SynchronizationContext.Current is not null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default; this.action = action ?? throw new ArgumentNullException(nameof(action)); this.mode = mode; this.delayTime = delayTime; } /// Indicates that an execution of the action delegate is requested. - public bool IsRunning => cancellationTokenSource != null; + public bool IsRunning => cancellationTokenSource is not null; /// Requests the execution of the action delegate. public void InvokeAccumulated() { - CancellationToken? token = null; - lock (cancellationTokenSourceLock) - { - if (mode == ThrottledActionMode.InvokeOnlyIfIdleForDelayTime || cancellationTokenSource == null) - { - cancellationTokenSource?.Cancel(); - cancellationTokenSource = new CancellationTokenSource(); - token = cancellationTokenSource.Token; - } - } + if (mode is not ThrottledActionMode.InvokeOnlyIfIdleForDelayTime && cancellationTokenSource is not null) return; - if (token != null) + var cts = new CancellationTokenSource(); + if (mode is ThrottledActionMode.InvokeOnlyIfIdleForDelayTime) + { + Interlocked.Exchange(ref cancellationTokenSource, cts)?.Cancel(); + } + else // mode is InvokeMaxEveryDelayTime { - Task.Delay(delayTime, token.Value).ContinueWith(t => - { - lock (cancellationTokenSourceLock) - { - cancellationTokenSource = null; - } - TaskHelper.Run(action, taskScheduler); - }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); + var old = Interlocked.CompareExchange(ref cancellationTokenSource, cts, null); + if (old is not null) return; } + + Task.Delay(delayTime, cts.Token).ContinueWith(t => + { + Interlocked.Exchange(ref cancellationTokenSource, null); + TaskHelper.Run(action, taskScheduler); + }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); } /// Cancel the execution of the action delegate that was requested. public void Cancel() { - lock (cancellationTokenSourceLock) - { - cancellationTokenSource?.Cancel(); - cancellationTokenSource = null; - } + Interlocked.Exchange(ref cancellationTokenSource, null)?.Cancel(); } } } From cd633f82b5fa9062df1cccc030377b14dadce3f4 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Mon, 6 Jan 2025 16:32:22 +0100 Subject: [PATCH 03/10] Test: Run unit tests on Net48 instead of Net472 --- .../System.Waf.Core.Test/System.Waf.Core.Test.csproj | 6 +----- .../System.Waf/System.Waf.Core/System.Waf.Core.csproj | 4 ---- .../System.Waf.UnitTesting.Core.csproj | 4 ---- .../System.Waf.Wpf.Test/System.Waf.Wpf.Test.csproj | 2 +- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/System.Waf/System.Waf/System.Waf.Core.Test/System.Waf.Core.Test.csproj b/src/System.Waf/System.Waf/System.Waf.Core.Test/System.Waf.Core.Test.csproj index 6c6cdf50..dea28971 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core.Test/System.Waf.Core.Test.csproj +++ b/src/System.Waf/System.Waf/System.Waf.Core.Test/System.Waf.Core.Test.csproj @@ -1,6 +1,6 @@  - net472;net8.0 + net48;net8.0 Test.Waf false @@ -12,8 +12,4 @@ - - - $(NoWarn);8625 - diff --git a/src/System.Waf/System.Waf/System.Waf.Core/System.Waf.Core.csproj b/src/System.Waf/System.Waf/System.Waf.Core/System.Waf.Core.csproj index 41adadb0..4244ff0a 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core/System.Waf.Core.csproj +++ b/src/System.Waf/System.Waf/System.Waf.Core/System.Waf.Core.csproj @@ -5,10 +5,6 @@ System.Waf is a lightweight framework that helps you to create well-structured XAML applications. This core package can be used in various application types. - - - - diff --git a/src/System.Waf/System.Waf/System.Waf.UnitTesting.Core/System.Waf.UnitTesting.Core.csproj b/src/System.Waf/System.Waf/System.Waf.UnitTesting.Core/System.Waf.UnitTesting.Core.csproj index 1e504b21..9560e1d2 100644 --- a/src/System.Waf/System.Waf/System.Waf.UnitTesting.Core/System.Waf.UnitTesting.Core.csproj +++ b/src/System.Waf/System.Waf/System.Waf.UnitTesting.Core/System.Waf.UnitTesting.Core.csproj @@ -5,10 +5,6 @@ System.Waf is a lightweight framework that helps you to create well-structured XAML applications. This package supports writing unit tests. It can be used in various application types. - - - - diff --git a/src/System.Waf/System.Waf/System.Waf.Wpf.Test/System.Waf.Wpf.Test.csproj b/src/System.Waf/System.Waf/System.Waf.Wpf.Test/System.Waf.Wpf.Test.csproj index b13af4b5..2832db41 100644 --- a/src/System.Waf/System.Waf/System.Waf.Wpf.Test/System.Waf.Wpf.Test.csproj +++ b/src/System.Waf/System.Waf/System.Waf.Wpf.Test/System.Waf.Wpf.Test.csproj @@ -1,6 +1,6 @@  - net472;net8.0-windows + net48;net8.0-windows Test.Waf false true From c7a9c6676fda7bf084c5156fa363bef1b66664d6 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Mon, 6 Jan 2025 16:48:13 +0100 Subject: [PATCH 04/10] Fix issue that VS is not able to run .NET Framework unit tests anymore - workaround: downgrade MSTest https://github.com/microsoft/testfx/issues/4426 --- src/System.Waf/Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Waf/Directory.Packages.props b/src/System.Waf/Directory.Packages.props index ad9c66b4..4fd16e2e 100644 --- a/src/System.Waf/Directory.Packages.props +++ b/src/System.Waf/Directory.Packages.props @@ -23,7 +23,7 @@ - - + + \ No newline at end of file From 7110b1d8f44cb5060284387cb5541618ab878a86 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Mon, 6 Jan 2025 17:04:02 +0100 Subject: [PATCH 05/10] Test: Fix warnings --- .../System.Waf.Core.Test/Foundation/ValidatableModelTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ValidatableModelTest.cs b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ValidatableModelTest.cs index 1cc71601..e6ddbd83 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ValidatableModelTest.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ValidatableModelTest.cs @@ -164,9 +164,9 @@ public void ValidationResultComparerTest() var comparerType = typeof(ValidatableModel).GetNestedType("ValidationResultComparer", BindingFlags.NonPublic)!; var comparer = (IEqualityComparer)comparerType.GetProperty("Default", BindingFlags.Static | BindingFlags.Public)!.GetValue(null)!; - Assert.IsTrue(comparer.Equals(null, null)); - Assert.IsFalse(comparer.Equals(new ValidationResult(null), null)); - Assert.IsFalse(comparer.Equals(null, new ValidationResult(null))); + Assert.IsTrue(comparer.Equals(null!, null!)); + Assert.IsFalse(comparer.Equals(new ValidationResult(null), null!)); + Assert.IsFalse(comparer.Equals(null!, new ValidationResult(null))); Assert.IsTrue(comparer.Equals(new ValidationResult(null), new ValidationResult(null))); Assert.IsFalse(comparer.Equals(new ValidationResult("Test"), new ValidationResult("Bill"))); Assert.IsTrue(comparer.Equals(new ValidationResult("Test"), new ValidationResult("Test"))); From 2d33d6038b367cb1b5412f7b08f47ebbd05de86b Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Mon, 6 Jan 2025 17:04:50 +0100 Subject: [PATCH 06/10] Test: try to improve stability of InvokeOnlyIfIdleForDelayTimePerformanceTest --- .../System.Waf.Core.Test/Foundation/ThrottledActionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ThrottledActionTest.cs b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ThrottledActionTest.cs index 80271c00..435ec9fa 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ThrottledActionTest.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/ThrottledActionTest.cs @@ -129,7 +129,7 @@ public void InvokeMaxEveryDelayTimeTestWithSynchronizationContext() public void InvokeOnlyIfIdleForDelayTimePerformanceTest() { int actionCallCount = 0; - var throttledAction = new ThrottledAction(() => Interlocked.Add(ref actionCallCount, 1), ThrottledActionMode.InvokeOnlyIfIdleForDelayTime, TimeSpan.FromMilliseconds(10)); + var throttledAction = new ThrottledAction(() => Interlocked.Add(ref actionCallCount, 1), ThrottledActionMode.InvokeOnlyIfIdleForDelayTime, TimeSpan.FromMilliseconds(20)); for (int i = 0; i < 200000; i++) { throttledAction.InvokeAccumulated(); From 08ced27eef998b77ac8922f6c0aff9067c32fef9 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Tue, 14 Jan 2025 19:19:37 +0100 Subject: [PATCH 07/10] Update (c) to 2025 --- LICENSE | 2 +- src/System.Waf/Directory.Build.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index bc0e9dab..84839348 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2023 jbe2277 +Copyright (c) 2016-2025 jbe2277 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/System.Waf/Directory.Build.props b/src/System.Waf/Directory.Build.props index 2ca98af6..16a75bc0 100644 --- a/src/System.Waf/Directory.Build.props +++ b/src/System.Waf/Directory.Build.props @@ -1,7 +1,7 @@  jbe2277 - Copyright © 2016-2024 jbe2277 + Copyright © 2016-2025 jbe2277 en-US enable true From 90bf3c37eb7aaaad8d3a1f2d3efbdc47c619927b Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Tue, 14 Jan 2025 19:27:28 +0100 Subject: [PATCH 08/10] NR: Update WAF packages --- src/NewsReader/Directory.Packages.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NewsReader/Directory.Packages.props b/src/NewsReader/Directory.Packages.props index 07ce125f..e75f89fe 100644 --- a/src/NewsReader/Directory.Packages.props +++ b/src/NewsReader/Directory.Packages.props @@ -2,9 +2,9 @@ true - + - + @@ -15,13 +15,13 @@ - - + + - + \ No newline at end of file From c70816d5062f8f66663a2a9cff7ee9ecd1cc2a3c Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Thu, 16 Jan 2025 21:40:12 +0100 Subject: [PATCH 09/10] WAF: Add TaskHelper.Run overloads with CancellationToken support --- .../Foundation/TaskHelperTest.cs | 19 ++++++++++++++ .../System.Waf.Core/Foundation/TaskHelper.cs | 25 +++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/TaskHelperTest.cs b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/TaskHelperTest.cs index 45942193..00e38657 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/TaskHelperTest.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core.Test/Foundation/TaskHelperTest.cs @@ -1,7 +1,9 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Threading; using System.Threading.Tasks; using System.Waf.Foundation; +using System.Waf.UnitTesting; namespace Test.Waf.Foundation { @@ -16,6 +18,23 @@ public async Task RunTest() Assert.AreEqual(42, result); } + [TestMethod] + public void RunWithCancellationTest() + { + using var context = UnitTestSynchronizationContext.Create(); + + var task = TaskHelper.Run(() => 42, TaskScheduler.FromCurrentSynchronizationContext()); + var result = task.GetResult(context); + Assert.AreEqual(42, result); + + bool called = false; + var cts = new CancellationTokenSource(); + var task2 = TaskHelper.Run(() => called = true, TaskScheduler.FromCurrentSynchronizationContext(), cts.Token); + cts.Cancel(); + AssertHelper.ExpectedException(() => task2.Wait(context)); + Assert.IsFalse(called); + } + [TestMethod] public async Task NoWaitTest() { diff --git a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/TaskHelper.cs b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/TaskHelper.cs index 67ac76ad..8e120c2c 100644 --- a/src/System.Waf/System.Waf/System.Waf.Core/Foundation/TaskHelper.cs +++ b/src/System.Waf/System.Waf/System.Waf.Core/Foundation/TaskHelper.cs @@ -12,7 +12,7 @@ public static class TaskHelper /// A task that represents the work queued to execute in the ThreadPool. public static Task Run(Action action, TaskScheduler scheduler) { - return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler); + return Run(action, scheduler, CancellationToken.None); } /// Queues the specified work to run on the thread pool and returns a proxy for the task returned by function. @@ -22,7 +22,28 @@ public static Task Run(Action action, TaskScheduler scheduler) /// A task that represents the work queued to execute in the ThreadPool. public static Task Run(Func action, TaskScheduler scheduler) { - return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler); + return Run(action, scheduler, CancellationToken.None); + } + + /// Queues the specified work to run on the thread pool and returns a Task object that represents that work. + /// The work to execute asynchronously + /// The TaskScheduler that is used to schedule the created Task. + /// The cancellation token that will be assigned to the new task. + /// A task that represents the work queued to execute in the ThreadPool. + public static Task Run(Action action, TaskScheduler scheduler, CancellationToken cancellation) + { + return Task.Factory.StartNew(action, cancellation, TaskCreationOptions.DenyChildAttach, scheduler); + } + + /// Queues the specified work to run on the thread pool and returns a proxy for the task returned by function. + /// The type of the result produced by this task. + /// The work to execute asynchronously + /// The TaskScheduler that is used to schedule the created Task. + /// The cancellation token that will be assigned to the new task. + /// A task that represents the work queued to execute in the ThreadPool. + public static Task Run(Func action, TaskScheduler scheduler, CancellationToken cancellation) + { + return Task.Factory.StartNew(action, cancellation, TaskCreationOptions.DenyChildAttach, scheduler); } /// From f73dbf03d65c53ea0615c342cbc30b6da3720c61 Mon Sep 17 00:00:00 2001 From: jbe2277 Date: Tue, 21 Jan 2025 21:11:08 +0100 Subject: [PATCH 10/10] NewsReader: Workaround for Graph SDK and use MSAL Broker on Windows (#70) * NR: Adapt MSAL on Windows; update packages * NR: Rollback unit testing packages to previous version * NR: Use MSAL Broker on Windows * NR: Workaround for MS Graph to get the required driveId https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2624 --- src/NewsReader/Directory.Build.props | 2 +- src/NewsReader/Directory.Packages.props | 8 +++---- .../NewsReader.Presentation/App.xaml.cs | 3 +++ .../NewsReader.Presentation.csproj | 2 +- .../Services/WebStorageService.cs | 24 ++++++++++++------- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/NewsReader/Directory.Build.props b/src/NewsReader/Directory.Build.props index 565f222c..cee095db 100644 --- a/src/NewsReader/Directory.Build.props +++ b/src/NewsReader/Directory.Build.props @@ -1,6 +1,6 @@  - 9.0.21 + 9.0.22 en enable diff --git a/src/NewsReader/Directory.Packages.props b/src/NewsReader/Directory.Packages.props index e75f89fe..81ec3ec7 100644 --- a/src/NewsReader/Directory.Packages.props +++ b/src/NewsReader/Directory.Packages.props @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/src/NewsReader/NewsReader.Presentation/App.xaml.cs b/src/NewsReader/NewsReader.Presentation/App.xaml.cs index 654ad8ae..0d7a23e6 100644 --- a/src/NewsReader/NewsReader.Presentation/App.xaml.cs +++ b/src/NewsReader/NewsReader.Presentation/App.xaml.cs @@ -43,6 +43,8 @@ public App(ISettingsService settingsService, IAppInfoService appInfoService, Laz public static string LogFileName { get; } = Path.Combine(FileSystem.CacheDirectory, "Logging", "AppLog.txt"); + public static Window? CurrentWindow { get; private set; } + protected override Window CreateWindow(IActivationState? activationState) { var window = new Window((Page)appController.MainView) @@ -56,6 +58,7 @@ protected override Window CreateWindow(IActivationState? activationState) window.Stopped += (_, _) => OnStopped(); window.Destroying += (_, _) => OnDestroying(); window.Resumed += (_, _) => OnResumed(); + CurrentWindow = window; return window; } diff --git a/src/NewsReader/NewsReader.Presentation/NewsReader.Presentation.csproj b/src/NewsReader/NewsReader.Presentation/NewsReader.Presentation.csproj index 23452585..3e6d4cd6 100644 --- a/src/NewsReader/NewsReader.Presentation/NewsReader.Presentation.csproj +++ b/src/NewsReader/NewsReader.Presentation/NewsReader.Presentation.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/NewsReader/NewsReader.Presentation/Services/WebStorageService.cs b/src/NewsReader/NewsReader.Presentation/Services/WebStorageService.cs index 4d829721..6d23aa2f 100644 --- a/src/NewsReader/NewsReader.Presentation/Services/WebStorageService.cs +++ b/src/NewsReader/NewsReader.Presentation/Services/WebStorageService.cs @@ -2,7 +2,6 @@ using Microsoft.Graph.Models; using Microsoft.Graph.Models.ODataErrors; using Microsoft.Identity.Client; -using Microsoft.Identity.Client.Extensions.Msal; using Microsoft.Kiota.Abstractions.Authentication; using Waf.NewsReader.Applications.Services; @@ -41,6 +40,12 @@ public WebStorageService() builder.WithParentActivityOrWindow(() => Platform.CurrentActivity); #elif IOS builder.WithIosKeychainSecurityGroup(Foundation.NSBundle.MainBundle.BundleIdentifier); +#elif WINDOWS + Microsoft.Identity.Client.Broker.BrokerExtension.WithBroker(builder, new BrokerOptions(BrokerOptions.OperatingSystems.Windows) + { + Title = AppInfo.Name + }); + builder.WithParentActivityOrWindow(() => WinRT.Interop.WindowNative.GetWindowHandle(App.CurrentWindow!.Handler.PlatformView!)); #endif publicClient = builder.Build(); } @@ -61,8 +66,8 @@ public async Task TrySilentSignIn() if (!cacheInitialized && publicClient is not null) { cacheInitialized = true; - var storageProperties = new StorageCreationPropertiesBuilder("msal.dat", FileSystem.CacheDirectory).Build(); - var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties); + var storageProperties = new Microsoft.Identity.Client.Extensions.Msal.StorageCreationPropertiesBuilder("msal.dat", FileSystem.CacheDirectory).Build(); + var cacheHelper = await Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper.CreateAsync(storageProperties); cacheHelper.RegisterCache(publicClient.UserTokenCache); } #endif @@ -180,11 +185,14 @@ private async Task InitGraphClient() private async Task GetItemRequest(string fileName) { if (graphClient is null) throw new InvalidOperationException("graphClient is null"); - var driveItem = await graphClient.Me.Drive.GetAsync().ConfigureAwait(false); - ArgumentNullException.ThrowIfNull(driveItem); - var appRootFolder = await graphClient.Drives[driveItem.Id].Special["AppRoot"].GetAsync().ConfigureAwait(false); - ArgumentNullException.ThrowIfNull(appRootFolder); - return graphClient.Drives[driveItem.Id].Items[appRootFolder.Id].ItemWithPath(fileName); + + // Using workaround to get the driveId because AppFolder scope does not allow to the read Drive directly. https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2624 + var result = await graphClient.Me.Drive.WithUrl($"{graphClient.RequestAdapter.BaseUrl}/drive/special/approot:/{fileName}").GetAsync().ConfigureAwait(false); + var driveId = result?.Id?.Split("!")[0] ?? throw new InvalidOperationException("graphClient: not able to get the driveId"); + + var appRootFolder = await graphClient.Drives[driveId].Special["AppRoot"].GetAsync().ConfigureAwait(false) + ?? throw new InvalidOperationException("graphClient: not able to get the appRootFolder"); + return graphClient.Drives[driveId].Items[appRootFolder.Id].ItemWithPath(fileName); } static partial void GetApplicationId(ref string? applicationId);