From 5b4ebab917c29cbc8872b962392f2fc73e9ecad1 Mon Sep 17 00:00:00 2001
From: m-nash <64171366+m-nash@users.noreply.github.com>
Date: Mon, 14 Mar 2022 14:43:54 -0700
Subject: [PATCH] Update to serialize / deserialize BinaryData to support
untyped yet dynamic used cases (#27382)
* wip
* wip
* update proj references for files needed by lro
* refactor code
* update api and unit tests
* update keyvault includes
* add round trip validation for all cases
* remove dupe from storage
* one more dupe in storage
* change to IDictionary
* fix proj files for storage
* Remove from json
* update to use jsonelement
* rename back to ToDictionaryFromJson
* throw exception if the json was not a json object
* Update sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
---
eng/Directory.Build.Common.targets | 10 +-
eng/Packages.Data.props | 2 +-
.../src/Azure.ServiceTemplate.Template.csproj | 8 -
.../Azure.Verticals.AgriFood.Farming.csproj | 5 -
.../src/Azure.AI.AnomalyDetector.csproj | 5 -
.../src/Azure.Security.Attestation.csproj | 5 -
.../Azure.AI.Language.Conversations.csproj | 5 -
...Azure.AI.Language.QuestionAnswering.csproj | 5 -
.../Azure.Communication.CallingServer.csproj | 5 -
.../src/Azure.Communication.Chat.csproj | 5 -
.../src/Azure.Communication.Identity.csproj | 5 -
...zure.Communication.NetworkTraversal.csproj | 5 -
.../Azure.Communication.PhoneNumbers.csproj | 5 -
.../src/Azure.Communication.Sms.csproj | 5 -
.../Azure.Security.ConfidentialLedger.csproj | 5 -
.../Azure.Containers.ContainerRegistry.csproj | 5 -
.../src/Azure.Core.Experimental.csproj | 5 -
.../src/Azure.Core.TestFramework.csproj | 5 -
sdk/core/Azure.Core/api/Azure.Core.net461.cs | 1 +
sdk/core/Azure.Core/api/Azure.Core.net5.0.cs | 1 +
.../api/Azure.Core.netcoreapp2.1.cs | 1 +
.../api/Azure.Core.netstandard2.0.cs | 1 +
.../Azure.Core/perf/Azure.Core.Perf.csproj | 8 +-
.../Azure.Core/perf/DynamicObjectBenchmark.cs | 104 +++++++
.../perf/TestData/JsonFormattedString.json | 1 +
.../src/Serialization/AzureCoreExtensions.cs | 58 ++++
.../Azure.Core/tests/Azure.Core.Tests.csproj | 5 +
.../tests/BinaryDataSerializationTests.cs | 256 ++++++++++++++++++
.../Azure.Core/tests/ModelWithBinaryData.cs | 69 +++++
sdk/core/Azure.Core/tests/ModelWithObject.cs | 64 +++++
.../tests/Properties/AssemblyInfo.cs | 6 +
.../BinaryData/JsonFormattedString.json | 1 +
.../tests/TestData/BinaryData/Properties.json | 1 +
.../BinaryData/PropertiesWithArrays.json | 1 +
.../PropertiesWithArraysOfArrays.json | 1 +
.../PropertiesWithArraysOfObjects.json | 1 +
.../PropertiesWithDifferentValueTypes.json | 1 +
.../src/Azure.IoT.DeviceUpdate.csproj | 5 -
.../src/Azure.DigitalTwins.Core.csproj | 13 -
.../src/Azure.Messaging.EventGrid.csproj | 5 -
.../src/Azure.AI.FormRecognizer.csproj | 5 -
.../src/Azure.IoT.Hub.Service.csproj | 13 -
...re.Security.KeyVault.Administration.csproj | 5 -
...zure.Security.KeyVault.Certificates.csproj | 5 -
.../src/Azure.Security.KeyVault.Keys.csproj | 7 -
.../Azure.Security.KeyVault.Secrets.csproj | 5 -
.../src/Azure.AI.MetricsAdvisor.csproj | 5 -
.../Azure.MixedReality.Authentication.csproj | 5 -
.../src/Azure.IoT.ModelsRepository.csproj | 13 -
...zure.Monitor.OpenTelemetry.Exporter.csproj | 5 -
.../src/Azure.Monitor.Query.csproj | 5 -
...xedReality.ObjectAnchors.Conversion.csproj | 5 -
.../src/Azure.AI.Personalizer.csproj | 5 -
.../Azure.Analytics.Purview.Account.csproj | 5 -
...re.Analytics.Purview.Administration.csproj | 5 -
.../Azure.Analytics.Purview.Catalog.csproj | 5 -
.../Azure.Analytics.Purview.Scanning.csproj | 5 -
.../src/Azure.Quantum.Jobs.csproj | 5 -
.../Azure.MixedReality.RemoteRendering.csproj | 5 -
.../src/Azure.Data.SchemaRegistry.csproj | 5 -
.../src/Azure.Search.Documents.csproj | 5 -
.../src/Azure.Storage.Blobs.Batch.csproj | 5 -
.../src/Azure.Storage.Blobs.csproj | 5 -
.../src/Azure.Storage.Common.csproj | 3 +-
.../tests/Azure.Storage.Common.Tests.csproj | 4 -
.../src/Azure.Storage.Files.DataLake.csproj | 5 -
.../src/Azure.Storage.Files.Shares.csproj | 5 -
.../src/Azure.Storage.Queues.csproj | 5 -
...ure.Analytics.Synapse.AccessControl.csproj | 5 -
.../Azure.Analytics.Synapse.Artifacts.csproj | 5 -
...ics.Synapse.ManagedPrivateEndpoints.csproj | 5 -
.../Azure.Analytics.Synapse.Monitoring.csproj | 5 -
.../src/Azure.Analytics.Synapse.Spark.csproj | 5 -
.../src/Azure.Data.Tables.csproj | 5 -
.../Azure.Template/src/Azure.Template.csproj | 5 -
.../src/Azure.AI.TextAnalytics.csproj | 5 -
.../src/Azure.IoT.TimeSeriesInsights.csproj | 5 -
.../src/Azure.AI.Translation.Document.csproj | 5 -
.../src/Azure.Media.VideoAnalyzer.Edge.csproj | 8 -
.../src/Azure.Messaging.WebPubSub.csproj | 5 -
80 files changed, 587 insertions(+), 330 deletions(-)
create mode 100644 sdk/core/Azure.Core/perf/DynamicObjectBenchmark.cs
create mode 100644 sdk/core/Azure.Core/perf/TestData/JsonFormattedString.json
create mode 100644 sdk/core/Azure.Core/tests/ModelWithBinaryData.cs
create mode 100644 sdk/core/Azure.Core/tests/ModelWithObject.cs
create mode 100644 sdk/core/Azure.Core/tests/Properties/AssemblyInfo.cs
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/JsonFormattedString.json
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/Properties.json
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/PropertiesWithArrays.json
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/PropertiesWithArraysOfArrays.json
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/PropertiesWithArraysOfObjects.json
create mode 100644 sdk/core/Azure.Core/tests/TestData/BinaryData/PropertiesWithDifferentValueTypes.json
diff --git a/eng/Directory.Build.Common.targets b/eng/Directory.Build.Common.targets
index 4b1e005fcaab6..f1855cf41e195 100644
--- a/eng/Directory.Build.Common.targets
+++ b/eng/Directory.Build.Common.targets
@@ -202,6 +202,11 @@
+
+
+
+
+
@@ -211,12 +216,7 @@
-
-
-
-
-
diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props
index c7c75276e3339..e09d471b2f91b 100644
--- a/eng/Packages.Data.props
+++ b/eng/Packages.Data.props
@@ -182,7 +182,7 @@
-
+
diff --git a/eng/templates/Azure.ServiceTemplate.Template/src/Azure.ServiceTemplate.Template.csproj b/eng/templates/Azure.ServiceTemplate.Template/src/Azure.ServiceTemplate.Template.csproj
index a1d1c526c4958..409f41a167f31 100644
--- a/eng/templates/Azure.ServiceTemplate.Template/src/Azure.ServiceTemplate.Template.csproj
+++ b/eng/templates/Azure.ServiceTemplate.Template/src/Azure.ServiceTemplate.Template.csproj
@@ -13,15 +13,7 @@
-
-
-
-
-
-
-
-
diff --git a/sdk/agrifood/Azure.Verticals.AgriFood.Farming/src/Azure.Verticals.AgriFood.Farming.csproj b/sdk/agrifood/Azure.Verticals.AgriFood.Farming/src/Azure.Verticals.AgriFood.Farming.csproj
index 4b3b35695c2a1..ac82769678483 100644
--- a/sdk/agrifood/Azure.Verticals.AgriFood.Farming/src/Azure.Verticals.AgriFood.Farming.csproj
+++ b/sdk/agrifood/Azure.Verticals.AgriFood.Farming/src/Azure.Verticals.AgriFood.Farming.csproj
@@ -18,13 +18,8 @@
-
-
-
-
-
diff --git a/sdk/anomalydetector/Azure.AI.AnomalyDetector/src/Azure.AI.AnomalyDetector.csproj b/sdk/anomalydetector/Azure.AI.AnomalyDetector/src/Azure.AI.AnomalyDetector.csproj
index 342412019d95c..dd1a2e3976010 100644
--- a/sdk/anomalydetector/Azure.AI.AnomalyDetector/src/Azure.AI.AnomalyDetector.csproj
+++ b/sdk/anomalydetector/Azure.AI.AnomalyDetector/src/Azure.AI.AnomalyDetector.csproj
@@ -17,14 +17,9 @@
-
-
-
-
-
diff --git a/sdk/attestation/Azure.Security.Attestation/src/Azure.Security.Attestation.csproj b/sdk/attestation/Azure.Security.Attestation/src/Azure.Security.Attestation.csproj
index 8d3a9ec828488..3375544b4c476 100644
--- a/sdk/attestation/Azure.Security.Attestation/src/Azure.Security.Attestation.csproj
+++ b/sdk/attestation/Azure.Security.Attestation/src/Azure.Security.Attestation.csproj
@@ -18,12 +18,7 @@
-
-
-
-
-
diff --git a/sdk/cognitivelanguage/Azure.AI.Language.Conversations/src/Azure.AI.Language.Conversations.csproj b/sdk/cognitivelanguage/Azure.AI.Language.Conversations/src/Azure.AI.Language.Conversations.csproj
index d43893a35c809..7b0e56888520d 100644
--- a/sdk/cognitivelanguage/Azure.AI.Language.Conversations/src/Azure.AI.Language.Conversations.csproj
+++ b/sdk/cognitivelanguage/Azure.AI.Language.Conversations/src/Azure.AI.Language.Conversations.csproj
@@ -16,14 +16,9 @@
-
-
-
-
-
diff --git a/sdk/cognitivelanguage/Azure.AI.Language.QuestionAnswering/src/Azure.AI.Language.QuestionAnswering.csproj b/sdk/cognitivelanguage/Azure.AI.Language.QuestionAnswering/src/Azure.AI.Language.QuestionAnswering.csproj
index 6930bdda4f667..deac062f2ec4d 100644
--- a/sdk/cognitivelanguage/Azure.AI.Language.QuestionAnswering/src/Azure.AI.Language.QuestionAnswering.csproj
+++ b/sdk/cognitivelanguage/Azure.AI.Language.QuestionAnswering/src/Azure.AI.Language.QuestionAnswering.csproj
@@ -18,14 +18,9 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.CallingServer/src/Azure.Communication.CallingServer.csproj b/sdk/communication/Azure.Communication.CallingServer/src/Azure.Communication.CallingServer.csproj
index 6ce05f7cdafca..6543de2a8833c 100644
--- a/sdk/communication/Azure.Communication.CallingServer/src/Azure.Communication.CallingServer.csproj
+++ b/sdk/communication/Azure.Communication.CallingServer/src/Azure.Communication.CallingServer.csproj
@@ -20,16 +20,11 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.Chat/src/Azure.Communication.Chat.csproj b/sdk/communication/Azure.Communication.Chat/src/Azure.Communication.Chat.csproj
index 4c574b657f848..379667cea8106 100644
--- a/sdk/communication/Azure.Communication.Chat/src/Azure.Communication.Chat.csproj
+++ b/sdk/communication/Azure.Communication.Chat/src/Azure.Communication.Chat.csproj
@@ -27,12 +27,7 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.Identity/src/Azure.Communication.Identity.csproj b/sdk/communication/Azure.Communication.Identity/src/Azure.Communication.Identity.csproj
index 072dcba061d3a..dee0d77f67674 100644
--- a/sdk/communication/Azure.Communication.Identity/src/Azure.Communication.Identity.csproj
+++ b/sdk/communication/Azure.Communication.Identity/src/Azure.Communication.Identity.csproj
@@ -28,14 +28,9 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.NetworkTraversal/src/Azure.Communication.NetworkTraversal.csproj b/sdk/communication/Azure.Communication.NetworkTraversal/src/Azure.Communication.NetworkTraversal.csproj
index f4f7f3c34bc66..bd1a4421d0504 100644
--- a/sdk/communication/Azure.Communication.NetworkTraversal/src/Azure.Communication.NetworkTraversal.csproj
+++ b/sdk/communication/Azure.Communication.NetworkTraversal/src/Azure.Communication.NetworkTraversal.csproj
@@ -25,14 +25,9 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.PhoneNumbers/src/Azure.Communication.PhoneNumbers.csproj b/sdk/communication/Azure.Communication.PhoneNumbers/src/Azure.Communication.PhoneNumbers.csproj
index e52572f32d7d9..6a5b8c3d88d29 100644
--- a/sdk/communication/Azure.Communication.PhoneNumbers/src/Azure.Communication.PhoneNumbers.csproj
+++ b/sdk/communication/Azure.Communication.PhoneNumbers/src/Azure.Communication.PhoneNumbers.csproj
@@ -27,14 +27,9 @@
-
-
-
-
-
diff --git a/sdk/communication/Azure.Communication.Sms/src/Azure.Communication.Sms.csproj b/sdk/communication/Azure.Communication.Sms/src/Azure.Communication.Sms.csproj
index bd46bb9b48c2c..6d4377c170729 100644
--- a/sdk/communication/Azure.Communication.Sms/src/Azure.Communication.Sms.csproj
+++ b/sdk/communication/Azure.Communication.Sms/src/Azure.Communication.Sms.csproj
@@ -25,14 +25,9 @@
-
-
-
-
-
diff --git a/sdk/confidentialledger/Azure.Security.ConfidentialLedger/src/Azure.Security.ConfidentialLedger.csproj b/sdk/confidentialledger/Azure.Security.ConfidentialLedger/src/Azure.Security.ConfidentialLedger.csproj
index 1d1f22aa86e10..eae260fadf8bd 100644
--- a/sdk/confidentialledger/Azure.Security.ConfidentialLedger/src/Azure.Security.ConfidentialLedger.csproj
+++ b/sdk/confidentialledger/Azure.Security.ConfidentialLedger/src/Azure.Security.ConfidentialLedger.csproj
@@ -21,15 +21,10 @@
-
-
-
-
-
diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj
index 67ede240a788c..ab7076d525283 100644
--- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj
+++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/src/Azure.Containers.ContainerRegistry.csproj
@@ -17,15 +17,10 @@
-
-
-
-
-
diff --git a/sdk/core/Azure.Core.Experimental/src/Azure.Core.Experimental.csproj b/sdk/core/Azure.Core.Experimental/src/Azure.Core.Experimental.csproj
index b6956ae0991ce..2b9e7503d195c 100644
--- a/sdk/core/Azure.Core.Experimental/src/Azure.Core.Experimental.csproj
+++ b/sdk/core/Azure.Core.Experimental/src/Azure.Core.Experimental.csproj
@@ -16,12 +16,7 @@
-
-
-
-
-
diff --git a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj
index 04b8c3740379d..c14e0f6510779 100644
--- a/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj
+++ b/sdk/core/Azure.Core.TestFramework/src/Azure.Core.TestFramework.csproj
@@ -23,14 +23,9 @@
-
-
-
-
-
diff --git a/sdk/core/Azure.Core/api/Azure.Core.net461.cs b/sdk/core/Azure.Core/api/Azure.Core.net461.cs
index 15d56ccb9824d..c014e0da5a019 100644
--- a/sdk/core/Azure.Core/api/Azure.Core.net461.cs
+++ b/sdk/core/Azure.Core/api/Azure.Core.net461.cs
@@ -17,6 +17,7 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
}
public static partial class AzureCoreExtensions
{
+ public static System.Collections.Generic.IDictionary ToDictionaryFromJson(this System.BinaryData data) { throw null; }
public static System.Threading.Tasks.ValueTask ToObjectAsync(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static T? ToObject(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
diff --git a/sdk/core/Azure.Core/api/Azure.Core.net5.0.cs b/sdk/core/Azure.Core/api/Azure.Core.net5.0.cs
index 8c94044c7c5c6..4b1a77bcd6df8 100644
--- a/sdk/core/Azure.Core/api/Azure.Core.net5.0.cs
+++ b/sdk/core/Azure.Core/api/Azure.Core.net5.0.cs
@@ -17,6 +17,7 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
}
public static partial class AzureCoreExtensions
{
+ public static System.Collections.Generic.IDictionary ToDictionaryFromJson(this System.BinaryData data) { throw null; }
public static System.Threading.Tasks.ValueTask ToObjectAsync(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static T? ToObject(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
diff --git a/sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs b/sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs
index 15d56ccb9824d..c014e0da5a019 100644
--- a/sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs
+++ b/sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs
@@ -17,6 +17,7 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
}
public static partial class AzureCoreExtensions
{
+ public static System.Collections.Generic.IDictionary ToDictionaryFromJson(this System.BinaryData data) { throw null; }
public static System.Threading.Tasks.ValueTask ToObjectAsync(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static T? ToObject(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
diff --git a/sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs b/sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs
index 15d56ccb9824d..c014e0da5a019 100644
--- a/sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs
+++ b/sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs
@@ -17,6 +17,7 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
}
public static partial class AzureCoreExtensions
{
+ public static System.Collections.Generic.IDictionary ToDictionaryFromJson(this System.BinaryData data) { throw null; }
public static System.Threading.Tasks.ValueTask ToObjectAsync(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static T? ToObject(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
diff --git a/sdk/core/Azure.Core/perf/Azure.Core.Perf.csproj b/sdk/core/Azure.Core/perf/Azure.Core.Perf.csproj
index d7724bbb97113..316cd80e305eb 100644
--- a/sdk/core/Azure.Core/perf/Azure.Core.Perf.csproj
+++ b/sdk/core/Azure.Core/perf/Azure.Core.Perf.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -10,6 +10,7 @@
+
@@ -18,5 +19,10 @@
+
+
+ Always
+
+
diff --git a/sdk/core/Azure.Core/perf/DynamicObjectBenchmark.cs b/sdk/core/Azure.Core/perf/DynamicObjectBenchmark.cs
new file mode 100644
index 0000000000000..9123b550da750
--- /dev/null
+++ b/sdk/core/Azure.Core/perf/DynamicObjectBenchmark.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text.Json;
+using Azure.Core.Tests;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Jobs;
+
+namespace Azure.Core.Perf
+{
+ [MemoryDiagnoser]
+ [SimpleJob(RuntimeMoniker.NetCoreApp31, baseline: true)]
+ [SimpleJob(RuntimeMoniker.Net461)]
+ [SimpleJob(RuntimeMoniker.Net60)]
+ public class DynamicObjectBenchmark
+ {
+ private static string _fileName = Path.Combine(Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName, "TestData", "JsonFormattedString.json"));
+ private JsonDocument _jsonDocument;
+ private ModelWithBinaryData _modelWithBinaryData;
+ private ModelWithObject _modelWithObject;
+
+ [GlobalSetup]
+ public void SetUp()
+ {
+ using var fs = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
+ _jsonDocument = JsonDocument.Parse(fs);
+
+ var anon = new
+ {
+ a = "properties.a.value",
+ innerProperties = new
+ {
+ a = "properties.innerProperties.a.value"
+ }
+ };
+
+ _modelWithBinaryData = new ModelWithBinaryData();
+ _modelWithBinaryData.A = "a.value";
+ _modelWithBinaryData.Properties = BinaryData.FromObjectAsJson(anon);
+
+ _modelWithObject = new ModelWithObject();
+ _modelWithObject.A = "a.value";
+ _modelWithObject.Properties = new Dictionary()
+ {
+ { "a", "a.value" },
+ { "innerProperties", new Dictionary()
+ {
+ {"a", "properties.innerProperties.a.value" }
+ }
+ }
+ };
+ }
+
+ [Benchmark]
+ public void DeserializeWithObject()
+ {
+ var model = ModelWithObject.DeserializeModelWithObject(_jsonDocument.RootElement);
+ }
+
+ [Benchmark]
+ public void DeserializeWithObjectAndAccess()
+ {
+ var model = ModelWithObject.DeserializeModelWithObject(_jsonDocument.RootElement);
+ var properties = model.Properties as Dictionary;
+ var innerProperties = properties["innerProperties"] as Dictionary;
+ var innerA = innerProperties["a"] as string;
+ }
+
+ [Benchmark]
+ public void SerializeWithObject()
+ {
+ using var ms = new MemoryStream();
+ using var writer = new Utf8JsonWriter(ms);
+ _modelWithObject.Write(writer);
+ }
+
+ [Benchmark]
+ public void DeserializeWithBinaryData()
+ {
+ var model = ModelWithBinaryData.DeserializeModelWithBinaryData(_jsonDocument.RootElement);
+ }
+
+ [Benchmark]
+ public void DeserializeWithBinaryDataAndAccess()
+ {
+ var model = ModelWithBinaryData.DeserializeModelWithBinaryData(_jsonDocument.RootElement);
+ var properties = model.Properties.ToDictionaryFromJson();
+ var innerProperties = properties["innerProperties"] as Dictionary;
+ var innerA = innerProperties["a"] as string;
+ }
+
+ [Benchmark]
+ public void SerializeWithBinaryData()
+ {
+ using var ms = new MemoryStream();
+ using var writer = new Utf8JsonWriter(ms);
+ _modelWithBinaryData.Write(writer);
+ }
+ }
+}
diff --git a/sdk/core/Azure.Core/perf/TestData/JsonFormattedString.json b/sdk/core/Azure.Core/perf/TestData/JsonFormattedString.json
new file mode 100644
index 0000000000000..fab40d4914a24
--- /dev/null
+++ b/sdk/core/Azure.Core/perf/TestData/JsonFormattedString.json
@@ -0,0 +1 @@
+{"a":"a.value","properties":{"a":"properties.a.value","innerProperties":{"a":"properties.innerProperties.a.value"}}}
diff --git a/sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs b/sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs
index 6d78a7eb8b567..e8194e9fbac42 100644
--- a/sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs
+++ b/sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs
@@ -2,6 +2,8 @@
// Licensed under the MIT License.
using System;
+using System.Collections.Generic;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Serialization;
@@ -40,5 +42,61 @@ public static class AzureCoreExtensions
///The data converted to the specified type.
public static async ValueTask ToObjectAsync(this BinaryData data, ObjectSerializer serializer, CancellationToken cancellationToken = default) =>
(T?)await serializer.DeserializeAsync(data.ToStream(), typeof(T), cancellationToken).ConfigureAwait(false);
+
+ ///
+ /// Converts the to a Dictionary of string to object.
+ /// Each value in the key value pair will be strongly typed as an int, long, string, Guid, double or bool.
+ /// Each value can also be another Dictionary of string object representing an inner object or
+ /// a List of objects representing an array.
+ ///
+ /// The instance to convert.
+ /// The data converted to the Dictionary of string to object.
+ public static IDictionary ToDictionaryFromJson(this BinaryData data)
+ {
+ JsonElement element = data.ToObjectFromJson();
+ return element.GetObject() as Dictionary ?? throw new InvalidOperationException("The BinaryData instance did not represent a JSON object so it cannot be converted into a dictionary.");
+ }
+
+ private static object? GetObject(in this JsonElement element)
+ {
+ switch (element.ValueKind)
+ {
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.Number:
+ if (element.TryGetInt32(out int intValue))
+ {
+ return intValue;
+ }
+ if (element.TryGetInt64(out long longValue))
+ {
+ return longValue;
+ }
+ return element.GetDouble();
+ case JsonValueKind.True:
+ return true;
+ case JsonValueKind.False:
+ return false;
+ case JsonValueKind.Undefined:
+ case JsonValueKind.Null:
+ return null;
+ case JsonValueKind.Object:
+ var dictionary = new Dictionary();
+ foreach (JsonProperty jsonProperty in element.EnumerateObject())
+ {
+ dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject());
+ }
+ return dictionary;
+ case JsonValueKind.Array:
+ var list = new List