diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index 0116180540d4..60f46b2492c7 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -439,6 +439,6 @@ 1.0.0-dev.20250501.1 1.0.0-alpha.20250523.1 - 1.0.0-alpha.20250515.2 + 1.0.0-alpha.20250523.1 diff --git a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementOutputLibrary.cs b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementOutputLibrary.cs index 1c708ef54d71..f539301b9b48 100644 --- a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementOutputLibrary.cs +++ b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementOutputLibrary.cs @@ -50,7 +50,14 @@ private static void BuildResourceCore(List resources, Li protected override TypeProvider[] BuildTypeProviders() { var (resources, collections) = BuildResources(); - return [.. base.BuildTypeProviders().Where(t => t is not InheritableSystemObjectModelProvider), ArmOperation, GenericArmOperation, .. resources, .. collections, .. resources.Select(r => r.Source)]; + return [ + .. base.BuildTypeProviders().Where(t => t is not InheritableSystemObjectModelProvider), + ArmOperation, + GenericArmOperation, + .. resources, + .. collections, + .. resources.Select(r => r.Source), + .. resources.SelectMany(r => r.SerializationProviders)]; } } } diff --git a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs index be437d8f7b0a..2b92dea88709 100644 --- a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs +++ b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs @@ -118,6 +118,8 @@ protected override PropertyProvider[] BuildProperties() return [hasDataProperty, dataProperty]; } + protected override TypeProvider[] BuildSerializationProviders() => [new ResourceSerializationProvider(this)]; + protected override ConstructorProvider[] BuildConstructors() => [ConstructorProviderHelper.BuildMockingConstructor(this), BuildResourceDataConstructor(), BuildResourceIdentifierConstructor()]; diff --git a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs index fe7a6dd037b8..38d85d72664d 100644 --- a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs +++ b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs @@ -52,6 +52,8 @@ public ResourceCollectionClientProvider(InputClient inputClient, ResourceMetadat } } + protected override TypeProvider[] BuildSerializationProviders() => []; + protected override string BuildName() => $"{SpecName}Collection"; protected override CSharpType[] BuildImplements() => diff --git a/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceSerializationProvider.cs b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceSerializationProvider.cs new file mode 100644 index 000000000000..386f85eace0f --- /dev/null +++ b/eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceSerializationProvider.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.TypeSpec.Generator.ClientModel.Snippets; +using Microsoft.TypeSpec.Generator.Expressions; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using System; +using System.ClientModel.Primitives; +using System.IO; +using System.Text.Json; +using static Microsoft.TypeSpec.Generator.Snippets.Snippet; + +namespace Azure.Generator.Management.Providers +{ + internal class ResourceSerializationProvider : TypeProvider + { + private readonly FieldProvider _dataField; + private readonly CSharpType _resourceDataType; + private readonly ResourceClientProvider _resoruce; + private readonly CSharpType _jsonModelInterfaceType; + public ResourceSerializationProvider(ResourceClientProvider resource) + { + _resoruce = resource; + _resourceDataType = resource.ResourceData.Type; + _jsonModelInterfaceType = new CSharpType(typeof(IJsonModel<>), _resourceDataType); + _dataField = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, _jsonModelInterfaceType, "s_dataDeserializationInstance", this); + } + + protected override string BuildName() => _resoruce.Name; + + protected override string BuildRelativeFilePath() + => Path.Combine("src", "Generated", $"{Name}.Serialization.cs"); + + protected override TypeSignatureModifiers BuildDeclarationModifiers() + => TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial; + + protected override CSharpType[] BuildImplements() => [_jsonModelInterfaceType]; + + protected override FieldProvider[] BuildFields() => [_dataField]; + + protected override PropertyProvider[] BuildProperties() => + [ + new PropertyProvider(null, MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, _jsonModelInterfaceType, "DataDeserializationInstance", new ExpressionPropertyBody(new AssignmentExpression(_dataField, New.Instance(_resourceDataType), true)), this) + ]; + + protected override MethodProvider[] BuildMethods() + { + var options = new ParameterProvider("options", $"The client options for reading and writing models.", typeof(ModelReaderWriterOptions)); + var iModelTInterface = new CSharpType(typeof(IPersistableModel<>), _resourceDataType); + var data = new ParameterProvider("data", $"The binary data to be processed.", typeof(BinaryData)); + + // void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + var writer = new ParameterProvider("writer", $"The writer to serialize the model to.", typeof(Utf8JsonWriter)); + var jsonModelWriteMethod = new MethodProvider( + new MethodSignature(nameof(IJsonModel.Write), null, MethodSignatureModifiers.None, null, null, [writer, options], ExplicitInterface: _jsonModelInterfaceType), + // => ((IJsonModel)Data).Write(writer, options); + new MemberExpression(null, "Data").CastTo(_jsonModelInterfaceType).Invoke(nameof(IJsonModel.Write), writer, options), + this); + + // T IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + var reader = new ParameterProvider("reader", $"The reader for deserializing the model.", typeof(Utf8JsonReader), isRef: true); + var jsonModelCreatemethod = new MethodProvider( + new MethodSignature(nameof(IJsonModel.Create), null, MethodSignatureModifiers.None, _resourceDataType, null, [reader, options], ExplicitInterface: _jsonModelInterfaceType), + // => DataDeserializationInstance.Create(reader, options); + new MemberExpression(null, "DataDeserializationInstance").Invoke(nameof(IJsonModel.Create), reader, options), + this); + + // BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + var persistableWriteMethod = new MethodProvider( + new MethodSignature(nameof(IPersistableModel.Write), null, MethodSignatureModifiers.None, typeof(BinaryData), null, [options], ExplicitInterface: iModelTInterface), + // => ModelReaderWriter.Write(Data, options); + Static(typeof(ModelReaderWriter)).Invoke("Write", [new MemberExpression(null, "Data"), options, ModelReaderWriterContextSnippets.Default], [_resourceDataType], false), + this); + + // T IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + var persistableCreateMethod = new MethodProvider( + new MethodSignature(nameof(IPersistableModel.Create), null, MethodSignatureModifiers.None, _resourceDataType, null, [data, options], ExplicitInterface: iModelTInterface), + // => ModelReaderWriter.Read(new BinaryData(reader.ValueSequence)); + Static(typeof(ModelReaderWriter)).Invoke("Read", [data, options, ModelReaderWriterContextSnippets.Default], [_resourceDataType], false), + this); + + // ModelReaderWriterFormat IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) + var persistableGetFormatMethod = new MethodProvider( + new MethodSignature(nameof(IPersistableModel.GetFormatFromOptions), null, MethodSignatureModifiers.None, typeof(string), null, [options], ExplicitInterface: iModelTInterface), + // => DataDeserializationInstance.GetFormatFromOptions(options); + new MemberExpression(null, "DataDeserializationInstance").Invoke(nameof(IPersistableModel.GetFormatFromOptions), options), + this); + + return [jsonModelWriteMethod, jsonModelCreatemethod, persistableWriteMethod, persistableCreateMethod, persistableGetFormatMethod]; + } + } +} \ No newline at end of file diff --git a/eng/packages/http-client-csharp-mgmt/generator/Directory.Build.props b/eng/packages/http-client-csharp-mgmt/generator/Directory.Build.props index 167d97e85200..6f83b87a83ac 100644 --- a/eng/packages/http-client-csharp-mgmt/generator/Directory.Build.props +++ b/eng/packages/http-client-csharp-mgmt/generator/Directory.Build.props @@ -3,7 +3,11 @@ enable false false - $(NoWarn);CS8002 + + $(NoWarn); + CS8002; + SCM0005; +