diff --git a/src/Components/Components/src/PublicAPI.Shipped.txt b/src/Components/Components/src/PublicAPI.Shipped.txt index c417cab5be3a..f5ab81693625 100644 --- a/src/Components/Components/src/PublicAPI.Shipped.txt +++ b/src/Components/Components/src/PublicAPI.Shipped.txt @@ -417,7 +417,6 @@ Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrameType.Region = 5 -> Mic Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrameType.Text = 2 -> Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrameType Microsoft.AspNetCore.Components.ResourceAsset Microsoft.AspNetCore.Components.ResourceAsset.Properties.get -> System.Collections.Generic.IReadOnlyList? -Microsoft.AspNetCore.Components.ResourceAsset.ResourceAsset(string! url, System.Collections.Generic.IReadOnlyList? properties) -> void Microsoft.AspNetCore.Components.ResourceAsset.Url.get -> string! Microsoft.AspNetCore.Components.ResourceAssetCollection Microsoft.AspNetCore.Components.ResourceAssetCollection.IsContentSpecificUrl(string! path) -> bool diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt index 89989d7da345..f889aa1f445d 100644 --- a/src/Components/Components/src/PublicAPI.Unshipped.txt +++ b/src/Components/Components/src/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ #nullable enable +Microsoft.AspNetCore.Components.ResourceAsset.ResourceAsset(string! url, System.Collections.Generic.IReadOnlyList? properties = null) -> void Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.get -> System.Type! Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.set -> void Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions diff --git a/src/Components/Components/src/ResourceAsset.cs b/src/Components/Components/src/ResourceAsset.cs index 3bd98d5e6e60..4336f66c85bd 100644 --- a/src/Components/Components/src/ResourceAsset.cs +++ b/src/Components/Components/src/ResourceAsset.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Components; /// The URL of the resource. /// The properties associated to this resource. [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] -public sealed class ResourceAsset(string url, IReadOnlyList? properties) +public sealed class ResourceAsset(string url, IReadOnlyList? properties = null) { /// /// Gets the URL that identifies this resource. diff --git a/src/Components/Components/test/ResourceAssetCollectionTest.cs b/src/Components/Components/test/ResourceAssetCollectionTest.cs index de19ebd48dcf..04502d37640b 100644 --- a/src/Components/Components/test/ResourceAssetCollectionTest.cs +++ b/src/Components/Components/test/ResourceAssetCollectionTest.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Serialization; + namespace Microsoft.AspNetCore.Components; public class ResourceAssetCollectionTest @@ -85,4 +88,68 @@ [new ResourceAssetProperty("label", "image2.jpg")]), Assert.False(isContentSpecificUrl1); Assert.True(isContentSpecificUrl2); } + + [Fact] + public void ResourceAsset_CanSerializeAndDeserialize_WithoutRespectRequiredConstructorParameters() + { + // Arrange + var originalAsset = new ResourceAsset("test-url", null); + var options = new JsonSerializerOptions { WriteIndented = true }; + + // Act + var json = JsonSerializer.Serialize(originalAsset, options); + var deserializedAsset = JsonSerializer.Deserialize(json, options); + + // Assert + Assert.NotNull(deserializedAsset); + Assert.Equal("test-url", deserializedAsset.Url); + Assert.Null(deserializedAsset.Properties); + } + + [Fact] + public void ResourceAsset_CanSerializeAndDeserialize_WithRespectRequiredConstructorParameters() + { + // Arrange + var originalAsset = new ResourceAsset("test-url", null); + var options = new JsonSerializerOptions + { + WriteIndented = true, + RespectRequiredConstructorParameters = true + }; + + // Act + var json = JsonSerializer.Serialize(originalAsset, options); + var deserializedAsset = JsonSerializer.Deserialize(json, options); + + // Assert + Assert.NotNull(deserializedAsset); + Assert.Equal("test-url", deserializedAsset.Url); + Assert.Null(deserializedAsset.Properties); + } + + [Fact] + public void ResourceAsset_WithSourceGenerationContext_CanSerializeAndDeserializeWithRespectRequiredConstructorParameters() + { + // Arrange - this test simulates the context from ResourceCollectionUrlEndpoint + var originalAsset = new ResourceAsset("test-url", null); + var assets = new List { originalAsset }; + + // Use a custom JsonSerializerOptions that mimics the source-generated context behavior + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, + WriteIndented = false, + RespectRequiredConstructorParameters = true + }; + + // Act + var json = JsonSerializer.Serialize>(assets, options); + var deserializedAssets = JsonSerializer.Deserialize>(json, options); + + // Assert + Assert.NotNull(deserializedAssets); + Assert.Single(deserializedAssets); + Assert.Equal("test-url", deserializedAssets[0].Url); + Assert.Null(deserializedAssets[0].Properties); + } } diff --git a/src/Components/test/testassets/Directory.Build.props b/src/Components/test/testassets/Directory.Build.props index f9fe6e921bf4..64274438641a 100644 --- a/src/Components/test/testassets/Directory.Build.props +++ b/src/Components/test/testassets/Directory.Build.props @@ -25,4 +25,9 @@ false + + + + +