Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to serialize / deserialize BinaryData to support untyped yet dynamic used cases #27382

Merged
merged 18 commits into from
Mar 14, 2022

Conversation

m-nash
Copy link
Member

@m-nash m-nash commented Mar 7, 2022

Contributing to the Azure SDK

In mgmt plane we have some APIs like the GenericResource that return a partially strongly typed model. In the past the serializer would model this as object but would instantiate it as a Dictionary<string, object>. The issue was that customers didn't know what to do with an object and googling "How to use object in Azure" was fruitless. We want to instead model this as BinaryData and then provide samples for customers on the 4 different ways to load data in but still give them the ability to use it on output as a Dictionary<string, object>.

For deserializing here is an example of how they would use this.

The csproj files happened because as part of this there are a few more files that are used when you include LRO in your project so they were moved into the common definition of IncludeOperationsSharedSource

Please see our CONTRIBUTING.md if you are not familiar with contributing to this repository or have questions.

For specific information about pull request etiquette and best practices, see this section.

@ghost ghost added the Azure.Core label Mar 7, 2022
@m-nash
Copy link
Member Author

m-nash commented Mar 7, 2022

Latest profile

Method Job Runtime Mean Error StdDev Ratio RatioSD Gen 0 Allocated
DeserializeWithObject .NET 6.0 .NET 6.0 536.0 ns 2.70 ns 2.40 ns 0.75 0.00 0.0134 768 B
DeserializeWithObject .NET Core 3.1 .NET Core 3.1 714.2 ns 3.29 ns 2.91 ns 1.00 0.00 0.0124 752 B
DeserializeWithObject .NET Framework 4.6.1 .NET Framework 4.6.1 1,069.1 ns 4.88 ns 4.57 ns 1.50 0.01 0.1240 786 B
DeserializeWithObjectAndAccess .NET 6.0 .NET 6.0 574.0 ns 4.44 ns 3.94 ns 0.75 0.01 0.0134 768 B
DeserializeWithObjectAndAccess .NET Core 3.1 .NET Core 3.1 760.0 ns 2.83 ns 2.65 ns 1.00 0.00 0.0124 752 B
DeserializeWithObjectAndAccess .NET Framework 4.6.1 .NET Framework 4.6.1 1,127.6 ns 8.10 ns 7.58 ns 1.48 0.01 0.1240 786 B
SerializeWithObject .NET 6.0 .NET 6.0 568.1 ns 2.10 ns 1.97 ns 0.73 0.00 0.0162 888 B
SerializeWithObject .NET Core 3.1 .NET Core 3.1 782.6 ns 3.00 ns 2.81 ns 1.00 0.00 0.0143 896 B
SerializeWithObject .NET Framework 4.6.1 .NET Framework 4.6.1 1,221.3 ns 8.11 ns 7.58 ns 1.56 0.01 0.1469 931 B
DeserializeWithBinaryData .NET 6.0 .NET 6.0 223.2 ns 1.02 ns 0.91 ns 0.82 0.00 0.0069 376 B
DeserializeWithBinaryData .NET Core 3.1 .NET Core 3.1 272.3 ns 0.72 ns 0.67 ns 1.00 0.00 0.0062 376 B
DeserializeWithBinaryData .NET Framework 4.6.1 .NET Framework 4.6.1 571.6 ns 1.78 ns 1.58 ns 2.10 0.01 0.0591 377 B
DeserializeWithBinaryDataAndAccess .NET 6.0 .NET 6.0 1,263.3 ns 4.11 ns 3.64 ns 0.60 0.00 0.0248 1,408 B
DeserializeWithBinaryDataAndAccess .NET Core 3.1 .NET Core 3.1 2,091.4 ns 3.42 ns 2.67 ns 1.00 0.00 0.0229 1,496 B
DeserializeWithBinaryDataAndAccess .NET Framework 4.6.1 .NET Framework 4.6.1 3,270.3 ns 24.87 ns 23.27 ns 1.56 0.01 0.2403 1,533 B
DeserializeWithBinaryDataAndAccessUsingCustomParse .NET 6.0 .NET 6.0 755.0 ns 4.31 ns 4.04 ns 0.79 0.00 0.0191 1,072 B
DeserializeWithBinaryDataAndAccessUsingCustomParse .NET Core 3.1 .NET Core 3.1 957.0 ns 2.15 ns 1.91 ns 1.00 0.00 0.0172 1,056 B
DeserializeWithBinaryDataAndAccessUsingCustomParse .NET Framework 4.6.1 .NET Framework 4.6.1 1,528.1 ns 3.49 ns 2.92 ns 1.60 0.01 0.1717 1,091 B
SerializeWithBinaryData .NET 6.0 .NET 6.0 408.1 ns 0.99 ns 0.83 ns 0.27 0.00 0.0143 776 B
SerializeWithBinaryData .NET Core 3.1 .NET Core 3.1 1,490.9 ns 3.75 ns 3.33 ns 1.00 0.00 0.0229 1,400 B
SerializeWithBinaryData .NET Framework 4.6.1 .NET Framework 4.6.1 2,423.1 ns 6.18 ns 5.78 ns 1.63 0.00 0.2251 1,436 B
DeserializeWithJsonElement .NET 6.0 .NET 6.0 116.5 ns 0.70 ns 0.66 ns 0.75 0.01 0.0007 40 B
DeserializeWithJsonElement .NET Core 3.1 .NET Core 3.1 154.8 ns 1.25 ns 1.05 ns 1.00 0.00 0.0005 40 B
DeserializeWithJsonElement .NET Framework 4.6.1 .NET Framework 4.6.1 314.1 ns 1.25 ns 1.05 ns 2.03 0.02 0.0062 40 B
DeserializeWithJsonElementAndAccess .NET 6.0 .NET 6.0 572.8 ns 1.56 ns 1.38 ns 0.75 0.00 0.0143 776 B
DeserializeWithJsonElementAndAccess .NET Core 3.1 .NET Core 3.1 759.2 ns 1.87 ns 1.75 ns 1.00 0.00 0.0124 760 B
DeserializeWithJsonElementAndAccess .NET Framework 4.6.1 .NET Framework 4.6.1 1,136.0 ns 1.71 ns 1.43 ns 1.50 0.00 0.1259 794 B
SerializeWithJsonElement .NET 6.0 .NET 6.0 430.4 ns 2.49 ns 2.33 ns 0.72 0.00 0.0143 776 B
SerializeWithJsonElement .NET Core 3.1 .NET Core 3.1 601.2 ns 2.13 ns 1.99 ns 1.00 0.00 0.0124 784 B
SerializeWithJsonElement .NET Framework 4.6.1 .NET Framework 4.6.1 1,105.5 ns 14.40 ns 13.47 ns 1.84 0.02 0.1297 818 B

