From c49a24c940153d738ecdd0966917edfd4965b161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EB=8F=99=EC=9A=B0?= Date: Wed, 10 Apr 2024 19:04:28 +0900 Subject: [PATCH 1/5] When ApplicationData.Current is used in winui3 unpackaged mode, Invalid Operation Exception is occured. so LocalSettingsWrapper was added and fixed the problem. --- samples/WinUI3/App.xaml.cs | 5 +- src/Auth.UI.WinUI3/Auth.UI.WinUI3.csproj | 4 +- src/Auth.UI.WinUI3/Helpers/Json.cs | 31 +++++ src/Auth.UI.WinUI3/Helpers/RuntimeHelper.cs | 26 ++++ .../Repository/LocalSettingsWrapper.cs | 130 ++++++++++++++++++ .../Repository/StorageRepository.cs | 30 ++-- 6 files changed, 212 insertions(+), 14 deletions(-) create mode 100644 src/Auth.UI.WinUI3/Helpers/Json.cs create mode 100644 src/Auth.UI.WinUI3/Helpers/RuntimeHelper.cs create mode 100644 src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs diff --git a/samples/WinUI3/App.xaml.cs b/samples/WinUI3/App.xaml.cs index 2ace63a..6746e82 100644 --- a/samples/WinUI3/App.xaml.cs +++ b/samples/WinUI3/App.xaml.cs @@ -55,7 +55,10 @@ private void AuthStateChanged(object sender, UserEventArgs e) { if (e.User == null) { - await FirebaseUI.Instance.Client.SignInAnonymouslyAsync(); + if (FirebaseUI.Instance.Config.IsAnonymousAllowed) + { + await FirebaseUI.Instance.Client.SignInAnonymouslyAsync(); + } (Window.Content as Frame).Navigate(typeof(LoginPage)); } else if (e.User.IsAnonymous) diff --git a/src/Auth.UI.WinUI3/Auth.UI.WinUI3.csproj b/src/Auth.UI.WinUI3/Auth.UI.WinUI3.csproj index 81cd1df..9d23a4b 100644 --- a/src/Auth.UI.WinUI3/Auth.UI.WinUI3.csproj +++ b/src/Auth.UI.WinUI3/Auth.UI.WinUI3.csproj @@ -36,12 +36,12 @@ The library provides a drop-in auth solution that handles the flows for signing - <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))"/> + <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" /> - + diff --git a/src/Auth.UI.WinUI3/Helpers/Json.cs b/src/Auth.UI.WinUI3/Helpers/Json.cs new file mode 100644 index 0000000..e401590 --- /dev/null +++ b/src/Auth.UI.WinUI3/Helpers/Json.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace Firebase.Auth.UI.Helpers +{ + public static class Json + { + public static async Task ToObjectAsync(string value) + { + return await Task.Run(() => + { + return JsonConvert.DeserializeObject(value); + }).ConfigureAwait(false); + } + + public static async Task StringifyAsync(object value) + { + return await Task.Run(() => + { + return JsonConvert.SerializeObject(value); + }).ConfigureAwait(false); + } + } + +} + diff --git a/src/Auth.UI.WinUI3/Helpers/RuntimeHelper.cs b/src/Auth.UI.WinUI3/Helpers/RuntimeHelper.cs new file mode 100644 index 0000000..4aea06d --- /dev/null +++ b/src/Auth.UI.WinUI3/Helpers/RuntimeHelper.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Firebase.Auth.UI.Helpers +{ + public class RuntimeHelper + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); + + public static bool IsMSIX + { + get + { + var length = 0; + + return GetCurrentPackageFullName(ref length, null) != 15700L; + } + } + } + +} diff --git a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs new file mode 100644 index 0000000..0b54c38 --- /dev/null +++ b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Windows.Storage; + +using Windows.ApplicationModel; +using Firebase.Auth.UI.Helpers; + + +namespace Firebase.Auth.UI.Repository +{ + internal class LocalSettingsWrapper + { + private const string _defaultApplicationDataFolder = "AutoVid/ApplicationData"; + private const string _defaultLocalSettingsFile = "LocalSettings.json"; + + + private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + private readonly string _applicationDataFolder; + private readonly string _localsettingsFile; + + + + + private IDictionary _settings; + + private bool _isInitialized; + + //make as singletion + private static LocalSettingsWrapper _instance; + public static LocalSettingsWrapper Instance + { + get + { + if (_instance == null) + { + _instance = new LocalSettingsWrapper(); + } + + return _instance; + } + } + public LocalSettingsWrapper() + { + _applicationDataFolder = System.IO.Path.Combine(_localApplicationData, _defaultApplicationDataFolder); + _localsettingsFile = _defaultLocalSettingsFile; + + _settings = new Dictionary(); + } + + public bool Exists(string key) + { + if (RuntimeHelper.IsMSIX) + { + return ApplicationData.Current.LocalSettings.Values.ContainsKey(key); + } + else + { + return _settings.ContainsKey(key); + } + } + + private async Task InitializeAsync() + { + if (!_isInitialized) + { + //_settings = await Task.Run(() => _fileService.Read>(_applicationDataFolder, _localsettingsFile)) ?? new Dictionary(); + + string filepath = System.IO.Path.Combine(_applicationDataFolder, _localsettingsFile); + if (System.IO.File.Exists(filepath)) + { + string content = await System.IO.File.ReadAllTextAsync(filepath); + _settings = await Json.ToObjectAsync>(content).ConfigureAwait(false); + } + else + { + _settings = new Dictionary(); + } + + _isInitialized = true; + } + } + + public async Task ReadSettingAsync(string key) + { + if (RuntimeHelper.IsMSIX) + { + if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj)) + { + return await Json.ToObjectAsync((string)obj).ConfigureAwait(false); + } + } + else + { + await InitializeAsync(); + + if (_settings != null && _settings.TryGetValue(key, out var obj)) + { + return await Json.ToObjectAsync((string)obj).ConfigureAwait(false); + } + } + + return default; + } + + public async Task SaveSettingAsync(string key, T value) + { + if (RuntimeHelper.IsMSIX) + { + ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value).ConfigureAwait(false); + } + else + { + await InitializeAsync(); + + _settings[key] = await Json.StringifyAsync(value).ConfigureAwait(false); + + string filepath = System.IO.Path.Combine(_applicationDataFolder, _localsettingsFile); + await System.IO.File.WriteAllTextAsync(filepath, await Json.StringifyAsync(_settings)).ConfigureAwait(false); + + + //await Task.Run(() => _fileService.Save(_applicationDataFolder, _localsettingsFile, _settings)); + } + } + } + +} diff --git a/src/Auth.UI.WinUI3/Repository/StorageRepository.cs b/src/Auth.UI.WinUI3/Repository/StorageRepository.cs index 364dfb3..6ad9d91 100644 --- a/src/Auth.UI.WinUI3/Repository/StorageRepository.cs +++ b/src/Auth.UI.WinUI3/Repository/StorageRepository.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using Firebase.Auth.UI.Repository; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System.Threading.Tasks; using Windows.Storage; @@ -10,39 +11,46 @@ public class StorageRepository : IUserRepository private const string UserStorageKey = "FirebaseUser"; private const string CredentialStorageKey = "FirebaseCredential"; - private readonly ApplicationDataContainer settings; + //private readonly ApplicationDataContainer settings; private readonly JsonSerializerSettings options; public StorageRepository() { - this.settings = ApplicationData.Current.LocalSettings; + //this.settings = ApplicationData.Current.LocalSettings; this.options = new JsonSerializerSettings(); this.options.Converters.Add(new StringEnumConverter()); } public void DeleteUser() { - this.settings.Values[UserStorageKey] = null; - this.settings.Values[CredentialStorageKey] = null; + LocalSettingsWrapper.Instance.SaveSettingAsync(UserStorageKey, null).Wait(); + LocalSettingsWrapper.Instance.SaveSettingAsync(CredentialStorageKey, null).Wait(); + //this.settings.Values[UserStorageKey] = null; + //this.settings.Values[CredentialStorageKey] = null; } public (UserInfo userInfo, FirebaseCredential credential) ReadUser() { - var info = JsonConvert.DeserializeObject(this.settings.Values[UserStorageKey].ToString(), this.options); - var credential = JsonConvert.DeserializeObject(this.settings.Values[CredentialStorageKey].ToString(), this.options); + string storageKey = LocalSettingsWrapper.Instance.ReadSettingAsync(UserStorageKey).Result; + string credentialKey = LocalSettingsWrapper.Instance.ReadSettingAsync(CredentialStorageKey).Result; + var info = JsonConvert.DeserializeObject(storageKey, this.options); + var credential = JsonConvert.DeserializeObject(credentialKey, this.options); - return (info, credential); + return (info, credential); } public void SaveUser(User user) { - this.settings.Values[UserStorageKey] = JsonConvert.SerializeObject(user.Info, this.options); - this.settings.Values[CredentialStorageKey] = JsonConvert.SerializeObject(user.Credential, this.options); + LocalSettingsWrapper.Instance.SaveSettingAsync(UserStorageKey, JsonConvert.SerializeObject(user.Info, this.options)).Wait(); + LocalSettingsWrapper.Instance.SaveSettingAsync(CredentialStorageKey, JsonConvert.SerializeObject(user.Credential, this.options)).Wait(); + //this.settings.Values[UserStorageKey] = JsonConvert.SerializeObject(user.Info, this.options); + //this.settings.Values[CredentialStorageKey] = JsonConvert.SerializeObject(user.Credential, this.options); } public bool UserExists() { - return this.settings.Values.ContainsKey(UserStorageKey); + return LocalSettingsWrapper.Instance.Exists(UserStorageKey); + //return this.settings.Values.ContainsKey(UserStorageKey); } } } From ca43f1797c1214ab230be4d442d530cf49d9d2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EB=8F=99=EC=9A=B0?= Date: Wed, 10 Apr 2024 22:33:09 +0900 Subject: [PATCH 2/5] LocalSetting path fixed --- src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs index 0b54c38..bef65fb 100644 --- a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs +++ b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs @@ -8,23 +8,18 @@ using Windows.ApplicationModel; using Firebase.Auth.UI.Helpers; +using System.Reflection; namespace Firebase.Auth.UI.Repository { internal class LocalSettingsWrapper { - private const string _defaultApplicationDataFolder = "AutoVid/ApplicationData"; private const string _defaultLocalSettingsFile = "LocalSettings.json"; - - private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); private readonly string _applicationDataFolder; private readonly string _localsettingsFile; - - - private IDictionary _settings; private bool _isInitialized; @@ -45,7 +40,8 @@ public static LocalSettingsWrapper Instance } public LocalSettingsWrapper() { - _applicationDataFolder = System.IO.Path.Combine(_localApplicationData, _defaultApplicationDataFolder); + var appName = Assembly.GetExecutingAssembly().GetName().Name; + _applicationDataFolder = System.IO.Path.Combine(_localApplicationData, $"{appName}/ApplicationData"); _localsettingsFile = _defaultLocalSettingsFile; _settings = new Dictionary(); From 01bafe465cd85baf210248545c528675b11e5b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EB=8F=99=EC=9A=B0?= Date: Sat, 13 Apr 2024 09:33:05 +0900 Subject: [PATCH 3/5] LocalSettingWrapper fix --- .../Repository/LocalSettingsWrapper.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs index bef65fb..f6b96f8 100644 --- a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs +++ b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs @@ -9,6 +9,7 @@ using Windows.ApplicationModel; using Firebase.Auth.UI.Helpers; using System.Reflection; +using System.Diagnostics; namespace Firebase.Auth.UI.Repository @@ -40,8 +41,11 @@ public static LocalSettingsWrapper Instance } public LocalSettingsWrapper() { - var appName = Assembly.GetExecutingAssembly().GetName().Name; - _applicationDataFolder = System.IO.Path.Combine(_localApplicationData, $"{appName}/ApplicationData"); + var process = Process.GetCurrentProcess(); + string mainExecutablePath = process.MainModule.FileName; + string appName = System.IO.Path.GetFileNameWithoutExtension(mainExecutablePath); + + _applicationDataFolder = System.IO.Path.Combine(_localApplicationData, $"{appName}Data"); _localsettingsFile = _defaultLocalSettingsFile; _settings = new Dictionary(); @@ -113,6 +117,10 @@ public async Task SaveSettingAsync(string key, T value) await InitializeAsync(); _settings[key] = await Json.StringifyAsync(value).ConfigureAwait(false); + if (System.IO.Directory.Exists(_applicationDataFolder) == false) + { + System.IO.Directory.CreateDirectory(_applicationDataFolder); + } string filepath = System.IO.Path.Combine(_applicationDataFolder, _localsettingsFile); await System.IO.File.WriteAllTextAsync(filepath, await Json.StringifyAsync(_settings)).ConfigureAwait(false); From beea78ae01a65ffa29dcca2a81056755ffc1c96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EB=8F=99=EC=9A=B0?= Date: Sun, 14 Apr 2024 02:24:38 +0900 Subject: [PATCH 4/5] fix localsettingwrapper deadlock when using async --- src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs index f6b96f8..07ba3b2 100644 --- a/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs +++ b/src/Auth.UI.WinUI3/Repository/LocalSettingsWrapper.cs @@ -72,7 +72,7 @@ private async Task InitializeAsync() string filepath = System.IO.Path.Combine(_applicationDataFolder, _localsettingsFile); if (System.IO.File.Exists(filepath)) { - string content = await System.IO.File.ReadAllTextAsync(filepath); + string content = await System.IO.File.ReadAllTextAsync(filepath).ConfigureAwait(false); _settings = await Json.ToObjectAsync>(content).ConfigureAwait(false); } else @@ -95,7 +95,7 @@ public async Task ReadSettingAsync(string key) } else { - await InitializeAsync(); + await InitializeAsync().ConfigureAwait(false); if (_settings != null && _settings.TryGetValue(key, out var obj)) { @@ -114,7 +114,7 @@ public async Task SaveSettingAsync(string key, T value) } else { - await InitializeAsync(); + await InitializeAsync().ConfigureAwait(false); _settings[key] = await Json.StringifyAsync(value).ConfigureAwait(false); if (System.IO.Directory.Exists(_applicationDataFolder) == false) From eebf1fb0de862a214190e827e0bba78a7d03a20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EB=8F=99=EC=9A=B0?= Date: Sun, 14 Apr 2024 15:52:15 +0900 Subject: [PATCH 5/5] fix user, credential null --- src/Auth.UI.WinUI3/Repository/StorageRepository.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Auth.UI.WinUI3/Repository/StorageRepository.cs b/src/Auth.UI.WinUI3/Repository/StorageRepository.cs index 6ad9d91..45c0b88 100644 --- a/src/Auth.UI.WinUI3/Repository/StorageRepository.cs +++ b/src/Auth.UI.WinUI3/Repository/StorageRepository.cs @@ -33,6 +33,10 @@ public void DeleteUser() { string storageKey = LocalSettingsWrapper.Instance.ReadSettingAsync(UserStorageKey).Result; string credentialKey = LocalSettingsWrapper.Instance.ReadSettingAsync(CredentialStorageKey).Result; + if (storageKey == null || credentialKey == null) + { + return (null, null); + } var info = JsonConvert.DeserializeObject(storageKey, this.options); var credential = JsonConvert.DeserializeObject(credentialKey, this.options); @@ -49,7 +53,9 @@ public void SaveUser(User user) public bool UserExists() { - return LocalSettingsWrapper.Instance.Exists(UserStorageKey); + string storageKey = LocalSettingsWrapper.Instance.ReadSettingAsync(UserStorageKey).Result; + return storageKey != null; + //return LocalSettingsWrapper.Instance.Exists(UserStorageKey); //return this.settings.Values.ContainsKey(UserStorageKey); } }