diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.Serialization.cs
new file mode 100644
index 00000000000..5eae2515b59
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.Serialization.cs
@@ -0,0 +1,140 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ ///
+ /// Base plant with discriminator
+ /// Please note this is the abstract base class. The derived classes available for instantiation are: .
+ ///
+ [PersistableModelProxy(typeof(UnknownPlant))]
+ public abstract partial class Plant : IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal Plant()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Plant)} does not support writing '{format}' format.");
+ }
+ writer.WritePropertyName("species"u8);
+ writer.WriteStringValue(Species);
+ writer.WritePropertyName("id"u8);
+ writer.WriteStringValue(Id);
+ writer.WritePropertyName("height"u8);
+ writer.WriteNumberValue(Height);
+ if (options.Format != "W" && _additionalBinaryDataProperties != null)
+ {
+ foreach (var item in _additionalBinaryDataProperties)
+ {
+ writer.WritePropertyName(item.Key);
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ }
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ Plant IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected virtual Plant JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Plant)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializePlant(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static Plant DeserializePlant(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ if (element.TryGetProperty("species"u8, out JsonElement discriminator))
+ {
+ switch (discriminator.GetString())
+ {
+ case "tree":
+ return Tree.DeserializeTree(element, options);
+ }
+ }
+ return UnknownPlant.DeserializeUnknownPlant(element, options);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(Plant)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ Plant IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected virtual Plant PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializePlant(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(Plant)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.cs
new file mode 100644
index 00000000000..6ba6c56a52a
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Plant.cs
@@ -0,0 +1,52 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ ///
+ /// Base plant with discriminator
+ /// Please note this is the abstract base class. The derived classes available for instantiation are: .
+ ///
+ public abstract partial class Plant
+ {
+ /// Keeps track of any properties unknown to the library.
+ private protected readonly IDictionary _additionalBinaryDataProperties;
+
+ /// Initializes a new instance of .
+ /// The species of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ private protected Plant(string species, string id, int height)
+ {
+ Species = species;
+ Id = id;
+ Height = height;
+ }
+
+ /// Initializes a new instance of .
+ /// The species of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// Keeps track of any properties unknown to the library.
+ internal Plant(string species, string id, int height, IDictionary additionalBinaryDataProperties)
+ {
+ Species = species;
+ Id = id;
+ Height = height;
+ _additionalBinaryDataProperties = additionalBinaryDataProperties;
+ }
+
+ /// The species of plant.
+ internal string Species { get; set; }
+
+ /// The unique identifier of the plant.
+ public string Id { get; }
+
+ /// The height of the plant in centimeters.
+ public int Height { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs
index acbd82d2f33..d24dba74895 100644
--- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/SampleTypeSpecContext.cs
@@ -24,12 +24,19 @@ namespace SampleTypeSpec
[ModelReaderWriterBuildable(typeof(ModelWithRequiredNullableProperties))]
[ModelReaderWriterBuildable(typeof(PageThing))]
[ModelReaderWriterBuildable(typeof(Pet))]
+ [ModelReaderWriterBuildable(typeof(Plant))]
[ModelReaderWriterBuildable(typeof(RenamedModel))]
[ModelReaderWriterBuildable(typeof(ReturnsAnonymousModelResponse))]
[ModelReaderWriterBuildable(typeof(RoundTripModel))]
[ModelReaderWriterBuildable(typeof(Thing))]
+ [ModelReaderWriterBuildable(typeof(Tree))]
[ModelReaderWriterBuildable(typeof(UnknownAnimal))]
[ModelReaderWriterBuildable(typeof(UnknownPet))]
+ [ModelReaderWriterBuildable(typeof(UnknownPlant))]
+ [ModelReaderWriterBuildable(typeof(XmlAdvancedModel))]
+ [ModelReaderWriterBuildable(typeof(XmlItem))]
+ [ModelReaderWriterBuildable(typeof(XmlModelWithNamespace))]
+ [ModelReaderWriterBuildable(typeof(XmlNestedModel))]
public partial class SampleTypeSpecContext : ModelReaderWriterContext
{
}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.Serialization.cs
new file mode 100644
index 00000000000..9795daa7a3f
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.Serialization.cs
@@ -0,0 +1,152 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// Tree is a specific type of plant.
+ public partial class Tree : Plant, IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal Tree()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Tree)} does not support writing '{format}' format.");
+ }
+ base.JsonModelWriteCore(writer, options);
+ writer.WritePropertyName("age"u8);
+ writer.WriteNumberValue(Age);
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ Tree IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => (Tree)JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected override Plant JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Tree)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializeTree(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static Tree DeserializeTree(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string species = "tree";
+ string id = default;
+ int height = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ int age = default;
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("species"u8))
+ {
+ species = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("id"u8))
+ {
+ id = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("height"u8))
+ {
+ height = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("age"u8))
+ {
+ age = prop.Value.GetInt32();
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new Tree(species, id, height, additionalBinaryDataProperties, age);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(Tree)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ Tree IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => (Tree)PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected override Plant PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializeTree(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(Tree)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+
+ /// The to deserialize the from.
+ public static explicit operator Tree(ClientResult result)
+ {
+ using PipelineResponse response = result.GetRawResponse();
+ using JsonDocument document = JsonDocument.Parse(response.Content);
+ return DeserializeTree(document.RootElement, ModelSerializationExtensions.WireOptions);
+ }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.cs
new file mode 100644
index 00000000000..acdeb24ca48
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/Tree.cs
@@ -0,0 +1,36 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ /// Tree is a specific type of plant.
+ public partial class Tree : Plant
+ {
+ /// Initializes a new instance of .
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// The age of the tree in years.
+ internal Tree(string id, int height, int age) : base("tree", id, height)
+ {
+ Age = age;
+ }
+
+ /// Initializes a new instance of .
+ /// The species of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// Keeps track of any properties unknown to the library.
+ /// The age of the tree in years.
+ internal Tree(string species, string id, int height, IDictionary additionalBinaryDataProperties, int age) : base(species, id, height, additionalBinaryDataProperties)
+ {
+ Age = age;
+ }
+
+ /// The age of the tree in years.
+ public int Age { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.Serialization.cs
new file mode 100644
index 00000000000..4aa376053e4
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.Serialization.cs
@@ -0,0 +1,134 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ internal partial class UnknownPlant : Plant, IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal UnknownPlant()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Plant)} does not support writing '{format}' format.");
+ }
+ base.JsonModelWriteCore(writer, options);
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ Plant IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected override Plant JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(Plant)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializePlant(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static UnknownPlant DeserializeUnknownPlant(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string species = "unknown";
+ string id = default;
+ int height = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("species"u8))
+ {
+ species = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("id"u8))
+ {
+ id = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("height"u8))
+ {
+ height = prop.Value.GetInt32();
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new UnknownPlant(species, id, height, additionalBinaryDataProperties);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(Plant)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ Plant IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected override Plant PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializePlant(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(Plant)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.cs
new file mode 100644
index 00000000000..7e2e30cea3a
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/UnknownPlant.cs
@@ -0,0 +1,21 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ internal partial class UnknownPlant : Plant
+ {
+ /// Initializes a new instance of .
+ /// The species of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// Keeps track of any properties unknown to the library.
+ internal UnknownPlant(string species, string id, int height, IDictionary additionalBinaryDataProperties) : base(species ?? "unknown", id, height, additionalBinaryDataProperties)
+ {
+ }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.Serialization.cs
new file mode 100644
index 00000000000..b96b5cc7205
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.Serialization.cs
@@ -0,0 +1,675 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// An advanced XML model for testing various property types and XML features.
+ public partial class XmlAdvancedModel : IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal XmlAdvancedModel()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlAdvancedModel)} does not support writing '{format}' format.");
+ }
+ writer.WritePropertyName("name"u8);
+ writer.WriteStringValue(Name);
+ writer.WritePropertyName("age"u8);
+ writer.WriteNumberValue(Age);
+ writer.WritePropertyName("enabled"u8);
+ writer.WriteBooleanValue(Enabled);
+ writer.WritePropertyName("score"u8);
+ writer.WriteNumberValue(Score);
+ if (Optional.IsDefined(OptionalString))
+ {
+ writer.WritePropertyName("optionalString"u8);
+ writer.WriteStringValue(OptionalString);
+ }
+ if (Optional.IsDefined(OptionalInt))
+ {
+ writer.WritePropertyName("optionalInt"u8);
+ writer.WriteNumberValue(OptionalInt.Value);
+ }
+ if (Optional.IsDefined(NullableString))
+ {
+ writer.WritePropertyName("nullableString"u8);
+ writer.WriteStringValue(NullableString);
+ }
+ else
+ {
+ writer.WriteNull("nullableString"u8);
+ }
+ writer.WritePropertyName("id"u8);
+ writer.WriteStringValue(Id);
+ writer.WritePropertyName("version"u8);
+ writer.WriteNumberValue(Version);
+ writer.WritePropertyName("isActive"u8);
+ writer.WriteBooleanValue(IsActive);
+ writer.WritePropertyName("RenamedProperty"u8);
+ writer.WriteStringValue(OriginalName);
+ writer.WritePropertyName("xml-id"u8);
+ writer.WriteStringValue(XmlIdentifier);
+ writer.WritePropertyName("content"u8);
+ writer.WriteStringValue(Content);
+ writer.WritePropertyName("unwrappedStrings"u8);
+ writer.WriteStartArray();
+ foreach (string item in UnwrappedStrings)
+ {
+ if (item == null)
+ {
+ writer.WriteNullValue();
+ continue;
+ }
+ writer.WriteStringValue(item);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("unwrappedCounts"u8);
+ writer.WriteStartArray();
+ foreach (int item in UnwrappedCounts)
+ {
+ writer.WriteNumberValue(item);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("unwrappedItems"u8);
+ writer.WriteStartArray();
+ foreach (XmlItem item in UnwrappedItems)
+ {
+ writer.WriteObjectValue(item, options);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("wrappedColors"u8);
+ writer.WriteStartArray();
+ foreach (string item in WrappedColors)
+ {
+ if (item == null)
+ {
+ writer.WriteNullValue();
+ continue;
+ }
+ writer.WriteStringValue(item);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("ItemCollection"u8);
+ writer.WriteStartArray();
+ foreach (XmlItem item in Items)
+ {
+ writer.WriteObjectValue(item, options);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("nestedModel"u8);
+ writer.WriteObjectValue(NestedModel, options);
+ if (Optional.IsDefined(OptionalNestedModel))
+ {
+ writer.WritePropertyName("optionalNestedModel"u8);
+ writer.WriteObjectValue(OptionalNestedModel, options);
+ }
+ writer.WritePropertyName("metadata"u8);
+ writer.WriteStartObject();
+ foreach (var item in Metadata)
+ {
+ writer.WritePropertyName(item.Key);
+ if (item.Value == null)
+ {
+ writer.WriteNullValue();
+ continue;
+ }
+ writer.WriteStringValue(item.Value);
+ }
+ writer.WriteEndObject();
+ writer.WritePropertyName("createdAt"u8);
+ writer.WriteStringValue(CreatedAt, "O");
+ writer.WritePropertyName("duration"u8);
+ writer.WriteStringValue(Duration, "P");
+ writer.WritePropertyName("data"u8);
+ writer.WriteBase64StringValue(Data.ToArray(), "D");
+ if (Optional.IsCollectionDefined(OptionalRecordUnknown))
+ {
+ writer.WritePropertyName("optionalRecordUnknown"u8);
+ writer.WriteStartObject();
+ foreach (var item in OptionalRecordUnknown)
+ {
+ writer.WritePropertyName(item.Key);
+ if (item.Value == null)
+ {
+ writer.WriteNullValue();
+ continue;
+ }
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ writer.WriteEndObject();
+ }
+ writer.WritePropertyName("fixedEnum"u8);
+ writer.WriteStringValue(FixedEnum.ToSerialString());
+ writer.WritePropertyName("extensibleEnum"u8);
+ writer.WriteStringValue(ExtensibleEnum.ToString());
+ if (Optional.IsDefined(OptionalFixedEnum))
+ {
+ writer.WritePropertyName("optionalFixedEnum"u8);
+ writer.WriteNumberValue((int)OptionalFixedEnum.Value);
+ }
+ if (Optional.IsDefined(OptionalExtensibleEnum))
+ {
+ writer.WritePropertyName("optionalExtensibleEnum"u8);
+ writer.WriteNumberValue(OptionalExtensibleEnum.Value.ToSerialInt32());
+ }
+ writer.WritePropertyName("label"u8);
+ writer.WriteStringValue(Label);
+ writer.WritePropertyName("daysUsed"u8);
+ writer.WriteNumberValue(DaysUsed);
+ writer.WritePropertyName("fooItems"u8);
+ writer.WriteStartArray();
+ foreach (string item in FooItems)
+ {
+ if (item == null)
+ {
+ writer.WriteNullValue();
+ continue;
+ }
+ writer.WriteStringValue(item);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("anotherModel"u8);
+ writer.WriteObjectValue(AnotherModel, options);
+ writer.WritePropertyName("modelsWithNamespaces"u8);
+ writer.WriteStartArray();
+ foreach (XmlModelWithNamespace item in ModelsWithNamespaces)
+ {
+ writer.WriteObjectValue(item, options);
+ }
+ writer.WriteEndArray();
+ writer.WritePropertyName("unwrappedModelsWithNamespaces"u8);
+ writer.WriteStartArray();
+ foreach (XmlModelWithNamespace item in UnwrappedModelsWithNamespaces)
+ {
+ writer.WriteObjectValue(item, options);
+ }
+ writer.WriteEndArray();
+ if (options.Format != "W" && _additionalBinaryDataProperties != null)
+ {
+ foreach (var item in _additionalBinaryDataProperties)
+ {
+ writer.WritePropertyName(item.Key);
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ }
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ XmlAdvancedModel IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected virtual XmlAdvancedModel JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlAdvancedModel)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializeXmlAdvancedModel(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static XmlAdvancedModel DeserializeXmlAdvancedModel(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string name = default;
+ int age = default;
+ bool enabled = default;
+ float score = default;
+ string optionalString = default;
+ int? optionalInt = default;
+ string nullableString = default;
+ string id = default;
+ int version = default;
+ bool isActive = default;
+ string originalName = default;
+ string xmlIdentifier = default;
+ string content = default;
+ IList unwrappedStrings = default;
+ IList unwrappedCounts = default;
+ IList unwrappedItems = default;
+ IList wrappedColors = default;
+ IList items = default;
+ XmlNestedModel nestedModel = default;
+ XmlNestedModel optionalNestedModel = default;
+ IDictionary metadata = default;
+ DateTimeOffset createdAt = default;
+ TimeSpan duration = default;
+ BinaryData data = default;
+ IDictionary optionalRecordUnknown = default;
+ StringFixedEnum fixedEnum = default;
+ StringExtensibleEnum extensibleEnum = default;
+ IntFixedEnum? optionalFixedEnum = default;
+ IntExtensibleEnum? optionalExtensibleEnum = default;
+ string label = default;
+ int daysUsed = default;
+ IList fooItems = default;
+ XmlNestedModel anotherModel = default;
+ IList modelsWithNamespaces = default;
+ IList unwrappedModelsWithNamespaces = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("name"u8))
+ {
+ name = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("age"u8))
+ {
+ age = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("enabled"u8))
+ {
+ enabled = prop.Value.GetBoolean();
+ continue;
+ }
+ if (prop.NameEquals("score"u8))
+ {
+ score = prop.Value.GetSingle();
+ continue;
+ }
+ if (prop.NameEquals("optionalString"u8))
+ {
+ optionalString = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("optionalInt"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ continue;
+ }
+ optionalInt = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("nullableString"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ nullableString = null;
+ continue;
+ }
+ nullableString = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("id"u8))
+ {
+ id = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("version"u8))
+ {
+ version = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("isActive"u8))
+ {
+ isActive = prop.Value.GetBoolean();
+ continue;
+ }
+ if (prop.NameEquals("RenamedProperty"u8))
+ {
+ originalName = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("xml-id"u8))
+ {
+ xmlIdentifier = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("content"u8))
+ {
+ content = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("unwrappedStrings"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ if (item.ValueKind == JsonValueKind.Null)
+ {
+ array.Add(null);
+ }
+ else
+ {
+ array.Add(item.GetString());
+ }
+ }
+ unwrappedStrings = array;
+ continue;
+ }
+ if (prop.NameEquals("unwrappedCounts"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ array.Add(item.GetInt32());
+ }
+ unwrappedCounts = array;
+ continue;
+ }
+ if (prop.NameEquals("unwrappedItems"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ array.Add(XmlItem.DeserializeXmlItem(item, options));
+ }
+ unwrappedItems = array;
+ continue;
+ }
+ if (prop.NameEquals("wrappedColors"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ if (item.ValueKind == JsonValueKind.Null)
+ {
+ array.Add(null);
+ }
+ else
+ {
+ array.Add(item.GetString());
+ }
+ }
+ wrappedColors = array;
+ continue;
+ }
+ if (prop.NameEquals("ItemCollection"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ array.Add(XmlItem.DeserializeXmlItem(item, options));
+ }
+ items = array;
+ continue;
+ }
+ if (prop.NameEquals("nestedModel"u8))
+ {
+ nestedModel = XmlNestedModel.DeserializeXmlNestedModel(prop.Value, options);
+ continue;
+ }
+ if (prop.NameEquals("optionalNestedModel"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ continue;
+ }
+ optionalNestedModel = XmlNestedModel.DeserializeXmlNestedModel(prop.Value, options);
+ continue;
+ }
+ if (prop.NameEquals("metadata"u8))
+ {
+ Dictionary dictionary = new Dictionary();
+ foreach (var prop0 in prop.Value.EnumerateObject())
+ {
+ if (prop0.Value.ValueKind == JsonValueKind.Null)
+ {
+ dictionary.Add(prop0.Name, null);
+ }
+ else
+ {
+ dictionary.Add(prop0.Name, prop0.Value.GetString());
+ }
+ }
+ metadata = dictionary;
+ continue;
+ }
+ if (prop.NameEquals("createdAt"u8))
+ {
+ createdAt = prop.Value.GetDateTimeOffset("O");
+ continue;
+ }
+ if (prop.NameEquals("duration"u8))
+ {
+ duration = prop.Value.GetTimeSpan("P");
+ continue;
+ }
+ if (prop.NameEquals("data"u8))
+ {
+ data = BinaryData.FromBytes(prop.Value.GetBytesFromBase64("D"));
+ continue;
+ }
+ if (prop.NameEquals("optionalRecordUnknown"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ continue;
+ }
+ Dictionary dictionary = new Dictionary();
+ foreach (var prop0 in prop.Value.EnumerateObject())
+ {
+ if (prop0.Value.ValueKind == JsonValueKind.Null)
+ {
+ dictionary.Add(prop0.Name, null);
+ }
+ else
+ {
+ dictionary.Add(prop0.Name, BinaryData.FromString(prop0.Value.GetRawText()));
+ }
+ }
+ optionalRecordUnknown = dictionary;
+ continue;
+ }
+ if (prop.NameEquals("fixedEnum"u8))
+ {
+ fixedEnum = prop.Value.GetString().ToStringFixedEnum();
+ continue;
+ }
+ if (prop.NameEquals("extensibleEnum"u8))
+ {
+ extensibleEnum = new StringExtensibleEnum(prop.Value.GetString());
+ continue;
+ }
+ if (prop.NameEquals("optionalFixedEnum"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ continue;
+ }
+ optionalFixedEnum = prop.Value.GetInt32().ToIntFixedEnum();
+ continue;
+ }
+ if (prop.NameEquals("optionalExtensibleEnum"u8))
+ {
+ if (prop.Value.ValueKind == JsonValueKind.Null)
+ {
+ continue;
+ }
+ optionalExtensibleEnum = new IntExtensibleEnum(prop.Value.GetInt32());
+ continue;
+ }
+ if (prop.NameEquals("label"u8))
+ {
+ label = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("daysUsed"u8))
+ {
+ daysUsed = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("fooItems"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ if (item.ValueKind == JsonValueKind.Null)
+ {
+ array.Add(null);
+ }
+ else
+ {
+ array.Add(item.GetString());
+ }
+ }
+ fooItems = array;
+ continue;
+ }
+ if (prop.NameEquals("anotherModel"u8))
+ {
+ anotherModel = XmlNestedModel.DeserializeXmlNestedModel(prop.Value, options);
+ continue;
+ }
+ if (prop.NameEquals("modelsWithNamespaces"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ array.Add(XmlModelWithNamespace.DeserializeXmlModelWithNamespace(item, options));
+ }
+ modelsWithNamespaces = array;
+ continue;
+ }
+ if (prop.NameEquals("unwrappedModelsWithNamespaces"u8))
+ {
+ List array = new List();
+ foreach (var item in prop.Value.EnumerateArray())
+ {
+ array.Add(XmlModelWithNamespace.DeserializeXmlModelWithNamespace(item, options));
+ }
+ unwrappedModelsWithNamespaces = array;
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new XmlAdvancedModel(
+ name,
+ age,
+ enabled,
+ score,
+ optionalString,
+ optionalInt,
+ nullableString,
+ id,
+ version,
+ isActive,
+ originalName,
+ xmlIdentifier,
+ content,
+ unwrappedStrings,
+ unwrappedCounts,
+ unwrappedItems,
+ wrappedColors,
+ items,
+ nestedModel,
+ optionalNestedModel,
+ metadata,
+ createdAt,
+ duration,
+ data,
+ optionalRecordUnknown ?? new ChangeTrackingDictionary(),
+ fixedEnum,
+ extensibleEnum,
+ optionalFixedEnum,
+ optionalExtensibleEnum,
+ label,
+ daysUsed,
+ fooItems,
+ anotherModel,
+ modelsWithNamespaces,
+ unwrappedModelsWithNamespaces,
+ additionalBinaryDataProperties);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(XmlAdvancedModel)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ XmlAdvancedModel IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected virtual XmlAdvancedModel PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializeXmlAdvancedModel(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(XmlAdvancedModel)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+
+ /// The to deserialize the from.
+ public static explicit operator XmlAdvancedModel(ClientResult result)
+ {
+ using PipelineResponse response = result.GetRawResponse();
+ using JsonDocument document = JsonDocument.Parse(response.Content);
+ return DeserializeXmlAdvancedModel(document.RootElement, ModelSerializationExtensions.WireOptions);
+ }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.cs
new file mode 100644
index 00000000000..e927de1c51d
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlAdvancedModel.cs
@@ -0,0 +1,304 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// An advanced XML model for testing various property types and XML features.
+ public partial class XmlAdvancedModel
+ {
+ /// Keeps track of any properties unknown to the library.
+ private protected readonly IDictionary _additionalBinaryDataProperties;
+
+ /// Initializes a new instance of .
+ /// A simple string property.
+ /// An integer property.
+ /// A boolean property.
+ /// A float property.
+ /// A nullable string.
+ /// A string as XML attribute.
+ /// An integer as XML attribute.
+ /// A boolean as XML attribute.
+ /// A property with a custom XML element name.
+ /// An attribute with a custom XML name.
+ /// Text content in the element (unwrapped string).
+ /// An unwrapped array of strings - items appear directly without wrapper.
+ /// An unwrapped array of integers.
+ /// An unwrapped array of models.
+ /// A wrapped array of strings (default).
+ /// A wrapped array with custom wrapper name.
+ /// A nested model property.
+ /// A dictionary property.
+ /// A date-time property.
+ /// A duration property.
+ /// A bytes property.
+ /// A fixed enum property.
+ /// An extensible enum property.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal XmlAdvancedModel(string name, int age, bool enabled, float score, string nullableString, string id, int version, bool isActive, string originalName, string xmlIdentifier, string content, IEnumerable unwrappedStrings, IEnumerable unwrappedCounts, IEnumerable unwrappedItems, IEnumerable wrappedColors, IEnumerable items, XmlNestedModel nestedModel, IDictionary metadata, DateTimeOffset createdAt, TimeSpan duration, BinaryData data, StringFixedEnum fixedEnum, StringExtensibleEnum extensibleEnum, string label, int daysUsed, IEnumerable fooItems, XmlNestedModel anotherModel, IEnumerable modelsWithNamespaces, IEnumerable unwrappedModelsWithNamespaces)
+ {
+ Name = name;
+ Age = age;
+ Enabled = enabled;
+ Score = score;
+ NullableString = nullableString;
+ Id = id;
+ Version = version;
+ IsActive = isActive;
+ OriginalName = originalName;
+ XmlIdentifier = xmlIdentifier;
+ Content = content;
+ UnwrappedStrings = unwrappedStrings.ToList();
+ UnwrappedCounts = unwrappedCounts.ToList();
+ UnwrappedItems = unwrappedItems.ToList();
+ WrappedColors = wrappedColors.ToList();
+ Items = items.ToList();
+ NestedModel = nestedModel;
+ Metadata = metadata;
+ CreatedAt = createdAt;
+ Duration = duration;
+ Data = data;
+ OptionalRecordUnknown = new ChangeTrackingDictionary();
+ FixedEnum = fixedEnum;
+ ExtensibleEnum = extensibleEnum;
+ Label = label;
+ DaysUsed = daysUsed;
+ FooItems = fooItems.ToList();
+ AnotherModel = anotherModel;
+ ModelsWithNamespaces = modelsWithNamespaces.ToList();
+ UnwrappedModelsWithNamespaces = unwrappedModelsWithNamespaces.ToList();
+ }
+
+ /// Initializes a new instance of .
+ /// A simple string property.
+ /// An integer property.
+ /// A boolean property.
+ /// A float property.
+ /// An optional string.
+ /// An optional integer.
+ /// A nullable string.
+ /// A string as XML attribute.
+ /// An integer as XML attribute.
+ /// A boolean as XML attribute.
+ /// A property with a custom XML element name.
+ /// An attribute with a custom XML name.
+ /// Text content in the element (unwrapped string).
+ /// An unwrapped array of strings - items appear directly without wrapper.
+ /// An unwrapped array of integers.
+ /// An unwrapped array of models.
+ /// A wrapped array of strings (default).
+ /// A wrapped array with custom wrapper name.
+ /// A nested model property.
+ /// An optional nested model.
+ /// A dictionary property.
+ /// A date-time property.
+ /// A duration property.
+ /// A bytes property.
+ /// optional record of unknown.
+ /// A fixed enum property.
+ /// An extensible enum property.
+ /// An optional fixed enum property.
+ /// An optional extensible enum property.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Keeps track of any properties unknown to the library.
+ internal XmlAdvancedModel(string name, int age, bool enabled, float score, string optionalString, int? optionalInt, string nullableString, string id, int version, bool isActive, string originalName, string xmlIdentifier, string content, IList unwrappedStrings, IList unwrappedCounts, IList unwrappedItems, IList wrappedColors, IList items, XmlNestedModel nestedModel, XmlNestedModel optionalNestedModel, IDictionary metadata, DateTimeOffset createdAt, TimeSpan duration, BinaryData data, IDictionary optionalRecordUnknown, StringFixedEnum fixedEnum, StringExtensibleEnum extensibleEnum, IntFixedEnum? optionalFixedEnum, IntExtensibleEnum? optionalExtensibleEnum, string label, int daysUsed, IList fooItems, XmlNestedModel anotherModel, IList modelsWithNamespaces, IList unwrappedModelsWithNamespaces, IDictionary additionalBinaryDataProperties)
+ {
+ Name = name;
+ Age = age;
+ Enabled = enabled;
+ Score = score;
+ OptionalString = optionalString;
+ OptionalInt = optionalInt;
+ NullableString = nullableString;
+ Id = id;
+ Version = version;
+ IsActive = isActive;
+ OriginalName = originalName;
+ XmlIdentifier = xmlIdentifier;
+ Content = content;
+ UnwrappedStrings = unwrappedStrings;
+ UnwrappedCounts = unwrappedCounts;
+ UnwrappedItems = unwrappedItems;
+ WrappedColors = wrappedColors;
+ Items = items;
+ NestedModel = nestedModel;
+ OptionalNestedModel = optionalNestedModel;
+ Metadata = metadata;
+ CreatedAt = createdAt;
+ Duration = duration;
+ Data = data;
+ OptionalRecordUnknown = optionalRecordUnknown;
+ FixedEnum = fixedEnum;
+ ExtensibleEnum = extensibleEnum;
+ OptionalFixedEnum = optionalFixedEnum;
+ OptionalExtensibleEnum = optionalExtensibleEnum;
+ Label = label;
+ DaysUsed = daysUsed;
+ FooItems = fooItems;
+ AnotherModel = anotherModel;
+ ModelsWithNamespaces = modelsWithNamespaces;
+ UnwrappedModelsWithNamespaces = unwrappedModelsWithNamespaces;
+ _additionalBinaryDataProperties = additionalBinaryDataProperties;
+ }
+
+ /// A simple string property.
+ public string Name { get; }
+
+ /// An integer property.
+ public int Age { get; }
+
+ /// A boolean property.
+ public bool Enabled { get; }
+
+ /// A float property.
+ public float Score { get; }
+
+ /// An optional string.
+ public string OptionalString { get; }
+
+ /// An optional integer.
+ public int? OptionalInt { get; }
+
+ /// A nullable string.
+ public string NullableString { get; }
+
+ /// A string as XML attribute.
+ public string Id { get; }
+
+ /// An integer as XML attribute.
+ public int Version { get; }
+
+ /// A boolean as XML attribute.
+ public bool IsActive { get; }
+
+ /// A property with a custom XML element name.
+ public string OriginalName { get; }
+
+ /// An attribute with a custom XML name.
+ public string XmlIdentifier { get; }
+
+ /// Text content in the element (unwrapped string).
+ public string Content { get; }
+
+ /// An unwrapped array of strings - items appear directly without wrapper.
+ public IList UnwrappedStrings { get; }
+
+ /// An unwrapped array of integers.
+ public IList UnwrappedCounts { get; }
+
+ /// An unwrapped array of models.
+ public IList UnwrappedItems { get; }
+
+ /// A wrapped array of strings (default).
+ public IList WrappedColors { get; }
+
+ /// A wrapped array with custom wrapper name.
+ public IList Items { get; }
+
+ /// A nested model property.
+ public XmlNestedModel NestedModel { get; }
+
+ /// An optional nested model.
+ public XmlNestedModel OptionalNestedModel { get; }
+
+ /// A dictionary property.
+ public IDictionary Metadata { get; }
+
+ /// A date-time property.
+ public DateTimeOffset CreatedAt { get; }
+
+ /// A duration property.
+ public TimeSpan Duration { get; }
+
+ ///
+ /// A bytes property
+ ///
+ /// To assign a byte[] to this property use .
+ /// The byte[] will be serialized to a Base64 encoded string.
+ ///
+ ///
+ /// Examples:
+ ///
+ /// -
+ /// BinaryData.FromBytes(new byte[] { 1, 2, 3 }).
+ /// Creates a payload of "AQID".
+ ///
+ ///
+ ///
+ ///
+ public BinaryData Data { get; }
+
+ ///
+ /// optional record of unknown
+ /// To assign an object to the value of this property use .
+ /// To assign an already formatted json string to this property use .
+ ///
+ /// Examples:
+ ///
+ /// -
+ /// BinaryData.FromObjectAsJson("foo").
+ /// Creates a payload of "foo".
+ ///
+ /// -
+ /// BinaryData.FromString("\"foo\"").
+ /// Creates a payload of "foo".
+ ///
+ /// -
+ /// BinaryData.FromObjectAsJson(new { key = "value" }).
+ /// Creates a payload of { "key": "value" }.
+ ///
+ /// -
+ /// BinaryData.FromString("{\"key\": \"value\"}").
+ /// Creates a payload of { "key": "value" }.
+ ///
+ ///
+ ///
+ ///
+ public IDictionary OptionalRecordUnknown { get; }
+
+ /// A fixed enum property.
+ public StringFixedEnum FixedEnum { get; }
+
+ /// An extensible enum property.
+ public StringExtensibleEnum ExtensibleEnum { get; }
+
+ /// An optional fixed enum property.
+ public IntFixedEnum? OptionalFixedEnum { get; }
+
+ /// An optional extensible enum property.
+ public IntExtensibleEnum? OptionalExtensibleEnum { get; }
+
+ /// Gets the Label.
+ public string Label { get; }
+
+ /// Gets the DaysUsed.
+ public int DaysUsed { get; }
+
+ /// Gets the FooItems.
+ public IList FooItems { get; }
+
+ /// Gets the AnotherModel.
+ public XmlNestedModel AnotherModel { get; }
+
+ /// Gets the ModelsWithNamespaces.
+ public IList ModelsWithNamespaces { get; }
+
+ /// Gets the UnwrappedModelsWithNamespaces.
+ public IList UnwrappedModelsWithNamespaces { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.Serialization.cs
new file mode 100644
index 00000000000..4ff55dda314
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.Serialization.cs
@@ -0,0 +1,155 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// An item model for XML array testing.
+ public partial class XmlItem : IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal XmlItem()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlItem)} does not support writing '{format}' format.");
+ }
+ writer.WritePropertyName("itemName"u8);
+ writer.WriteStringValue(ItemName);
+ writer.WritePropertyName("itemValue"u8);
+ writer.WriteNumberValue(ItemValue);
+ writer.WritePropertyName("itemId"u8);
+ writer.WriteStringValue(ItemId);
+ if (options.Format != "W" && _additionalBinaryDataProperties != null)
+ {
+ foreach (var item in _additionalBinaryDataProperties)
+ {
+ writer.WritePropertyName(item.Key);
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ }
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ XmlItem IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected virtual XmlItem JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlItem)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializeXmlItem(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static XmlItem DeserializeXmlItem(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string itemName = default;
+ int itemValue = default;
+ string itemId = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("itemName"u8))
+ {
+ itemName = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("itemValue"u8))
+ {
+ itemValue = prop.Value.GetInt32();
+ continue;
+ }
+ if (prop.NameEquals("itemId"u8))
+ {
+ itemId = prop.Value.GetString();
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new XmlItem(itemName, itemValue, itemId, additionalBinaryDataProperties);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(XmlItem)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ XmlItem IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected virtual XmlItem PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializeXmlItem(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(XmlItem)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.cs
new file mode 100644
index 00000000000..e291e9324a7
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlItem.cs
@@ -0,0 +1,49 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ /// An item model for XML array testing.
+ public partial class XmlItem
+ {
+ /// Keeps track of any properties unknown to the library.
+ private protected readonly IDictionary _additionalBinaryDataProperties;
+
+ /// Initializes a new instance of .
+ /// The item name.
+ /// The item value.
+ /// Item ID as attribute.
+ internal XmlItem(string itemName, int itemValue, string itemId)
+ {
+ ItemName = itemName;
+ ItemValue = itemValue;
+ ItemId = itemId;
+ }
+
+ /// Initializes a new instance of .
+ /// The item name.
+ /// The item value.
+ /// Item ID as attribute.
+ /// Keeps track of any properties unknown to the library.
+ internal XmlItem(string itemName, int itemValue, string itemId, IDictionary additionalBinaryDataProperties)
+ {
+ ItemName = itemName;
+ ItemValue = itemValue;
+ ItemId = itemId;
+ _additionalBinaryDataProperties = additionalBinaryDataProperties;
+ }
+
+ /// The item name.
+ public string ItemName { get; }
+
+ /// The item value.
+ public int ItemValue { get; }
+
+ /// Item ID as attribute.
+ public string ItemId { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.Serialization.cs
new file mode 100644
index 00000000000..35865a54fae
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.Serialization.cs
@@ -0,0 +1,139 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// The XmlModelWithNamespace.
+ public partial class XmlModelWithNamespace : IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal XmlModelWithNamespace()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlModelWithNamespace)} does not support writing '{format}' format.");
+ }
+ writer.WritePropertyName("foo"u8);
+ writer.WriteStringValue(Foo);
+ if (options.Format != "W" && _additionalBinaryDataProperties != null)
+ {
+ foreach (var item in _additionalBinaryDataProperties)
+ {
+ writer.WritePropertyName(item.Key);
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ }
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ XmlModelWithNamespace IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected virtual XmlModelWithNamespace JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlModelWithNamespace)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializeXmlModelWithNamespace(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static XmlModelWithNamespace DeserializeXmlModelWithNamespace(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string foo = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("foo"u8))
+ {
+ foo = prop.Value.GetString();
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new XmlModelWithNamespace(foo, additionalBinaryDataProperties);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(XmlModelWithNamespace)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ XmlModelWithNamespace IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected virtual XmlModelWithNamespace PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializeXmlModelWithNamespace(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(XmlModelWithNamespace)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.cs
new file mode 100644
index 00000000000..c3b9a6294ec
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlModelWithNamespace.cs
@@ -0,0 +1,35 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ /// The XmlModelWithNamespace.
+ public partial class XmlModelWithNamespace
+ {
+ /// Keeps track of any properties unknown to the library.
+ private protected readonly IDictionary _additionalBinaryDataProperties;
+
+ /// Initializes a new instance of .
+ ///
+ internal XmlModelWithNamespace(string foo)
+ {
+ Foo = foo;
+ }
+
+ /// Initializes a new instance of .
+ ///
+ /// Keeps track of any properties unknown to the library.
+ internal XmlModelWithNamespace(string foo, IDictionary additionalBinaryDataProperties)
+ {
+ Foo = foo;
+ _additionalBinaryDataProperties = additionalBinaryDataProperties;
+ }
+
+ /// Gets the Foo.
+ public string Foo { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.Serialization.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.Serialization.cs
new file mode 100644
index 00000000000..9f463bc25fb
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.Serialization.cs
@@ -0,0 +1,147 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace SampleTypeSpec
+{
+ /// A nested model for XML testing.
+ public partial class XmlNestedModel : IJsonModel
+ {
+ /// Initializes a new instance of for deserialization.
+ internal XmlNestedModel()
+ {
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ writer.WriteStartObject();
+ JsonModelWriteCore(writer, options);
+ writer.WriteEndObject();
+ }
+
+ /// The JSON writer.
+ /// The client options for reading and writing models.
+ protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlNestedModel)} does not support writing '{format}' format.");
+ }
+ writer.WritePropertyName("value"u8);
+ writer.WriteStringValue(Value);
+ writer.WritePropertyName("nestedId"u8);
+ writer.WriteNumberValue(NestedId);
+ if (options.Format != "W" && _additionalBinaryDataProperties != null)
+ {
+ foreach (var item in _additionalBinaryDataProperties)
+ {
+ writer.WritePropertyName(item.Key);
+#if NET6_0_OR_GREATER
+ writer.WriteRawValue(item.Value);
+#else
+ using (JsonDocument document = JsonDocument.Parse(item.Value))
+ {
+ JsonSerializer.Serialize(writer, document.RootElement);
+ }
+#endif
+ }
+ }
+ }
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ XmlNestedModel IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options);
+
+ /// The JSON reader.
+ /// The client options for reading and writing models.
+ protected virtual XmlNestedModel JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ if (format != "J")
+ {
+ throw new FormatException($"The model {nameof(XmlNestedModel)} does not support reading '{format}' format.");
+ }
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return DeserializeXmlNestedModel(document.RootElement, options);
+ }
+
+ /// The JSON element to deserialize.
+ /// The client options for reading and writing models.
+ internal static XmlNestedModel DeserializeXmlNestedModel(JsonElement element, ModelReaderWriterOptions options)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+ string value = default;
+ int nestedId = default;
+ IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary();
+ foreach (var prop in element.EnumerateObject())
+ {
+ if (prop.NameEquals("value"u8))
+ {
+ value = prop.Value.GetString();
+ continue;
+ }
+ if (prop.NameEquals("nestedId"u8))
+ {
+ nestedId = prop.Value.GetInt32();
+ continue;
+ }
+ if (options.Format != "W")
+ {
+ additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText()));
+ }
+ }
+ return new XmlNestedModel(value, nestedId, additionalBinaryDataProperties);
+ }
+
+ /// The client options for reading and writing models.
+ BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options);
+
+ /// The client options for reading and writing models.
+ protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ return ModelReaderWriter.Write(this, options, SampleTypeSpecContext.Default);
+ default:
+ throw new FormatException($"The model {nameof(XmlNestedModel)} does not support writing '{options.Format}' format.");
+ }
+ }
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ XmlNestedModel IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options);
+
+ /// The data to parse.
+ /// The client options for reading and writing models.
+ protected virtual XmlNestedModel PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options)
+ {
+ string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format;
+ switch (format)
+ {
+ case "J":
+ using (JsonDocument document = JsonDocument.Parse(data))
+ {
+ return DeserializeXmlNestedModel(document.RootElement, options);
+ }
+ default:
+ throw new FormatException($"The model {nameof(XmlNestedModel)} does not support reading '{options.Format}' format.");
+ }
+ }
+
+ /// The client options for reading and writing models.
+ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.cs
new file mode 100644
index 00000000000..ff4f7c80a97
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/Models/XmlNestedModel.cs
@@ -0,0 +1,42 @@
+//
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+
+namespace SampleTypeSpec
+{
+ /// A nested model for XML testing.
+ public partial class XmlNestedModel
+ {
+ /// Keeps track of any properties unknown to the library.
+ private protected readonly IDictionary _additionalBinaryDataProperties;
+
+ /// Initializes a new instance of .
+ /// The value of the nested model.
+ /// An attribute on the nested model.
+ internal XmlNestedModel(string value, int nestedId)
+ {
+ Value = value;
+ NestedId = nestedId;
+ }
+
+ /// Initializes a new instance of .
+ /// The value of the nested model.
+ /// An attribute on the nested model.
+ /// Keeps track of any properties unknown to the library.
+ internal XmlNestedModel(string value, int nestedId, IDictionary additionalBinaryDataProperties)
+ {
+ Value = value;
+ NestedId = nestedId;
+ _additionalBinaryDataProperties = additionalBinaryDataProperties;
+ }
+
+ /// The value of the nested model.
+ public string Value { get; }
+
+ /// An attribute on the nested model.
+ public int NestedId { get; }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.RestClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.RestClient.cs
new file mode 100644
index 00000000000..b239f96c136
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.RestClient.cs
@@ -0,0 +1,28 @@
+//
+
+#nullable disable
+
+using System.ClientModel.Primitives;
+
+namespace SampleTypeSpec
+{
+ ///
+ public partial class PlantOperations
+ {
+ private static PipelineMessageClassifier _pipelineMessageClassifier200;
+
+ private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 });
+
+ internal PipelineMessage CreateGetTreeRequest(RequestOptions options)
+ {
+ ClientUriBuilder uri = new ClientUriBuilder();
+ uri.Reset(_endpoint);
+ uri.AppendPath("/plants/tree/as-plant", false);
+ PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200);
+ PipelineRequest request = message.Request;
+ request.Headers.Set("Accept", "application/xml");
+ message.Apply(options);
+ return message;
+ }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.cs
new file mode 100644
index 00000000000..cecc2329768
--- /dev/null
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/PlantOperations.cs
@@ -0,0 +1,139 @@
+//
+
+#nullable disable
+
+using System;
+using System.ClientModel;
+using System.ClientModel.Primitives;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SampleTypeSpec
+{
+ /// The PlantOperations sub-client.
+ public partial class PlantOperations
+ {
+ private readonly Uri _endpoint;
+
+ /// Initializes a new instance of PlantOperations for mocking.
+ protected PlantOperations()
+ {
+ }
+
+ /// Initializes a new instance of PlantOperations.
+ /// The HTTP pipeline for sending and receiving REST requests and responses.
+ /// Service endpoint.
+ internal PlantOperations(ClientPipeline pipeline, Uri endpoint)
+ {
+ _endpoint = endpoint;
+ Pipeline = pipeline;
+ }
+
+ /// The HTTP pipeline for sending and receiving REST requests and responses.
+ public ClientPipeline Pipeline { get; }
+
+ ///
+ /// [Protocol Method] Get a tree as a plant
+ ///
+ /// -
+ /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios.
+ ///
+ ///
+ ///
+ /// The request options, which can override default behaviors of the client pipeline on a per-call basis.
+ /// Service returned a non-success status code.
+ /// The response returned from the service.
+ public virtual ClientResult GetTree(RequestOptions options)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetTree.");
+ using PipelineMessage message = CreateGetTreeRequest(options);
+ return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetTree: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetTree.");
+ }
+ }
+
+ ///
+ /// [Protocol Method] Get a tree as a plant
+ ///
+ /// -
+ /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios.
+ ///
+ ///
+ ///
+ /// The request options, which can override default behaviors of the client pipeline on a per-call basis.
+ /// Service returned a non-success status code.
+ /// The response returned from the service.
+ public virtual async Task GetTreeAsync(RequestOptions options)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetTreeAsync.");
+ using PipelineMessage message = CreateGetTreeRequest(options);
+ return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetTreeAsync: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetTreeAsync.");
+ }
+ }
+
+ /// Get a tree as a plant.
+ /// The cancellation token that can be used to cancel the operation.
+ /// Service returned a non-success status code.
+ public virtual ClientResult GetTree(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetTree.");
+ ClientResult result = GetTree(cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null);
+ return ClientResult.FromValue((Tree)result, result.GetRawResponse());
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetTree: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetTree.");
+ }
+ }
+
+ /// Get a tree as a plant.
+ /// The cancellation token that can be used to cancel the operation.
+ /// Service returned a non-success status code.
+ public virtual async Task> GetTreeAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetTreeAsync.");
+ ClientResult result = await GetTreeAsync(cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false);
+ return ClientResult.FromValue((Tree)result, result.GetRawResponse());
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetTreeAsync: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetTreeAsync.");
+ }
+ }
+ }
+}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.RestClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.RestClient.cs
index 6037a87bb26..8b916e68004 100644
--- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.RestClient.cs
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.RestClient.cs
@@ -403,5 +403,17 @@ internal PipelineMessage CreateDynamicModelOperationRequest(BinaryContent conten
message.Apply(options);
return message;
}
+
+ internal PipelineMessage CreateGetXmlAdvancedModelRequest(RequestOptions options)
+ {
+ ClientUriBuilder uri = new ClientUriBuilder();
+ uri.Reset(_endpoint);
+ uri.AppendPath("/xmlAdvanced", false);
+ PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200);
+ PipelineRequest request = message.Request;
+ request.Headers.Set("Accept", "application/xml");
+ message.Apply(options);
+ return message;
+ }
}
}
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs
index 3fe80eeac86..b33976451bc 100644
--- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecClient.cs
@@ -35,6 +35,7 @@ public partial class SampleTypeSpecClient
private AnimalOperations _cachedAnimalOperations;
private PetOperations _cachedPetOperations;
private DogOperations _cachedDogOperations;
+ private PlantOperations _cachedPlantOperations;
private Metrics _cachedMetrics;
/// Initializes a new instance of SampleTypeSpecClient for mocking.
@@ -3033,6 +3034,110 @@ public virtual async Task DynamicModelOperationAsync(DynamicModel
}
}
+ ///
+ /// [Protocol Method] Get an advanced XML model with various property types
+ ///
+ /// -
+ /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios.
+ ///
+ ///
+ ///
+ /// The request options, which can override default behaviors of the client pipeline on a per-call basis.
+ /// Service returned a non-success status code.
+ /// The response returned from the service.
+ public virtual ClientResult GetXmlAdvancedModel(RequestOptions options)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetXmlAdvancedModel.");
+ using PipelineMessage message = CreateGetXmlAdvancedModelRequest(options);
+ return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetXmlAdvancedModel: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetXmlAdvancedModel.");
+ }
+ }
+
+ ///
+ /// [Protocol Method] Get an advanced XML model with various property types
+ ///
+ /// -
+ /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios.
+ ///
+ ///
+ ///
+ /// The request options, which can override default behaviors of the client pipeline on a per-call basis.
+ /// Service returned a non-success status code.
+ /// The response returned from the service.
+ public virtual async Task GetXmlAdvancedModelAsync(RequestOptions options)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetXmlAdvancedModelAsync.");
+ using PipelineMessage message = CreateGetXmlAdvancedModelRequest(options);
+ return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetXmlAdvancedModelAsync: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetXmlAdvancedModelAsync.");
+ }
+ }
+
+ /// Get an advanced XML model with various property types.
+ /// The cancellation token that can be used to cancel the operation.
+ /// Service returned a non-success status code.
+ public virtual ClientResult GetXmlAdvancedModel(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetXmlAdvancedModel.");
+ ClientResult result = GetXmlAdvancedModel(cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null);
+ return ClientResult.FromValue((XmlAdvancedModel)result, result.GetRawResponse());
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetXmlAdvancedModel: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetXmlAdvancedModel.");
+ }
+ }
+
+ /// Get an advanced XML model with various property types.
+ /// The cancellation token that can be used to cancel the operation.
+ /// Service returned a non-success status code.
+ public virtual async Task> GetXmlAdvancedModelAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ System.Console.WriteLine("Entering method GetXmlAdvancedModelAsync.");
+ ClientResult result = await GetXmlAdvancedModelAsync(cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false);
+ return ClientResult.FromValue((XmlAdvancedModel)result, result.GetRawResponse());
+ }
+ catch (Exception ex)
+ {
+ System.Console.WriteLine($"An exception was thrown in method GetXmlAdvancedModelAsync: {ex}");
+ throw;
+ }
+ finally
+ {
+ System.Console.WriteLine("Exiting method GetXmlAdvancedModelAsync.");
+ }
+ }
+
/// Initializes a new instance of AnimalOperations.
public virtual AnimalOperations GetAnimalOperationsClient()
{
@@ -3051,6 +3156,12 @@ public virtual DogOperations GetDogOperationsClient()
return Volatile.Read(ref _cachedDogOperations) ?? Interlocked.CompareExchange(ref _cachedDogOperations, new DogOperations(Pipeline, _endpoint), null) ?? _cachedDogOperations;
}
+ /// Initializes a new instance of PlantOperations.
+ public virtual PlantOperations GetPlantOperationsClient()
+ {
+ return Volatile.Read(ref _cachedPlantOperations) ?? Interlocked.CompareExchange(ref _cachedPlantOperations, new PlantOperations(Pipeline, _endpoint), null) ?? _cachedPlantOperations;
+ }
+
/// Initializes a new instance of Metrics.
public virtual Metrics GetMetricsClient()
{
diff --git a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs
index ff9639bb364..8e41d4923f4 100644
--- a/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs
+++ b/docs/samples/client/csharp/SampleService/SampleClient/src/Generated/SampleTypeSpecModelFactory.cs
@@ -240,6 +240,122 @@ public static AnotherDynamicModel AnotherDynamicModel(string bar = default)
return new AnotherDynamicModel(bar, additionalBinaryDataProperties: null);
}
+ /// An advanced XML model for testing various property types and XML features.
+ /// A simple string property.
+ /// An integer property.
+ /// A boolean property.
+ /// A float property.
+ /// An optional string.
+ /// An optional integer.
+ /// A nullable string.
+ /// A string as XML attribute.
+ /// An integer as XML attribute.
+ /// A boolean as XML attribute.
+ /// A property with a custom XML element name.
+ /// An attribute with a custom XML name.
+ /// Text content in the element (unwrapped string).
+ /// An unwrapped array of strings - items appear directly without wrapper.
+ /// An unwrapped array of integers.
+ /// An unwrapped array of models.
+ /// A wrapped array of strings (default).
+ /// A wrapped array with custom wrapper name.
+ /// A nested model property.
+ /// An optional nested model.
+ /// A dictionary property.
+ /// A date-time property.
+ /// A duration property.
+ /// A bytes property.
+ /// optional record of unknown.
+ /// A fixed enum property.
+ /// An extensible enum property.
+ /// An optional fixed enum property.
+ /// An optional extensible enum property.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// A new instance for mocking.
+ public static XmlAdvancedModel XmlAdvancedModel(string name = default, int age = default, bool enabled = default, float score = default, string optionalString = default, int? optionalInt = default, string nullableString = default, string id = default, int version = default, bool isActive = default, string originalName = default, string xmlIdentifier = default, string content = default, IEnumerable unwrappedStrings = default, IEnumerable unwrappedCounts = default, IEnumerable unwrappedItems = default, IEnumerable wrappedColors = default, IEnumerable items = default, XmlNestedModel nestedModel = default, XmlNestedModel optionalNestedModel = default, IDictionary metadata = default, DateTimeOffset createdAt = default, TimeSpan duration = default, BinaryData data = default, IDictionary optionalRecordUnknown = default, StringFixedEnum fixedEnum = default, StringExtensibleEnum extensibleEnum = default, IntFixedEnum? optionalFixedEnum = default, IntExtensibleEnum? optionalExtensibleEnum = default, string label = default, int daysUsed = default, IEnumerable fooItems = default, XmlNestedModel anotherModel = default, IEnumerable modelsWithNamespaces = default, IEnumerable unwrappedModelsWithNamespaces = default)
+ {
+ unwrappedStrings ??= new ChangeTrackingList();
+ unwrappedCounts ??= new ChangeTrackingList();
+ unwrappedItems ??= new ChangeTrackingList();
+ wrappedColors ??= new ChangeTrackingList();
+ items ??= new ChangeTrackingList();
+ metadata ??= new ChangeTrackingDictionary();
+ optionalRecordUnknown ??= new ChangeTrackingDictionary();
+ fooItems ??= new ChangeTrackingList();
+ modelsWithNamespaces ??= new ChangeTrackingList();
+ unwrappedModelsWithNamespaces ??= new ChangeTrackingList();
+
+ return new XmlAdvancedModel(
+ name,
+ age,
+ enabled,
+ score,
+ optionalString,
+ optionalInt,
+ nullableString,
+ id,
+ version,
+ isActive,
+ originalName,
+ xmlIdentifier,
+ content,
+ unwrappedStrings.ToList(),
+ unwrappedCounts.ToList(),
+ unwrappedItems.ToList(),
+ wrappedColors.ToList(),
+ items.ToList(),
+ nestedModel,
+ optionalNestedModel,
+ metadata,
+ createdAt,
+ duration,
+ data,
+ optionalRecordUnknown,
+ fixedEnum,
+ extensibleEnum,
+ optionalFixedEnum,
+ optionalExtensibleEnum,
+ label,
+ daysUsed,
+ fooItems.ToList(),
+ anotherModel,
+ modelsWithNamespaces.ToList(),
+ unwrappedModelsWithNamespaces.ToList(),
+ additionalBinaryDataProperties: null);
+ }
+
+ /// An item model for XML array testing.
+ /// The item name.
+ /// The item value.
+ /// Item ID as attribute.
+ /// A new instance for mocking.
+ public static XmlItem XmlItem(string itemName = default, int itemValue = default, string itemId = default)
+ {
+ return new XmlItem(itemName, itemValue, itemId, additionalBinaryDataProperties: null);
+ }
+
+ /// A nested model for XML testing.
+ /// The value of the nested model.
+ /// An attribute on the nested model.
+ /// A new instance for mocking.
+ public static XmlNestedModel XmlNestedModel(string value = default, int nestedId = default)
+ {
+ return new XmlNestedModel(value, nestedId, additionalBinaryDataProperties: null);
+ }
+
+ /// The XmlModelWithNamespace.
+ ///
+ /// A new instance for mocking.
+ public static XmlModelWithNamespace XmlModelWithNamespace(string foo = default)
+ {
+ return new XmlModelWithNamespace(foo, additionalBinaryDataProperties: null);
+ }
+
///
/// Base animal with discriminator
/// Please note this is the abstract base class. The derived classes available for instantiation are: and .
@@ -271,6 +387,29 @@ public static Dog Dog(string name = default, bool trained = default, string bree
return new Dog("pet", name, additionalBinaryDataProperties: null, trained, breed);
}
+ /// Tree is a specific type of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// The age of the tree in years.
+ /// A new instance for mocking.
+ public static Tree Tree(string id = default, int height = default, int age = default)
+ {
+ return new Tree("tree", id, height, additionalBinaryDataProperties: null, age);
+ }
+
+ ///
+ /// Base plant with discriminator
+ /// Please note this is the abstract base class. The derived classes available for instantiation are: .
+ ///
+ /// The species of plant.
+ /// The unique identifier of the plant.
+ /// The height of the plant in centimeters.
+ /// A new instance for mocking.
+ public static Plant Plant(string species = default, string id = default, int height = default)
+ {
+ return new UnknownPlant(species, id, height, additionalBinaryDataProperties: null);
+ }
+
/// The GetWidgetMetricsResponse.
///
///
diff --git a/docs/samples/client/csharp/SampleService/main.tsp b/docs/samples/client/csharp/SampleService/main.tsp
index e93467b99b1..c2b189ecb0a 100644
--- a/docs/samples/client/csharp/SampleService/main.tsp
+++ b/docs/samples/client/csharp/SampleService/main.tsp
@@ -1,5 +1,6 @@
import "@typespec/rest";
import "@typespec/http";
+import "@typespec/xml";
import "@typespec/http-client-csharp";
import "@azure-tools/typespec-client-generator-core";
import "@azure-tools/typespec-azure-core";
@@ -20,6 +21,7 @@ namespace SampleTypeSpec;
using TypeSpec.Http;
using TypeSpec.Versioning;
using TypeSpec.HttpClient.CSharp;
+using TypeSpec.Xml;
using Azure.ClientGenerator.Core;
alias SampleOAuth2 = OAuth2Auth<[
@@ -309,6 +311,161 @@ model AnotherDynamicModel {
bar: string;
}
+@nsDeclarations
+enum XmlNamespaces {
+ ns1: "https://example.com/ns1",
+ ns2: "https://example.com/ns2",
+}
+
+@doc("An advanced XML model for testing various property types and XML features.")
+@Xml.name("AdvancedXmlModel")
+model XmlAdvancedModel {
+ @doc("A simple string property")
+ name: string;
+
+ @doc("An integer property")
+ age: int32;
+
+ @doc("A boolean property")
+ enabled: boolean;
+
+ @doc("A float property")
+ score: float32;
+
+ @doc("An optional string")
+ optionalString?: string;
+
+ @doc("An optional integer")
+ optionalInt?: int32;
+
+ @doc("A nullable string")
+ nullableString: string | null;
+
+ @doc("A string as XML attribute")
+ @attribute
+ id: string;
+
+ @doc("An integer as XML attribute")
+ @attribute
+ version: int32;
+
+ @doc("A boolean as XML attribute")
+ @attribute
+ isActive: boolean;
+
+ @doc("A property with a custom XML element name")
+ @Xml.name("RenamedProperty")
+ originalName: string;
+
+ @doc("An attribute with a custom XML name")
+ @attribute
+ @Xml.name("xml-id")
+ xmlIdentifier: string;
+
+ @doc("Text content in the element (unwrapped string)")
+ @unwrapped
+ content: string;
+
+ @doc("An unwrapped array of strings - items appear directly without wrapper")
+ @unwrapped
+ unwrappedStrings: string[];
+
+ @doc("An unwrapped array of integers")
+ @unwrapped
+ unwrappedCounts: int32[];
+
+ @doc("An unwrapped array of models")
+ @unwrapped
+ unwrappedItems: XmlItem[];
+
+ @doc("A wrapped array of strings (default)")
+ wrappedColors: string[];
+
+ @doc("A wrapped array with custom wrapper name")
+ @Xml.name("ItemCollection")
+ items: XmlItem[];
+
+ @doc("A nested model property")
+ nestedModel: XmlNestedModel;
+
+ @doc("An optional nested model")
+ optionalNestedModel?: XmlNestedModel;
+
+ @doc("A dictionary property")
+ metadata: Record;
+
+ @doc("A date-time property")
+ createdAt: utcDateTime;
+
+ @doc("A duration property")
+ duration: duration;
+
+ @doc("A bytes property")
+ data: bytes;
+
+ @doc("optional record of unknown")
+ optionalRecordUnknown?: Record;
+
+ @doc("A fixed enum property")
+ fixedEnum: StringFixedEnum;
+
+ @doc("An extensible enum property")
+ extensibleEnum: StringExtensibleEnum;
+
+ @doc("An optional fixed enum property")
+ optionalFixedEnum?: IntFixedEnum;
+
+ @doc("An optional extensible enum property")
+ optionalExtensibleEnum?: IntExtensibleEnum;
+
+ @attribute
+ @ns(XmlNamespaces.ns1)
+ label: string;
+
+ @ns(XmlNamespaces.ns2)
+ daysUsed: int32;
+
+ @ns("http://www.contoso.com/anotherbook.dtd", "foo")
+ fooItems: string[];
+
+ @ns("http://www.contoso.com/anothermodel.dtd", "bar")
+ anotherModel: XmlNestedModel;
+
+ modelsWithNamespaces: XmlModelWithNamespace[];
+
+ @unwrapped
+ unwrappedModelsWithNamespaces: XmlModelWithNamespace[];
+}
+
+@doc("A nested model for XML testing")
+model XmlNestedModel {
+ @doc("The value of the nested model")
+ value: string;
+
+ @doc("An attribute on the nested model")
+ @attribute
+ nestedId: int32;
+}
+
+@doc("An item model for XML array testing")
+@Xml.name("Item")
+model XmlItem {
+ @doc("The item name")
+ itemName: string;
+
+ @doc("The item value")
+ itemValue: int32;
+
+ @doc("Item ID as attribute")
+ @attribute
+ itemId: string;
+}
+
+@ns("http://www.example.com/namespace", "ns1")
+model XmlModelWithNamespace {
+ foo: string;
+}
+
union DaysOfWeekExtensibleEnum {
string,
Monday: "Monday",
@@ -513,6 +670,14 @@ op EmbeddedParameters(@bodyRoot body: ModelWithEmbeddedNonBodyParameters): void;
@post
op DynamicModelOperation(@body body: DynamicModel): void;
+@route("xmlAdvanced")
+@doc("Get an advanced XML model with various property types")
+@get
+op GetXmlAdvancedModel(): {
+ @header contentType: "application/xml";
+ @body body: XmlAdvancedModel;
+};
+
@doc("Base animal with discriminator")
@discriminator("kind")
model Animal {
@@ -581,6 +746,39 @@ interface DogOperations {
updateDogAsDog(@body dog: Dog): Dog;
}
+@doc("Base plant with discriminator")
+@discriminator("species")
+model Plant {
+ @doc("The species of plant")
+ species: string;
+
+ @doc("The unique identifier of the plant")
+ id: string;
+
+ @doc("The height of the plant in centimeters")
+ height: int32;
+}
+
+@doc("Tree is a specific type of plant")
+@usage(Usage.xml | Usage.output | Usage.json)
+model Tree extends Plant {
+ species: "tree";
+
+ @doc("The age of the tree in years")
+ age: int32;
+}
+
+@route("/plants")
+interface PlantOperations {
+ @doc("Get a tree as a plant")
+ @get
+ @route("/tree/as-plant")
+ getTree(): {
+ @header contentType: "application/xml";
+ @body body: Tree;
+ };
+}
+
@clientInitialization({
initializedBy: InitializedBy.individually | InitializedBy.parent,
})
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs
index bfbefd24fbb..9ff28ed9363 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs
@@ -21,7 +21,6 @@ internal static class ScmKnownParameters
public static readonly ParameterProvider XmlWriter = new("writer", FormattableStringHelpers.Empty, typeof(XmlWriter));
public static readonly ParameterProvider NameHint = new("nameHint", FormattableStringHelpers.Empty, typeof(string));
- public static readonly ParameterProvider XElement = new("element", FormattableStringHelpers.Empty, typeof(XElement));
public static readonly ParameterProvider Utf8JsonWriter = new("writer", FormattableStringHelpers.Empty, typeof(Utf8JsonWriter));
public static readonly ParameterProvider Utf8JsonReader = new("reader", FormattableStringHelpers.Empty, typeof(Utf8JsonReader), isRef: true);
public static readonly ParameterProvider JsonOptions = new("options", FormattableStringHelpers.Empty, typeof(JsonSerializerOptions));
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmSerializationOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmSerializationOptions.cs
new file mode 100644
index 00000000000..607db81f950
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmSerializationOptions.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.TypeSpec.Generator.Input;
+using Microsoft.TypeSpec.Generator.Primitives;
+
+namespace Microsoft.TypeSpec.Generator.ClientModel.Primitives
+{
+ public class ScmSerializationOptions : SerializationOptions
+ {
+ public ScmSerializationOptions(InputSerializationOptions inputSerializationOptions) : base()
+ {
+ Xml = inputSerializationOptions.Xml != null
+ ? new(inputSerializationOptions.Xml)
+ : null;
+ }
+
+ public XmlSerialization? Xml { get; }
+
+ // TO-DO: Add remaining SCM serialization options https://github.com/microsoft/typespec/issues/5861.
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerialization.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerialization.cs
new file mode 100644
index 00000000000..404fc499a64
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerialization.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.TypeSpec.Generator.Input;
+
+namespace Microsoft.TypeSpec.Generator.ClientModel.Primitives
+{
+ public class XmlSerialization
+ {
+ public XmlSerialization(InputXmlSerializationOptions xmlOptions)
+ {
+ Name = xmlOptions.Name;
+ Attribute = xmlOptions.Attribute;
+ Namespace = xmlOptions.Namespace != null
+ ? new(xmlOptions.Namespace)
+ : null;
+ Unwrapped = xmlOptions.Unwrapped;
+ ItemsName = xmlOptions.ItemsName;
+ ItemsNamespace = xmlOptions.ItemsNamespace != null
+ ? new(xmlOptions.ItemsNamespace)
+ : null;
+ }
+
+ public string Name { get; }
+
+ public bool? Attribute { get; }
+
+ public XmlSerializationNamespace? Namespace { get; }
+
+ public bool? Unwrapped { get; }
+
+ public string? ItemsName { get; }
+
+ public XmlSerializationNamespace? ItemsNamespace { get; }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerializationNamespace.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerializationNamespace.cs
new file mode 100644
index 00000000000..5bae1386c10
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/XmlSerializationNamespace.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.TypeSpec.Generator.Input;
+
+namespace Microsoft.TypeSpec.Generator.ClientModel.Primitives
+{
+ public class XmlSerializationNamespace
+ {
+ public XmlSerializationNamespace(InputXmlNamespaceOptions options)
+ {
+ Namespace = options.Namespace;
+ Prefix = options.Prefix;
+ }
+
+ public string Namespace { get; }
+
+ public string Prefix { get; }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.Xml.cs
new file mode 100644
index 00000000000..98703cd546c
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.Xml.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Xml.Linq;
+using Microsoft.TypeSpec.Generator.ClientModel.Snippets;
+using Microsoft.TypeSpec.Generator.Expressions;
+using Microsoft.TypeSpec.Generator.Primitives;
+using Microsoft.TypeSpec.Generator.Providers;
+using Microsoft.TypeSpec.Generator.Snippets;
+using static Microsoft.TypeSpec.Generator.Snippets.Snippet;
+
+namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
+{
+ public sealed partial class ModelSerializationExtensionsDefinition
+ {
+ private readonly ParameterProvider _xElementParameter =
+ new ParameterProvider("element", FormattableStringHelpers.Empty, typeof(XElement));
+
+ private MethodProvider[] BuildXmlExtensionMethods()
+ {
+ if (!ScmCodeModelGenerator.Instance.InputLibrary.HasXmlModelSerialization)
+ {
+ return [];
+ }
+
+ return
+ [
+ BuildXmlGetDateTimeOffsetMethodProvider(),
+ BuildXmlGetTimeSpanMethodProvider(),
+ BuildXmlGetBytesFromBase64MethodProvider()
+ ];
+ }
+
+ private MethodProvider BuildXmlGetDateTimeOffsetMethodProvider()
+ {
+ var signature = new MethodSignature(
+ Name: _getDateTimeOffsetMethodName,
+ Modifiers: _methodModifiers,
+ Parameters: [_xElementParameter, _formatParameter],
+ ReturnType: typeof(DateTimeOffset),
+ Description: null,
+ ReturnDescription: null);
+
+ var element = _xElementParameter.As();
+ var body = new SwitchExpression(
+ _formatParameter,
+ new SwitchCaseExpression(Literal("U"), DateTimeOffsetSnippets.FromUnixTimeSeconds(element.CastTo(typeof(long)))),
+ SwitchCaseExpression.Default(TypeFormattersSnippets.ParseDateTimeOffset(element.Value(), _formatParameter)));
+
+ return new MethodProvider(signature, body, this, XmlDocProvider.Empty);
+ }
+
+ private MethodProvider BuildXmlGetTimeSpanMethodProvider()
+ {
+ var signature = new MethodSignature(
+ Name: _getTimeSpanMethodName,
+ Modifiers: _methodModifiers,
+ Parameters: [_xElementParameter, _formatParameter],
+ ReturnType: typeof(TimeSpan),
+ Description: null,
+ ReturnDescription: null);
+
+ var element = _xElementParameter.As();
+ var body = TypeFormattersSnippets.ParseTimeSpan(element.Value(), _formatParameter);
+
+ return new MethodProvider(signature, body, this, XmlDocProvider.Empty);
+ }
+
+ private MethodProvider BuildXmlGetBytesFromBase64MethodProvider()
+ {
+ var signature = new MethodSignature(
+ Name: _getBytesFromBase64MethodName,
+ Modifiers: _methodModifiers,
+ Parameters: [_xElementParameter, _formatParameter],
+ ReturnType: typeof(byte[]),
+ Description: null,
+ ReturnDescription: null);
+
+ var element = _xElementParameter.As();
+ var body = new SwitchExpression(
+ _formatParameter,
+ new SwitchCaseExpression(Literal("U"), TypeFormattersSnippets.FromBase64UrlString(element.Value())),
+ new SwitchCaseExpression(Literal("D"), Static(typeof(Convert)).Invoke(nameof(Convert.FromBase64String), element.Value())),
+ SwitchCaseExpression.Default(ThrowExpression(New.ArgumentException(_formatParameter, Literal("Format is not supported: "), true))));
+
+ return new MethodProvider(signature, body, this, XmlDocProvider.Empty);
+ }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs
index 5a839f27088..2b1ecb328f4 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs
@@ -8,7 +8,6 @@
using System.Diagnostics;
using System.Globalization;
using System.IO;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
@@ -23,7 +22,7 @@
namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
{
- public sealed class ModelSerializationExtensionsDefinition : TypeProvider
+ public sealed partial class ModelSerializationExtensionsDefinition : TypeProvider
{
public const string WireOptionsFieldName = "WireOptions";
public const string JsonDocumentOptionsFieldName = "JsonDocumentOptions";
@@ -158,7 +157,8 @@ protected override MethodProvider[] BuildMethods()
BuildWriteObjectValueMethodGeneric(),
BuildWriteObjectValueMethodProvider(),
BuildGetUtf8BytesMethodProvider(),
- .. BuildDynamicModelHelpers()
+ .. BuildDynamicModelHelpers(),
+ .. BuildXmlExtensionMethods()
];
}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs
index c62dfd0df8b..609019fa210 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Dynamic.cs
@@ -503,14 +503,14 @@ private static string BuildJsonPathForElement(string propertySerializedName, Lis
private static ValueExpression GetDeserializationMethodInvocationForType(
ModelProvider model,
- ScopedApi jsonElementVariable,
+ ScopedApi element,
ValueExpression? dataVariable = null,
ValueExpression? optionsVariable = null)
{
optionsVariable ??= ModelSerializationExtensionsSnippets.Wire;
return model is ScmModelProvider { IsDynamicModel: true }
- ? model.Type.Deserialize(jsonElementVariable, dataVariable, optionsVariable)
- : model.Type.Deserialize(jsonElementVariable, null, optionsVariable);
+ ? model.Type.Deserialize(element, dataVariable, optionsVariable)
+ : model.Type.Deserialize(element, null, optionsVariable);
}
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs
new file mode 100644
index 00000000000..d89d149d08e
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs
@@ -0,0 +1,749 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text.Json;
+using System.Xml.Linq;
+using Microsoft.TypeSpec.Generator.ClientModel.Primitives;
+using Microsoft.TypeSpec.Generator.ClientModel.Snippets;
+using Microsoft.TypeSpec.Generator.Expressions;
+using Microsoft.TypeSpec.Generator.Input;
+using Microsoft.TypeSpec.Generator.Input.Extensions;
+using Microsoft.TypeSpec.Generator.Primitives;
+using Microsoft.TypeSpec.Generator.Providers;
+using Microsoft.TypeSpec.Generator.Snippets;
+using Microsoft.TypeSpec.Generator.SourceInput;
+using Microsoft.TypeSpec.Generator.Statements;
+using static Microsoft.TypeSpec.Generator.Snippets.Snippet;
+
+namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
+{
+ public partial class MrwSerializationTypeDefinition
+ {
+ private readonly ParameterProvider _xElementDeserializationParam = new("element", $"The xml element to deserialize.", typeof(XElement));
+ private readonly ScopedApi _xmlElementParameterSnippet;
+ private const string ContentTypeHeader = "Content-Type";
+
+ private record XmlPropertyInfo(
+ string PropertyName,
+ CSharpType PropertyType,
+ VariableExpression PropertyExpression,
+ XmlSerialization XmlWireInfo,
+ SerializationFormat SerializationFormat,
+ IEnumerable SerializationAttributes);
+
+ private record XmlNamespaceInfo(string Namespace, string VariableName, VariableExpression VariableExpression);
+
+ private record XmlPropertyCategories(
+ List? AttributeProperties,
+ List? ElementProperties,
+ XmlPropertyInfo? TextContentProperty,
+ Dictionary? Namespaces);
+
+ internal MethodProvider BuildXmlDeserializationMethod()
+ {
+ var methodName = $"{DeserializationMethodNamePrefix}{_model.Name}";
+ var signatureModifiers = MethodSignatureModifiers.Internal | MethodSignatureModifiers.Static;
+ var parameters = new List
+ {
+ _xElementDeserializationParam,
+ _serializationOptionsParameter,
+ };
+
+ var methodBody = _inputModel.DiscriminatedSubtypes.Count > 0
+ ? BuildXmlDiscriminatedModelDeserializationMethodBody()
+ : BuildXmlDeserializationMethodBody();
+
+ return new MethodProvider(
+ new MethodSignature(methodName, null, signatureModifiers, _model.Type, null, parameters),
+ methodBody,
+ this);
+ }
+
+ private MethodBodyStatement[] BuildXmlDiscriminatedModelDeserializationMethodBody()
+ {
+ var unknownVariant = _model.DerivedModels.First(m => m.IsUnknownDiscriminatorModel);
+ bool onlyContainsUnknownDerivedModel = _model.DerivedModels.Count == 1;
+ var discriminator = _model.CanonicalView.Properties.Where(p => p.IsDiscriminator).FirstOrDefault();
+ if (discriminator == null && _model.BaseModelProvider != null)
+ {
+ // Look for discriminator property in the base model
+ discriminator = _model.BaseModelProvider.CanonicalView.Properties.Where(p => p.IsDiscriminator).FirstOrDefault();
+ }
+
+ var deserializeDiscriminatedModelsConditions = BuildXmlDiscriminatedModelsCondition(
+ discriminator,
+ GetXmlDiscriminatorSwitchCases(unknownVariant),
+ onlyContainsUnknownDerivedModel,
+ _xmlElementParameterSnippet);
+
+ return
+ [
+ new IfStatement(_xmlElementParameterSnippet.Equal(Null)) { Return(Null) },
+ MethodBodyStatement.EmptyLine,
+ deserializeDiscriminatedModelsConditions,
+ Return(GetDeserializationMethodInvocationForType(unknownVariant, _xmlElementParameterSnippet, null, _serializationOptionsParameter))
+ ];
+ }
+
+ private static MethodBodyStatement BuildXmlDiscriminatedModelsCondition(
+ PropertyProvider? discriminatorProperty,
+ SwitchCaseStatement[] abstractSwitchCases,
+ bool onlyContainsUnknownDerivedModel,
+ ScopedApi elementParameter)
+ {
+ var xmlSerializationOptions = (discriminatorProperty?.WireInfo?.SerializationOptions as ScmSerializationOptions)?.Xml;
+ if (!onlyContainsUnknownDerivedModel && xmlSerializationOptions?.Name != null)
+ {
+ var discriminatorElementName = xmlSerializationOptions.Name;
+ var discriminatorElement = new VariableExpression(typeof(XElement), "discriminatorElement");
+
+ return new MethodBodyStatements(
+ [
+ Declare(discriminatorElement, elementParameter.Element(Literal(discriminatorElementName))),
+ new IfStatement(discriminatorElement.NotEqual(Null))
+ {
+ new SwitchStatement(discriminatorElement.CastTo(typeof(string)), abstractSwitchCases)
+ }
+ ]);
+ }
+
+ return MethodBodyStatement.Empty;
+ }
+
+ private SwitchCaseStatement[] GetXmlDiscriminatorSwitchCases(ModelProvider unknownVariant)
+ {
+ SwitchCaseStatement[] cases = new SwitchCaseStatement[_model.DerivedModels.Count - 1];
+ int index = 0;
+ for (int i = 0; i < _model.DerivedModels.Count; i++)
+ {
+ var model = _model.DerivedModels[i];
+ if (ReferenceEquals(model, unknownVariant))
+ {
+ continue;
+ }
+ cases[index++] = new SwitchCaseStatement(
+ Literal(model.DiscriminatorValue!),
+ Return(GetDeserializationMethodInvocationForType(model, _xmlElementParameterSnippet, _dataParameter, _serializationOptionsParameter)));
+ }
+ return cases;
+ }
+
+ private MethodBodyStatement[] BuildXmlDeserializationMethodBody()
+ {
+ var valueKindEqualsNullReturn = _isStruct
+ ? Return(Default)
+ : Return(Null);
+
+ var categorizedProperties = CategorizeXmlProperties();
+ var statements = new List
+ {
+ new IfStatement(_xmlElementParameterSnippet.Equal(Null)) { valueKindEqualsNullReturn },
+ MethodBodyStatement.EmptyLine,
+ GetXmlNamespaceDeclarations(categorizedProperties.Namespaces),
+ GetPropertyVariableDeclarations(),
+ MethodBodyStatement.EmptyLine
+ };
+
+ if (categorizedProperties.AttributeProperties?.Count > 0)
+ {
+ statements.Add(CreateXmlDeserializeForEachStatement(
+ _xmlElementParameterSnippet,
+ categorizedProperties.AttributeProperties,
+ categorizedProperties.Namespaces,
+ isAttributes: true));
+ statements.Add(MethodBodyStatement.EmptyLine);
+ }
+
+ if (categorizedProperties.ElementProperties?.Count > 0)
+ {
+ statements.Add(CreateXmlDeserializeForEachStatement(
+ _xmlElementParameterSnippet,
+ categorizedProperties.ElementProperties,
+ categorizedProperties.Namespaces,
+ isAttributes: false));
+ }
+
+ if (categorizedProperties.TextContentProperty != null)
+ {
+ statements.Add(categorizedProperties.TextContentProperty.PropertyExpression.Assign(_xmlElementParameterSnippet.Value()).Terminate());
+ statements.Add(MethodBodyStatement.EmptyLine);
+ }
+
+ statements.Add(Return(New.Instance(_model.Type, GetSerializationCtorParameterValues())));
+
+ return [.. statements];
+ }
+
+ private XmlPropertyCategories CategorizeXmlProperties()
+ {
+ List? attributeProperties = null;
+ List? elementProperties = null;
+ XmlPropertyInfo? textContentProperty = null;
+ Dictionary? namespaces = null;
+
+ var parameters = SerializationConstructor.Signature.Parameters;
+
+ // Get the custom serialization attributes
+ var serializationAttributes = GetSerializationAttributes();
+
+ for (int i = 0; i < parameters.Count; i++)
+ {
+ var parameter = parameters[i];
+ if (parameter.Property == null && parameter.Field == null)
+ {
+ continue;
+ }
+
+ var wireInfo = parameter.Property?.WireInfo ?? parameter.Field?.WireInfo;
+ var xmlWireInfo = (wireInfo?.SerializationOptions as ScmSerializationOptions)?.Xml;
+ if (xmlWireInfo == null || wireInfo?.IsHttpMetadata == true)
+ {
+ continue;
+ }
+
+ var propertyType = parameter.Property?.Type ?? parameter.Field?.Type;
+ var propertyExpression = parameter.Property?.AsVariableExpression ?? parameter.Field?.AsVariableExpression;
+ var propertyName = parameter.Property?.Name ?? parameter.Field?.Name;
+ if (propertyType == null || propertyExpression == null || propertyName == null)
+ {
+ continue;
+ }
+
+ // Collect unique namespaces
+ if (xmlWireInfo.Namespace != null)
+ {
+ namespaces ??= [];
+ CollectNamespace(propertyName, xmlWireInfo.Namespace, namespaces);
+ }
+ if (xmlWireInfo.ItemsNamespace != null)
+ {
+ namespaces ??= [];
+ CollectNamespace(propertyName, xmlWireInfo.ItemsNamespace, namespaces);
+ }
+
+ var serializationFormat = wireInfo?.SerializationFormat ?? SerializationFormat.Default;
+ var propertyInfo = new XmlPropertyInfo(propertyName, propertyType, propertyExpression, xmlWireInfo, serializationFormat, serializationAttributes);
+
+ // Categorize by XML serialization type
+ if (xmlWireInfo.Attribute == true)
+ {
+ (attributeProperties ??= []).Add(propertyInfo);
+ continue;
+ }
+ if (xmlWireInfo.Unwrapped == true && !propertyType.IsCollection)
+ {
+ textContentProperty = propertyInfo;
+ continue;
+ }
+
+ (elementProperties ??= []).Add(propertyInfo);
+ }
+
+ return new XmlPropertyCategories(attributeProperties, elementProperties, textContentProperty, namespaces);
+ }
+
+ private ForEachStatement CreateXmlDeserializeForEachStatement(
+ ScopedApi elementParameter,
+ List properties,
+ Dictionary? namespaces,
+ bool isAttributes)
+ {
+ return isAttributes switch
+ {
+ true => new ForEachStatement("attr", elementParameter.Attributes(), out var attr)
+ {
+ CreateXmlDeserializeAttributeStatements(attr.As(), properties, namespaces)
+ },
+ false => new ForEachStatement("child", elementParameter.Elements(), out var child)
+ {
+ CreateXmlDeserializeElementStatements(child.As(), properties, namespaces)
+ }
+ };
+ }
+
+ private MethodBodyStatement CreateXmlDeserializeElementStatements(
+ ScopedApi childElement,
+ List elementProperties,
+ Dictionary? namespaces)
+ {
+ var statements = new List();
+ var localNameVariable = new VariableExpression(typeof(string), "localName");
+ var nsVariable = new VariableExpression(typeof(XNamespace), "ns");
+
+ statements.Add(Declare(localNameVariable, childElement.GetLocalName()));
+ if (namespaces?.Count > 0)
+ {
+ statements.AddRange(
+ Declare(nsVariable, childElement.Property("Name").Property("Namespace").As()),
+ MethodBodyStatement.EmptyLine);
+ }
+
+ foreach (var prop in elementProperties)
+ {
+ MethodBodyStatement deserializationStatement = GetXmlDeserializationHookStatement(
+ prop.PropertyName,
+ prop.SerializationAttributes,
+ childElement,
+ prop.PropertyExpression,
+ out bool hasHook);
+
+ if (!hasHook)
+ {
+ deserializationStatement = CreateXmlDeserializePropertyAssignment(
+ childElement,
+ prop.PropertyType,
+ prop.PropertyExpression,
+ prop.XmlWireInfo,
+ prop.SerializationFormat,
+ namespaces);
+ }
+
+ // Build condition: check localName and optionally namespace
+ ScopedApi condition = localNameVariable.Equal(Literal(prop.XmlWireInfo.Name));
+ if (prop.XmlWireInfo.Namespace != null && namespaces != null && namespaces.TryGetValue(prop.XmlWireInfo.Namespace.Namespace, out var nsInfo))
+ {
+ condition = condition.And(nsVariable.Equal(nsInfo.VariableExpression));
+ }
+
+ var checkIfLocalNameEquals = new IfStatement(condition)
+ {
+ deserializationStatement,
+ Continue
+ };
+
+ statements.Add(checkIfLocalNameEquals);
+ }
+
+ return statements;
+ }
+
+ private static MethodBodyStatement GetXmlDeserializationHookStatement(
+ string propertyName,
+ IEnumerable serializationAttributes,
+ ValueExpression xmlValue,
+ VariableExpression variableExpression,
+ out bool hasHook)
+ {
+ hasHook = false;
+ foreach (var attribute in serializationAttributes)
+ {
+ if (CodeGenAttributes.TryGetCodeGenSerializationAttributeValue(
+ attribute,
+ out var name,
+ out _,
+ out _,
+ out var deserializationHook,
+ out _) && name == propertyName && deserializationHook != null)
+ {
+ hasHook = true;
+ return Static().Invoke(deserializationHook, xmlValue, ByRef(variableExpression)).Terminate();
+ }
+ }
+
+ return MethodBodyStatement.Empty;
+ }
+
+ private MethodBodyStatement CreateXmlDeserializePropertyAssignment(
+ ScopedApi childElement,
+ CSharpType propertyType,
+ VariableExpression propertyExpression,
+ XmlSerialization xmlWireInfo,
+ SerializationFormat serializationFormat,
+ Dictionary? namespaces = null)
+ {
+ if (propertyType.IsList || propertyType.IsArray)
+ {
+ return CreateXmlDeserializeListAssignment(childElement, propertyType, propertyExpression, xmlWireInfo, serializationFormat, namespaces);
+ }
+
+ if (propertyType.IsDictionary)
+ {
+ return CreateXmlDeserializeDictionaryAssignment(childElement, propertyType, propertyExpression, xmlWireInfo, serializationFormat);
+ }
+
+ var deserializedValue = CreateXmlDeserializeValueExpression(childElement, propertyType, serializationFormat);
+ return propertyExpression.Assign(deserializedValue).Terminate();
+ }
+
+ private MethodBodyStatement CreateXmlDeserializeListAssignment(
+ ScopedApi childElement,
+ CSharpType listType,
+ VariableExpression listExpression,
+ XmlSerialization xmlWireInfo,
+ SerializationFormat serializationFormat,
+ Dictionary? namespaces = null)
+ {
+ var elementType = listType.ElementType;
+ if (xmlWireInfo.Unwrapped == true)
+ {
+ return new MethodBodyStatements(
+ [
+ new IfStatement(listExpression.Equal(Null))
+ {
+ listExpression.Assign(New.List(elementType)).Terminate(),
+ },
+ DeserializeXmlValue(childElement, elementType, serializationFormat, out var itemValue),
+ listExpression.Invoke("Add", itemValue).Terminate()
+ ]);
+ }
+ else
+ {
+ var itemsName = xmlWireInfo.ItemsName;
+ var arrayDeclaration = Declare("array", New.List(elementType), out var listVariable);
+
+ // Build element name expression - with namespace if available
+ ValueExpression elementNameExpression;
+ if (xmlWireInfo.ItemsNamespace != null && namespaces != null && namespaces.TryGetValue(xmlWireInfo.ItemsNamespace.Namespace, out var nsInfo))
+ {
+ elementNameExpression = new BinaryOperatorExpression("+", nsInfo.VariableExpression, Literal(itemsName)).As();
+ }
+ else
+ {
+ elementNameExpression = Literal(itemsName);
+ }
+
+ var foreachStatement = ForEachStatement.Create("e", childElement.Elements(elementNameExpression), out ScopedApi item)
+ .Add(new MethodBodyStatement[]
+ {
+ DeserializeXmlValue(item, elementType, serializationFormat, out var deserializedItem),
+ listVariable.Add(deserializedItem)
+ });
+
+ return new MethodBodyStatements(
+ [
+ arrayDeclaration,
+ foreachStatement,
+ listExpression.Assign(listVariable).Terminate()
+ ]);
+ }
+ }
+
+ private MethodBodyStatement CreateXmlDeserializeDictionaryAssignment(
+ ScopedApi childElement,
+ CSharpType dictionaryType,
+ VariableExpression dictionaryExpression,
+ XmlSerialization xmlWireInfo,
+ SerializationFormat serializationFormat)
+ {
+ var valueType = dictionaryType.ElementType;
+ if (xmlWireInfo.Unwrapped == true)
+ {
+ return new MethodBodyStatements(
+ [
+ new IfStatement(dictionaryExpression.Equal(Null))
+ {
+ dictionaryExpression.Assign(New.Dictionary(dictionaryType.Arguments[0], dictionaryType.Arguments[1])).Terminate(),
+ },
+ CreateXmlDeserializeDictionaryValueStatement(valueType, dictionaryExpression, childElement, serializationFormat)
+ ]);
+ }
+
+ var dictionaryDeclaration = Declare(
+ "dictionary",
+ New.Dictionary(dictionaryType.Arguments[0], dictionaryType.Arguments[1]),
+ out var dictVariable);
+
+ var foreachStatement = ForEachStatement.Create("e", childElement.Elements(), out ScopedApi item)
+ .Add(new MethodBodyStatement[]
+ {
+ CreateXmlDeserializeDictionaryValueStatement(valueType, dictVariable, item, serializationFormat)
+ });
+
+ return new MethodBodyStatements(
+ [
+ dictionaryDeclaration,
+ foreachStatement,
+ dictionaryExpression.Assign(dictVariable).Terminate()
+ ]);
+ }
+
+ private MethodBodyStatement CreateXmlDeserializeDictionaryValueStatement(
+ CSharpType valueType,
+ ValueExpression dictionary,
+ ScopedApi element,
+ SerializationFormat serializationFormat)
+ {
+ return new MethodBodyStatement[]
+ {
+ DeserializeXmlValue(element, valueType, serializationFormat, out var value),
+ dictionary.Invoke("Add", element.GetLocalName(), value).Terminate()
+ };
+ }
+
+ private MethodBodyStatement DeserializeXmlValue(
+ ScopedApi element,
+ CSharpType valueType,
+ SerializationFormat serializationFormat,
+ out ValueExpression value)
+ {
+ if (valueType.IsList || valueType.IsArray)
+ {
+ var listDeclaration = Declare("list", New.List(valueType.ElementType), out var listVariable);
+ var foreachStatement = ForEachStatement.Create("item", element.Elements(), out ScopedApi item)
+ .Add(new MethodBodyStatement[]
+ {
+ DeserializeXmlValue(item, valueType.ElementType, serializationFormat, out var deserializedItem),
+ listVariable.Add(deserializedItem)
+ });
+
+ value = listVariable;
+ return new MethodBodyStatement[] { listDeclaration, foreachStatement };
+ }
+
+ if (valueType.IsDictionary)
+ {
+ var dictDeclaration = Declare("dict", New.Dictionary(valueType.Arguments[0], valueType.Arguments[1]), out var dictVariable);
+ var foreachStatement = ForEachStatement.Create("item", element.Elements(), out ScopedApi item)
+ .Add(CreateXmlDeserializeDictionaryValueStatement(valueType.ElementType, dictVariable, item, serializationFormat));
+
+ value = dictVariable;
+ return new MethodBodyStatement[] { dictDeclaration, foreachStatement };
+ }
+
+ value = CreateXmlDeserializeValueExpression(element, valueType, serializationFormat);
+ return MethodBodyStatement.Empty;
+ }
+
+ private ValueExpression CreateXmlDeserializeValueExpression(ScopedApi element, CSharpType valueType, SerializationFormat serializationFormat)
+ {
+ var underlyingType = valueType.IsNullable && valueType.Arguments.Count > 0
+ ? valueType.Arguments[0]
+ : valueType;
+
+ if (underlyingType.IsEnum && underlyingType.UnderlyingEnumType != null)
+ {
+ var underlyingExpression = CreateXmlDeserializePrimitiveExpression(element, underlyingType.UnderlyingEnumType, serializationFormat);
+ return underlyingType.ToEnum(underlyingExpression);
+ }
+
+ if (!underlyingType.IsFrameworkType)
+ {
+ return GetDeserializationMethodInvocationForType(underlyingType, element, null, _serializationOptionsParameter);
+ }
+
+ return CreateXmlDeserializePrimitiveExpression(element, valueType, serializationFormat);
+ }
+
+ private static ValueExpression CreateXmlDeserializePrimitiveExpression(
+ ScopedApi element,
+ CSharpType valueType,
+ SerializationFormat serializationFormat)
+ {
+ return valueType.FrameworkType switch
+ {
+ Type t when t == typeof(Uri) => New.Instance(valueType.FrameworkType, element.Value()),
+ Type t when t == typeof(IPAddress) => Static().Invoke(nameof(IPAddress.Parse), element.Value()),
+ Type t when t == typeof(Stream) => BinaryDataSnippets.FromString(element.Value()).ToStream(),
+ Type t when t == typeof(byte[]) => element.GetBytesFromBase64(serializationFormat.ToFormatSpecifier()),
+ Type t when t == typeof(BinaryData) => serializationFormat is SerializationFormat.Bytes_Base64 or SerializationFormat.Bytes_Base64Url
+ ? BinaryDataSnippets.FromBytes(element.GetBytesFromBase64(serializationFormat.ToFormatSpecifier()))
+ : BinaryDataSnippets.FromString(element.Value()),
+ Type t when t == typeof(DateTimeOffset) => element.GetDateTimeOffset(serializationFormat.ToFormatSpecifier()),
+ Type t when t == typeof(TimeSpan) => element.GetTimeSpan(serializationFormat.ToFormatSpecifier()),
+ Type t when t == typeof(byte) => element.CastTo(typeof(int)).CastTo(typeof(byte)),
+ Type t when t == typeof(sbyte) => element.CastTo(typeof(int)).CastTo(typeof(sbyte)),
+ Type t when t == typeof(short) => element.CastTo(typeof(int)).CastTo(typeof(short)),
+ Type t when t == typeof(ushort) => element.CastTo(typeof(int)).CastTo(typeof(ushort)),
+ _ => element.CastTo(valueType)
+ };
+ }
+
+ private MethodBodyStatement CreateXmlDeserializeAttributeStatements(
+ ScopedApi attrVariable,
+ List attributeProperties,
+ Dictionary? namespaces)
+ {
+ var hasNamespacedAttributes = attributeProperties.Any(p => p.XmlWireInfo.Namespace != null);
+ var statements = new List
+ {
+ Declare("localName", typeof(string), attrVariable.GetLocalName(), out var localNameVar)
+ };
+
+ VariableExpression? nsVar = null;
+ if (hasNamespacedAttributes)
+ {
+ statements.AddRange(
+ Declare("ns", typeof(XNamespace), attrVariable.Name().Namespace(), out nsVar),
+ MethodBodyStatement.EmptyLine);
+ }
+
+ foreach (var prop in attributeProperties)
+ {
+ MethodBodyStatement deserializationStatement = GetXmlDeserializationHookStatement(
+ prop.PropertyName,
+ prop.SerializationAttributes,
+ attrVariable,
+ prop.PropertyExpression,
+ out bool hasHook);
+
+ if (!hasHook)
+ {
+ var deserializedValue = attrVariable.CastTo(prop.PropertyType);
+ deserializationStatement = prop.PropertyExpression.Assign(deserializedValue).Terminate();
+ }
+
+ ScopedApi condition = localNameVar.Equal(Literal(prop.XmlWireInfo.Name));
+ if (prop.XmlWireInfo.Namespace != null && namespaces != null && nsVar != null)
+ {
+ var nsInfo = namespaces[prop.XmlWireInfo.Namespace.Namespace];
+ condition = condition.And(nsVar.Equal(nsInfo.VariableExpression));
+ }
+
+ var checkIfLocalNameEquals = new IfStatement(condition)
+ {
+ deserializationStatement,
+ Continue
+ };
+
+ statements.Add(checkIfLocalNameEquals);
+ }
+
+ return statements;
+ }
+
+ private SwitchCaseStatement CreatePersistableModelCreateCoreXmlSwitchCase(CSharpType typeForDeserialize)
+ {
+ return new SwitchCaseStatement(
+ ModelReaderWriterOptionsSnippets.XmlFormat,
+ new MethodBodyStatement[]
+ {
+ new UsingScopeStatement(typeof(Stream), "dataStream", _dataParameter.As().ToStream(), out var streamVar)
+ {
+ Return(GetDeserializationMethodInvocationForType(
+ typeForDeserialize,
+ XElementSnippets.Load(streamVar.As(), XmlLinqSnippets.PreserveWhitespace),
+ _dataParameter,
+ _serializationOptionsParameter))
+ },
+ });
+ }
+
+ private MethodProvider BuildXmlExplicitFromClientResult()
+ {
+ var result = new ParameterProvider(
+ ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ResponseParameterName,
+ $"The {ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseType:C} to deserialize the {Type:C} from.",
+ ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseType);
+ var modifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static |
+ MethodSignatureModifiers.Explicit | MethodSignatureModifiers.Operator;
+
+ var response = result.ToApi();
+ MethodBodyStatement responseDeclaration;
+
+ if (response.Original == response.GetRawResponse().Original)
+ {
+ responseDeclaration = MethodBodyStatement.Empty;
+ }
+ else
+ {
+ responseDeclaration = UsingDeclare("response", ScmCodeModelGenerator.Instance.TypeFactory.HttpResponseApi.HttpResponseType, result.ToApi().GetRawResponse(), out var responseVar);
+ response = responseVar.ToApi();
+ }
+
+ MethodBodyStatement[] methodBody =
+ [
+ responseDeclaration,
+ UsingDeclare("stream", typeof(Stream), response.Property(nameof(HttpResponseApi.ContentStream)), out var streamVar),
+ new IfStatement(streamVar.Equal(Null)) { Return(Default) },
+ MethodBodyStatement.EmptyLine,
+ Return(GetDeserializationMethodInvocationForType(
+ _model,
+ XElementSnippets.Load(streamVar.As(), XmlLinqSnippets.PreserveWhitespace)))
+ ];
+
+ return new MethodProvider(
+ new MethodSignature(Type.Name, null, modifiers, Type, null, [result]),
+ methodBody,
+ this);
+ }
+
+ private MethodProvider BuildJsonAndXmlExplicitFromClientResult()
+ {
+ var result = new ParameterProvider(
+ ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ResponseParameterName,
+ $"The {ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseType:C} to deserialize the {Type:C} from.",
+ ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseType);
+ var modifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static |
+ MethodSignatureModifiers.Explicit | MethodSignatureModifiers.Operator;
+
+ var response = result.ToApi();
+ MethodBodyStatement responseDeclaration;
+ ScopedApi tryGetContentType;
+ ScopedApi? contentTypeVar;
+
+ if (response.Original == response.GetRawResponse().Original)
+ {
+ responseDeclaration = MethodBodyStatement.Empty;
+ tryGetContentType = result.ToApi().TryGetHeader(ContentTypeHeader, out contentTypeVar);
+ }
+ else
+ {
+ responseDeclaration = UsingDeclare("response", ScmCodeModelGenerator.Instance.TypeFactory.HttpResponseApi.HttpResponseType, response.GetRawResponse(), out var responseVar);
+ response = responseVar.ToApi();
+ tryGetContentType = responseVar.ToApi().TryGetHeader(ContentTypeHeader, out contentTypeVar);
+ }
+
+ var startsWithJson = contentTypeVar!.StartsWith(Literal("application/json"), StringComparison.OrdinalIgnoreCase);
+ var isJsonCondition = tryGetContentType.And(startsWithJson);
+ var jsonDeserializationBlock = new MethodBodyStatement[]
+ {
+ UsingDeclare("document", typeof(JsonDocument), response.Property(nameof(HttpResponseApi.Content)).As().Parse(ModelSerializationExtensionsSnippets.JsonDocumentOptions), out var docVariable),
+ Return(GetDeserializationMethodInvocationForType(_model, docVariable.As().RootElement()))
+ };
+
+ var xmlDeserialization = new MethodBodyStatement[]
+ {
+ UsingDeclare("stream", typeof(Stream), response.Property(nameof(HttpResponseApi.ContentStream)), out var streamVar),
+ new IfStatement(streamVar.Equal(Null)) { Return(Default) },
+ MethodBodyStatement.EmptyLine,
+ Return(GetDeserializationMethodInvocationForType(_model, XElementSnippets.Load(streamVar.As(), XmlLinqSnippets.PreserveWhitespace)))
+ };
+
+ MethodBodyStatement[] methodBody =
+ [
+ responseDeclaration,
+ MethodBodyStatement.EmptyLine,
+ new IfStatement(isJsonCondition) { jsonDeserializationBlock },
+ MethodBodyStatement.EmptyLine,
+ xmlDeserialization
+ ];
+
+ return new MethodProvider(
+ new MethodSignature(Type.Name, null, modifiers, Type, null, [result]),
+ methodBody,
+ this);
+ }
+
+ private static void CollectNamespace(string propertyName, XmlSerializationNamespace nsOptions, Dictionary namespaces)
+ {
+ if (!namespaces.ContainsKey(nsOptions.Namespace))
+ {
+ var variableName = $"{propertyName}Ns".ToVariableName();
+ var variableExpression = new VariableExpression(typeof(XNamespace), variableName);
+ namespaces[nsOptions.Namespace] = new XmlNamespaceInfo(nsOptions.Namespace, variableName, variableExpression);
+ }
+ }
+
+ private static MethodBodyStatement GetXmlNamespaceDeclarations(Dictionary? namespaces)
+ {
+ if (namespaces == null || namespaces.Count == 0)
+ {
+ return MethodBodyStatement.Empty;
+ }
+
+ var statements = new List();
+ foreach (var ns in namespaces.Values)
+ {
+ statements.Add(Declare(ns.VariableExpression, Literal(ns.Namespace)));
+ }
+
+ statements.Add(MethodBodyStatement.EmptyLine);
+ return statements;
+ }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs
index 3fe0464ffcb..7c1f55bb3b5 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs
@@ -10,6 +10,7 @@
using System.Net;
using System.Text;
using System.Text.Json;
+using System.Xml.Linq;
using Microsoft.TypeSpec.Generator.ClientModel.Snippets;
using Microsoft.TypeSpec.Generator.ClientModel.Utilities;
using Microsoft.TypeSpec.Generator.EmitterRpc;
@@ -34,6 +35,7 @@ public partial class MrwSerializationTypeDefinition : TypeProvider
private const string JsonModelCreateCoreMethodName = "JsonModelCreateCore";
private const string PersistableModelWriteCoreMethodName = "PersistableModelWriteCore";
private const string PersistableModelCreateCoreMethodName = "PersistableModelCreateCore";
+ private const string DeserializationMethodNamePrefix = "Deserialize";
private const string WriteAction = "writing";
private const string ReadAction = "reading";
private readonly ParameterProvider _utf8JsonWriterParameter = new("writer", $"The JSON writer.", typeof(Utf8JsonWriter));
@@ -57,6 +59,8 @@ public partial class MrwSerializationTypeDefinition : TypeProvider
private readonly Lazy _additionalBinaryDataProperty;
private readonly PropertyProvider? _jsonPatchProperty;
private readonly bool _isStruct;
+ private readonly bool _supportsJson;
+ private readonly bool _supportsXml;
private ConstructorProvider? _serializationConstructor;
// Flag to determine if the model should override the serialization methods
private readonly bool _shouldOverrideMethods;
@@ -73,6 +77,8 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m
: null;
_inputModel = inputModel;
_isStruct = _model.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Struct);
+ _supportsJson = inputModel.Usage.HasFlag(InputModelTypeUsage.Json);
+ _supportsXml = inputModel.Usage.HasFlag(InputModelTypeUsage.Xml);
// Initialize the serialization interfaces
var interfaceType = inputModel.IsUnknownDiscriminatorModel ? ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel.BaseModel!)! : _model;
_jsonModelTInterface = new CSharpType(typeof(IJsonModel<>), interfaceType.Type);
@@ -86,6 +92,7 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m
_utf8JsonWriterSnippet = _utf8JsonWriterParameter.As();
_mrwOptionsParameterSnippet = _serializationOptionsParameter.As();
_jsonElementParameterSnippet = _jsonElementDeserializationParam.As();
+ _xmlElementParameterSnippet = _xElementDeserializationParam.As