From fadfc13a9fae79a537bbbdffa1b8911017661890 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 30 Apr 2025 14:33:43 +0200 Subject: [PATCH 1/3] Refactoring + registrations. --- ...orComponentsServiceCollectionExtensions.cs | 1 + .../Shared/src/ResourceCollectionProvider.cs | 23 +++++++------------ .../src/Hosting/WebAssemblyHostBuilder.cs | 1 + 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs b/src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs index 302dec7dcb16..5ed3f2ce195d 100644 --- a/src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs +++ b/src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs @@ -75,6 +75,7 @@ public static IRazorComponentsBuilder AddRazorComponents(this IServiceCollection services.TryAddScoped(); services.TryAddScoped(); + RegisterPersistentComponentStateServiceCollectionExtensions.AddPersistentServiceRegistration(services, RenderMode.InteractiveWebAssembly); // Form handling services.AddSupplyValueFromFormProvider(); diff --git a/src/Components/Shared/src/ResourceCollectionProvider.cs b/src/Components/Shared/src/ResourceCollectionProvider.cs index 78ebef9d13d2..957ba8bf3d97 100644 --- a/src/Components/Shared/src/ResourceCollectionProvider.cs +++ b/src/Components/Shared/src/ResourceCollectionProvider.cs @@ -11,22 +11,22 @@ namespace Microsoft.AspNetCore.Components; internal class ResourceCollectionProvider { - private const string ResourceCollectionUrlKey = "__ResourceCollectionUrl"; private string? _url; + + [SupplyParameterFromPersistentComponentState] + public string? ResourceCollectionUrl + { + get => _url; + set => _url = value; + } private ResourceAssetCollection? _resourceCollection; - private readonly PersistentComponentState _state; private readonly IJSRuntime _jsRuntime; - - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Strings are not trimmed")] - public ResourceCollectionProvider(PersistentComponentState state, IJSRuntime jsRuntime) + public ResourceCollectionProvider(IJSRuntime jsRuntime) { - _state = state; _jsRuntime = jsRuntime; - _ = _state.TryTakeFromJson(ResourceCollectionUrlKey, out _url); } [MemberNotNull(nameof(_url))] - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Strings are not trimmed")] internal void SetResourceCollectionUrl(string url) { if (_url != null) @@ -34,13 +34,6 @@ internal void SetResourceCollectionUrl(string url) throw new InvalidOperationException("The resource collection URL has already been set."); } _url = url; - PersistingComponentStateSubscription registration = default; - registration = _state.RegisterOnPersisting(() => - { - _state.PersistAsJson(ResourceCollectionUrlKey, _url); - registration.Dispose(); - return Task.CompletedTask; - }, RenderMode.InteractiveWebAssembly); } internal async Task GetResourceCollection() diff --git a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs index 218936a9c1d8..e90fdab63e70 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs @@ -308,6 +308,7 @@ internal void InitializeDefaultServices() Services.AddSupplyValueFromPersistentComponentStateProvider(); Services.AddSingleton(); Services.AddSingleton(); + RegisterPersistentComponentStateServiceCollectionExtensions.AddPersistentServiceRegistration(Services, RenderMode.InteractiveWebAssembly); Services.AddLogging(builder => { builder.AddProvider(new WebAssemblyConsoleLoggerProvider(DefaultWebAssemblyJSRuntime.Instance)); From db43fd20d43fce09d14ae44f546ce69a0359bc7a Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Mon, 12 May 2025 10:17:28 +0200 Subject: [PATCH 2/3] Fix internal shared assemblies with static mapping. --- .../PersistentServicesRegistry.cs | 19 +++++++++++++-- .../src/Rendering/EndpointHtmlRenderer.cs | 2 +- .../Shared/src/ResourceCollectionProvider.cs | 24 +++++++++---------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs b/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs index 3a91043bb6d9..aa7d537faf57 100644 --- a/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs +++ b/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs @@ -206,13 +206,28 @@ public PropertiesAccessor([DynamicallyAccessedMembers(LinkerFlags.Component)] Ty public (string, Type)[] KeyTypePairs => _cachedKeysForService; + // Mapping for internal classes bundled in different assemblies during prerendering and WASM rendering. + private static readonly Dictionary _canonicalMap = new(StringComparer.OrdinalIgnoreCase) + { + { "Microsoft.AspNetCore.Components.Endpoints", "Microsoft.AspNetCore.Components" }, + { "Microsoft.AspNetCore.Components.WebAssembly", "Microsoft.AspNetCore.Components" } + }; + private static string ComputeKey(Type keyType, string propertyName) { // This happens once per type and property combo, so allocations are ok. var assemblyName = keyType.Assembly.FullName; + var assemblySimpleName = keyType.Assembly.GetName().Name ?? ""; + if (_canonicalMap.TryGetValue(assemblySimpleName, out var canonicalAssembly)) + { + assemblyName = canonicalAssembly; + } + var typeName = keyType.FullName; - var input = Encoding.UTF8.GetBytes(string.Join(".", assemblyName, typeName, propertyName)); - return Convert.ToBase64String(SHA256.HashData(input)); + var inputString = string.Join(".", assemblyName, typeName, propertyName); + var input = Encoding.UTF8.GetBytes(inputString); + var hash = SHA256.HashData(input); + return Convert.ToBase64String(hash); } internal static IEnumerable GetCandidateBindableProperties( diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index e99574aa881e..d7e6a20d698c 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -149,7 +149,7 @@ private static void InitializeResourceCollection(HttpContext httpContext) var resourceCollectionProvider = resourceCollectionUrl != null ? httpContext.RequestServices.GetService() : null; if (resourceCollectionUrl != null && resourceCollectionProvider != null) { - resourceCollectionProvider.SetResourceCollectionUrl(resourceCollectionUrl.Url); + resourceCollectionProvider.ResourceCollectionUrl = resourceCollectionUrl.Url; resourceCollectionProvider.SetResourceCollection(resourceCollection ?? ResourceAssetCollection.Empty); } } diff --git a/src/Components/Shared/src/ResourceCollectionProvider.cs b/src/Components/Shared/src/ResourceCollectionProvider.cs index 957ba8bf3d97..e5e45e53eca9 100644 --- a/src/Components/Shared/src/ResourceCollectionProvider.cs +++ b/src/Components/Shared/src/ResourceCollectionProvider.cs @@ -17,8 +17,16 @@ internal class ResourceCollectionProvider public string? ResourceCollectionUrl { get => _url; - set => _url = value; + set + { + if (_url != null) + { + throw new InvalidOperationException("The resource collection URL has already been set."); + } + _url = value; + } } + private ResourceAssetCollection? _resourceCollection; private readonly IJSRuntime _jsRuntime; public ResourceCollectionProvider(IJSRuntime jsRuntime) @@ -26,16 +34,6 @@ public ResourceCollectionProvider(IJSRuntime jsRuntime) _jsRuntime = jsRuntime; } - [MemberNotNull(nameof(_url))] - internal void SetResourceCollectionUrl(string url) - { - if (_url != null) - { - throw new InvalidOperationException("The resource collection URL has already been set."); - } - _url = url; - } - internal async Task GetResourceCollection() { _resourceCollection = _resourceCollection ??= await LoadResourceCollection(); @@ -58,6 +56,8 @@ private async Task LoadResourceCollection() var module = await _jsRuntime.InvokeAsync("import", _url); var result = await module.InvokeAsync("get"); - return result == null ? ResourceAssetCollection.Empty : new ResourceAssetCollection(result); + var collection = result == null ? ResourceAssetCollection.Empty : new ResourceAssetCollection(result); + var asset = collection["BasicTestApp.styles.css"]; + return collection; } } From 4a98d9aef5792001f55abfb13ca3fc63eb8be7f2 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Mon, 12 May 2025 10:18:59 +0200 Subject: [PATCH 3/3] Remove debugging changes. --- src/Components/Shared/src/ResourceCollectionProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Components/Shared/src/ResourceCollectionProvider.cs b/src/Components/Shared/src/ResourceCollectionProvider.cs index e5e45e53eca9..030d4b0e684c 100644 --- a/src/Components/Shared/src/ResourceCollectionProvider.cs +++ b/src/Components/Shared/src/ResourceCollectionProvider.cs @@ -56,8 +56,6 @@ private async Task LoadResourceCollection() var module = await _jsRuntime.InvokeAsync("import", _url); var result = await module.InvokeAsync("get"); - var collection = result == null ? ResourceAssetCollection.Empty : new ResourceAssetCollection(result); - var asset = collection["BasicTestApp.styles.css"]; - return collection; + return result == null ? ResourceAssetCollection.Empty : new ResourceAssetCollection(result); } }