diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index 145487da..72d96dd1 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.0.0 + uses: dependabot/fetch-metadata@v2.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a41d403..def05faf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Adds asynchronous deserialization support and marks synchronous as obsolete. htt - Added IAsyncParseNodeFactory interface to provide asynchronous version of GetRootParseNode: GetRootParseNodeAsync. - Added ParseNodeFactoryRegistry.GetRootParseNodeAsync method. - Added ParseNodeProxyFactory.GetRootParseNodeAsync method +- Adds async overloads for serialization helpers ### Changed @@ -24,29 +25,30 @@ Adds asynchronous deserialization support and marks synchronous as obsolete. htt - Marked IParseNodeFactory.GetRootParseNode as obsolete. - Refactored ParseNodeFactoryRegistry.GetFactory to support both asynchronous (IAsyncParseNodeFactory) and synchronous (IParseNodeFactory) factories. + ## [1.8.4] - 2024-04-19 - Bumps Std.UriTemplate to version 0.0.57 ## [1.8.3] - 2024-04-18 -- Have set the license expression on the nuget package rather than bundling in a file (https://github.com/microsoft/kiota-abstractions-dotnet/issues/219) +- Have set the license expression on the nuget package rather than bundling in a file () ## [1.8.2] - 2024-04-18 -- Have made System.Diagnostics.DiagnosticSource only be included on Net Standard's TFM & net 5 (https://github.com/microsoft/kiota-abstractions-dotnet/issues/218) +- Have made System.Diagnostics.DiagnosticSource only be included on Net Standard's TFM & net 5 () ## [1.8.1] - 2024-03-26 ### Changed -- `MultipartBody` now supports an optional `fileName` parameter to specify the file name of the part. (https://github.com/microsoft/kiota-abstractions-dotnet/issues/212) +- `MultipartBody` now supports an optional `fileName` parameter to specify the file name of the part. () ## [1.8.0] - 2024-03-18 ### Added -- Added support for untyped nodes. (https://github.com/microsoft/kiota-abstractions-dotnet/issues/175) +- Added support for untyped nodes. () ## [1.7.12] - 2024-03-08 @@ -61,7 +63,7 @@ Adds asynchronous deserialization support and marks synchronous as obsolete. htt - Updated IParseNode enum methods `DynamicallyAccessedMembersAttribute` to `PublicFields`. - Fixed AOT compiler warnings from ILC. - + ## [1.7.10] - 2024-02-26 ### Changed @@ -91,20 +93,20 @@ Adds asynchronous deserialization support and marks synchronous as obsolete. htt ### Changed -- Improve AllowedHost validator to throw an error if `https://` or `http://` prefix is present in a allowed host value.(https://github.com/microsoft/kiota-abstractions-dotnet/issues/165) +- Improve AllowedHost validator to throw an error if `https://` or `http://` prefix is present in a allowed host value.() ## [1.7.5] - 2024-01-11 ### Changed -- Fixes missing query parameters when the parameter values are empty strings.(https://github.com/microsoft/kiota-abstractions-dotnet/issues/172) +- Fixes missing query parameters when the parameter values are empty strings.() ## [1.7.4] - 2024-01-09 ### Changed - Fixed Method not found error due to conflicting dependencies by updating Std.UriTemplate dependency. -- Fixed unicode characters decoding in URI (https://github.com/std-uritemplate/std-uritemplate/issues/114). +- Fixed unicode characters decoding in URI (). ## [1.7.3] - 2023-11-30 @@ -183,7 +185,7 @@ Adds asynchronous deserialization support and marks synchronous as obsolete. htt ### Fixed -- Fixed a bug where excess duplicate subscriptions would be created on the same property in the backing store causing performance issues in some scenarios. Related to https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/1994 +- Fixed a bug where excess duplicate subscriptions would be created on the same property in the backing store causing performance issues in some scenarios. Related to ## [1.3.0] - 2023-08-01 diff --git a/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj b/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj index 47d57a54..c2424637 100644 --- a/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj +++ b/Microsoft.Kiota.Abstractions.Tests/Microsoft.Kiota.Abstractions.Tests.csproj @@ -18,8 +18,8 @@ environments https://github.com/microsoft/vstest/issues/2469--> - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Microsoft.Kiota.Abstractions.Tests/Serialization/SerializationHelpersTests.cs b/Microsoft.Kiota.Abstractions.Tests/Serialization/SerializationHelpersTests.cs index 79d8e2a9..0b119223 100644 --- a/Microsoft.Kiota.Abstractions.Tests/Serialization/SerializationHelpersTests.cs +++ b/Microsoft.Kiota.Abstractions.Tests/Serialization/SerializationHelpersTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading.Tasks; using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions.Tests.Mocks; using Moq; @@ -25,7 +26,7 @@ public void DefensiveObjectCollection() Assert.Throws(() => KiotaSerializer.SerializeAsStream(_jsonContentType, (IEnumerable)null)); } [Fact] - public void SerializesObject() + public async Task SerializesObject() { var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("{'id':'123'}"))); @@ -33,7 +34,7 @@ public void SerializesObject() mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; - var result = KiotaSerializer.SerializeAsString(_jsonContentType, new TestEntity() + var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new TestEntity() { Id = "123" }); @@ -45,7 +46,7 @@ public void SerializesObject() mockSerializationWriter.Verify(x => x.GetSerializedContent(), Times.Once); } [Fact] - public void SerializesObjectCollection() + public async Task SerializesObjectCollection() { var mockSerializationWriter = new Mock(); mockSerializationWriter.Setup(x => x.GetSerializedContent()).Returns(new MemoryStream(UTF8Encoding.UTF8.GetBytes("[{'id':'123'}]"))); @@ -53,7 +54,7 @@ public void SerializesObjectCollection() mockSerializationWriterFactory.Setup(x => x.GetSerializationWriter(It.IsAny())).Returns(mockSerializationWriter.Object); SerializationWriterFactoryRegistry.DefaultInstance.ContentTypeAssociatedFactories[_jsonContentType] = mockSerializationWriterFactory.Object; - var result = KiotaSerializer.SerializeAsString(_jsonContentType, new List { + var result = await KiotaSerializer.SerializeAsStringAsync(_jsonContentType, new List { new() { Id = "123" diff --git a/Microsoft.Kiota.Abstractions.Tests/Store/InMemoryBackingStoreTests.cs b/Microsoft.Kiota.Abstractions.Tests/Store/InMemoryBackingStoreTests.cs index 0758b56f..27993a78 100644 --- a/Microsoft.Kiota.Abstractions.Tests/Store/InMemoryBackingStoreTests.cs +++ b/Microsoft.Kiota.Abstractions.Tests/Store/InMemoryBackingStoreTests.cs @@ -440,6 +440,32 @@ public void TestsBackingStoreEmbeddedInModelWithByUpdatingNestedIBackedModelColl var colleagueSubscriptions = GetSubscriptionsPropertyFromBackingStore(testUser.Colleagues[0].BackingStore); Assert.Single(colleagueSubscriptions);// only one subscription to be invoked for the collection "colleagues" } + + [Fact] + public void TestsBackingStoreNestedInvocationCounts() + { + // Arrange dummy user with initialized backing store + var invocationCount = 0; + var testUser = new TestEntity(); + testUser.BackingStore.Subscribe((_, _, _) => invocationCount++, "testId"); + testUser.Id = "84c747c1-d2c0-410d-ba50-fc23e0b4abbe"; // invocation site 1 + var colleagues = new List(); + for(int i = 0; i < 10; i++) + { + colleagues.Add(new TestEntity + { + Id = "2fe22fe5-1132-42cf-90f9-1dc17e325a74", + BusinessPhones = new List + { + "+1 234 567 891" + } + }); + } + testUser.Colleagues = colleagues; // invocation site 2 + testUser.BackingStore.InitializationCompleted = true; // initialize + + Assert.Equal(2,invocationCount);// only called twice + } /// /// Helper function to pull out the private `subscriptions` collection property from the InMemoryBackingStore class diff --git a/src/serialization/KiotaJsonSerializer.Serialization.cs b/src/serialization/KiotaJsonSerializer.Serialization.cs index aa87f420..a35df57a 100644 --- a/src/serialization/KiotaJsonSerializer.Serialization.cs +++ b/src/serialization/KiotaJsonSerializer.Serialization.cs @@ -2,8 +2,11 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using System.IO; +using System.Threading; +using System.Threading.Tasks; #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -27,9 +30,20 @@ public static Stream SerializeAsStream(T value) where T : IParsable /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the async method instead")] public static string SerializeAsString(T value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(T value, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, cancellationToken); + /// /// Serializes the given object into a string based on the content type. /// @@ -45,7 +59,17 @@ public static Stream SerializeAsStream(IEnumerable value) where T : IParsa /// Type of the object to serialize /// The object to serialize. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the async method instead")] public static string SerializeAsString(IEnumerable value) where T : IParsable => KiotaSerializer.SerializeAsString(_jsonContentType, value); + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// The object to serialize. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(IEnumerable value, CancellationToken cancellationToken = default) where T : IParsable + => KiotaSerializer.SerializeAsStringAsync(_jsonContentType, value, cancellationToken); } \ No newline at end of file diff --git a/src/serialization/KiotaSerializer.Serialization.cs b/src/serialization/KiotaSerializer.Serialization.cs index 7abbd99b..732b89e4 100644 --- a/src/serialization/KiotaSerializer.Serialization.cs +++ b/src/serialization/KiotaSerializer.Serialization.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; +using System.Threading.Tasks; #if NET5_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -37,6 +39,7 @@ public static Stream SerializeAsStream(string contentType, T value) where T : /// Content type to serialize the object to /// The object to serialize. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the async method instead")] public static string SerializeAsString(string contentType, T value) where T : IParsable { using var stream = SerializeAsStream(contentType, value); @@ -48,6 +51,19 @@ public static string SerializeAsString(string contentType, T value) where T : /// Type of the object to serialize /// Content type to serialize the object to /// The object to serialize. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(string contentType, T value, CancellationToken cancellationToken = default) where T : IParsable + { + using var stream = SerializeAsStream(contentType, value); + return GetStringFromStreamAsync(stream, cancellationToken); + } + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// Content type to serialize the object to + /// The object to serialize. /// The serialized representation as a stream. public static Stream SerializeAsStream(string contentType, IEnumerable value) where T : IParsable { @@ -62,16 +78,40 @@ public static Stream SerializeAsStream(string contentType, IEnumerable val /// Content type to serialize the object to /// The object to serialize. /// The serialized representation as a string. + [Obsolete("This method is obsolete, use the async method instead")] public static string SerializeAsString(string contentType, IEnumerable value) where T : IParsable { using var stream = SerializeAsStream(contentType, value); return GetStringFromStream(stream); } + /// + /// Serializes the given object into a string based on the content type. + /// + /// Type of the object to serialize + /// Content type to serialize the object to + /// The object to serialize. + /// The token to monitor for cancellation requests. + /// The serialized representation as a string. + public static Task SerializeAsStringAsync(string contentType, IEnumerable value, CancellationToken cancellationToken = default) where T : IParsable + { + using var stream = SerializeAsStream(contentType, value); + return GetStringFromStreamAsync(stream, cancellationToken); + } + [Obsolete("This method is obsolete, use the async method instead")] private static string GetStringFromStream(Stream stream) { using var reader = new StreamReader(stream); return reader.ReadToEndAsync().ConfigureAwait(false).GetAwaiter().GetResult(); // so the asp.net projects don't get an error } + private static async Task GetStringFromStreamAsync(Stream stream, CancellationToken cancellationToken) + { + using var reader = new StreamReader(stream); +#if NET7_0_OR_GREATER + return await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); +#else + return await reader.ReadToEndAsync().ConfigureAwait(false); +#endif + } private static ISerializationWriter GetSerializationWriter(string contentType, object value) { if(string.IsNullOrEmpty(contentType)) throw new ArgumentNullException(nameof(contentType));