diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index c239069201b6..d663ad5c1d88 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -276,6 +276,7 @@ + diff --git a/eng/packages/http-client-csharp/emitter/src/sdk-context-options.ts b/eng/packages/http-client-csharp/emitter/src/sdk-context-options.ts index be00637ea0f5..4ef2d9901152 100644 --- a/eng/packages/http-client-csharp/emitter/src/sdk-context-options.ts +++ b/eng/packages/http-client-csharp/emitter/src/sdk-context-options.ts @@ -9,6 +9,14 @@ export const azureSDKContextOptions: CreateSdkContextOptions = { // https://github.com/Azure/typespec-azure/blob/main/packages/typespec-client-generator-core/README.md#usesystemtextjsonconverter "Azure\\.ClientGenerator\\.Core\\.@useSystemTextJsonConverter", // https://github.com/Azure/typespec-azure/blob/main/packages/typespec-azure-resource-manager/README.md#armprovidernamespace - "Azure\\.ResourceManager\\.@armProviderNamespace" + "Azure\\.ResourceManager\\.@armProviderNamespace", + // https://github.com/Azure/typespec-azure/blob/main/packages/typespec-azure-resource-manager/README.md#armresourceoperations + "Azure\\.ResourceManager\\.@armResourceOperations", + // https://github.com/Azure/typespec-azure/blob/main/packages/typespec-azure-resource-manager/README.md#armResourceRead + "Azure\\.ResourceManager\\.@armResourceRead", + // https://github.com/microsoft/typespec/blob/main/packages/rest/README.md#parentresource + "TypeSpec\\.Rest\\.parentResource", + // https://github.com/Azure/typespec-azure/blob/main/packages/typespec-azure-resource-manager/README.md#singleton + "Azure\\.ResourceManager\\.@singleton" ] }; diff --git a/eng/packages/http-client-csharp/eng/scripts/Generate.ps1 b/eng/packages/http-client-csharp/eng/scripts/Generate.ps1 index c62d8074bdde..a13969bb2aa1 100644 --- a/eng/packages/http-client-csharp/eng/scripts/Generate.ps1 +++ b/eng/packages/http-client-csharp/eng/scripts/Generate.ps1 @@ -18,10 +18,9 @@ if (-not $LaunchOnly) { Write-Host "Generating BasicTypeSpec" -ForegroundColor Cyan $testProjectsLocalDir = Join-Path $packageRoot 'generator' 'TestProjects' 'Local' - $unbrandedTypespecTestProject = Join-Path $testProjectsLocalDir "Basic-TypeSpec" - $unbrandedTypespecTestProject = $unbrandedTypespecTestProject + $basicTypespecTestProject = Join-Path $testProjectsLocalDir "Basic-TypeSpec" - Invoke (Get-TspCommand "$unbrandedTypespecTestProject/Basic-TypeSpec.tsp" $unbrandedTypespecTestProject -forceNewProject $ForceNewProject) + Invoke (Get-TspCommand "$basicTypespecTestProject/Basic-TypeSpec.tsp" $basicTypespecTestProject -forceNewProject $ForceNewProject) # exit if the generation failed if ($LASTEXITCODE -ne 0) { @@ -36,6 +35,28 @@ if (-not $LaunchOnly) { exit $LASTEXITCODE } } + + if ($null -eq $filter -or $filter -eq "Mgmt-TypeSpec") { + Write-Host "Generating MgmtTypeSpec" -ForegroundColor Cyan + $testProjectsLocalDir = Join-Path $packageRoot 'generator' 'TestProjects' 'Local' + + $mgmtTypespecTestProject = Join-Path $testProjectsLocalDir "Mgmt-TypeSpec" + + Invoke (Get-TspCommand "$mgmtTypespecTestProject/main.tsp" $mgmtTypespecTestProject -forceNewProject $ForceNewProject) + + # exit if the generation failed + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + + Write-Host "Building MgmtTypeSpec" -ForegroundColor Cyan + Invoke "dotnet build $packageRoot/generator/TestProjects/Local/Mgmt-TypeSpec/src/MgmtTypeSpec.csproj" + + # exit if the generation failed + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + } } $specsDirectory = "$packageRoot/node_modules/@typespec/http-specs" @@ -174,14 +195,20 @@ if ($null -eq $filter) { Write-Host "Writing new launch settings" -ForegroundColor Cyan $mgcExe = "`$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe" $sampleExe = "`$(SolutionDir)/../generator/artifacts/bin/SamplePlugin/Debug/net8.0/Microsoft.Generator.CSharp.exe" - $unbrandedSpec = "TestProjects/Local/Basic-TypeSpec" + $basicSpec = "TestProjects/Local/Basic-TypeSpec" + $mgmtSpec = "TestProjects/Local/Mgmt-TypeSpec" $launchSettings = @{} $launchSettings.Add("profiles", @{}) $launchSettings["profiles"].Add("Basic-TypeSpec", @{}) - $launchSettings["profiles"]["Basic-TypeSpec"].Add("commandLineArgs", "`$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll `$(SolutionDir)/$unbrandedSpec -p AzureClientPlugin") + $launchSettings["profiles"]["Basic-TypeSpec"].Add("commandLineArgs", "`$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll `$(SolutionDir)/$basicSpec -p AzureClientPlugin") $launchSettings["profiles"]["Basic-TypeSpec"].Add("commandName", "Executable") $launchSettings["profiles"]["Basic-TypeSpec"].Add("executablePath", "dotnet") + + $launchSettings["profiles"].Add("Mgmt-TypeSpec", @{}) + $launchSettings["profiles"]["Mgmt-TypeSpec"].Add("commandLineArgs", "`$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll `$(SolutionDir)/$mgmtSpec -p AzureClientPlugin") + $launchSettings["profiles"]["Mgmt-TypeSpec"].Add("commandName", "Executable") + $launchSettings["profiles"]["Mgmt-TypeSpec"].Add("executablePath", "dotnet") foreach ($kvp in $spectorLaunchProjects.GetEnumerator()) { $launchSettings["profiles"].Add($kvp.Key, @{}) diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureClientPlugin.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureClientPlugin.cs index 583c25447305..c441c62a7c6b 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureClientPlugin.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureClientPlugin.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.ResourceManager; using Azure.Generator.Utilities; using Microsoft.CodeAnalysis; using Microsoft.TypeSpec.Generator; @@ -9,6 +10,7 @@ using System.ComponentModel.Composition; using System.IO; using System.Linq; +using Azure.Generator.Primitives; namespace Azure.Generator; @@ -29,8 +31,6 @@ public class AzureClientPlugin : ScmCodeModelPlugin /// public override AzureOutputLibrary OutputLibrary => _azureOutputLibrary ??= new(); - internal ResourceDetection ResourceDetection { get; } = new(); - /// /// The Azure client plugin to generate the Azure client SDK. /// @@ -55,6 +55,8 @@ public override void Configure() AddVisitor(new NamespaceVisitor()); if (IsAzureArm.Value) { + // Include Azure.ResourceManager + AddMetadataReference(MetadataReference.CreateFromFile(typeof(ArmClient).Assembly.Location)); AddVisitor(new RestClientVisitor()); AddVisitor(new ResourceVisitor()); } @@ -71,5 +73,5 @@ public override void Configure() /// /// Identify if the input is generated for Azure ARM. /// - internal Lazy IsAzureArm => new Lazy(() => InputLibrary.InputNamespace.Clients.Any(c => c.Decorators.Any(d => d.Name.Equals("Azure.ResourceManager.@armProviderNamespace")))); + internal Lazy IsAzureArm => new Lazy(() => InputLibrary.InputNamespace.Clients.Any(c => c.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmProviderNamespace)))); } diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureOutputLibrary.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureOutputLibrary.cs index d2e9a8da24f4..09f561d9e57c 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureOutputLibrary.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureOutputLibrary.cs @@ -1,96 +1,61 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Azure.Generator.Mgmt.Models; +using Azure.Generator.Primitives; using Azure.Generator.Providers; -using Azure.Generator.Utilities; using Microsoft.TypeSpec.Generator.ClientModel; +using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Providers; using System.Collections.Generic; +using System.Linq; namespace Azure.Generator { /// public class AzureOutputLibrary : ScmOutputLibrary { - // TODO: categorize clients into operationSets, which contains operations sharing the same Path - private Dictionary _pathToOperationSetMap; - private Dictionary> _resourceDataBySpecNameMap; + private LongRunningOperationProvider? _armOperation; + internal LongRunningOperationProvider ArmOperation => _armOperation ??= new LongRunningOperationProvider(false); - /// - public AzureOutputLibrary() - { - _pathToOperationSetMap = CategorizeClients(); - _resourceDataBySpecNameMap = EnsureResourceDataMap(); - } + private LongRunningOperationProvider? _genericArmOperation; + internal LongRunningOperationProvider GenericArmOperation => _genericArmOperation ??= new LongRunningOperationProvider(true); - private Dictionary> EnsureResourceDataMap() + private IReadOnlyList BuildResources() { - var result = new Dictionary>(); - foreach (var operationSet in _pathToOperationSetMap.Values) + var result = new List(); + foreach (var client in AzureClientPlugin.Instance.InputLibrary.InputNamespace.Clients) { - if (AzureClientPlugin.Instance.ResourceDetection.TryGetResourceDataSchema(operationSet, out var resourceSpecName, out var resourceSchema)) + // A resource client should contain the decorator "Azure.ResourceManager.@armResourceOperations" + // and it should contain a get operation, which contains the decorator "Azure.ResourceManager.@armResourceRead" + if (client.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceOperations)) + && client.Operations.Any(operation => operation.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceRead)))) { - // if this operation set corresponds to a SDK resource, we add it to the map - if (!result.TryGetValue(resourceSpecName!, out HashSet? value)) - { - value = new HashSet(); - result.Add(resourceSpecName!, value); - } - value.Add(operationSet); + var resource = CreateResourceCore(client); + AzureClientPlugin.Instance.AddTypeToKeep(resource.Name); + result.Add(CreateResourceCore(client)); } } - return result; } - private Dictionary CategorizeClients() - { - var result = new Dictionary(); - foreach (var inputClient in AzureClientPlugin.Instance.InputLibrary.InputNamespace.Clients) - { - var requestPathList = new HashSet(); - foreach (var operation in inputClient.Operations) - { - var path = operation.GetHttpPath(); - requestPathList.Add(path); - if (result.TryGetValue(path, out var operationSet)) - { - operationSet.Add(operation); - } - else - { - operationSet = new OperationSet(path, inputClient) - { - operation - }; - result.Add(path, operationSet); - } - } - } - - // TODO: add operation set for the partial resources here - - return result; - } + /// + /// Create a resource client provider + /// + /// + /// + public virtual TypeProvider CreateResourceCore(InputClient inputClient) => new ResourceClientProvider(inputClient); /// - // TODO: generate resources and collections + // TODO: generate collections protected override TypeProvider[] BuildTypeProviders() { + var baseProviders = base.BuildTypeProviders(); if (AzureClientPlugin.Instance.IsAzureArm.Value == true) { - var armOperation = new MgmtLongRunningOperationProvider(false); - var genericArmOperation = new MgmtLongRunningOperationProvider(true); - - // TODO: remove them once they are referenced in Resource operation implementation - AzureClientPlugin.Instance.AddTypeToKeep(armOperation.Name); - AzureClientPlugin.Instance.AddTypeToKeep(genericArmOperation.Name); - return [.. base.BuildTypeProviders(), new RequestContextExtensionsDefinition(), armOperation, genericArmOperation]; + var resources = BuildResources(); + return [.. baseProviders, new RequestContextExtensionsDefinition(), ArmOperation, GenericArmOperation, .. resources, .. resources.Select(r => ((ResourceClientProvider)r).Source)]; } - return [.. base.BuildTypeProviders(), new RequestContextExtensionsDefinition()]; + return [.. baseProviders, new RequestContextExtensionsDefinition()]; } - - internal bool IsResource(string name) => _resourceDataBySpecNameMap.ContainsKey(name); } } diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/OperationSet.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/OperationSet.cs deleted file mode 100644 index feebbee65b16..000000000000 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/OperationSet.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Azure.Core; -using Azure.Generator.Utilities; -using Microsoft.TypeSpec.Generator.Input; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Azure.Generator.Mgmt.Models -{ - /// - /// An represents a collection of with the same request path. - /// - internal class OperationSet : IReadOnlyCollection, IEquatable - { - private readonly InputClient? _inputClient; - - /// - /// The raw request path of string of the operations in this - /// - public string RequestPath { get; } - - /// - /// The operation set - /// - private HashSet _operations; - - public int Count => _operations.Count; - - public OperationSet(string requestPath, InputClient? inputClient) - { - _inputClient = inputClient; - RequestPath = requestPath; - _operations = new HashSet(); - } - - /// - /// Add a new operation to this - /// - /// The operation to be added - /// when trying to add an operation with a different path from - public void Add(InputOperation operation) - { - var path = operation.GetHttpPath(); - if (path != RequestPath) - throw new InvalidOperationException($"Cannot add operation with path {path} to OperationSet with path {RequestPath}"); - _operations.Add(operation); - } - - public IEnumerator GetEnumerator() => _operations.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => _operations.GetEnumerator(); - - public override int GetHashCode() - { - return RequestPath.GetHashCode(); - } - - public bool Equals([AllowNull] OperationSet other) - { - if (other is null) - return false; - - return RequestPath == other.RequestPath; - } - - /// - /// Get the operation with the given verb. - /// We cannot have two operations with the same verb under the same request path, therefore this method is only returning one operation or null - /// - /// - /// - public InputOperation? GetOperation(RequestMethod method) - { - foreach (var operation in _operations) - { - if (operation.HttpMethod == method.ToString()) - return operation; - } - - return null; - } - - private InputOperation? FindBestOperation() - { - // first we try GET operation - var getOperation = FindOperation(RequestMethod.Get); - if (getOperation != null) - return getOperation; - // if no GET operation, we return PUT operation - var putOperation = FindOperation(RequestMethod.Put); - if (putOperation != null) - return putOperation; - - // if no PUT or GET, we just return the first one - return _operations.FirstOrDefault(); - } - - public InputOperation? FindOperation(RequestMethod method) - { - return this.FirstOrDefault(operation => operation.HttpMethod == method.ToString()); - } - - public override string? ToString() - { - return RequestPath; - } - } -} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/RequestPath.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/RequestPath.cs new file mode 100644 index 000000000000..95e41abdcdbd --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Mgmt/Models/RequestPath.cs @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Azure.Generator.Mgmt.Models +{ + internal class RequestPath : IEquatable, IReadOnlyList + { + private const string ProviderPath = "/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}"; + private const string FeaturePath = "/subscriptions/{subscriptionId}/providers/Microsoft.Features/providers/{resourceProviderNamespace}/features"; + + public const string ManagementGroupScopePrefix = "/providers/Microsoft.Management/managementGroups"; + public const string ResourceGroupScopePrefix = "/subscriptions/{subscriptionId}/resourceGroups"; + public const string SubscriptionScopePrefix = "/subscriptions"; + public const string TenantScopePrefix = "/tenants"; + public const string Providers = "/providers"; + + public static readonly RequestPath ManagementGroup = new("/providers/Microsoft.Management/managementGroups/{managementGroupId}"); + public static readonly RequestPath ResourceGroup = new("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}"); + public static readonly RequestPath Subscription = new("/subscriptions/{subscriptionId}"); + public static readonly RequestPath Tenant = new(string.Empty); + + private string _path; + private IReadOnlyList _segments; + + public RequestPath(string path) + { + _path = path; + _segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries); + IndexOfLastProviders = _path.LastIndexOf(Providers); + } + + public RequestPath(IEnumerable segments) + { + _segments = segments.ToArray(); + _path = string.Join("/", _segments); + } + + public int Count => _segments.Count; + + public string SerializedPath => _path; + + public int IndexOfLastProviders { get; } + + public string this[int index] => _segments[index]; + + /// + /// Check if this is a prefix path of the other request path. + /// Note that this.IsAncestorOf(this) will return false which indicates that this method is testing the "proper ancestor" like a proper subset. + /// + /// + /// + public bool IsAncestorOf(RequestPath other) + { + // To be the parent of other, you must at least be shorter than other. + if (other.Count <= Count) + return false; + for (int i = 0; i < Count; i++) + { + // we need the segment to be identical when strict is true (which is the default value) + // when strict is false, we also need the segment to be identical if it is constant. + // but if it is a reference, we only require they have the same type, do not require they have the same variable name. + // This case happens a lot during the management group parent detection - different RP calls this different things + if (!this[i].Equals(other[i])) + return false; + } + return true; + } + + /// + /// Trim this from the other and return the that remain. + /// The result is "other - this" by removing this as a prefix of other. + /// If this == other, return empty request path + /// + /// + /// + /// if this.IsAncestorOf(other) is false + public RequestPath TrimAncestorFrom(RequestPath other) + { + if (TryTrimAncestorFrom(other, out var diff)) + return diff; + + throw new InvalidOperationException($"Request path {this} is not parent of {other}"); + } + + private bool TryTrimAncestorFrom(RequestPath other, [MaybeNullWhen(false)] out RequestPath diff) + { + diff = default; + if (this == other) + { + diff = Tenant; + return true; + } + if (IsAncestorOf(other)) + { + diff = new RequestPath(string.Join("", other._segments.Skip(Count))); + return true; + } + // Handle the special case of trim provider from feature + else if (_path == ProviderPath && other._path.StartsWith(FeaturePath)) + { + diff = new RequestPath(string.Join("", other._segments.Skip(Count + 2))); + return true; + } + return false; + } + + public bool Equals(RequestPath? other) + { + if (Count != other?.Count) + return false; + for (int i = 0; i < Count; i++) + { + if (!this[i].Equals(other[i])) + return false; + } + return true; + } + + public override bool Equals(object? obj) => obj is RequestPath other && Equals(other); + + public override int GetHashCode() => _path.GetHashCode(); + + public override string ToString() => _path; + + public IEnumerator GetEnumerator() => _segments.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => _segments.GetEnumerator(); + + public static bool operator ==(RequestPath left, RequestPath right) + { + return left.Equals(right); + } + + public static bool operator !=(RequestPath left, RequestPath right) + { + return !(left == right); + } + + public static implicit operator string(RequestPath requestPath) + { + return requestPath._path; + } + + public static bool IsSegmentConstant(string segment) + { + var trimmed = segment.TrimStart('{').TrimEnd('}'); + var isScope = trimmed == "scope"; + return !isScope && !segment.StartsWith('{'); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownAzureParameters.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownAzureParameters.cs new file mode 100644 index 000000000000..1389eceebbc4 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownAzureParameters.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using System.Threading; + +namespace Azure.Generator.Primitives +{ + internal class KnownAzureParameters + { + public static readonly ParameterProvider Response = new("response", $"The response from the service.", new CSharpType(typeof(Response))); + + public static readonly ParameterProvider WaitUntil = new("waitUntil", $" if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples.", new CSharpType(typeof(WaitUntil))); + + public static readonly ParameterProvider CancellationTokenWithoutDefault = new("cancellationToken", $"The cancellation token to use.", new CSharpType(typeof(CancellationToken))); + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownDecorators.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownDecorators.cs new file mode 100644 index 000000000000..f9ba6a2b6533 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Primitives/KnownDecorators.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Generator.Primitives +{ + internal class KnownDecorators + { + public const string ArmResourceOperations = "Azure.ResourceManager.@armResourceOperations"; + public const string ArmResourceRead = "Azure.ResourceManager.@armResourceRead"; + public const string ArmProviderNamespace = "Azure.ResourceManager.@armProviderNamespace"; + public const string Singleton= "Azure.ResourceManager.@singleton"; + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Properties/launchSettings.json b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Properties/launchSettings.json index 1fd60a55a7a8..206cc9b0b730 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Properties/launchSettings.json +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Properties/launchSettings.json @@ -144,6 +144,11 @@ "commandLineArgs": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll $(SolutionDir)/TestProjects/Spector/http/type/property/nullable -p AzureStubPlugin", "commandName": "Executable", "executablePath": "dotnet" + }, + "Mgmt-TypeSpec": { + "commandLineArgs": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.dll $(SolutionDir)/TestProjects/Local/Mgmt-TypeSpec -p AzureClientPlugin", + "commandName": "Executable", + "executablePath": "dotnet" } } } diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/Abstraction/HttpPipelineProvider.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/Abstraction/HttpPipelineProvider.cs index aa6fe8374432..c6f557002d61 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/Abstraction/HttpPipelineProvider.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/Abstraction/HttpPipelineProvider.cs @@ -37,7 +37,7 @@ public override ValueExpression Create(ValueExpression options, ValueExpression => Static(typeof(HttpPipelineBuilder)).Invoke(nameof(HttpPipelineBuilder.Build), [options, perRetryPolicies]); public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - => Original.Invoke(nameof(HttpPipeline.CreateMessage), requestOptions, responseClassifier).As(); + => AzureClientPlugin.Instance.IsAzureArm.Value ? Original.Invoke(nameof(HttpPipeline.CreateMessage)) : Original.Invoke(nameof(HttpPipeline.CreateMessage), requestOptions, responseClassifier).As(); public override ClientPipelineApi FromExpression(ValueExpression expression) => new HttpPipelineProvider(expression); diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/MgmtLongRunningOperationProvider.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/LongRunningOperationProvider.cs similarity index 98% rename from eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/MgmtLongRunningOperationProvider.cs rename to eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/LongRunningOperationProvider.cs index 9082319badf7..55fcee6f545f 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/MgmtLongRunningOperationProvider.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/LongRunningOperationProvider.cs @@ -19,7 +19,7 @@ namespace Azure.Generator.Providers { - internal class MgmtLongRunningOperationProvider : TypeProvider + internal class LongRunningOperationProvider : TypeProvider { private class Template { } private readonly CSharpType _t = typeof(Template<>).GetGenericArguments()[0]; @@ -30,7 +30,7 @@ private class Template { } private FieldProvider _nextLinkOperationField; private FieldProvider _operationIdField; - public MgmtLongRunningOperationProvider(bool isGeneric) + public LongRunningOperationProvider(bool isGeneric) { _isGeneric = isGeneric; _operationField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, isGeneric ? new CSharpType(typeof(OperationInternal<>), _t) : typeof(OperationInternal), "_operation", this); @@ -174,7 +174,7 @@ private ConstructorProvider BuildInitializationConstructor() skipApiVersionOverrideParameter, apiVersionOverrideValueParameter, }; - var signature = new ConstructorSignature(Type, $"", MethodSignatureModifiers.Internal, parameters, null); + var signature = new ConstructorSignature(Type, $"", MethodSignatureModifiers.Internal, parameters); var responseDeclaration = Declare("nextLinkOperation", typeof(IOperation), Static(typeof(NextLinkOperationImplementation)).Invoke("Create", [pipelineParameter, requestParameter.Property("Method"), requestParameter.Property("Uri").Invoke("ToUri"), responseParameter, finalStateViaParameter, skipApiVersionOverrideParameter, apiVersionOverrideValueParameter]), out var nextLinkOperationVariable); var body = new MethodBodyStatement[] diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/OperationSourceProvider.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/OperationSourceProvider.cs new file mode 100644 index 000000000000..7e3fd3512bcd --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/OperationSourceProvider.cs @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using Azure.Generator.Primitives; +using Azure.ResourceManager; +using Microsoft.TypeSpec.Generator.ClientModel.Providers; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Statements; +using System.ClientModel.Primitives; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using static Microsoft.TypeSpec.Generator.Snippets.Snippet; + +namespace Azure.Generator.Providers +{ + internal class OperationSourceProvider : TypeProvider + { + private ResourceClientProvider _resource; + private CSharpType _operationSourceInterface; + + private FieldProvider _clientField; + + public OperationSourceProvider(ResourceClientProvider resource) + { + _resource = resource; + _clientField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(ArmClient), "_client", this); + _operationSourceInterface = new CSharpType(typeof(IOperationSource<>), _resource.Type); + } + + protected override string BuildName() => $"{_resource.SpecName}OperationSource"; + + protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "LongRunningOperation", $"{Name}.cs"); + + protected override CSharpType[] BuildImplements() + { + return [new CSharpType(typeof(IOperationSource<>), _resource.Type)]; + } + + protected override MethodProvider[] BuildMethods() => [BuildCreateResult(), BuildCreateResultAsync()]; + + private MethodProvider BuildCreateResultAsync() + { + var signature = new MethodSignature( + "CreateResultAsync", + null, + MethodSignatureModifiers.Async, + new CSharpType(typeof(ValueTask<>), _resource.Type), + $"", + [KnownAzureParameters.Response, KnownAzureParameters.CancellationTokenWithoutDefault], + ExplicitInterface: _operationSourceInterface); + var body = new MethodBodyStatement[] + { + UsingDeclare("document", typeof(JsonDocument), Static(typeof(JsonDocument)).Invoke(nameof(JsonDocument.ParseAsync), [KnownAzureParameters.Response.Property(nameof(Response.ContentStream)), Default, KnownAzureParameters.CancellationTokenWithoutDefault], true), out var documentVariable), + Declare("data", _resource.ResourceData.Type, Static(_resource.ResourceData.Type).Invoke($"Deserialize{_resource.ResourceData.Name}", documentVariable.Property(nameof(JsonDocument.RootElement)), Static().Property("WireOptions").As()), out var dataVariable), + Return(New.Instance(_resource.Type, [_clientField, dataVariable])), + }; + return new MethodProvider(signature, body, this); + } + + private MethodProvider BuildCreateResult() + { + var signature = new MethodSignature( + "CreateResult", + null, + MethodSignatureModifiers.None, + _resource.Type, + $"", + [KnownAzureParameters.Response, KnownAzureParameters.CancellationTokenWithoutDefault], + ExplicitInterface: _operationSourceInterface); + var body = new MethodBodyStatement[] + { + UsingDeclare("document", typeof(JsonDocument), Static(typeof(JsonDocument)).Invoke(nameof(JsonDocument.Parse), [KnownAzureParameters.Response.Property(nameof(Response.ContentStream))]), out var documentVariable), + Declare("data", _resource.ResourceData.Type, Static(_resource.ResourceData.Type).Invoke($"Deserialize{_resource.ResourceData.Name}", documentVariable.Property(nameof(JsonDocument.RootElement)), New.Instance(Literal("W"))), out var dataVariable), + Return(New.Instance(_resource.Type, [_clientField, dataVariable])), + }; + return new MethodProvider(signature, body, this); + } + + protected override FieldProvider[] BuildFields() => [_clientField]; + + protected override ConstructorProvider[] BuildConstructors() => [BuildInitializationConstructor()]; + + private ConstructorProvider BuildInitializationConstructor() + { + var clientParameter = new ParameterProvider("client", $"", typeof(ArmClient)); + var signature = new ConstructorSignature(Type, $"", MethodSignatureModifiers.Internal, [clientParameter]); + var body = new MethodBodyStatement[] + { + _clientField.Assign(clientParameter).Terminate(), + }; + return new ConstructorProvider(signature, body, this); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/ResourceClientProvider.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/ResourceClientProvider.cs new file mode 100644 index 000000000000..ace446cddd1e --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Providers/ResourceClientProvider.cs @@ -0,0 +1,418 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Generator.Mgmt.Models; +using Azure.Generator.Primitives; +using Azure.Generator.Utilities; +using Azure.ResourceManager; +using Microsoft.TypeSpec.Generator.ClientModel.Providers; +using Microsoft.TypeSpec.Generator.Expressions; +using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Snippets; +using Microsoft.TypeSpec.Generator.Statements; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static Microsoft.TypeSpec.Generator.Snippets.Snippet; + +namespace Azure.Generator.Providers +{ + /// + /// Provides a resource client type. + /// + internal class ResourceClientProvider : TypeProvider + { + private const string ResourceGroupScopePrefix = "/subscriptions/{subscriptionId}/resourceGroups"; + private const string SubscriptionScopePrefix = "/subscriptions"; + private const string TenantScopePrefix = "/tenants"; + + private IReadOnlyCollection _resourceOperations; + private ClientProvider _clientProvider; + private readonly IReadOnlyList _contextualParameters; + private bool _isSingleton; + + private FieldProvider _dataField; + private FieldProvider _clientDiagonosticsField; + private FieldProvider _restClientField; + private FieldProvider _resourcetypeField; + + public ResourceClientProvider(InputClient inputClient) + { + var getResourceOperation = inputClient.Operations.First(operation => operation.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceRead))); + var resourceModel = (InputModelType)getResourceOperation.Responses.First(r => r.BodyType != null).BodyType!; + var requestPath = new RequestPath(getResourceOperation.Path); + + _resourceOperations = inputClient.Operations.Where(operation => operation.Path.Equals(requestPath)).ToList(); + SpecName = resourceModel.Name; + ResourceData = AzureClientPlugin.Instance.TypeFactory.CreateModel(resourceModel)!; + _isSingleton = resourceModel.Decorators.Any(d => d.Name.Equals(KnownDecorators.Singleton)); + _clientProvider = AzureClientPlugin.Instance.TypeFactory.CreateClient(inputClient)!; + _contextualParameters = GetContextualParameters(requestPath); + + _dataField = new FieldProvider(FieldModifiers.Private, ResourceData.Type, "_data", this); + _clientDiagonosticsField = new FieldProvider(FieldModifiers.Private, typeof(ClientDiagnostics), $"_{SpecName.ToLower()}ClientDiagnostics", this); + _restClientField = new FieldProvider(FieldModifiers.Private, _clientProvider.Type, $"_{SpecName.ToLower()}RestClient", this); + _resourcetypeField = new FieldProvider(FieldModifiers.Public | FieldModifiers.Static | FieldModifiers.ReadOnly, typeof(ResourceType), "ResourceType", this, description: $"Gets the resource type for the operations.", initializationValue: Literal(GetResourceTypeFromPath(requestPath))); + } + + private static string GetResourceTypeFromPath(RequestPath requestPath) + { + var index = requestPath.IndexOfLastProviders; + if (index < 0) + { + if (requestPath.SerializedPath.StartsWith(ResourceGroupScopePrefix, StringComparison.OrdinalIgnoreCase)) + { + return "Microsoft.Resources/resourceGroups"; + } + else if (requestPath.SerializedPath.StartsWith(SubscriptionScopePrefix, StringComparison.OrdinalIgnoreCase)) + { + return "Microsoft.Resources/subscriptions"; + } + else if (requestPath.SerializedPath.StartsWith(TenantScopePrefix, StringComparison.OrdinalIgnoreCase)) + { + return "Microsoft.Resources/tenants"; + } + throw new InvalidOperationException($"Cannot find resource type from path {requestPath}"); + } + + var left = new RequestPath(requestPath.SerializedPath.Substring(index + RequestPath.Providers.Length)); + var result = new StringBuilder(left[0]); + for (int i = 1; i < left.Count; i += 2) + { + result.Append($"/{left[i]}"); + } + return result.ToString(); + } + + private IReadOnlyList GetContextualParameters(string contextualRequestPath) + { + var contextualParameters = new List(); + var contextualSegments = new RequestPath(contextualRequestPath); + foreach (var segment in contextualSegments) + { + if (segment.StartsWith("{")) + { + contextualParameters.Add(segment.TrimStart('{').TrimEnd('}')); + } + } + return contextualParameters; + } + + protected override string BuildName() => $"{SpecName}Resource"; + + private OperationSourceProvider? _source; + internal OperationSourceProvider Source => _source ??= new OperationSourceProvider(this); + + internal ModelProvider ResourceData { get; } + internal string SpecName { get; } + + protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.cs"); + + protected override FieldProvider[] BuildFields() => [_dataField, _clientDiagonosticsField, _restClientField, _resourcetypeField]; + + protected override PropertyProvider[] BuildProperties() + { + var hasDataProperty = new PropertyProvider( + $"Gets whether or not the current instance has data.", + MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual, + typeof(bool), + "HasData", + new AutoPropertyBody(false), + this); + + var dataProperty = new PropertyProvider( + $"Gets the data representing this Feature.", + MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual, + ResourceData.Type, + "Data", + new MethodPropertyBody(new MethodBodyStatement[] + { + new IfStatement(Not(hasDataProperty)) + { + Throw(New.Instance(typeof(InvalidOperationException), Literal("The current instance does not have data, you must call Get first."))) + }, + Return(_dataField) + }), + this); + + return [hasDataProperty, dataProperty]; + } + + protected override ConstructorProvider[] BuildConstructors() + => [ConstructorProviderHelper.BuildMockingConstructor(this), BuildPrimaryConstructor(), BuildInitializationConstructor(),]; + + private ConstructorProvider BuildPrimaryConstructor() + { + var clientParameter = new ParameterProvider("client", $"The client parameters to use in these operations.", typeof(ArmClient)); + var dataParameter = new ParameterProvider("data", $"The resource that is the target of operations.", ResourceData.Type); + + var initializer = new ConstructorInitializer(false, [clientParameter, dataParameter.Property("Id")]); + var signature = new ConstructorSignature( + Type, + $"Initializes a new instance of {Type:C} class.", + MethodSignatureModifiers.Internal, + [clientParameter, dataParameter], + null, + initializer); + + var bodyStatements = new MethodBodyStatement[] + { + This.Property("HasData").Assign(Literal(true)).Terminate(), + _dataField.Assign(dataParameter).Terminate(), + }; + + return new ConstructorProvider(signature, bodyStatements, this); + } + + private ConstructorProvider BuildInitializationConstructor() + { + var idParameter = new ParameterProvider("id", $"The identifier of the resource that is the target of operations.", typeof(ResourceIdentifier)); + var parameters = new List + { + new("client", $"The client parameters to use in these operations.", typeof(ArmClient)), + idParameter + }; + + var initializer = new ConstructorInitializer(true, parameters); + var signature = new ConstructorSignature( + Type, + $"Initializes a new instance of {Type:C} class.", + MethodSignatureModifiers.Internal, + parameters, + null, + initializer); + + var bodyStatements = new MethodBodyStatement[] + { + _clientDiagonosticsField.Assign(New.Instance(typeof(ClientDiagnostics), Literal(Type.Namespace), _resourcetypeField.Property(nameof(ResourceType.Namespace)), This.Property("Diagnostics"))).Terminate(), + TryGetApiVersion(out var apiVersion).Terminate(), + _restClientField.Assign(New.Instance(_clientProvider.Type, This.Property("Pipeline"), This.Property("Endpoint"), apiVersion)).Terminate(), + Static(Type).Invoke(ValidateResourceIdMethodName, idParameter).Terminate() + }; + + return new ConstructorProvider(signature, bodyStatements, this); + } + + private const string ValidateResourceIdMethodName = "ValidateResourceId"; + private MethodProvider BuildValidateResourceIdMethod() + { + var idParameter = new ParameterProvider("id", $"", typeof(ResourceIdentifier)); + var signature = new MethodSignature( + ValidateResourceIdMethodName, + null, + MethodSignatureModifiers.Internal | MethodSignatureModifiers.Static, + null, + null, + [ + idParameter + ], + [new AttributeStatement(typeof(ConditionalAttribute), Literal("DEBUG"))]); + var bodyStatements = new IfStatement(idParameter.NotEqual(_resourcetypeField)) + { + Throw(New.ArgumentException(idParameter, StringSnippets.Format(Literal("Invalid resource type {0} expected {1}"), idParameter.Property(nameof(ResourceIdentifier.ResourceType)), _resourcetypeField), false)) + }; + return new MethodProvider(signature, bodyStatements, this); + } + + protected override CSharpType[] BuildImplements() => [typeof(ArmResource)]; + + protected override MethodProvider[] BuildMethods() + { + var operationMethods = new List(); + foreach (var operation in _resourceOperations) + { + var convenienceMethod = GetCorrespondingConvenienceMethod(operation, false); + // exclude the List operations for resource, they will be in ResourceCollection + if (convenienceMethod.IsListMethod(out var itemType) && itemType.AreNamesEqual(ResourceData.Type)) + { + continue; + } + + // only update for non-singleton resource + var isUpdateOnly = operation.HttpMethod == HttpMethod.Put.ToString() && !_isSingleton; + operationMethods.Add(BuildOperationMethod(operation, convenienceMethod, false, isUpdateOnly)); + var asyncConvenienceMethod = GetCorrespondingConvenienceMethod(operation, true); + operationMethods.Add(BuildOperationMethod(operation, asyncConvenienceMethod, true, isUpdateOnly)); + } + + return [BuildValidateResourceIdMethod(), .. operationMethods]; + } + + private MethodProvider BuildOperationMethod(InputOperation operation, MethodProvider convenienceMethod, bool isAsync, bool isUpdateOnly = false) + { + var isLongRunning = operation.LongRunning != null; + var signature = new MethodSignature( + isUpdateOnly ? (isAsync ? "UpdateAsync" : "Update") : convenienceMethod.Signature.Name, + isUpdateOnly ? $"Update a {SpecName}" : convenienceMethod.Signature.Description, + convenienceMethod.Signature.Modifiers, + GetOperationMethodReturnType(isAsync, isLongRunning, operation.Responses, out var isGeneric), + convenienceMethod.Signature.ReturnDescription, + GetOperationMethodParameters(convenienceMethod, isLongRunning), + convenienceMethod.Signature.Attributes, + convenienceMethod.Signature.GenericArguments, + convenienceMethod.Signature.GenericParameterConstraints, + convenienceMethod.Signature.ExplicitInterface, + convenienceMethod.Signature.NonDocumentComment); + + var bodyStatements = new MethodBodyStatement[] + { + UsingDeclare("scope", typeof(DiagnosticScope), _clientDiagonosticsField.Invoke(nameof(ClientDiagnostics.CreateScope), [Literal($"{Type.Namespace}.{operation.Name}")]), out var scopeVariable), + scopeVariable.Invoke(nameof(DiagnosticScope.Start)).Terminate(), + new TryCatchFinallyStatement + (BuildOperationMethodTryStatement(convenienceMethod, isAsync, isLongRunning, operation, isGeneric), Catch(Declare("e", out var exceptionVarialble), [scopeVariable.Invoke(nameof(DiagnosticScope.Failed), exceptionVarialble).Terminate(), Throw()])) + }; + + return new MethodProvider(signature, bodyStatements, this); + } + + private IReadOnlyList GetOperationMethodParameters(MethodProvider convenienceMethod, bool isLongRunning) + { + var result = new List(); + if (isLongRunning) + { + result.Add(KnownAzureParameters.WaitUntil); + } + foreach (var parameter in convenienceMethod.Signature.Parameters) + { + if (!_contextualParameters.Contains(parameter.Name)) + { + result.Add(parameter); + } + } + return result; + } + + private CSharpType GetOperationMethodReturnType(bool isAsync, bool isLongRunningOperation, IReadOnlyList operationResponses, out bool isGeneric) + { + isGeneric = false; + if (isLongRunningOperation) + { + var response = operationResponses.FirstOrDefault(r => !r.IsErrorResponse); + var responseBodyType = response?.BodyType is null ? null : AzureClientPlugin.Instance.TypeFactory.CreateCSharpType(response.BodyType); + if (responseBodyType is null) + { + return isAsync ? new CSharpType(typeof(Task<>), typeof(ArmOperation)) : typeof(ArmOperation); + } + else + { + isGeneric = true; + return isAsync ? new CSharpType(typeof(Task<>), new CSharpType(typeof(ArmOperation<>), Type)) : new CSharpType(typeof(ArmOperation<>), Type); + } + } + return isAsync ? new CSharpType(typeof(Task<>), new CSharpType(typeof(Response<>), Type)) : new CSharpType(typeof(Response<>), Type); + } + + private TryStatement BuildOperationMethodTryStatement(MethodProvider convenienceMethod, bool isAsync, bool isLongRunning, InputOperation operation, bool isGeneric) + { + var cancellationToken = convenienceMethod.Signature.Parameters.Single(p => p.Type.Equals(typeof(CancellationToken))); + var tryStatement = new TryStatement(); + var contextDeclaration = Declare("context", typeof(RequestContext), New.Instance(typeof(RequestContext), new Dictionary { { Identifier(nameof(RequestContext.CancellationToken)), cancellationToken } }), out var contextVariable); + tryStatement.Add(contextDeclaration); + var requestMethod = GetCorrespondingRequestMethod(operation); + var messageDeclaration = Declare("message", typeof(HttpMessage), _restClientField.Invoke(requestMethod.Signature.Name, PopulateArguments(requestMethod.Signature.Parameters, convenienceMethod, contextVariable)), out var messageVariable); + tryStatement.Add(messageDeclaration); + var responseType = GetResponseType(convenienceMethod, isAsync); + VariableExpression responseVariable; + if (!responseType.Equals(typeof(Response))) + { + var resultDeclaration = Declare("result", typeof(Response), This.Property("Pipeline").Invoke(isAsync ? "ProcessMessageAsync" : "ProcessMessage", [messageVariable, contextVariable], null, isAsync), out var resultVariable); + tryStatement.Add(resultDeclaration); + var responseDeclaration = Declare("response", responseType, Static(typeof(Response)).Invoke(nameof(Response.FromValue), [resultVariable.CastTo(ResourceData.Type), resultVariable]), out responseVariable); + tryStatement.Add(responseDeclaration); + } + else + { + var responseDeclaration = Declare("response", typeof(Response), This.Property("Pipeline").Invoke(isAsync ? "ProcessMessageAsync" : "ProcessMessage", [messageVariable, contextVariable], null, isAsync), out responseVariable); + tryStatement.Add(responseDeclaration); + } + + if (isLongRunning) + { + var armOperationType = !isGeneric ? AzureClientPlugin.Instance.OutputLibrary.ArmOperation.Type : AzureClientPlugin.Instance.OutputLibrary.GenericArmOperation.Type.MakeGenericType([Type]); + ValueExpression[] armOperationArguments = [_clientDiagonosticsField, This.Property("Pipeline"), messageVariable.Property("Request"), isGeneric ? responseVariable.Invoke("GetRawResponse") : responseVariable, Static(typeof(OperationFinalStateVia)).Property(((OperationFinalStateVia)operation.LongRunning!.FinalStateVia).ToString())]; + var operationDeclaration = Declare("operation", armOperationType, New.Instance(armOperationType, isGeneric ? [New.Instance(Source.Type, This.Property("Client")), .. armOperationArguments] : armOperationArguments), out var operationVariable); + + tryStatement.Add(operationDeclaration); + tryStatement.Add(new IfStatement(KnownAzureParameters.WaitUntil.Equal(Static(typeof(WaitUntil)).Property(nameof(WaitUntil.Completed)))) + { + isAsync + ? operationVariable.Invoke(isGeneric ? "WaitForCompletionAsync" : "WaitForCompletionResponseAsync", [cancellationToken], null, isAsync).Terminate() + : operationVariable.Invoke(isGeneric ? "WaitForCompletion" : "WaitForCompletionResponse", cancellationToken).Terminate() + }); + tryStatement.Add(Return(operationVariable)); + } + else + { + tryStatement.Add(new IfStatement(responseVariable.Property("Value").Equal(Null)) + { + ((KeywordExpression)ThrowExpression(New.Instance(typeof(RequestFailedException), responseVariable.Invoke("GetRawResponse")))).Terminate() + }); + tryStatement.Add(Return(Static(typeof(Response)).Invoke(nameof(Response.FromValue), New.Instance(Type, This.Property("Client"), responseVariable.Property("Value")), responseVariable.Invoke("GetRawResponse")))); + } + return tryStatement; + } + + private static CSharpType GetResponseType(MethodProvider convenienceMethod, bool isAsync) => isAsync ? convenienceMethod.Signature.ReturnType?.Arguments[0]! : convenienceMethod.Signature.ReturnType!; + + private ValueExpression[] PopulateArguments(IReadOnlyList parameters, MethodProvider convenienceMethod, VariableExpression contextVariable) + { + var arguments = new List(); + foreach (var parameter in parameters) + { + if (parameter.Name.Equals("subscriptionId", StringComparison.InvariantCultureIgnoreCase)) + { + arguments.Add(Static(typeof(Guid)).Invoke(nameof(Guid.Parse), This.Property(nameof(ArmResource.Id)).Property(nameof(ResourceIdentifier.SubscriptionId)))); + } + else if (parameter.Name.Equals("resourceGroupName", StringComparison.InvariantCultureIgnoreCase)) + { + arguments.Add(This.Property(nameof(ArmResource.Id)).Property(nameof(ResourceIdentifier.ResourceGroupName))); + } + // TODO: handle parents + else if (parameter.Name.Equals(_contextualParameters.Last(), StringComparison.InvariantCultureIgnoreCase)) + { + arguments.Add(This.Property(nameof(ArmResource.Id)).Property(nameof(ResourceIdentifier.Name))); + } + else if (parameter.Type.Equals(typeof(RequestContent))) + { + var resource = convenienceMethod.Signature.Parameters.Single(p => p.Type.Equals(ResourceData.Type)); + arguments.Add(resource); + } + else if (parameter.Type.Equals(typeof(RequestContext))) + { + var cancellationToken = convenienceMethod.Signature.Parameters.Single(p => p.Type.Equals(typeof(CancellationToken))); + arguments.Add(contextVariable); + } + else + { + arguments.Add(parameter); + } + } + return arguments.ToArray(); + } + + // TODO: get clean name of operation Name + private MethodProvider GetCorrespondingConvenienceMethod(InputOperation operation, bool isAsync) + => _clientProvider.CanonicalView.Methods.Single(m => m.Signature.Name.Equals(isAsync ? $"{operation.Name}Async" : operation.Name, StringComparison.OrdinalIgnoreCase) && m.Signature.Parameters.Any(p => p.Type.Equals(typeof(CancellationToken)))); + + private MethodProvider GetCorrespondingRequestMethod(InputOperation operation) + => _clientProvider.RestClient.Methods.Single(m => m.Signature.Name.Equals($"Create{operation.Name}Request", StringComparison.OrdinalIgnoreCase)); + + public ScopedApi TryGetApiVersion(out ScopedApi apiVersion) + { + var apiVersionDeclaration = new VariableExpression(typeof(string), $"{SpecName.ToLower()}ApiVersion"); + apiVersion = apiVersionDeclaration.As(); + var invocation = new InvokeMethodExpression(This, "TryGetApiVersion", [_resourcetypeField, new DeclarationExpression(apiVersionDeclaration, true)]); + return invocation.As(); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/ResourceVisitor.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/ResourceVisitor.cs index a73e9aae23bc..10bcf9181934 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/ResourceVisitor.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/ResourceVisitor.cs @@ -1,15 +1,27 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Generator.Primitives; using Microsoft.TypeSpec.Generator.ClientModel; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Providers; +using System.Collections.Generic; using System.IO; +using System.Linq; namespace Azure.Generator { internal class ResourceVisitor : ScmLibraryVisitor { + private HashSet _resourceNames; + + public ResourceVisitor() + { + _resourceNames = AzureClientPlugin.Instance.InputLibrary.InputNamespace.Clients + .Where(client => client.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceOperations)) && client.Operations.Any(operation => operation.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceRead)))) + .Select(client => client.Operations.First(operation => operation.Decorators.Any(d => d.Name.Equals(KnownDecorators.ArmResourceRead))).Responses.First(r => r.BodyType != null).BodyType!.Name).ToHashSet(); + } + protected override ModelProvider? PreVisitModel(InputModelType model, ModelProvider? type) { if (type is not null) @@ -25,9 +37,9 @@ internal class ResourceVisitor : ScmLibraryVisitor return type; } - private static void TransformResource(TypeProvider type) + private void TransformResource(TypeProvider type) { - if (type is ModelProvider && AzureClientPlugin.Instance.OutputLibrary.IsResource(type.Name)) + if (type is ModelProvider && _resourceNames.Contains(type.Name)) { type.Update(relativeFilePath: TransformRelativeFilePath(type)); type.Type.Update(TransformName(type)); diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/RestClientVisitor.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/RestClientVisitor.cs index af3847959914..29a87f7715c6 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/RestClientVisitor.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/RestClientVisitor.cs @@ -15,24 +15,24 @@ internal class RestClientVisitor : ScmLibraryVisitor /// protected override TypeProvider? VisitType(TypeProvider type) { - if (type is not null && type is ClientProvider) + if (type is not null && type is ClientProvider client) { - type.Update(modifiers: TransfromPublicModifiersToInternal(type), relativeFilePath: TransformRelativeFilePathForClient(type)); + // omit methods for ClientProvider, MPG will implement its own client methods + // put create request methods to client directly and remove RestClientProvider + type.Update(methods: [.. client.RestClient.Methods], modifiers: TransfromPublicModifiersToInternal(type), relativeFilePath: TransformRelativeFilePathForClient(type)); } - // TODO: uncomment this once resources are generated - //if (type is RestClientProvider) - //{ - // type.Update(modifiers: TransfromPublicModifiersToInternal(type), relativeFilePath: TransformRelativeFilePathForRestClient(type)); - //} + + if (type is RestClientProvider) + { + return null; + } + return type; } private static string TransformRelativeFilePathForClient(TypeProvider type) => Path.Combine("src", "Generated", "RestOperations", $"{type.Name}RestOperations.cs"); - private static string TransformRelativeFilePathForRestClient(TypeProvider type) - => Path.Combine("src", "Generated", "RestOperations", $"{type.Name}.RestClient.cs"); - private static TypeSignatureModifiers TransfromPublicModifiersToInternal(TypeProvider type) { var modifiers = type.DeclarationModifiers; diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/InputExtensions.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/InputExtensions.cs deleted file mode 100644 index 7a77b71592be..000000000000 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/InputExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.TypeSpec.Generator.Input; -using System.Collections.Generic; -using System.Linq; - -namespace Azure.Generator.Utilities -{ - internal static class InputExtensions - { - /// - /// Union all the properties on myself and all the properties from my parents - /// - /// - /// - internal static IEnumerable GetAllProperties(this InputModelType inputModel) - { - return inputModel.GetAllBaseModels().SelectMany(parentInputModelType => parentInputModelType.Properties).Concat(inputModel.Properties); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/MethodExtensions.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/MethodExtensions.cs new file mode 100644 index 000000000000..da3dd4aea79d --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/MethodExtensions.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using System.Diagnostics.CodeAnalysis; + +namespace Azure.Generator.Utilities +{ + internal static class MethodExtensions + { + /// + /// Return true if this operation is a list method. Also returns the itemType of what this operation is listing of. + /// + /// + /// The type of the item in the collection + /// + public static bool IsListMethod(this MethodProvider method, [MaybeNullWhen(false)] out CSharpType itemType) + { + itemType = null; + var returnType = method.Signature.ReturnType; + if (returnType == null) + return false; + if (returnType.IsFrameworkType && returnType.IsList) + { + itemType = returnType.Arguments[0]; + return true; + } + return itemType != null; + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/OperationExtensions.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/OperationExtensions.cs deleted file mode 100644 index 8553556a2576..000000000000 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/OperationExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.TypeSpec.Generator.Input; -using System; -using System.Linq; - -namespace Azure.Generator.Utilities -{ - internal static class OperationExtensions - { - public static string GetHttpPath(this InputOperation operation) - { - var path = operation.Path; - // Do not trim the tenant resource path '/'. - return (path?.Length == 1 ? path : path?.TrimEnd('/')) ?? - throw new InvalidOperationException($"Cannot get HTTP path from operation {operation.Name}"); - } - - public static OperationResponse? GetServiceResponse(this InputOperation operation, int code = 200) - { - return operation.Responses.FirstOrDefault(r => r.StatusCodes.Contains(code)); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/ResourceDetection.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/ResourceDetection.cs deleted file mode 100644 index 0a956705fde3..000000000000 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/src/Utilities/ResourceDetection.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Azure.Core; -using Azure.Generator.Mgmt.Models; -using Microsoft.TypeSpec.Generator.Input; -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Azure.Generator.Utilities -{ - internal class ResourceDetection - { - private const string ProvidersSegment = "/providers/"; - private ConcurrentDictionary _resourceDataSchemaCache = new ConcurrentDictionary(); - - private static InputModelType? FindObjectSchemaWithName(string name) - => AzureClientPlugin.Instance.InputLibrary.InputNamespace.Models.OfType().FirstOrDefault(inputModel => inputModel.Name == name); - - public bool TryGetResourceDataSchema(OperationSet set, [MaybeNullWhen(false)] out string resourceSpecName, out InputModelType? inputModel) - { - resourceSpecName = null; - inputModel = null; - - // get the result from cache - if (_resourceDataSchemaCache.TryGetValue(set.RequestPath, out var resourceSchemaTuple)) - { - resourceSpecName = resourceSchemaTuple is null ? null : resourceSchemaTuple?.Name!; - inputModel = resourceSchemaTuple?.InputModel; - return resourceSchemaTuple != null; - } - - // TODO: try to find it in the partial resource list - - // Check if the request path has even number of segments after the providers segment - if (!CheckEvenSegments(set.RequestPath)) - return false; - - // before we are finding any operations, we need to ensure this operation set has a GET request. - if (set.FindOperation(RequestMethod.Get) is null) - return false; - - // try put operation to get the resource name - if (TryOperationWithMethod(set, RequestMethod.Put, out inputModel)) - { - resourceSpecName = inputModel.Name; - _resourceDataSchemaCache.TryAdd(set.RequestPath, (resourceSpecName, inputModel)); - return true; - } - - // try get operation to get the resource name - if (TryOperationWithMethod(set, RequestMethod.Get, out inputModel)) - { - resourceSpecName = inputModel.Name; - _resourceDataSchemaCache.TryAdd(set.RequestPath, (resourceSpecName, inputModel)); - return true; - } - - // We tried everything, this is not a resource - _resourceDataSchemaCache.TryAdd(set.RequestPath, null); - return false; - } - - private static bool CheckEvenSegments(string requestPath) - { - var index = requestPath.LastIndexOf(ProvidersSegment); - // this request path does not have providers segment - it can be a "ById" request, skip to next criteria - if (index < 0) - return true; - // get whatever following the providers - var following = requestPath.Substring(index); - var segments = following.Split("/", StringSplitOptions.RemoveEmptyEntries); - return segments.Length % 2 == 0; - } - - private bool TryOperationWithMethod(OperationSet set, RequestMethod method, [MaybeNullWhen(false)] out InputModelType inputModel) - { - inputModel = null; - - var operation = set.FindOperation(method); - if (operation is null) - return false; - // find the response with code 200 - var response = operation.GetServiceResponse(); - if (response is null) - return false; - // find the response schema - var responseType = response.BodyType?.GetImplementType() as InputModelType; - if (responseType is null) - return false; - - // we need to verify this schema has ID, type and name so that this is a resource model - if (!IsResourceModel(responseType)) - return false; - - inputModel = responseType; - return true; - } - - private static bool IsResourceModel(InputModelType inputModelType) - { - var allProperties = inputModelType.GetAllProperties(); - bool idPropertyFound = false; - bool typePropertyFound = false; - bool namePropertyFound = false; - - foreach (var property in allProperties) - { - if (FoundPropertiesForResource()) - { - return true; - } - - var serializationName = property.SerializationOptions?.Json?.Name; - if (serializationName is null) - continue; - switch (serializationName) - { - case "id": - if (property.Type.GetImplementType() is InputPrimitiveType { Kind: InputPrimitiveTypeKind.String } inputPrimitiveType) - idPropertyFound = true; - continue; - case "type": - if (property.Type.GetImplementType() is InputPrimitiveType { Kind: InputPrimitiveTypeKind.String } inputPrimitive) - typePropertyFound = true; - continue; - case "name": - if (property.Type.GetImplementType() is InputPrimitiveType { Kind: InputPrimitiveTypeKind.String } primitive) - namePropertyFound = true; - continue; - } - } - - return FoundPropertiesForResource(); - - bool FoundPropertiesForResource() => idPropertyFound && typePropertyFound && namePropertyFound; - } - } -} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputData.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputData.cs new file mode 100644 index 000000000000..dd18a455d68c --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputData.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Input; +using System.Collections.Generic; + +namespace Azure.Generator.Tests.Common +{ + internal static class InputData + { + public static (InputClient InputClient, IReadOnlyList InputModels) ClientWithResource() + { + const string TestClientName = "TestClient"; + const string resourceModelName = "ResponseType"; + var responseModel = InputFactory.Model(resourceModelName, + usage: InputModelTypeUsage.Output | InputModelTypeUsage.Json, + properties: + [ + InputFactory.Property("id", InputPrimitiveType.String), + InputFactory.Property("type", InputPrimitiveType.String), + InputFactory.Property("name", InputFactory.Primitive.String()), + ]); + var responseType = InputFactory.OperationResponse(statusCodes: [200], bodytype: responseModel); + var testNameParameter = InputFactory.Parameter("testName", InputPrimitiveType.String, location: RequestLocation.Path); + var operation = InputFactory.Operation(name: "Get", responses: [responseType], parameters: [testNameParameter], path: "/providers/a/test/{testName}", decorators: [new InputDecoratorInfo(KnownDecorators.ArmResourceRead, null)]); + var client = InputFactory.Client(TestClientName, operations: [operation], decorators: [new InputDecoratorInfo(KnownDecorators.ArmResourceOperations, null), new InputDecoratorInfo(KnownDecorators.ArmProviderNamespace, null)]); + return (client, [responseModel]); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputFactory.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputFactory.cs index d582b277b20b..461bdeada87c 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputFactory.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Common/InputFactory.cs @@ -170,10 +170,11 @@ public static InputModelType Model( string? discriminatedKind = null, InputType? additionalProperties = null, IDictionary? discriminatedModels = null, - IEnumerable? derivedModels = null) + IEnumerable? derivedModels = null, + IReadOnlyList? decorators = null) { IEnumerable propertiesList = properties ?? [Property("StringProperty", InputPrimitiveType.String)]; - return new InputModelType( + var model = new InputModelType( name, clientNamespace, name, @@ -191,6 +192,13 @@ public static InputModelType Model( additionalProperties, modelAsStruct, new()); + if (decorators is not null) + { + var decoratorProperty = typeof(InputModelType).GetProperty(nameof(InputModelType.Decorators)); + var setDecoratorMethod = decoratorProperty?.GetSetMethod(true); + setDecoratorMethod!.Invoke(model, [decorators]); + } + return model; } public static InputType Array(InputType elementType) @@ -213,9 +221,11 @@ public static InputOperation Operation( string access = "public", IEnumerable? parameters = null, IEnumerable? responses = null, - IEnumerable? requestMediaTypes = null) + IEnumerable? requestMediaTypes = null, + string? path = null, + IReadOnlyList? decorators = null) { - return new InputOperation( + var operation = new InputOperation( name, null, null, @@ -226,8 +236,8 @@ public static InputOperation Operation( responses is null ? [OperationResponse()] : [.. responses], "GET", BodyMediaType.Json, - "", - "", + string.Empty, + path ?? string.Empty, null, requestMediaTypes is null ? null : [.. requestMediaTypes], false, @@ -236,6 +246,13 @@ public static InputOperation Operation( true, true, name); + if (decorators is not null) + { + var decoratorProperty = typeof(InputOperation).GetProperty(nameof(InputOperation.Decorators)); + var setDecoratorMethod = decoratorProperty?.GetSetMethod(true); + setDecoratorMethod!.Invoke(operation, [decorators]); + } + return operation; } public static OperationResponse OperationResponse(IEnumerable? statusCodes = null, InputType? bodytype = null) @@ -249,9 +266,9 @@ public static OperationResponse OperationResponse(IEnumerable? statusCodes ["application/json"]); } - public static InputClient Client(string name, string clientNamespace = "Samples", string? doc = null, IEnumerable? operations = null, IEnumerable? parameters = null, string? parent = null) + public static InputClient Client(string name, string clientNamespace = "Samples", string? doc = null, IEnumerable? operations = null, IEnumerable? parameters = null, string? parent = null, IReadOnlyList? decorators = null) { - return new InputClient( + var client = new InputClient( name, clientNamespace, string.Empty, @@ -259,6 +276,13 @@ public static InputClient Client(string name, string clientNamespace = "Samples" operations is null ? [] : [.. operations], parameters is null ? [] : [.. parameters], parent); + if (decorators is not null) + { + var decoratorProperty = typeof(InputClient).GetProperty(nameof(InputClient.Decorators)); + var setDecoratorMethod = decoratorProperty?.GetSetMethod(true); + setDecoratorMethod!.Invoke(client, [decorators]); + } + return client; } } } diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/MgmtLongRunningOperationProviderTests.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/LongRunningOperationProviderTests.cs similarity index 73% rename from eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/MgmtLongRunningOperationProviderTests.cs rename to eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/LongRunningOperationProviderTests.cs index a6e0e6ab332d..59f17abe533e 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/MgmtLongRunningOperationProviderTests.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/LongRunningOperationProviderTests.cs @@ -9,7 +9,7 @@ namespace Azure.Generator.Tests.Providers { - internal class MgmtLongRunningOperationProviderTests + internal class LongRunningOperationProviderTests { [SetUp] public void SetUp() @@ -18,9 +18,9 @@ public void SetUp() } [TestCase] - public void Verify_NonGeneric_MgmtLROProviderGeneration() + public void Verify_NonGeneric_LROProviderGeneration() { - var nonGenericLROProvider = new MgmtLongRunningOperationProvider(false); + var nonGenericLROProvider = new LongRunningOperationProvider(false); var codeFile = new TypeProviderWriter(nonGenericLROProvider).Write(); var result = codeFile.Content; @@ -30,9 +30,9 @@ public void Verify_NonGeneric_MgmtLROProviderGeneration() } [TestCase] - public void Verify_Generic_MgmtLROProviderGeneration() + public void Verify_Generic_LROProviderGeneration() { - var genericLROProvider = new MgmtLongRunningOperationProvider(true); + var genericLROProvider = new LongRunningOperationProvider(true); var codeFile = new TypeProviderWriter(genericLROProvider).Write(); var result = codeFile.Content; diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/OperationSourceProviderTests.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/OperationSourceProviderTests.cs new file mode 100644 index 000000000000..d7d308ca321c --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/OperationSourceProviderTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Generator.Providers; +using Azure.Generator.Tests.Common; +using Azure.Generator.Tests.TestHelpers; +using Microsoft.TypeSpec.Generator.Primitives; +using NUnit.Framework; +using System.Linq; + +namespace Azure.Generator.Tests.Providers +{ + internal class OperationSourceProviderTests + { + [TestCase] + public void Verify_ResourceProviderGeneration() + { + var (client, models) = InputData.ClientWithResource(); + var plugin = MockHelpers.LoadMockPlugin(inputModels: () => models, clients: () => [client]); + + var operationSourceProvider = plugin.Object.OutputLibrary.TypeProviders.Single(p => p is OperationSourceProvider) as OperationSourceProvider; + Assert.NotNull(operationSourceProvider); + var codeFile = new TypeProviderWriter(operationSourceProvider!).Write(); + var result = codeFile.Content; + + var exptected = Helpers.GetExpectedFromFile(); + + Assert.AreEqual(exptected, result); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/ResourceClientProviderTests.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/ResourceClientProviderTests.cs new file mode 100644 index 000000000000..bd5f2d97d73b --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/ResourceClientProviderTests.cs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Generator.Providers; +using Azure.Generator.Tests.Common; +using Azure.Generator.Tests.TestHelpers; +using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using NUnit.Framework; +using System.Linq; + +namespace Azure.Generator.Tests.Providers +{ + internal class ResourceClientProviderTests + { + private class MockBaseResourceClientProvider : ResourceClientProvider + { + public MockBaseResourceClientProvider(InputClient inputClient) + : base(inputClient) + { + } + protected override FieldProvider[] BuildFields() => []; + protected override PropertyProvider[] BuildProperties() => []; + protected override ConstructorProvider[] BuildConstructors() => []; + } + + [TestCase] + public void Verify_ValidateIdMethod() + { + var (client, models) = InputData.ClientWithResource(); + var plugin = MockHelpers.LoadMockPlugin(inputModels: () => models, clients: () => [client], + createResourceCore: (inputClient) => new MockValidateIdResourceClientProvider(inputClient)); + + var resourceProvider = plugin.Object.OutputLibrary.TypeProviders.FirstOrDefault(p => p is ResourceClientProvider) as ResourceClientProvider; + Assert.NotNull(resourceProvider); + var codeFile = new TypeProviderWriter(resourceProvider!).Write(); + var result = codeFile.Content; + + var exptected = Helpers.GetExpectedFromFile(); + + Assert.AreEqual(exptected, result); + } + + private class MockValidateIdResourceClientProvider : MockBaseResourceClientProvider + { + public MockValidateIdResourceClientProvider(InputClient inputClient) + : base(inputClient) + { + } + + protected override MethodProvider[] BuildMethods() => [.. base.BuildMethods().Where(m => m.Signature.Name == "ValidateResourceId")]; + } + + [TestCase] + public void Verify_SyncOperationMethod() + { + var (client, models) = InputData.ClientWithResource(); + var plugin = MockHelpers.LoadMockPlugin(inputModels: () => models, clients: () => [client], + createResourceCore: (inputClient) => new MockSyncOperationResourceClientProvider(inputClient)); + var resourceProvider = plugin.Object.OutputLibrary.TypeProviders.FirstOrDefault(p => p is ResourceClientProvider) as ResourceClientProvider; + Assert.NotNull(resourceProvider); + var codeFile = new TypeProviderWriter(resourceProvider!).Write(); + var result = codeFile.Content; + var exptected = Helpers.GetExpectedFromFile(); + Assert.AreEqual(exptected, result); + } + + private class MockSyncOperationResourceClientProvider : MockBaseResourceClientProvider + { + public MockSyncOperationResourceClientProvider(InputClient inputClient) : base(inputClient) + { + } + + protected override MethodProvider[] BuildMethods() => [.. base.BuildMethods().Where(m => m.Signature.Name == "Get")]; + } + + [TestCase] + public void Verify_AsyncOperationMethod() + { + var (client, models) = InputData.ClientWithResource(); + var plugin = MockHelpers.LoadMockPlugin(inputModels: () => models, clients: () => [client], + createResourceCore: (inputClient) => new MockAsyncOperationResourceClientProvider(inputClient)); + var resourceProvider = plugin.Object.OutputLibrary.TypeProviders.FirstOrDefault(p => p is ResourceClientProvider) as ResourceClientProvider; + Assert.NotNull(resourceProvider); + var codeFile = new TypeProviderWriter(resourceProvider!).Write(); + var result = codeFile.Content; + var exptected = Helpers.GetExpectedFromFile(); + Assert.AreEqual(exptected, result); + } + + private class MockAsyncOperationResourceClientProvider : MockBaseResourceClientProvider + { + public MockAsyncOperationResourceClientProvider(InputClient inputClient) : base(inputClient) + { + } + + protected override MethodProvider[] BuildMethods() => [.. base.BuildMethods().Where(m => m.Signature.Name == "GetAsync")]; + } + + [TestCase] + public void Verify_Constructors() + { + var (client, models) = InputData.ClientWithResource(); + var plugin = MockHelpers.LoadMockPlugin(inputModels: () => models, clients: () => [client], + createResourceCore: (inputClient) => new MockConstructorsResourceClientProvider(inputClient)); + var resourceProvider = plugin.Object.OutputLibrary.TypeProviders.FirstOrDefault(p => p is ResourceClientProvider) as ResourceClientProvider; + Assert.NotNull(resourceProvider); + var codeFile = new TypeProviderWriter(resourceProvider!).Write(); + var result = codeFile.Content; + var exptected = Helpers.GetExpectedFromFile(); + Assert.AreEqual(exptected, result); + } + + private class MockConstructorsResourceClientProvider : ResourceClientProvider + { + public MockConstructorsResourceClientProvider(InputClient inputClient) : base(inputClient) + { + } + + protected override MethodProvider[] BuildMethods() => []; + protected override FieldProvider[] BuildFields() => []; + protected override PropertyProvider[] BuildProperties() => []; + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/MgmtLongRunningOperationProviderTests/Verify_Generic_MgmtLROProviderGeneration.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/LongRunningOperationProviderTests/Verify_Generic_LROProviderGeneration.cs similarity index 100% rename from eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/MgmtLongRunningOperationProviderTests/Verify_Generic_MgmtLROProviderGeneration.cs rename to eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/LongRunningOperationProviderTests/Verify_Generic_LROProviderGeneration.cs diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/MgmtLongRunningOperationProviderTests/Verify_NonGeneric_MgmtLROProviderGeneration.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/LongRunningOperationProviderTests/Verify_NonGeneric_LROProviderGeneration.cs similarity index 100% rename from eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/MgmtLongRunningOperationProviderTests/Verify_NonGeneric_MgmtLROProviderGeneration.cs rename to eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/LongRunningOperationProviderTests/Verify_NonGeneric_LROProviderGeneration.cs diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/OperationSourceProviderTests/Verify_ResourceProviderGeneration.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/OperationSourceProviderTests/Verify_ResourceProviderGeneration.cs new file mode 100644 index 000000000000..db434a5f80c0 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/OperationSourceProviderTests/Verify_ResourceProviderGeneration.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.ResourceManager; +using Samples.Models; + +namespace Samples +{ + /// + public partial class ResponseTypeOperationSource : global::Azure.Core.IOperationSource + { + private readonly global::Azure.ResourceManager.ArmClient _client; + + internal ResponseTypeOperationSource(global::Azure.ResourceManager.ArmClient client) + { + _client = client; + } + + global::Samples.ResponseTypeResource global::Azure.Core.IOperationSource.CreateResult(global::Azure.Response response, global::System.Threading.CancellationToken cancellationToken) + { + using global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(response.ContentStream); + global::Samples.Models.ResponseTypeData data = global::Samples.Models.ResponseTypeData.DeserializeResponseTypeData(document.RootElement, new global::System.ClientModel.Primitives.ModelReaderWriterOptions("W")); + return new global::Samples.ResponseTypeResource(_client, data); + } + + async global::System.Threading.Tasks.ValueTask global::Azure.Core.IOperationSource.CreateResultAsync(global::Azure.Response response, global::System.Threading.CancellationToken cancellationToken) + { + using global::System.Text.Json.JsonDocument document = await global::System.Text.Json.JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + global::Samples.Models.ResponseTypeData data = global::Samples.Models.ResponseTypeData.DeserializeResponseTypeData(document.RootElement, global::Samples.ModelSerializationExtensions.WireOptions); + return new global::Samples.ResponseTypeResource(_client, data); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_AsyncOperationMethod.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_AsyncOperationMethod.cs new file mode 100644 index 000000000000..704352fcbbd9 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_AsyncOperationMethod.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; +using Samples.Models; + +namespace Samples +{ + /// + public partial class ResponseTypeResource : global::Azure.ResourceManager.ArmResource + { + /// Get description. + /// The cancellation token that can be used to cancel the operation. + public virtual async global::System.Threading.Tasks.Task> GetAsync(global::System.Threading.CancellationToken cancellationToken = default) + { + using global::Azure.Core.Pipeline.DiagnosticScope scope = _responsetypeClientDiagnostics.CreateScope("Samples.Get"); + scope.Start(); + try + { + global::Azure.RequestContext context = new global::Azure.RequestContext + { + CancellationToken = cancellationToken + } + ; + global::Azure.Core.HttpMessage message = _responsetypeRestClient.CreateGetRequest(this.Id.Name, context); + global::Azure.Response result = await this.Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + global::Azure.Response response = global::Azure.Response.FromValue(((global::Samples.Models.ResponseTypeData)result), result); + if ((response.Value == null)) + { + throw new global::Azure.RequestFailedException(response.GetRawResponse()); + } + return global::Azure.Response.FromValue(new global::Samples.ResponseTypeResource(this.Client, response.Value), response.GetRawResponse()); + } + catch (global::System.Exception e) + { + scope.Failed(e); + throw; + } + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_Constructors.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_Constructors.cs new file mode 100644 index 000000000000..f07e6883a4f7 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_Constructors.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; +using Samples.Models; + +namespace Samples +{ + /// + public partial class ResponseTypeResource : global::Azure.ResourceManager.ArmResource + { + /// Initializes a new instance of ResponseTypeResource for mocking. + protected ResponseTypeResource() + { + } + + internal ResponseTypeResource(global::Azure.ResourceManager.ArmClient client, global::Samples.Models.ResponseTypeData data) : this(client, data.Id) + { + this.HasData = true; + _data = data; + } + + internal ResponseTypeResource(global::Azure.ResourceManager.ArmClient client, global::Azure.Core.ResourceIdentifier id) : base(client, id) + { + _responsetypeClientDiagnostics = new global::Azure.Core.Pipeline.ClientDiagnostics("Samples", ResourceType.Namespace, this.Diagnostics); + this.TryGetApiVersion(ResourceType, out string responsetypeApiVersion); + _responsetypeRestClient = new global::Samples.TestClient(this.Pipeline, this.Endpoint, responsetypeApiVersion); + global::Samples.ResponseTypeResource.ValidateResourceId(id); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_SyncOperationMethod.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_SyncOperationMethod.cs new file mode 100644 index 000000000000..dcdbc7d5e56b --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_SyncOperationMethod.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; +using Samples.Models; + +namespace Samples +{ + /// + public partial class ResponseTypeResource : global::Azure.ResourceManager.ArmResource + { + /// Get description. + /// The cancellation token that can be used to cancel the operation. + public virtual global::Azure.Response Get(global::System.Threading.CancellationToken cancellationToken = default) + { + using global::Azure.Core.Pipeline.DiagnosticScope scope = _responsetypeClientDiagnostics.CreateScope("Samples.Get"); + scope.Start(); + try + { + global::Azure.RequestContext context = new global::Azure.RequestContext + { + CancellationToken = cancellationToken + } + ; + global::Azure.Core.HttpMessage message = _responsetypeRestClient.CreateGetRequest(this.Id.Name, context); + global::Azure.Response result = this.Pipeline.ProcessMessage(message, context); + global::Azure.Response response = global::Azure.Response.FromValue(((global::Samples.Models.ResponseTypeData)result), result); + if ((response.Value == null)) + { + throw new global::Azure.RequestFailedException(response.GetRawResponse()); + } + return global::Azure.Response.FromValue(new global::Samples.ResponseTypeResource(this.Client, response.Value), response.GetRawResponse()); + } + catch (global::System.Exception e) + { + scope.Failed(e); + throw; + } + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_ValidateIdMethod.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_ValidateIdMethod.cs new file mode 100644 index 000000000000..8be9e6128734 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/Providers/TestData/ResourceClientProviderTests/Verify_ValidateIdMethod.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Diagnostics; +using Azure.Core; +using Azure.ResourceManager; + +namespace Samples +{ + /// + public partial class ResponseTypeResource : global::Azure.ResourceManager.ArmResource + { + [global::System.Diagnostics.ConditionalAttribute("DEBUG")] + internal static void ValidateResourceId(global::Azure.Core.ResourceIdentifier id) + { + if ((id != ResourceType)) + { + throw new global::System.ArgumentException(string.Format("Invalid resource type {0} expected {1}", id.ResourceType, ResourceType), id); + } + } + } +} diff --git a/eng/packages/http-client-csharp/generator/Azure.Generator/test/TestHelpers/MockHelpers.cs b/eng/packages/http-client-csharp/generator/Azure.Generator/test/TestHelpers/MockHelpers.cs index da65c3cabe89..85659232663c 100644 --- a/eng/packages/http-client-csharp/generator/Azure.Generator/test/TestHelpers/MockHelpers.cs +++ b/eng/packages/http-client-csharp/generator/Azure.Generator/test/TestHelpers/MockHelpers.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Generator.Providers; using Microsoft.TypeSpec.Generator; using Microsoft.TypeSpec.Generator.ClientModel; using Microsoft.TypeSpec.Generator.ClientModel.Providers; @@ -33,7 +34,8 @@ public static Mock LoadMockPlugin( Func>? clients = null, ClientResponseApi? clientResponseApi = null, ClientPipelineApi? clientPipelineApi = null, - HttpMessageApi? httpMessageApi = null) + HttpMessageApi? httpMessageApi = null, + Func? createResourceCore = null) { IReadOnlyList inputNsApiVersions = apiVersions?.Invoke() ?? []; IReadOnlyList inputNsEnums = inputEnums?.Invoke() ?? []; @@ -73,6 +75,17 @@ public static Mock LoadMockPlugin( azureInstance!.SetValue(null, mockPluginInstance.Object); mockPluginInstance.SetupGet(p => p.InputLibrary).Returns(mockInputLibrary.Object); + if (createResourceCore is not null) + { + Mock mockOutputLibrary = new Mock() { CallBase = true }; + mockOutputLibrary.Setup(p => p.CreateResourceCore(It.IsAny())).Returns( + (InputClient inputClient) => + { + return createResourceCore(inputClient); + }); + mockPluginInstance.Setup(p => p.OutputLibrary).Returns(mockOutputLibrary.Object); + } + if (mockTypeFactory is not null) { mockPluginInstance.SetupGet(p => p.TypeFactory).Returns(mockTypeFactory.Object); diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local.Tests/TestProjects.Local.Tests.csproj b/eng/packages/http-client-csharp/generator/TestProjects/Local.Tests/TestProjects.Local.Tests.csproj index de21ce011954..9a04fcd504af 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local.Tests/TestProjects.Local.Tests.csproj +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local.Tests/TestProjects.Local.Tests.csproj @@ -7,6 +7,7 @@ + @@ -19,14 +20,30 @@ - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FooResource.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FooResource.cs new file mode 100644 index 000000000000..30d24b265940 --- /dev/null +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FooResource.cs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; +using MgmtTypeSpec.Models; + +namespace MgmtTypeSpec +{ + /// + public partial class FooResource : ArmResource + { + private FooData _data; + private ClientDiagnostics _fooClientDiagnostics; + private Foos _fooRestClient; + /// Gets the resource type for the operations. + public static readonly ResourceType ResourceType = "MgmtTypeSpec/foos"; + + /// Initializes a new instance of FooResource for mocking. + protected FooResource() + { + } + + internal FooResource(ArmClient client, FooData data) : this(client, data.Id) + { + HasData = true; + _data = data; + } + + internal FooResource(ArmClient client, ResourceIdentifier id) : base(client, id) + { + _fooClientDiagnostics = new ClientDiagnostics("MgmtTypeSpec", ResourceType.Namespace, Diagnostics); + TryGetApiVersion(ResourceType, out string fooApiVersion); + _fooRestClient = new Foos(Pipeline, Endpoint, fooApiVersion); + ValidateResourceId(id); + } + + /// Gets whether or not the current instance has data. + public virtual bool HasData { get; } + + /// Gets the data representing this Feature. + public virtual FooData Data + { + get + { + if (!HasData) + { + throw new InvalidOperationException("The current instance does not have data, you must call Get first."); + } + return _data; + } + } + + [Conditional("DEBUG")] + internal static void ValidateResourceId(ResourceIdentifier id) + { + if (id != ResourceType) + { + throw new ArgumentException(string.Format("Invalid resource type {0} expected {1}", id.ResourceType, ResourceType), id); + } + } + + /// Update a Foo. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// Resource create parameters. + /// The cancellation token that can be used to cancel the operation. + /// is null. + public virtual ArmOperation Update(WaitUntil waitUntil, FooData resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(resource, nameof(resource)); + + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.createOrUpdate"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateCreateOrUpdateRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, resource, context); + Response result = Pipeline.ProcessMessage(message, context); + Response response = Response.FromValue((FooData)result, result); + MgmtTypeSpecArmOperation operation = new MgmtTypeSpecArmOperation( + new FooOperationSource(Client), + _fooClientDiagnostics, + Pipeline, + message.Request, + response.GetRawResponse(), + OperationFinalStateVia.AzureAsyncOperation); + if (waitUntil == WaitUntil.Completed) + { + operation.WaitForCompletion(cancellationToken); + } + return operation; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Update a Foo. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// Resource create parameters. + /// The cancellation token that can be used to cancel the operation. + /// is null. + public virtual async Task> UpdateAsync(WaitUntil waitUntil, FooData resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(resource, nameof(resource)); + + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.createOrUpdate"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateCreateOrUpdateRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, resource, context); + Response result = await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + Response response = Response.FromValue((FooData)result, result); + MgmtTypeSpecArmOperation operation = new MgmtTypeSpecArmOperation( + new FooOperationSource(Client), + _fooClientDiagnostics, + Pipeline, + message.Request, + response.GetRawResponse(), + OperationFinalStateVia.AzureAsyncOperation); + if (waitUntil == WaitUntil.Completed) + { + await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); + } + return operation; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Get a Foo. + /// The cancellation token that can be used to cancel the operation. + public virtual Response Get(CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.get"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateGetRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, context); + Response result = Pipeline.ProcessMessage(message, context); + Response response = Response.FromValue((FooData)result, result); + if (response.Value == null) + { + throw new RequestFailedException(response.GetRawResponse()); + } + return Response.FromValue(new FooResource(Client, response.Value), response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Get a Foo. + /// The cancellation token that can be used to cancel the operation. + public virtual async Task> GetAsync(CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.get"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateGetRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, context); + Response result = await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + Response response = Response.FromValue((FooData)result, result); + if (response.Value == null) + { + throw new RequestFailedException(response.GetRawResponse()); + } + return Response.FromValue(new FooResource(Client, response.Value), response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Delete a Foo. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The cancellation token that can be used to cancel the operation. + public virtual ArmOperation Delete(WaitUntil waitUntil, CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.delete"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateDeleteRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, context); + Response response = Pipeline.ProcessMessage(message, context); + MgmtTypeSpecArmOperation operation = new MgmtTypeSpecArmOperation(_fooClientDiagnostics, Pipeline, message.Request, response, OperationFinalStateVia.Location); + if (waitUntil == WaitUntil.Completed) + { + operation.WaitForCompletionResponse(cancellationToken); + } + return operation; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Delete a Foo. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The cancellation token that can be used to cancel the operation. + public virtual async Task DeleteAsync(WaitUntil waitUntil, CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _fooClientDiagnostics.CreateScope("MgmtTypeSpec.delete"); + scope.Start(); + try + { + RequestContext context = new RequestContext + { + CancellationToken = cancellationToken + } + ; + HttpMessage message = _fooRestClient.CreateDeleteRequest(Guid.Parse(Id.SubscriptionId), Id.ResourceGroupName, Id.Name, context); + Response response = await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + MgmtTypeSpecArmOperation operation = new MgmtTypeSpecArmOperation(_fooClientDiagnostics, Pipeline, message.Request, response, OperationFinalStateVia.Location); + if (waitUntil == WaitUntil.Completed) + { + await operation.WaitForCompletionResponseAsync(cancellationToken).ConfigureAwait(false); + } + return operation; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + } +} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Foos.RestClient.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Foos.RestClient.cs deleted file mode 100644 index 49adfd91dd97..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Foos.RestClient.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using Azure; -using Azure.Core; - -namespace MgmtTypeSpec -{ - /// - public partial class Foos - { - private static ResponseClassifier _pipelineMessageClassifier200; - private static ResponseClassifier _pipelineMessageClassifier200201; - private static ResponseClassifier _pipelineMessageClassifier202204; - - private static ResponseClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = new StatusCodeClassifier(stackalloc ushort[] { 200 }); - - private static ResponseClassifier PipelineMessageClassifier200201 => _pipelineMessageClassifier200201 = new StatusCodeClassifier(stackalloc ushort[] { 200, 201 }); - - private static ResponseClassifier PipelineMessageClassifier202204 => _pipelineMessageClassifier202204 = new StatusCodeClassifier(stackalloc ushort[] { 202, 204 }); - - internal HttpMessage CreateCreateOrUpdateRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContent content, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier200201); - Request request = message.Request; - request.Method = RequestMethod.Put; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); - uri.AppendPath(fooName, true); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Content-Type", "application/json"); - request.Headers.SetValue("Accept", "application/json"); - request.Content = content; - return message; - } - - internal HttpMessage CreateGetRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier200); - Request request = message.Request; - request.Method = RequestMethod.Get; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); - uri.AppendPath(fooName, true); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Accept", "application/json"); - return message; - } - - internal HttpMessage CreateDeleteRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier202204); - Request request = message.Request; - request.Method = RequestMethod.Delete; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); - uri.AppendPath(fooName, true); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Accept", "application/json"); - return message; - } - - internal HttpMessage CreateListRequest(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier200); - Request request = message.Request; - request.Method = RequestMethod.Get; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/foos", false); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Accept", "application/json"); - return message; - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Internal/TypeFormatters.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Internal/TypeFormatters.cs index f278d1694ec5..a30bf8ce5689 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Internal/TypeFormatters.cs +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Internal/TypeFormatters.cs @@ -37,7 +37,7 @@ internal static partial class TypeFormatters public static string ToString(TimeSpan value, string format) => format switch { - "P" => System.Xml.XmlConvert.ToString(value), + "P" => XmlConvert.ToString(value), _ => value.ToString(format, CultureInfo.InvariantCulture) }; @@ -130,7 +130,7 @@ public static byte[] FromBase64UrlString(string value) public static TimeSpan ParseTimeSpan(string value, string format) => format switch { - "P" => System.Xml.XmlConvert.ToTimeSpan(value), + "P" => XmlConvert.ToTimeSpan(value), _ => TimeSpan.ParseExact(value, format, CultureInfo.InvariantCulture) }; @@ -144,7 +144,7 @@ public static byte[] FromBase64UrlString(string value) IEnumerable s0 => string.Join(",", s0), DateTimeOffset dateTime when format != null => ToString(dateTime, format), TimeSpan timeSpan when format != null => ToString(timeSpan, format), - TimeSpan timeSpan0 => System.Xml.XmlConvert.ToString(timeSpan0), + TimeSpan timeSpan0 => XmlConvert.ToString(timeSpan0), Guid guid => guid.ToString(), BinaryData binaryData => ConvertToString(binaryData.ToArray(), format), _ => value.ToString() diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/FooOperationSource.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/FooOperationSource.cs new file mode 100644 index 000000000000..5f3109db217d --- /dev/null +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/FooOperationSource.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.ResourceManager; +using MgmtTypeSpec.Models; + +namespace MgmtTypeSpec +{ + /// + internal partial class FooOperationSource : IOperationSource + { + private readonly ArmClient _client; + + internal FooOperationSource(ArmClient client) + { + _client = client; + } + + FooResource IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) + { + using JsonDocument document = JsonDocument.Parse(response.ContentStream); + FooData data = FooData.DeserializeFooData(document.RootElement, new ModelReaderWriterOptions("W")); + return new FooResource(_client, data); + } + + async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using JsonDocument document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + FooData data = FooData.DeserializeFooData(document.RootElement, ModelSerializationExtensions.WireOptions); + return new FooResource(_client, data); + } + } +} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperation.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperation.cs index 07d3a751287a..7d33ce653e1a 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperation.cs +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperation.cs @@ -17,7 +17,7 @@ namespace MgmtTypeSpec { - internal partial class MgmtTypeSpecArmOperation : Azure.ResourceManager.ArmOperation + internal partial class MgmtTypeSpecArmOperation : ArmOperation { private readonly OperationInternal _operation; private readonly RehydrationToken? _completeRehydrationToken; diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperationOfT.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperationOfT.cs index b194efb15887..3ad9866e71f9 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperationOfT.cs +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/LongRunningOperation/MgmtTypeSpecArmOperationOfT.cs @@ -17,7 +17,7 @@ namespace MgmtTypeSpec { - internal partial class MgmtTypeSpecArmOperation : Azure.ResourceManager.ArmOperation + internal partial class MgmtTypeSpecArmOperation : ArmOperation { private readonly OperationInternal _operation; private readonly RehydrationToken? _completeRehydrationToken; diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/MgmtTypeSpecModelFactory.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/MgmtTypeSpecModelFactory.cs index dfd050a4f16e..aee6259bea17 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/MgmtTypeSpecModelFactory.cs +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/MgmtTypeSpecModelFactory.cs @@ -126,28 +126,6 @@ public static SystemData SystemData(string createdBy = default, CreatedByType? c additionalBinaryDataProperties: null); } - /// The response of a Foo list operation. - /// The Foo items on this page. - /// The link to the next page of items. - /// A new instance for mocking. - public static FooListResult FooListResult(IEnumerable value = default, Uri nextLink = default) - { - value ??= new ChangeTrackingList(); - - return new FooListResult(value?.ToList(), nextLink, additionalBinaryDataProperties: null); - } - - /// The response of a PrivateLinkResource list operation. - /// The PrivateLinkResource items on this page. - /// The link to the next page of items. - /// A new instance for mocking. - public static PrivateLinkResourceListResult PrivateLinkResourceListResult(IEnumerable value = default, Uri nextLink = default) - { - value ??= new ChangeTrackingList(); - - return new PrivateLinkResourceListResult(value?.ToList(), nextLink, additionalBinaryDataProperties: null); - } - /// Concrete proxy resource types can be created by aliasing this type using a specific property type. /// Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. /// The name of the resource. @@ -216,14 +194,5 @@ public static ProxyResource ProxyResource(ResourceIdentifier id = default, strin return new ProxyResource(id, name, @type, systemData, additionalBinaryDataProperties: null); } - - /// Start SAP instance(s) request body. - /// The boolean value indicates whether to start the virtual machines before starting the SAP instances. - /// A new instance for mocking. - public static StartRequest StartRequest(bool? startVm = default) - { - - return new StartRequest(startVm, additionalBinaryDataProperties: null); - } } } diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.Serialization.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.Serialization.cs deleted file mode 100644 index 29bc815ca84c..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.Serialization.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Text.Json; -using Azure; -using Azure.Core; -using MgmtTypeSpec; - -namespace MgmtTypeSpec.Models -{ - /// - public partial class FooListResult : IJsonModel - { - internal FooListResult() - { - } - - 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(FooListResult)} does not support writing '{format}' format."); - } - writer.WritePropertyName("value"u8); - writer.WriteStartArray(); - foreach (FooData item in Value) - { - writer.WriteObjectValue(item, options); - } - writer.WriteEndArray(); - if (Optional.IsDefined(NextLink)) - { - writer.WritePropertyName("nextLink"u8); - writer.WriteStringValue(NextLink.AbsoluteUri); - } - 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 - } - } - } - - FooListResult IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); - - /// The JSON reader. - /// The client options for reading and writing models. - protected virtual FooListResult 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(FooListResult)} does not support reading '{format}' format."); - } - using JsonDocument document = JsonDocument.ParseValue(ref reader); - return DeserializeFooListResult(document.RootElement, options); - } - - internal static FooListResult DeserializeFooListResult(JsonElement element, ModelReaderWriterOptions options) - { - if (element.ValueKind == JsonValueKind.Null) - { - return null; - } - IList value = default; - Uri nextLink = default; - IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); - foreach (var prop in element.EnumerateObject()) - { - if (prop.NameEquals("value"u8)) - { - List array = new List(); - foreach (var item in prop.Value.EnumerateArray()) - { - array.Add(FooData.DeserializeFooData(item, options)); - } - value = array; - continue; - } - if (prop.NameEquals("nextLink"u8)) - { - if (prop.Value.ValueKind == JsonValueKind.Null) - { - continue; - } - nextLink = new Uri(prop.Value.GetString()); - continue; - } - if (options.Format != "W") - { - additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); - } - } - return new FooListResult(value, nextLink, additionalBinaryDataProperties); - } - - 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); - default: - throw new FormatException($"The model {nameof(FooListResult)} does not support writing '{options.Format}' format."); - } - } - - FooListResult IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); - - /// The data to parse. - /// The client options for reading and writing models. - protected virtual FooListResult 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 DeserializeFooListResult(document.RootElement, options); - } - default: - throw new FormatException($"The model {nameof(FooListResult)} does not support reading '{options.Format}' format."); - } - } - - string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; - - /// The to serialize into . - public static implicit operator RequestContent(FooListResult fooListResult) - { - if (fooListResult == null) - { - return null; - } - Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); - content.JsonWriter.WriteObjectValue(fooListResult, ModelSerializationExtensions.WireOptions); - return content; - } - - /// The to deserialize the from. - public static explicit operator FooListResult(Response result) - { - using Response response = result; - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeFooListResult(document.RootElement, ModelSerializationExtensions.WireOptions); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.cs deleted file mode 100644 index 94684e14fe92..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooListResult.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MgmtTypeSpec.Models -{ - /// The response of a Foo list operation. - public partial class FooListResult - { - /// Keeps track of any properties unknown to the library. - private protected readonly IDictionary _additionalBinaryDataProperties; - - internal FooListResult(IEnumerable value) - { - Value = value.ToList(); - } - - internal FooListResult(IList value, Uri nextLink, IDictionary additionalBinaryDataProperties) - { - Value = value; - NextLink = nextLink; - _additionalBinaryDataProperties = additionalBinaryDataProperties; - } - - /// The Foo items on this page. - public IList Value { get; } - - /// The link to the next page of items. - public Uri NextLink { get; } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.Serialization.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.Serialization.cs deleted file mode 100644 index 872284b61629..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.Serialization.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Text.Json; -using Azure; -using Azure.Core; -using MgmtTypeSpec; - -namespace MgmtTypeSpec.Models -{ - /// - public partial class PrivateLinkResourceListResult : IJsonModel - { - internal PrivateLinkResourceListResult() - { - } - - 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(PrivateLinkResourceListResult)} does not support writing '{format}' format."); - } - writer.WritePropertyName("value"u8); - writer.WriteStartArray(); - foreach (PrivateLinkResource item in Value) - { - writer.WriteObjectValue(item, options); - } - writer.WriteEndArray(); - if (Optional.IsDefined(NextLink)) - { - writer.WritePropertyName("nextLink"u8); - writer.WriteStringValue(NextLink.AbsoluteUri); - } - 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 - } - } - } - - PrivateLinkResourceListResult IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); - - /// The JSON reader. - /// The client options for reading and writing models. - protected virtual PrivateLinkResourceListResult 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(PrivateLinkResourceListResult)} does not support reading '{format}' format."); - } - using JsonDocument document = JsonDocument.ParseValue(ref reader); - return DeserializePrivateLinkResourceListResult(document.RootElement, options); - } - - internal static PrivateLinkResourceListResult DeserializePrivateLinkResourceListResult(JsonElement element, ModelReaderWriterOptions options) - { - if (element.ValueKind == JsonValueKind.Null) - { - return null; - } - IList value = default; - Uri nextLink = default; - IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); - foreach (var prop in element.EnumerateObject()) - { - if (prop.NameEquals("value"u8)) - { - List array = new List(); - foreach (var item in prop.Value.EnumerateArray()) - { - array.Add(PrivateLinkResource.DeserializePrivateLinkResource(item, options)); - } - value = array; - continue; - } - if (prop.NameEquals("nextLink"u8)) - { - if (prop.Value.ValueKind == JsonValueKind.Null) - { - continue; - } - nextLink = new Uri(prop.Value.GetString()); - continue; - } - if (options.Format != "W") - { - additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); - } - } - return new PrivateLinkResourceListResult(value, nextLink, additionalBinaryDataProperties); - } - - 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); - default: - throw new FormatException($"The model {nameof(PrivateLinkResourceListResult)} does not support writing '{options.Format}' format."); - } - } - - PrivateLinkResourceListResult IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); - - /// The data to parse. - /// The client options for reading and writing models. - protected virtual PrivateLinkResourceListResult 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 DeserializePrivateLinkResourceListResult(document.RootElement, options); - } - default: - throw new FormatException($"The model {nameof(PrivateLinkResourceListResult)} does not support reading '{options.Format}' format."); - } - } - - string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; - - /// The to serialize into . - public static implicit operator RequestContent(PrivateLinkResourceListResult privateLinkResourceListResult) - { - if (privateLinkResourceListResult == null) - { - return null; - } - Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); - content.JsonWriter.WriteObjectValue(privateLinkResourceListResult, ModelSerializationExtensions.WireOptions); - return content; - } - - /// The to deserialize the from. - public static explicit operator PrivateLinkResourceListResult(Response result) - { - using Response response = result; - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializePrivateLinkResourceListResult(document.RootElement, ModelSerializationExtensions.WireOptions); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.cs deleted file mode 100644 index ba71137ba657..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/PrivateLinkResourceListResult.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MgmtTypeSpec.Models -{ - /// The response of a PrivateLinkResource list operation. - public partial class PrivateLinkResourceListResult - { - /// Keeps track of any properties unknown to the library. - private protected readonly IDictionary _additionalBinaryDataProperties; - - internal PrivateLinkResourceListResult(IEnumerable value) - { - Value = value.ToList(); - } - - internal PrivateLinkResourceListResult(IList value, Uri nextLink, IDictionary additionalBinaryDataProperties) - { - Value = value; - NextLink = nextLink; - _additionalBinaryDataProperties = additionalBinaryDataProperties; - } - - /// The PrivateLinkResource items on this page. - public IList Value { get; } - - /// The link to the next page of items. - public Uri NextLink { get; } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.Serialization.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.Serialization.cs deleted file mode 100644 index e25548dc6e6b..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.Serialization.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Text.Json; -using Azure; -using Azure.Core; -using MgmtTypeSpec; - -namespace MgmtTypeSpec.Models -{ - /// - public partial class StartRequest : IJsonModel - { - 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(StartRequest)} does not support writing '{format}' format."); - } - if (Optional.IsDefined(StartVm)) - { - writer.WritePropertyName("startVm"u8); - writer.WriteBooleanValue(StartVm.Value); - } - 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 - } - } - } - - StartRequest IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); - - /// The JSON reader. - /// The client options for reading and writing models. - protected virtual StartRequest 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(StartRequest)} does not support reading '{format}' format."); - } - using JsonDocument document = JsonDocument.ParseValue(ref reader); - return DeserializeStartRequest(document.RootElement, options); - } - - internal static StartRequest DeserializeStartRequest(JsonElement element, ModelReaderWriterOptions options) - { - if (element.ValueKind == JsonValueKind.Null) - { - return null; - } - bool? startVm = default; - IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); - foreach (var prop in element.EnumerateObject()) - { - if (prop.NameEquals("startVm"u8)) - { - if (prop.Value.ValueKind == JsonValueKind.Null) - { - continue; - } - startVm = prop.Value.GetBoolean(); - continue; - } - if (options.Format != "W") - { - additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); - } - } - return new StartRequest(startVm, additionalBinaryDataProperties); - } - - 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); - default: - throw new FormatException($"The model {nameof(StartRequest)} does not support writing '{options.Format}' format."); - } - } - - StartRequest IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); - - /// The data to parse. - /// The client options for reading and writing models. - protected virtual StartRequest 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 DeserializeStartRequest(document.RootElement, options); - } - default: - throw new FormatException($"The model {nameof(StartRequest)} does not support reading '{options.Format}' format."); - } - } - - string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; - - /// The to serialize into . - public static implicit operator RequestContent(StartRequest startRequest) - { - if (startRequest == null) - { - return null; - } - Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); - content.JsonWriter.WriteObjectValue(startRequest, ModelSerializationExtensions.WireOptions); - return content; - } - - /// The to deserialize the from. - public static explicit operator StartRequest(Response result) - { - using Response response = result; - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeStartRequest(document.RootElement, ModelSerializationExtensions.WireOptions); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.cs deleted file mode 100644 index 17631d3b56a2..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/StartRequest.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.Collections.Generic; - -namespace MgmtTypeSpec.Models -{ - /// Start SAP instance(s) request body. - public partial class StartRequest - { - /// Keeps track of any properties unknown to the library. - private protected readonly IDictionary _additionalBinaryDataProperties; - - /// Initializes a new instance of . - public StartRequest() - { - } - - internal StartRequest(bool? startVm, IDictionary additionalBinaryDataProperties) - { - StartVm = startVm; - _additionalBinaryDataProperties = additionalBinaryDataProperties; - } - - /// The boolean value indicates whether to start the virtual machines before starting the SAP instances. - public bool? StartVm { get; set; } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/PrivateLinks.RestClient.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/PrivateLinks.RestClient.cs deleted file mode 100644 index 901fcbe2a9bf..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/PrivateLinks.RestClient.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using Azure; -using Azure.Core; - -namespace MgmtTypeSpec -{ - /// - public partial class PrivateLinks - { - private static ResponseClassifier _pipelineMessageClassifier200; - private static ResponseClassifier _pipelineMessageClassifier200202; - - private static ResponseClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = new StatusCodeClassifier(stackalloc ushort[] { 200 }); - - private static ResponseClassifier PipelineMessageClassifier200202 => _pipelineMessageClassifier200202 = new StatusCodeClassifier(stackalloc ushort[] { 200, 202 }); - - internal HttpMessage CreateGetAllPrivateLinkResourcesRequest(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier200); - Request request = message.Request; - request.Method = RequestMethod.Get; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/privateLinkResources", false); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Accept", "application/json"); - return message; - } - - internal HttpMessage CreateStartRequest(Guid subscriptionId, string resourceGroupName, string privateLinkResourceName, RequestContent content, RequestContext context) - { - HttpMessage message = Pipeline.CreateMessage(context, PipelineMessageClassifier200202); - Request request = message.Request; - request.Method = RequestMethod.Post; - RawRequestUriBuilder uri = new RawRequestUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/subscriptions/", false); - uri.AppendPath(subscriptionId.ToString(), true); - uri.AppendPath("/resourceGroups/", false); - uri.AppendPath(resourceGroupName, true); - uri.AppendPath("/providers/MgmtTypeSpec/privateLinkResources/", false); - uri.AppendPath(privateLinkResourceName, true); - uri.AppendPath("/start", false); - uri.AppendQuery("api-version", _apiVersion, true); - request.Uri = uri; - request.Headers.SetValue("Content-Type", "application/json"); - request.Headers.SetValue("Accept", "application/json"); - request.Content = content; - return message; - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/FoosRestOperations.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/FoosRestOperations.cs index 2d4366f46dd7..e015342bf88b 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/FoosRestOperations.cs +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/FoosRestOperations.cs @@ -6,12 +6,9 @@ #nullable disable using System; -using System.Threading; -using System.Threading.Tasks; using Azure; using Azure.Core; using Azure.Core.Pipeline; -using MgmtTypeSpec.Models; namespace MgmtTypeSpec { @@ -35,322 +32,81 @@ internal Foos(HttpPipeline pipeline, Uri endpoint, string apiVersion) /// The HTTP pipeline for sending and receiving REST requests and responses. public HttpPipeline Pipeline { get; } - /// - /// [Protocol Method] Create a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response CreateOrUpdate(Guid subscriptionId, string resourceGroupName, string fooName, RequestContent content, RequestContext context = null) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - Argument.AssertNotNull(content, nameof(content)); - - using HttpMessage message = CreateCreateOrUpdateRequest(subscriptionId, resourceGroupName, fooName, content, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] Create a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CreateOrUpdateAsync(Guid subscriptionId, string resourceGroupName, string fooName, RequestContent content, RequestContext context = null) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - Argument.AssertNotNull(content, nameof(content)); - - using HttpMessage message = CreateCreateOrUpdateRequest(subscriptionId, resourceGroupName, fooName, content, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// Create a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// Resource create parameters. - /// The cancellation token that can be used to cancel the operation. - /// , or is null. - /// Service returned a non-success status code. - public virtual Response CreateOrUpdate(Guid subscriptionId, string resourceGroupName, string fooName, FooData resource, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - Argument.AssertNotNull(resource, nameof(resource)); - - Response result = CreateOrUpdate(subscriptionId, resourceGroupName, fooName, resource, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - return Response.FromValue((FooData)result, result); - } - - /// Create a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// Resource create parameters. - /// The cancellation token that can be used to cancel the operation. - /// , or is null. - /// Service returned a non-success status code. - public virtual async Task> CreateOrUpdateAsync(Guid subscriptionId, string resourceGroupName, string fooName, FooData resource, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - Argument.AssertNotNull(resource, nameof(resource)); - - Response result = await CreateOrUpdateAsync(subscriptionId, resourceGroupName, fooName, resource, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - return Response.FromValue((FooData)result, result); - } - - /// - /// [Protocol Method] Get a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response Get(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - using HttpMessage message = CreateGetRequest(subscriptionId, resourceGroupName, fooName, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] Get a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetAsync(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - using HttpMessage message = CreateGetRequest(subscriptionId, resourceGroupName, fooName, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// Get a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual Response Get(Guid subscriptionId, string resourceGroupName, string fooName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - Response result = Get(subscriptionId, resourceGroupName, fooName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - return Response.FromValue((FooData)result, result); - } - - /// Get a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual async Task> GetAsync(Guid subscriptionId, string resourceGroupName, string fooName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - Response result = await GetAsync(subscriptionId, resourceGroupName, fooName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - return Response.FromValue((FooData)result, result); - } - - /// - /// [Protocol Method] Delete a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response Delete(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - using HttpMessage message = CreateDeleteRequest(subscriptionId, resourceGroupName, fooName, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] Delete a Foo - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task DeleteAsync(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - using HttpMessage message = CreateDeleteRequest(subscriptionId, resourceGroupName, fooName, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// Delete a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual Response Delete(Guid subscriptionId, string resourceGroupName, string fooName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - return Delete(subscriptionId, resourceGroupName, fooName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - } - - /// Delete a Foo. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the Foo. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual async Task DeleteAsync(Guid subscriptionId, string resourceGroupName, string fooName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(fooName, nameof(fooName)); - - return await DeleteAsync(subscriptionId, resourceGroupName, fooName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - } - - /// - /// [Protocol Method] List Foo resources by resource group - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response List(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - using HttpMessage message = CreateListRequest(subscriptionId, resourceGroupName, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] List Foo resources by resource group - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task ListAsync(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - using HttpMessage message = CreateListRequest(subscriptionId, resourceGroupName, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// List Foo resources by resource group. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The cancellation token that can be used to cancel the operation. - /// is null. - /// Service returned a non-success status code. - public virtual Response List(Guid subscriptionId, string resourceGroupName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - Response result = List(subscriptionId, resourceGroupName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - return Response.FromValue((FooListResult)result, result); - } - - /// List Foo resources by resource group. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The cancellation token that can be used to cancel the operation. - /// is null. - /// Service returned a non-success status code. - public virtual async Task> ListAsync(Guid subscriptionId, string resourceGroupName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - Response result = await ListAsync(subscriptionId, resourceGroupName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - return Response.FromValue((FooListResult)result, result); + internal HttpMessage CreateCreateOrUpdateRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContent content, RequestContext context) + { + HttpMessage message = Pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Put; + RawRequestUriBuilder uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/subscriptions/", false); + uri.AppendPath(subscriptionId.ToString(), true); + uri.AppendPath("/resourceGroups/", false); + uri.AppendPath(resourceGroupName, true); + uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); + uri.AppendPath(fooName, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.SetValue("Content-Type", "application/json"); + request.Headers.SetValue("Accept", "application/json"); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) + { + HttpMessage message = Pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Get; + RawRequestUriBuilder uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/subscriptions/", false); + uri.AppendPath(subscriptionId.ToString(), true); + uri.AppendPath("/resourceGroups/", false); + uri.AppendPath(resourceGroupName, true); + uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); + uri.AppendPath(fooName, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.SetValue("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateDeleteRequest(Guid subscriptionId, string resourceGroupName, string fooName, RequestContext context) + { + HttpMessage message = Pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Delete; + RawRequestUriBuilder uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/subscriptions/", false); + uri.AppendPath(subscriptionId.ToString(), true); + uri.AppendPath("/resourceGroups/", false); + uri.AppendPath(resourceGroupName, true); + uri.AppendPath("/providers/MgmtTypeSpec/foos/", false); + uri.AppendPath(fooName, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.SetValue("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateListRequest(Guid subscriptionId, string resourceGroupName, RequestContext context) + { + HttpMessage message = Pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Get; + RawRequestUriBuilder uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/subscriptions/", false); + uri.AppendPath(subscriptionId.ToString(), true); + uri.AppendPath("/resourceGroups/", false); + uri.AppendPath(resourceGroupName, true); + uri.AppendPath("/providers/MgmtTypeSpec/foos", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.SetValue("Accept", "application/json"); + return message; } } } diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/PrivateLinksRestOperations.cs b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/PrivateLinksRestOperations.cs deleted file mode 100644 index e3d81cf4bfb3..000000000000 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/RestOperations/PrivateLinksRestOperations.cs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; -using System.Threading; -using System.Threading.Tasks; -using Azure; -using Azure.Core; -using Azure.Core.Pipeline; -using MgmtTypeSpec.Models; - -namespace MgmtTypeSpec -{ - internal partial class PrivateLinks - { - private readonly Uri _endpoint; - private readonly string _apiVersion; - - /// Initializes a new instance of PrivateLinks for mocking. - protected PrivateLinks() - { - } - - internal PrivateLinks(HttpPipeline pipeline, Uri endpoint, string apiVersion) - { - _endpoint = endpoint; - Pipeline = pipeline; - _apiVersion = apiVersion; - } - - /// The HTTP pipeline for sending and receiving REST requests and responses. - public HttpPipeline Pipeline { get; } - - /// - /// [Protocol Method] list private links on the given resource - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response GetAllPrivateLinkResources(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - using HttpMessage message = CreateGetAllPrivateLinkResourcesRequest(subscriptionId, resourceGroupName, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] list private links on the given resource - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetAllPrivateLinkResourcesAsync(Guid subscriptionId, string resourceGroupName, RequestContext context) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - using HttpMessage message = CreateGetAllPrivateLinkResourcesRequest(subscriptionId, resourceGroupName, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// list private links on the given resource. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The cancellation token that can be used to cancel the operation. - /// is null. - /// Service returned a non-success status code. - public virtual Response GetAllPrivateLinkResources(Guid subscriptionId, string resourceGroupName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - Response result = GetAllPrivateLinkResources(subscriptionId, resourceGroupName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - return Response.FromValue((PrivateLinkResourceListResult)result, result); - } - - /// list private links on the given resource. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The cancellation token that can be used to cancel the operation. - /// is null. - /// Service returned a non-success status code. - public virtual async Task> GetAllPrivateLinkResourcesAsync(Guid subscriptionId, string resourceGroupName, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - - Response result = await GetAllPrivateLinkResourcesAsync(subscriptionId, resourceGroupName, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - return Response.FromValue((PrivateLinkResourceListResult)result, result); - } - - /// - /// [Protocol Method] Starts the SAP Application Server Instance. - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the private link associated with the Azure resource. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual Response Start(Guid subscriptionId, string resourceGroupName, string privateLinkResourceName, RequestContent content, RequestContext context = null) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(privateLinkResourceName, nameof(privateLinkResourceName)); - - using HttpMessage message = CreateStartRequest(subscriptionId, resourceGroupName, privateLinkResourceName, content, context); - return Pipeline.ProcessMessage(message, context); - } - - /// - /// [Protocol Method] Starts the SAP Application Server Instance. - /// - /// - /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. - /// - /// - /// - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the private link associated with the Azure resource. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task StartAsync(Guid subscriptionId, string resourceGroupName, string privateLinkResourceName, RequestContent content, RequestContext context = null) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(privateLinkResourceName, nameof(privateLinkResourceName)); - - using HttpMessage message = CreateStartRequest(subscriptionId, resourceGroupName, privateLinkResourceName, content, context); - return await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); - } - - /// Starts the SAP Application Server Instance. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the private link associated with the Azure resource. - /// SAP Application server instance start request body. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual Response Start(Guid subscriptionId, string resourceGroupName, string privateLinkResourceName, StartRequest body = null, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(privateLinkResourceName, nameof(privateLinkResourceName)); - - return Start(subscriptionId, resourceGroupName, privateLinkResourceName, body, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null); - } - - /// Starts the SAP Application Server Instance. - /// The ID of the target subscription. The value must be an UUID. - /// The name of the resource group. The name is case insensitive. - /// The name of the private link associated with the Azure resource. - /// SAP Application server instance start request body. - /// The cancellation token that can be used to cancel the operation. - /// or is null. - /// Service returned a non-success status code. - public virtual async Task StartAsync(Guid subscriptionId, string resourceGroupName, string privateLinkResourceName, StartRequest body = null, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(resourceGroupName, nameof(resourceGroupName)); - Argument.AssertNotNull(privateLinkResourceName, nameof(privateLinkResourceName)); - - return await StartAsync(subscriptionId, resourceGroupName, privateLinkResourceName, body, cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null).ConfigureAwait(false); - } - } -} diff --git a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/tspCodeModel.json b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/tspCodeModel.json index 1e14d5b4fb7c..172c496c6871 100644 --- a/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/tspCodeModel.json +++ b/eng/packages/http-client-csharp/generator/TestProjects/Local/Mgmt-TypeSpec/tspCodeModel.json @@ -3450,27 +3450,35 @@ } } ], - "Decorators": [] + "Decorators": [ + { + "$id": "438", + "name": "Azure.ResourceManager.@armResourceOperations", + "arguments": { + "$id": "439" + } + } + ] }, { - "$id": "438", + "$id": "440", "Name": "Foos", "ClientNamespace": "MgmtTypeSpec", "Operations": [ { - "$id": "439", + "$id": "441", "Name": "createOrUpdate", "ResourceName": "Foo", "Doc": "Create a Foo", "Accessibility": "public", "Parameters": [ { - "$id": "440", + "$id": "442", "Name": "apiVersion", "NameInRequest": "api-version", "Doc": "The API version to use for this operation.", "Type": { - "$id": "441", + "$id": "443", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3484,9 +3492,9 @@ "IsRequired": true, "Kind": "Client", "DefaultValue": { - "$id": "442", + "$id": "444", "Type": { - "$id": "443", + "$id": "445", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -3497,17 +3505,17 @@ "SkipUrlEncoding": false }, { - "$id": "444", + "$id": "446", "Name": "subscriptionId", "NameInRequest": "subscriptionId", "Doc": "The ID of the target subscription. The value must be an UUID.", "Type": { - "$id": "445", + "$id": "447", "kind": "string", "name": "uuid", "crossLanguageDefinitionId": "Azure.Core.uuid", "baseType": { - "$id": "446", + "$id": "448", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3526,12 +3534,12 @@ "SkipUrlEncoding": false }, { - "$id": "447", + "$id": "449", "Name": "resourceGroupName", "NameInRequest": "resourceGroupName", "Doc": "The name of the resource group. The name is case insensitive.", "Type": { - "$id": "448", + "$id": "450", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3548,12 +3556,12 @@ "SkipUrlEncoding": false }, { - "$id": "449", + "$id": "451", "Name": "fooName", "NameInRequest": "fooName", "Doc": "The name of the Foo", "Type": { - "$id": "450", + "$id": "452", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3570,15 +3578,15 @@ "SkipUrlEncoding": false }, { - "$id": "451", + "$id": "453", "Name": "contentType", "NameInRequest": "Content-Type", "Doc": "Body parameter's content type. Known values are application/json", "Type": { - "$id": "452", + "$id": "454", "kind": "constant", "valueType": { - "$id": "453", + "$id": "455", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3598,14 +3606,14 @@ "SkipUrlEncoding": false }, { - "$id": "454", + "$id": "456", "Name": "accept", "NameInRequest": "Accept", "Type": { - "$id": "455", + "$id": "457", "kind": "constant", "valueType": { - "$id": "456", + "$id": "458", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3625,7 +3633,7 @@ "SkipUrlEncoding": false }, { - "$id": "457", + "$id": "459", "Name": "resource", "NameInRequest": "resource", "Doc": "Resource create parameters.", @@ -3645,7 +3653,7 @@ ], "Responses": [ { - "$id": "458", + "$id": "460", "StatusCodes": [ 200 ], @@ -3660,7 +3668,7 @@ ] }, { - "$id": "459", + "$id": "461", "StatusCodes": [ 201 ], @@ -3670,12 +3678,12 @@ "BodyMediaType": "Json", "Headers": [ { - "$id": "460", + "$id": "462", "Name": "azureAsyncOperation", "NameInResponse": "Azure-AsyncOperation", "Doc": "A link to the status monitor", "Type": { - "$id": "461", + "$id": "463", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3683,12 +3691,12 @@ } }, { - "$id": "462", + "$id": "464", "Name": "retryAfter", "NameInResponse": "Retry-After", "Doc": "The Retry-After header can indicate how long the client should wait before polling the operation status.", "Type": { - "$id": "463", + "$id": "465", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -3711,10 +3719,10 @@ ], "BufferResponse": true, "LongRunning": { - "$id": "464", + "$id": "466", "FinalStateVia": 0, "FinalResponse": { - "$id": "465", + "$id": "467", "StatusCodes": [ 200 ], @@ -3730,19 +3738,19 @@ "Decorators": [] }, { - "$id": "466", + "$id": "468", "Name": "get", "ResourceName": "Foo", "Doc": "Get a Foo", "Accessibility": "public", "Parameters": [ { - "$id": "467", + "$id": "469", "Name": "apiVersion", "NameInRequest": "api-version", "Doc": "The API version to use for this operation.", "Type": { - "$id": "468", + "$id": "470", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3756,9 +3764,9 @@ "IsRequired": true, "Kind": "Client", "DefaultValue": { - "$id": "469", + "$id": "471", "Type": { - "$id": "470", + "$id": "472", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -3769,17 +3777,17 @@ "SkipUrlEncoding": false }, { - "$id": "471", + "$id": "473", "Name": "subscriptionId", "NameInRequest": "subscriptionId", "Doc": "The ID of the target subscription. The value must be an UUID.", "Type": { - "$id": "472", + "$id": "474", "kind": "string", "name": "uuid", "crossLanguageDefinitionId": "Azure.Core.uuid", "baseType": { - "$id": "473", + "$id": "475", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3798,12 +3806,12 @@ "SkipUrlEncoding": false }, { - "$id": "474", + "$id": "476", "Name": "resourceGroupName", "NameInRequest": "resourceGroupName", "Doc": "The name of the resource group. The name is case insensitive.", "Type": { - "$id": "475", + "$id": "477", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3820,12 +3828,12 @@ "SkipUrlEncoding": false }, { - "$id": "476", + "$id": "478", "Name": "fooName", "NameInRequest": "fooName", "Doc": "The name of the Foo", "Type": { - "$id": "477", + "$id": "479", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3842,14 +3850,14 @@ "SkipUrlEncoding": false }, { - "$id": "478", + "$id": "480", "Name": "accept", "NameInRequest": "Accept", "Type": { - "$id": "479", + "$id": "481", "kind": "constant", "valueType": { - "$id": "480", + "$id": "482", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3871,7 +3879,7 @@ ], "Responses": [ { - "$id": "481", + "$id": "483", "StatusCodes": [ 200 ], @@ -3894,22 +3902,30 @@ "GenerateProtocolMethod": true, "GenerateConvenienceMethod": true, "CrossLanguageDefinitionId": "MgmtTypeSpec.Foos.get", - "Decorators": [] + "Decorators": [ + { + "$id": "484", + "name": "Azure.ResourceManager.@armResourceRead", + "arguments": { + "$id": "485" + } + } + ] }, { - "$id": "482", + "$id": "486", "Name": "delete", "ResourceName": "Foo", "Doc": "Delete a Foo", "Accessibility": "public", "Parameters": [ { - "$id": "483", + "$id": "487", "Name": "apiVersion", "NameInRequest": "api-version", "Doc": "The API version to use for this operation.", "Type": { - "$id": "484", + "$id": "488", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3923,9 +3939,9 @@ "IsRequired": true, "Kind": "Client", "DefaultValue": { - "$id": "485", + "$id": "489", "Type": { - "$id": "486", + "$id": "490", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -3936,17 +3952,17 @@ "SkipUrlEncoding": false }, { - "$id": "487", + "$id": "491", "Name": "subscriptionId", "NameInRequest": "subscriptionId", "Doc": "The ID of the target subscription. The value must be an UUID.", "Type": { - "$id": "488", + "$id": "492", "kind": "string", "name": "uuid", "crossLanguageDefinitionId": "Azure.Core.uuid", "baseType": { - "$id": "489", + "$id": "493", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3965,12 +3981,12 @@ "SkipUrlEncoding": false }, { - "$id": "490", + "$id": "494", "Name": "resourceGroupName", "NameInRequest": "resourceGroupName", "Doc": "The name of the resource group. The name is case insensitive.", "Type": { - "$id": "491", + "$id": "495", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -3987,12 +4003,12 @@ "SkipUrlEncoding": false }, { - "$id": "492", + "$id": "496", "Name": "fooName", "NameInRequest": "fooName", "Doc": "The name of the Foo", "Type": { - "$id": "493", + "$id": "497", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4009,14 +4025,14 @@ "SkipUrlEncoding": false }, { - "$id": "494", + "$id": "498", "Name": "accept", "NameInRequest": "Accept", "Type": { - "$id": "495", + "$id": "499", "kind": "constant", "valueType": { - "$id": "496", + "$id": "500", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4038,19 +4054,19 @@ ], "Responses": [ { - "$id": "497", + "$id": "501", "StatusCodes": [ 202 ], "BodyMediaType": "Json", "Headers": [ { - "$id": "498", + "$id": "502", "Name": "location", "NameInResponse": "Location", "Doc": "The Location header contains the URL where the status of the long running operation can be checked.", "Type": { - "$id": "499", + "$id": "503", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4058,12 +4074,12 @@ } }, { - "$id": "500", + "$id": "504", "Name": "retryAfter", "NameInResponse": "Retry-After", "Doc": "The Retry-After header can indicate how long the client should wait before polling the operation status.", "Type": { - "$id": "501", + "$id": "505", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -4074,7 +4090,7 @@ "IsErrorResponse": false }, { - "$id": "502", + "$id": "506", "StatusCodes": [ 204 ], @@ -4089,10 +4105,10 @@ "Path": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/MgmtTypeSpec/foos/{fooName}", "BufferResponse": true, "LongRunning": { - "$id": "503", + "$id": "507", "FinalStateVia": 1, "FinalResponse": { - "$id": "504", + "$id": "508", "StatusCodes": [ 204 ], @@ -4105,19 +4121,19 @@ "Decorators": [] }, { - "$id": "505", + "$id": "509", "Name": "list", "ResourceName": "Foo", "Doc": "List Foo resources by resource group", "Accessibility": "public", "Parameters": [ { - "$id": "506", + "$id": "510", "Name": "apiVersion", "NameInRequest": "api-version", "Doc": "The API version to use for this operation.", "Type": { - "$id": "507", + "$id": "511", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4131,9 +4147,9 @@ "IsRequired": true, "Kind": "Client", "DefaultValue": { - "$id": "508", + "$id": "512", "Type": { - "$id": "509", + "$id": "513", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -4144,17 +4160,17 @@ "SkipUrlEncoding": false }, { - "$id": "510", + "$id": "514", "Name": "subscriptionId", "NameInRequest": "subscriptionId", "Doc": "The ID of the target subscription. The value must be an UUID.", "Type": { - "$id": "511", + "$id": "515", "kind": "string", "name": "uuid", "crossLanguageDefinitionId": "Azure.Core.uuid", "baseType": { - "$id": "512", + "$id": "516", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4173,12 +4189,12 @@ "SkipUrlEncoding": false }, { - "$id": "513", + "$id": "517", "Name": "resourceGroupName", "NameInRequest": "resourceGroupName", "Doc": "The name of the resource group. The name is case insensitive.", "Type": { - "$id": "514", + "$id": "518", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4195,14 +4211,14 @@ "SkipUrlEncoding": false }, { - "$id": "515", + "$id": "519", "Name": "accept", "NameInRequest": "Accept", "Type": { - "$id": "516", + "$id": "520", "kind": "constant", "valueType": { - "$id": "517", + "$id": "521", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -4224,7 +4240,7 @@ ], "Responses": [ { - "$id": "518", + "$id": "522", "StatusCodes": [ 200 ], @@ -4245,7 +4261,7 @@ "Path": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/MgmtTypeSpec/foos", "BufferResponse": true, "Paging": { - "$id": "519", + "$id": "523", "ItemName": "value", "NextLinkName": "nextLink" }, @@ -4256,17 +4272,17 @@ } ], "Protocol": { - "$id": "520" + "$id": "524" }, "Parent": "MgmtTypeSpecClient", "Parameters": [ { - "$id": "521", + "$id": "525", "Name": "endpoint", "NameInRequest": "endpoint", "Doc": "Service host", "Type": { - "$id": "522", + "$id": "526", "kind": "url", "name": "url", "crossLanguageDefinitionId": "TypeSpec.url" @@ -4281,9 +4297,9 @@ "Explode": false, "Kind": "Client", "DefaultValue": { - "$id": "523", + "$id": "527", "Type": { - "$id": "524", + "$id": "528", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -4292,13 +4308,21 @@ } } ], - "Decorators": [] + "Decorators": [ + { + "$id": "529", + "name": "Azure.ResourceManager.@armResourceOperations", + "arguments": { + "$id": "530" + } + } + ] } ], "Auth": { - "$id": "525", + "$id": "531", "OAuth2": { - "$id": "526", + "$id": "532", "Scopes": [ "user_impersonation" ] diff --git a/eng/scripts/typespec/Generate-Code.ps1 b/eng/scripts/typespec/Generate-Code.ps1 index aa48e603e7d0..6b7e5be1693a 100644 --- a/eng/scripts/typespec/Generate-Code.ps1 +++ b/eng/scripts/typespec/Generate-Code.ps1 @@ -52,9 +52,8 @@ Invoke-LoggedCommand "dotnet build $packageRoot/generator/TestProjects/Local/Bas Write-Host "Generating MgmtTypeSpec" -ForegroundColor Cyan Invoke-LoggedCommand (Get-TspCommand "$mgmtTypespecTestProject/main.tsp" $mgmtTypespecTestProject) -# temporarily disable building MgmtTypeSpec because now the generated code of this project cannot build -# Write-Host "Building BasicTypeSpec" -ForegroundColor Cyan -# Invoke-LoggedCommand "dotnet build $packageRoot/generator/TestProjects/Local/Mgmt-TypeSpec/src/MgmtTypeSpec.csproj" +Write-Host "Building MgmtTypeSpec" -ForegroundColor Cyan +Invoke-LoggedCommand "dotnet build $packageRoot/generator/TestProjects/Local/Mgmt-TypeSpec/src/MgmtTypeSpec.csproj" Pop-Location