Skip to content

Commit

Permalink
Initial move to separate model reader writer in System.ClientModel (#…
Browse files Browse the repository at this point in the history
…39478)

* initial move to separate model reader writer in System.Net.ClientModel

* update api

* update doc settings for readme

* address pr feedback

* first cut at readme / changelog

* fix perf issue in helper methods

* add perf for srcgen

* address feedback

* update IModel to have a GetWireFormat

* update api

* update ci

* remove GetOptions

* WIP on new format changes (#39817)

* wip on new format changes

* more tweaks to the API

* impl tweaks

* address feedback

* update api

* fix tests

* address feedback

* rename based on feedback (#39885)

* Remove wire (#40021)

* remove wire

* Update sdk/core/Azure.Core/tests/common/Internal/ModelReaderWriterHelper.cs

Co-authored-by: Anne Thompson <[email protected]>

* revert nullability since azure core tests don't support this right now

---------

Co-authored-by: Anne Thompson <[email protected]>

* Rename package (#40030)

* rename package

* comment out bad test

* feedback

* more feedback

* update basic sample

* remove next steps

* update docs

* address feedback

* remove unused frozen code

* address feedback

* address additional feedback

* update ci.yml

* move file inside mrw folder

* Add exception documentation

* move helper file

* update comment

* readme feedback

* follow static field convention

* remove unecessary interlock

* add azure sdk analyzers back

* throw when cancelled

* remove unused #if

* remove azureicon

* update readme

* fix package icon

* remove unnecessary conditions

---------

Co-authored-by: Anne Thompson <[email protected]>
  • Loading branch information
m-nash and annelo-msft authored Nov 22, 2023
1 parent 9af180c commit 8b96eb1
Show file tree
Hide file tree
Showing 199 changed files with 38,740 additions and 1 deletion.
1 change: 1 addition & 0 deletions eng/.docsettings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ known_content_issues:
- ['sdk/core/Microsoft.Azure.Core.NewtonsoftJson/README.md', 'https://github.com/Azure/azure-sdk-tools/issues/404']
- ['sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/README.md', 'https://github.com/Azure/azure-sdk-tools/issues/404']
- ['sdk/core/Microsoft.Azure.Core.Spatial/README.md', 'https://github.com/Azure/azure-sdk-tools/issues/404']
- ['sdk/core/System.ClientModel/README.md', 'Opt out of sections: https://github.com/Azure/azure-sdk-tools/issues/404']
- ['sdk/core/System.Memory.Data/README.md', 'Opt out of sections: https://github.com/Azure/azure-sdk-tools/issues/404']
- ['sdk/eventgrid/Microsoft.Azure.Messaging.EventGrid.CloudNativeCloudEvents/README.md', 'https://github.com/Azure/azure-sdk-tools/issues/404', 'Missing section: Azure .+ client library for .NET']
- ['sdk/eventhub/Azure.Messaging.EventHubs.Shared/README.md','https://github.com/Azure/azure-sdk-tools/issues/404']
Expand Down
File renamed without changes
30 changes: 30 additions & 0 deletions sdk/core/Azure.Core/Azure.Core.sln
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.Tests.Public", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.Tests.Common", "tests\common\Azure.Core.Tests.Common.csproj", "{0EEDF53F-120A-45B1-8468-A97A0D46DBAC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel", "..\System.ClientModel\src\System.ClientModel.csproj", "{70B67A2C-3CA5-44A0-AF2D-51241A0076E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel.Tests.Client", "..\System.ClientModel\tests\client\System.ClientModel.Tests.Client.csproj", "{062EA07F-5F75-4447-9453-44FF8A99EF1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel.Tests.Internal", "..\System.ClientModel\tests\internal\System.ClientModel.Tests.Internal.csproj", "{23F1EA7A-8576-4877-9B1D-1F1FDADB0EE9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel.Tests.Internal.Perf", "..\System.ClientModel\tests\internal.perf\System.ClientModel.Tests.Internal.Perf.csproj", "{2E79B809-C520-4A07-8BC2-23C43B4D3C35}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel.Tests", "..\System.ClientModel\tests\System.ClientModel.Tests.csproj", "{F317D37D-AA38-4557-A724-6ADA56281B77}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -131,6 +141,26 @@ Global
{0EEDF53F-120A-45B1-8468-A97A0D46DBAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EEDF53F-120A-45B1-8468-A97A0D46DBAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EEDF53F-120A-45B1-8468-A97A0D46DBAC}.Release|Any CPU.Build.0 = Release|Any CPU
{70B67A2C-3CA5-44A0-AF2D-51241A0076E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70B67A2C-3CA5-44A0-AF2D-51241A0076E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70B67A2C-3CA5-44A0-AF2D-51241A0076E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70B67A2C-3CA5-44A0-AF2D-51241A0076E2}.Release|Any CPU.Build.0 = Release|Any CPU
{062EA07F-5F75-4447-9453-44FF8A99EF1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{062EA07F-5F75-4447-9453-44FF8A99EF1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{062EA07F-5F75-4447-9453-44FF8A99EF1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{062EA07F-5F75-4447-9453-44FF8A99EF1B}.Release|Any CPU.Build.0 = Release|Any CPU
{23F1EA7A-8576-4877-9B1D-1F1FDADB0EE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23F1EA7A-8576-4877-9B1D-1F1FDADB0EE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23F1EA7A-8576-4877-9B1D-1F1FDADB0EE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23F1EA7A-8576-4877-9B1D-1F1FDADB0EE9}.Release|Any CPU.Build.0 = Release|Any CPU
{2E79B809-C520-4A07-8BC2-23C43B4D3C35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E79B809-C520-4A07-8BC2-23C43B4D3C35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E79B809-C520-4A07-8BC2-23C43B4D3C35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E79B809-C520-4A07-8BC2-23C43B4D3C35}.Release|Any CPU.Build.0 = Release|Any CPU
{F317D37D-AA38-4557-A724-6ADA56281B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F317D37D-AA38-4557-A724-6ADA56281B77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F317D37D-AA38-4557-A724-6ADA56281B77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F317D37D-AA38-4557-A724-6ADA56281B77}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
34 changes: 34 additions & 0 deletions sdk/core/Azure.Core/tests/common/Azure.Core.Tests.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<ProjectReference Include="..\..\..\Azure.Core.Experimental\src\Azure.Core.Experimental.csproj" />
<ProjectReference Include="..\..\..\System.ClientModel\src\System.ClientModel.csproj" />
<ProjectReference Include="..\..\src\Azure.Core.csproj" />
</ItemGroup>

Expand All @@ -15,4 +16,37 @@
<Compile Include="$(AzureCoreSharedSources)ArrayBufferWriter.cs" LinkBase="Shared/Core" />
</ItemGroup>

<ItemGroup>
<None Update="TestData\AvailabilitySetData\AvailabilitySetDataWithVMs.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\AvailabilitySetData\AvailabilitySetData.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\AvailabilitySetData\AvailabilitySetDataWithVMsWireFormat.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\AvailabilitySetData\AvailabilitySetDataWireFormat.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ModelXml.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ModelXmlX.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ResourceProviderData\ResourceProviderData-Collapsed.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ResourceProviderData\ResourceProviderData.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ModelX\ModelX.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\ModelX\ModelXWireFormat.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Runtime.CompilerServices;

namespace Azure.Core.Tests.Common
{
internal static class ModelReaderWriterHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateFormat<T>(IPersistableModel<T> model, string format)
{
bool implementsJson = model is IJsonModel<T>;
bool isValid = (format == "J" && implementsJson) || format == "W";
if (!isValid)
{
throw new FormatException($"The model {model.GetType().Name} does not support '{format}' format.");
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateFormat(IPersistableModel<object> model, string format) => ValidateFormat<object>(model, format);

private static ModelReaderWriterOptions _wireOptions;
public static ModelReaderWriterOptions WireOptions => _wireOptions ??= new ModelReaderWriterOptions("W");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Text.Json;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using Azure.Core.Tests.Common;

namespace Azure.Core.Tests.ModelReaderWriterTests.Models
{
[XmlRoot("ChildTag")]
public class ChildModelXml : IXmlSerializable, IPersistableModel<ChildModelXml>, IJsonModel<ChildModelXml>, IUtf8JsonSerializable
{
internal ChildModelXml() { }

/// <summary> Initializes a new instance of ModelXml for testing. </summary>
/// <param name="value"></param>
/// <exception cref="ArgumentNullException"> <paramref name="value"/> is null. </exception>
public ChildModelXml(string value, string readonlyProperty)
{
Argument.AssertNotNull(value, nameof(value));

ChildValue = value;
ChildReadOnlyProperty = readonlyProperty;
}

/// <summary> Gets or sets the value. </summary>
[XmlElement("ChildValue")]
public string ChildValue { get; set; }
/// <summary> Gets or sets the value. </summary>
[XmlElement("ChildReadOnlyProperty")]
public string ChildReadOnlyProperty { get; }

void IXmlSerializable.Write(XmlWriter writer, string nameHint) =>
Serialize(writer, ModelReaderWriterHelper.WireOptions, nameHint);

private void Serialize(XmlWriter writer, ModelReaderWriterOptions options, string nameHint)
{
writer.WriteStartElement(nameHint ?? "ChildTag");
writer.WriteStartElement("ChildValue");
writer.WriteValue(ChildValue);
writer.WriteEndElement();
if (options.Format == "J")
{
writer.WriteStartElement("ChildReadOnlyProperty");
writer.WriteValue(ChildReadOnlyProperty);
writer.WriteEndElement();
}
writer.WriteEndElement();
}

internal static ChildModelXml DeserializeChildModelXml(XElement element, ModelReaderWriterOptions options = default)
{
options ??= ModelReaderWriterHelper.WireOptions;

string value = default;
string readonlyProperty = default;
if (element.Element("ChildValue") is XElement valueElement)
{
value = (string)valueElement;
}
if (element.Element("ChildReadOnlyProperty") is XElement readonlyPropertyElement)
{
readonlyProperty = (string)readonlyPropertyElement;
}
return new ChildModelXml(value, readonlyProperty);
}

internal static ChildModelXml DeserializeChildModelXml(JsonElement element, ModelReaderWriterOptions options = default)
{
options ??= ModelReaderWriterHelper.WireOptions;

string childValue = default;
string childReadOnlyProperty = default;

Dictionary<string, BinaryData> rawData = new Dictionary<string, BinaryData>();
foreach (var property in element.EnumerateObject())
{
if (property.NameEquals("childValue"u8))
{
childValue = property.Value.GetString();
continue;
}
if (property.NameEquals("childReadOnlyProperty"u8))
{
childReadOnlyProperty = property.Value.GetString();
continue;
}
}
return new ChildModelXml(childValue, childReadOnlyProperty);
}

ChildModelXml IPersistableModel<ChildModelXml>.Create(BinaryData data, ModelReaderWriterOptions options)
{
ModelReaderWriterHelper.ValidateFormat(this, options.Format);

if (options.Format == "J")
{
using var doc = JsonDocument.Parse(data);
return DeserializeChildModelXml(doc.RootElement, options);
}
else
{
return DeserializeChildModelXml(XElement.Load(data.ToStream()), options);
}
}

BinaryData IPersistableModel<ChildModelXml>.Write(ModelReaderWriterOptions options)
{
ModelReaderWriterHelper.ValidateFormat(this, options.Format);

if (options.Format == "J")
{
return ModelReaderWriter.Write(this, options);
}
else
{
options ??= ModelReaderWriterHelper.WireOptions;
using MemoryStream stream = new MemoryStream();
using XmlWriter writer = XmlWriter.Create(stream);
Serialize(writer, options, null);
writer.Flush();
if (stream.Position > int.MaxValue)
{
return BinaryData.FromStream(stream);
}
else
{
return new BinaryData(stream.GetBuffer().AsMemory(0, (int)stream.Position));
}
}
}

private void Serialize(Utf8JsonWriter writer, ModelReaderWriterOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("childValue"u8);
writer.WriteStringValue(ChildValue);
if (options.Format == "J")
{
writer.WritePropertyName("childReadOnlyProperty"u8);
writer.WriteStringValue(ChildReadOnlyProperty);
}
writer.WriteEndObject();
}

void IJsonModel<ChildModelXml>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
{
ModelReaderWriterHelper.ValidateFormat(this, options.Format);

Serialize(writer, options);
}

ChildModelXml IJsonModel<ChildModelXml>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
{
ModelReaderWriterHelper.ValidateFormat(this, options.Format);

using var doc = JsonDocument.ParseValue(ref reader);
return DeserializeChildModelXml(doc.RootElement, options);
}

void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) =>
Serialize(writer, ModelReaderWriterHelper.WireOptions);

string IPersistableModel<ChildModelXml>.GetFormatFromOptions(ModelReaderWriterOptions options) => "X";
}
}
Loading

0 comments on commit 8b96eb1

Please sign in to comment.