@azure-sdk
Copy link
Collaborator

API changes have been detected in Azure.Core. You can review API changes here

API changes

+         public static Dictionary<string, object?> ToDictionaryFromJson(this BinaryData data);

Copy link
Member

@annelo-msft annelo-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be willing to add a description to the PR sharing what motivates this change, and the context behind it? In the past we haven't used Dictionary APIs in .NET, so I'm curious what changed in our thinking about this.

Copy link
Member

@heaths heaths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to Cognitive Language and KV LGTM, but I do not think we should be returning a concrete type. I see no benefit over an IDictionary<string, object>, though I appreciate that in this case with an extension method it's not as important as with model properties or other mockable members.

sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs Outdated Show resolved Hide resolved
@azure-sdk
Copy link
Collaborator

API changes have been detected in Azure.Core. You can review API changes here

API changes

+         public static IDictionary<string, object?> ToDictionary(this BinaryData data);

Copy link
Member

@KrzysztofCwalina KrzysztofCwalina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we agreed to ship the slower implementation now and optimize it later. I think it's a better option given we want to GA Azure.Core in the next couple of days and the slow implementation is much simpler.

@m-nash
Copy link
Member Author

m-nash commented Mar 8, 2022

I thought we agreed to ship the slower implementation now and optimize it later. I think it's a better option given we want to GA Azure.Core in the next couple of days and the slow implementation is much simpler.

This was the slower one, it doesn't include any of the optimizations we talked about that are needed in BCL.

I did show one other straw man in our meeting that double parsed when you accessed which was over 3x slower and 2.5x allocs do you mean use that one?

@m-nash
Copy link
Member Author

m-nash commented Mar 8, 2022

New perf profile after switching to JsonElement implementation

Method Job Runtime Mean Error StdDev Ratio RatioSD Gen 0 Allocated
DeserializeWithObject .NET 6.0 .NET 6.0 550.8 ns 6.76 ns 6.32 ns 0.76 0.01 0.0134 768 B
DeserializeWithObject .NET Core 3.1 .NET Core 3.1 722.5 ns 2.00 ns 1.77 ns 1.00 0.00 0.0124 752 B
DeserializeWithObject .NET Framework 4.6.1 .NET Framework 4.6.1 1,115.5 ns 10.21 ns 9.05 ns 1.54 0.01 0.1240 786 B
DeserializeWithObjectAndAccess .NET 6.0 .NET 6.0 587.6 ns 7.05 ns 6.60 ns 0.76 0.01 0.0134 768 B
DeserializeWithObjectAndAccess .NET Core 3.1 .NET Core 3.1 771.7 ns 2.79 ns 2.47 ns 1.00 0.00 0.0124 752 B
DeserializeWithObjectAndAccess .NET Framework 4.6.1 .NET Framework 4.6.1 1,147.7 ns 7.96 ns 6.65 ns 1.49 0.01 0.1240 786 B
SerializeWithObject .NET 6.0 .NET 6.0 570.4 ns 2.48 ns 2.20 ns 0.72 0.01 0.0162 888 B
SerializeWithObject .NET Core 3.1 .NET Core 3.1 797.6 ns 5.23 ns 4.37 ns 1.00 0.00 0.0143 896 B
SerializeWithObject .NET Framework 4.6.1 .NET Framework 4.6.1 1,269.0 ns 8.71 ns 8.14 ns 1.59 0.02 0.1469 931 B
DeserializeWithBinaryData .NET 6.0 .NET 6.0 228.8 ns 0.49 ns 0.41 ns 0.84 0.00 0.0069 376 B
DeserializeWithBinaryData .NET Core 3.1 .NET Core 3.1 272.1 ns 0.95 ns 0.85 ns 1.00 0.00 0.0062 376 B
DeserializeWithBinaryData .NET Framework 4.6.1 .NET Framework 4.6.1 577.4 ns 3.20 ns 2.99 ns 2.12 0.01 0.0591 377 B
DeserializeWithBinaryDataAndAccess .NET 6.0 .NET 6.0 1,364.4 ns 8.28 ns 7.74 ns 0.63 0.01 0.0248 1,440 B
DeserializeWithBinaryDataAndAccess .NET Core 3.1 .NET Core 3.1 2,169.1 ns 39.59 ns 42.36 ns 1.00 0.00 0.0229 1,496 B
DeserializeWithBinaryDataAndAccess .NET Framework 4.6.1 .NET Framework 4.6.1 3,305.3 ns 23.77 ns 19.85 ns 1.52 0.04 0.2403 1,533 B
SerializeWithBinaryData .NET 6.0 .NET 6.0 425.9 ns 2.30 ns 2.04 ns 0.28 0.00 0.0143 776 B
SerializeWithBinaryData .NET Core 3.1 .NET Core 3.1 1,498.1 ns 5.69 ns 5.32 ns 1.00 0.00 0.0229 1,400 B
SerializeWithBinaryData .NET Framework 4.6.1 .NET Framework 4.6.1 2,502.8 ns 11.88 ns 10.53 ns 1.67 0.01 0.2251 1,436 B

@azure-sdk
Copy link
Collaborator

API changes have been detected in Azure.Core. You can review API changes here

API changes

+         public static IDictionary<string, object?> ToDictionaryFromJson(this BinaryData data);

@m-nash m-nash merged commit 5b4ebab into main Mar 14, 2022
@m-nash m-nash deleted the mnash-binaryData branch March 14, 2022 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants