diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs index fd69bab995..989cac3dae 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs @@ -2,12 +2,12 @@ // Licensed under the MIT License. using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Text.Json; using System.Xml; using System.Xml.Linq; using Microsoft.Generator.CSharp.Providers; -using Microsoft.Generator.CSharp.Snippets; using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel @@ -17,25 +17,19 @@ internal static class ScmKnownParameters private static readonly CSharpType modelReaderWriterOptionsType = typeof(ModelReaderWriterOptions); private static readonly CSharpType nullableModelReaderWriterOptionsType = new CSharpType(typeof(ModelReaderWriterOptions), isNullable: true); - public static readonly ParameterProvider XmlWriter = new ParameterProvider("writer", FormattableStringHelpers.Empty, typeof(XmlWriter)); - public static readonly ParameterProvider NameHint = new ParameterProvider("nameHint", FormattableStringHelpers.Empty, typeof(string)); - public static readonly ParameterProvider XElement = new ParameterProvider("element", FormattableStringHelpers.Empty, typeof(XElement)); - - public static readonly ParameterProvider Utf8JsonWriter = new ParameterProvider("writer", FormattableStringHelpers.Empty, typeof(Utf8JsonWriter)); - public static readonly ParameterProvider Utf8JsonReader = new ParameterProvider("reader", FormattableStringHelpers.Empty, typeof(Utf8JsonReader), isRef: true); - public static readonly ParameterProvider JsonOptions = new ParameterProvider("options", FormattableStringHelpers.Empty, typeof(JsonSerializerOptions)); - public static readonly ParameterProvider Options = new ParameterProvider("options", FormattableStringHelpers.Empty, modelReaderWriterOptionsType); - public static readonly ParameterProvider OptionalOptions = new ParameterProvider("options", FormattableStringHelpers.Empty, nullableModelReaderWriterOptionsType, DefaultOf(nullableModelReaderWriterOptionsType)); - public static readonly ParameterProvider JsonElement = new ParameterProvider("element", FormattableStringHelpers.Empty, typeof(JsonElement)); - public static readonly ParameterProvider Data = new ParameterProvider("data", FormattableStringHelpers.Empty, typeof(BinaryData)); - - private static ParameterProvider? _tokenAuth; - public static ParameterProvider TokenAuth => _tokenAuth ??= new("tokenCredential", $"The token credential to copy", ClientModelPlugin.Instance.TypeFactory.TokenCredentialType()); - - private static ParameterProvider? _matchConditionsParameter; - public static ParameterProvider MatchConditionsParameter => _matchConditionsParameter ??= new("matchConditions", $"The content to send as the request conditions of the request.", ClientModelPlugin.Instance.TypeFactory.MatchConditionsType(), Snippet.DefaultOf(ClientModelPlugin.Instance.TypeFactory.RequestConditionsType())); - - private static ParameterProvider? _requestConditionsParameter; - public static ParameterProvider RequestConditionsParameter => _requestConditionsParameter ??= new("requestConditions", $"The content to send as the request conditions of the request.", ClientModelPlugin.Instance.TypeFactory.RequestConditionsType(), Snippet.DefaultOf(ClientModelPlugin.Instance.TypeFactory.RequestConditionsType())); + public static readonly ParameterProvider XmlWriter = new("writer", FormattableStringHelpers.Empty, typeof(XmlWriter)); + public static readonly ParameterProvider NameHint = new("nameHint", FormattableStringHelpers.Empty, typeof(string)); + public static readonly ParameterProvider XElement = new("element", FormattableStringHelpers.Empty, typeof(XElement)); + public static readonly ParameterProvider Utf8JsonWriter = new("writer", FormattableStringHelpers.Empty, typeof(Utf8JsonWriter)); + public static readonly ParameterProvider Utf8JsonReader = new("reader", FormattableStringHelpers.Empty, typeof(Utf8JsonReader), isRef: true); + public static readonly ParameterProvider JsonOptions = new("options", FormattableStringHelpers.Empty, typeof(JsonSerializerOptions)); + public static readonly ParameterProvider Options = new("options", FormattableStringHelpers.Empty, modelReaderWriterOptionsType); + public static readonly ParameterProvider OptionalOptions = new("options", FormattableStringHelpers.Empty, nullableModelReaderWriterOptionsType, DefaultOf(nullableModelReaderWriterOptionsType)); + public static readonly ParameterProvider JsonElement = new("element", FormattableStringHelpers.Empty, typeof(JsonElement)); + public static readonly ParameterProvider Data = new("data", FormattableStringHelpers.Empty, typeof(BinaryData)); + public static readonly ParameterProvider TokenAuth = new("tokenCredential", $"The token credential to copy", ClientModelPlugin.Instance.TypeFactory.TokenCredentialType()); + public static readonly ParameterProvider MatchConditionsParameter = new("matchConditions", $"The content to send as the request conditions of the request.", ClientModelPlugin.Instance.TypeFactory.MatchConditionsType(), DefaultOf(ClientModelPlugin.Instance.TypeFactory.MatchConditionsType())); + public static readonly ParameterProvider RequestOptions = new("options", $"The request options, which can override default behaviors of the client pipeline on a per-call basis.", typeof(RequestOptions)); + public static readonly ParameterProvider BinaryContent = new("content", $"The content to send as the body of the request.", typeof(BinaryContent)); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs index dfa7ec4af5..70bb87afa5 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs @@ -37,7 +37,9 @@ protected override TypeProvider[] BuildTypeProviders() ..baseTypes, ..BuildClients(), new ModelSerializationExtensionsProvider(), - new TypeFormattersProvider() + new TypeFormattersProvider(), + new ClientPipelineExtensionsProvider(), + new ErrorResultProvider() ]; } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmTypeFactory.cs index 65a0de09ec..f6aa05c1fd 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmTypeFactory.cs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; +using System.ClientModel; +using System.ClientModel.Primitives; using System.Collections.Generic; using Microsoft.Generator.CSharp.ClientModel.Providers; using Microsoft.Generator.CSharp.Input; @@ -21,28 +22,8 @@ public class ScmTypeFactory : TypeFactory /// The enclosing type of the operation. public override MethodProviderCollection CreateMethodProviders(InputOperation operation, TypeProvider enclosingType) => new ScmMethodProviderCollection(operation, enclosingType); - public virtual CSharpType MatchConditionsType() - { - // TO-DO: Determine what the correct type is for MatchConditions: https://github.com/Azure/autorest.csharp/issues/4166 - throw new NotImplementedException(); - } + public virtual CSharpType MatchConditionsType() => typeof(PipelineMessageClassifier); - public virtual CSharpType RequestConditionsType() - { - // TO-DO: Determine what the correct type is for RequestConditions: https://github.com/Azure/autorest.csharp/issues/4166 - throw new NotImplementedException(); - } - - public virtual CSharpType TokenCredentialType() - { - // TO-DO: Determine what the correct type is for TokenCredential: https://github.com/Azure/autorest.csharp/issues/4166 - throw new NotImplementedException(); - } - - public virtual CSharpType PageResponseType() - { - // TO-DO: Determine what the correct type is for Page: https://github.com/Azure/autorest.csharp/issues/4166 - throw new NotImplementedException(); - } + public virtual CSharpType TokenCredentialType() => typeof(ApiKeyCredential); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs index 04f3a5448e..8d3f9a2f19 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs @@ -1,19 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ClientModel; using System.ClientModel.Primitives; -using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; using Microsoft.Generator.CSharp.ClientModel.Snippets; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Statements; +using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel.Providers { internal class ClientPipelineExtensionsProvider : TypeProvider { - public override string RelativeFilePath => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - public override string Name { get; } + private static readonly Lazy _instance = new(() => new ClientPipelineExtensionsProvider()); + + public static ClientPipelineExtensionsProvider Instance => _instance.Value; private const string _processMessageAsync = "ProcessMessageAsync"; private const string _processMessage = "ProcessMessage"; @@ -22,16 +27,19 @@ internal class ClientPipelineExtensionsProvider : TypeProvider private ParameterProvider _pipelineParam; private ParameterProvider _messageParam; - private ParameterProvider _requestContextParam; - private MemberExpression _messageResponse; + private ParameterProvider _requestOptionsParam; + private ClientPipelineSnippet _pipeline; + private PipelineMessageSnippet _message; + private RequestOptionsSnippet _options; - internal ClientPipelineExtensionsProvider() + public ClientPipelineExtensionsProvider() { - Name = "ClientPipelineExtensions"; - _pipelineParam = new ParameterProvider("pipeline", $"The pipeline.", typeof(ClientPipeline)); - _messageParam = new ParameterProvider("message", $"The message.", typeof(PipelineMessage)); - _requestContextParam = new ParameterProvider("requestContext", $"The request context.", typeof(RequestOptions)); - _messageResponse = new MemberExpression(_messageParam, "Response"); + _pipelineParam = new ParameterProvider("pipeline", FormattableStringHelpers.Empty, typeof(ClientPipeline)); + _messageParam = new ParameterProvider("message", FormattableStringHelpers.Empty, typeof(PipelineMessage)); + _requestOptionsParam = new ParameterProvider("options", FormattableStringHelpers.Empty, typeof(RequestOptions)); + _pipeline = new ClientPipelineSnippet(_pipelineParam); + _message = new PipelineMessageSnippet(_messageParam); + _options = new RequestOptionsSnippet(_requestOptionsParam); } protected override TypeSignatureModifiers GetDeclarationModifiers() @@ -39,14 +47,135 @@ protected override TypeSignatureModifiers GetDeclarationModifiers() return TypeSignatureModifiers.Internal | TypeSignatureModifiers.Static; } - internal PipelineResponseSnippet ProcessMessage(IReadOnlyList arguments, bool isAsync) + public override string Name => "ClientPipelineExtensions"; + + public override string RelativeFilePath => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); + + protected override MethodProvider[] BuildMethods() { - return new(new InvokeStaticMethodExpression(Type, isAsync ? _processMessageAsync : _processMessage, arguments, CallAsExtension: true, CallAsAsync: isAsync)); + return + [ + BuildProcessMessageAsync(), + BuildProcessMessage(), + ProcessHeadAsBoolMessageAsync(), + ProcessHeadAsBoolMessage() + ]; } - internal ClientResultSnippet ProcessHeadAsBoolMessage(IReadOnlyList arguments, bool isAsync) + private MethodProvider ProcessHeadAsBoolMessage() { - return new(new InvokeStaticMethodExpression(Type, isAsync ? _processHeadAsBoolMessageAsync : _processHeadAsBoolMessage, arguments, CallAsExtension: true, CallAsAsync: isAsync)); + MethodSignature signature = GetProcessHeadAsBoolMessageSignature(false); + var responseVariable = new VariableExpression(typeof(PipelineResponse), "response"); + var response = new PipelineResponseSnippet(responseVariable); + return new MethodProvider(signature, new MethodBodyStatement[] + { + new DeclarationExpression(responseVariable, false).Assign(_pipeline.ProcessMessage(_message, _options, false)).Terminate(), + GetProcessHeadAsBoolMessageBody(response) + }, this); + } + + private MethodProvider ProcessHeadAsBoolMessageAsync() + { + MethodSignature signature = GetProcessHeadAsBoolMessageSignature(true); + var responseVariable = new VariableExpression(typeof(PipelineResponse), "response"); + var response = new PipelineResponseSnippet(responseVariable); + return new MethodProvider(signature, new MethodBodyStatement[] + { + new DeclarationExpression(responseVariable, false).Assign(_pipeline.ProcessMessage(_message, _options, true)).Terminate(), + GetProcessHeadAsBoolMessageBody(response) + }, this); + } + + private MethodBodyStatement GetProcessHeadAsBoolMessageBody(PipelineResponseSnippet response) + { + return new MethodBodyStatement[] + { + new SwitchStatement(new MemberExpression(response, "Status"), new SwitchCaseStatement[] + { + new SwitchCaseStatement(ValueExpression.Empty.GreaterThanOrEqual(Literal(200)).AndExpr(ValueExpression.Empty.LessThan(Literal(300))), new MethodBodyStatement[] + { + Return(ClientResultSnippet.FromValue(typeof(bool), True, response)) + }), + new SwitchCaseStatement(ValueExpression.Empty.GreaterThanOrEqual(Literal(400)).AndExpr(ValueExpression.Empty.LessThan(Literal(500))), new MethodBodyStatement[] + { + Return(ClientResultSnippet.FromValue(typeof(bool), False, response)) + }), + new SwitchCaseStatement(Array.Empty(), new MethodBodyStatement[] + { + Return(new NewInstanceExpression(ErrorResultSnippet.ErrorResultType.MakeGenericType([typeof(bool)]), [response, new NewInstanceExpression(typeof(ClientResultException), [response])])) + }) + }), + }; + } + + private MethodSignature GetProcessHeadAsBoolMessageSignature(bool isAsync) + { + var modifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Extension; + if (isAsync) + { + modifiers |= MethodSignatureModifiers.Async; + } + return new MethodSignature( + isAsync ? "ProcessHeadAsBoolMessageAsync" : "ProcessHeadAsBoolMessage", + null, + modifiers, + isAsync ? typeof(ValueTask>) : typeof(ClientResult), + null, + [_pipelineParam, _messageParam, _requestOptionsParam]); + } + + private MethodProvider BuildProcessMessage() + { + MethodSignature signature = GetProcessMessageSignature(false); + + var clientErrorNoThrow = FrameworkEnumValue(ClientErrorBehaviors.NoThrow); + return new MethodProvider(signature, new MethodBodyStatement[] + { + _pipeline.Invoke(nameof(ClientPipeline.Send), [_message]).Terminate(), + MethodBodyStatement.EmptyLine, + new IfStatement(_message.Response.IsError.And(new BinaryOperatorExpression("&", _options.Property("ErrorOptions", true), clientErrorNoThrow).NotEqual(clientErrorNoThrow))) + { + Throw(New.Instance(typeof(ClientResultException), _message.Response)) + }, + MethodBodyStatement.EmptyLine, + Declare(typeof(PipelineResponse), "response", new TernaryConditionalExpression(_message.BufferResponse, _message.Response, _message.ExtractResponse()), out var response), + Return(response) + }, this); + } + + private MethodSignature GetProcessMessageSignature(bool isAsync) + { + var modifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Extension; + if (isAsync) + { + modifiers |= MethodSignatureModifiers.Async; + } + return new MethodSignature( + isAsync ? "ProcessMessageAsync" : "ProcessMessage", + null, + modifiers, + isAsync ? typeof(ValueTask) : typeof(PipelineResponse), + null, + [_pipelineParam, _messageParam, _requestOptionsParam]); + } + + private MethodProvider BuildProcessMessageAsync() + { + MethodSignature signature = GetProcessMessageSignature(true); + + var clientErrorNoThrow = FrameworkEnumValue(ClientErrorBehaviors.NoThrow); + return new MethodProvider(signature, new MethodBodyStatement[] + { + _pipeline.Expression.Invoke(nameof(ClientPipeline.SendAsync), [_message], true).Terminate(), + MethodBodyStatement.EmptyLine, + new IfStatement(_message.Response.IsError.And(new BinaryOperatorExpression("&", _options.Property("ErrorOptions", true), clientErrorNoThrow).NotEqual(clientErrorNoThrow))) + { + Throw(new InvokeStaticMethodExpression(typeof(ClientResultException), nameof(ClientResultException.CreateAsync), [_message.Response], CallAsAsync: true)) + }, + MethodBodyStatement.EmptyLine, + Declare(typeof(PipelineResponse), "response", new TernaryConditionalExpression(_message.BufferResponse, _message.Response, _message.ExtractResponse()), out var response), + Return(response) + }, this); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs index e742878f13..8e1ec50686 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs @@ -1,14 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.ClientModel.Primitives; using System.Collections.Generic; using System.IO; +using Microsoft.Generator.CSharp.ClientModel.Snippets; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; namespace Microsoft.Generator.CSharp.ClientModel.Providers { - public sealed class ClientProvider : TypeProvider + public class ClientProvider : TypeProvider { private readonly InputClient _inputClient; @@ -20,6 +24,25 @@ public ClientProvider(InputClient inputClient) { _inputClient = inputClient; Name = inputClient.Name.ToCleanName(); + PipelineField = new FieldProvider(FieldModifiers.Private, typeof(ClientPipeline), "_pipeline"); + } + + public FieldProvider PipelineField { get; } + + protected override FieldProvider[] BuildFields() + { + return [PipelineField]; + } + + protected override MethodProvider[] BuildConstructors() + { + return + [ + new MethodProvider( + new ConstructorSignature(Type, $"{_inputClient.Description}", MethodSignatureModifiers.Public, []), + new MethodBodyStatement[] { PipelineField.Assign(ClientPipelineSnippet.Create()).Terminate() }, + this) + ]; } protected override MethodProvider[] BuildMethods() diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ErrorResultProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ErrorResultProvider.cs new file mode 100644 index 0000000000..cefb16755d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ErrorResultProvider.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.IO; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Statements; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Providers +{ + internal class ErrorResultProvider : TypeProvider + { + private class ErrorResultTemplate { } + + private CSharpType _t = typeof(ErrorResultTemplate<>).GetGenericArguments()[0]; + private FieldProvider _responseField; + private FieldProvider _exceptionField; + private VariableExpression _response; + private VariableExpression _exception; + + public ErrorResultProvider() + { + _responseField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(PipelineResponse), "_response"); + _exceptionField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(ClientResultException), "_exception"); + _response = new VariableExpression(_responseField.Type, _responseField.Declaration); + _exception = new VariableExpression(_exceptionField.Type, _exceptionField.Declaration); + } + + protected override TypeSignatureModifiers GetDeclarationModifiers() + { + return TypeSignatureModifiers.Internal; + } + + public override string Name => "ErrorResult"; + + public override string RelativeFilePath => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); + + protected override CSharpType[] BuildTypeArguments() + { + return [_t]; + } + + protected override CSharpType[] BuildImplements() + { + return [new CSharpType(typeof(ClientResult<>), _t)]; + } + + protected override FieldProvider[] BuildFields() + { + return [_responseField, _exceptionField]; + } + + protected override MethodProvider[] BuildConstructors() + { + return [BuildCtor()]; + } + + private MethodProvider BuildCtor() + { + var response = new ParameterProvider("response", FormattableStringHelpers.Empty, typeof(PipelineResponse)); + var exception = new ParameterProvider("exception", FormattableStringHelpers.Empty, typeof(ClientResultException)); + var baseInitializer = new ConstructorInitializer(true, new List { Default, response }); + var signature = new ConstructorSignature(Type, null, MethodSignatureModifiers.Public, [response, exception], Initializer: baseInitializer); + return new MethodProvider(signature, new MethodBodyStatement[] + { + _response.Assign(response).Terminate(), + _exception.Assign(exception).Terminate(), + }, this); + } + + protected override PropertyProvider[] BuildProperties() + { + return [BuildValue()]; + } + + private PropertyProvider BuildValue() + { + return new PropertyProvider(null, MethodSignatureModifiers.Public | MethodSignatureModifiers.Override, _t, "Value", new ExpressionPropertyBody( + ThrowExpression(_exception) + )); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs index 63cb122f6d..d2b94bcb8a 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs @@ -206,7 +206,7 @@ private MethodProvider BuildGetBytesFromBase64() { Return(Null) }, - EmptyLineStatement, + MethodBodyStatement.EmptyLine, Return(new SwitchExpression(format, new SwitchCaseExpression(Literal("U"), FromBase64UrlString(GetRequiredString(element))), new SwitchCaseExpression(Literal("D"), element.GetBytesFromBase64()), diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs index 770b371ccf..f141116349 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs @@ -350,7 +350,7 @@ private MethodBodyStatement CallBaseJsonModelWriteCore() // base.() return _shouldOverrideMethods ? Base.Invoke(JsonModelWriteCoreMethodName, [_utf8JsonWriterParameter, _serializationOptionsParameter]).Terminate() - : EmptyStatement; + : MethodBodyStatement.Empty; } private MethodBodyStatement GetPropertyInitializers(IReadOnlyList parameters) @@ -601,7 +601,7 @@ private MethodBodyStatement CreateDictionarySerializationStatement( { _utf8JsonWriterSnippet.WritePropertyName(keyValuePair.Key), TypeRequiresNullCheckInSerialization(keyValuePair.ValueType) ? - new IfStatement(keyValuePair.Value.Equal(Null)) { _utf8JsonWriterSnippet.WriteNullValue(), Continue }: EmptyStatement, + new IfStatement(keyValuePair.Value.Equal(Null)) { _utf8JsonWriterSnippet.WriteNullValue(), Continue }: MethodBodyStatement.Empty, CreateSerializationStatement(keyValuePair.ValueType, keyValuePair.Value, serializationFormat) }, _utf8JsonWriterSnippet.WriteEndObject() @@ -618,7 +618,7 @@ private MethodBodyStatement CreateListSerializationStatement( new ForeachStatement("item", array, out VariableExpression item) { TypeRequiresNullCheckInSerialization(item.Type) ? - new IfStatement(item.Equal(Null)) { _utf8JsonWriterSnippet.WriteNullValue(), Continue } : EmptyStatement, + new IfStatement(item.Equal(Null)) { _utf8JsonWriterSnippet.WriteNullValue(), Continue } : MethodBodyStatement.Empty, CreateSerializationStatement(item.Type, item, serializationFormat) }, _utf8JsonWriterSnippet.WriteEndArray() @@ -763,7 +763,7 @@ private MethodBodyStatement CreateWriteAdditionalRawDataStatement() { if (_rawDataField == null) { - return EmptyStatement; + return MethodBodyStatement.Empty; } var rawDataMemberExp = new MemberExpression(null, _rawDataField.Name); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ScmMethodProviderCollection.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ScmMethodProviderCollection.cs index 059fd29fcc..6bd4310559 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ScmMethodProviderCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ScmMethodProviderCollection.cs @@ -1,23 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ClientModel; +using System.ClientModel.Primitives; using System.Collections.Generic; -using Microsoft.Generator.CSharp.Expressions; using System.Linq; using System.Threading.Tasks; +using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Providers; using Microsoft.Generator.CSharp.Statements; using static Microsoft.Generator.CSharp.Snippets.Snippet; -using Microsoft.Generator.CSharp.Snippets; namespace Microsoft.Generator.CSharp.ClientModel.Providers { internal class ScmMethodProviderCollection : MethodProviderCollection { + private string _cleanOperationName; + private string _createRequestMethodName; + public ScmMethodProviderCollection(InputOperation operation, TypeProvider enclosingType) : base(operation, enclosingType) { + _cleanOperationName = operation.Name.ToCleanName(); + _createRequestMethodName = "Create" + _cleanOperationName + "Request"; } protected override IReadOnlyList BuildMethods() @@ -25,19 +32,41 @@ protected override IReadOnlyList BuildMethods() return [ // TO-DO: Add Protocol and Convenience methods https://github.com/Azure/autorest.csharp/issues/4585, https://github.com/Azure/autorest.csharp/issues/4586 - BuildCreateMessageMethod(_operation, _enclosingType), - BuildProtocolMethod(_operation, _enclosingType, false), - BuildProtocolMethod(_operation, _enclosingType, true) + BuildCreateMessageMethod(), + BuildProtocolMethod(false), + BuildProtocolMethod(true) ]; } - private static MethodProvider BuildProtocolMethod(InputOperation operation, TypeProvider enclosingType, bool isAsync) + + private List? _methodParameters; + private List MethodParameters => _methodParameters ??= GetMethodParameters(_operation); + + private static List GetMethodParameters(InputOperation operation) { List methodParameters = new(); foreach (InputParameter inputParam in operation.Parameters) { if (inputParam.Kind != InputOperationParameterKind.Method) continue; - methodParameters.Add(ClientModelPlugin.Instance.TypeFactory.CreateCSharpParam(inputParam)); + if (inputParam.Location == RequestLocation.Body) + { + // TODO: add concrete body with https://github.com/Azure/autorest.csharp/issues/4586 + methodParameters.Add(ScmKnownParameters.BinaryContent); + } + else + { + methodParameters.Add(ClientModelPlugin.Instance.TypeFactory.CreateCSharpParam(inputParam)); + } + } + return methodParameters; + } + + private MethodProvider BuildProtocolMethod(bool isAsync) + { + ClientProvider? client = _enclosingType as ClientProvider; + if (client is null) + { + throw new InvalidOperationException("Protocol methods can only be built for client types."); } var methodModifier = MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual; @@ -45,52 +74,61 @@ private static MethodProvider BuildProtocolMethod(InputOperation operation, Type { methodModifier |= MethodSignatureModifiers.Async; } - var opName = operation.Name.ToCleanName(); var methodSignature = new MethodSignature( - isAsync ? opName + "Async" : opName, - FormattableStringHelpers.FromString(operation.Description), + isAsync ? _cleanOperationName + "Async" : _cleanOperationName, + FormattableStringHelpers.FromString(_operation.Description), methodModifier, - GetResponseType(operation.Responses, isAsync), - null, - Parameters: [.. methodParameters, KnownParameters.CancellationTokenParameter]); + GetResponseType(_operation.Responses, false, isAsync), + $"The response returned from the service.", + Parameters: [.. MethodParameters, ScmKnownParameters.RequestOptions]); + var processMessageName = isAsync ? "ProcessMessageAsync" : "ProcessMessage"; MethodBodyStatement[] methodBody = [ - //UsingDeclare("message", typeof(RequestMess) - //using PipelineMessage message = CreateSayHiRequest(headParameter, queryParameter, optionalQuery, options); - isAsync ? new InvokeStaticPropertyExpression(typeof(Task), nameof(Task.CompletedTask), true).Terminate() : EmptyStatement + UsingDeclare("message", typeof(PipelineMessage), This.Invoke(_createRequestMethodName, [.. MethodParameters, ScmKnownParameters.RequestOptions]), out var message), + Return(new InvokeStaticMethodExpression( + typeof(ClientResult), + nameof(ClientResult.FromResponse), + client.PipelineField.Invoke(processMessageName, [message, ScmKnownParameters.RequestOptions], isAsync, true))), ]; - return new MethodProvider(methodSignature, methodBody, enclosingType); + var protocolMethod = new MethodProvider(methodSignature, methodBody, _enclosingType); + protocolMethod.XmlDocs!.Exceptions.Add(new(typeof(ClientResultException), "Service returned a non-success status code.", [])); + List listItems = new List(); + listItems.Add(new XmlDocStatement("item", [], new XmlDocStatement("description", [$"This protocol method allows explicit creation of the request and processing of the response for advanced scenarios."]))); + XmlDocStatement listXmlDoc = new XmlDocStatement("", "", [], innerStatements: [.. listItems]); + protocolMethod.XmlDocs.Summary = new XmlDocSummaryStatement([$"[Protocol Method] {_operation.Description}"], listXmlDoc); + return protocolMethod; } - private static CSharpType? GetResponseType(IReadOnlyList responses, bool isAsync) + private static CSharpType? GetResponseType(IReadOnlyList responses, bool isConvenience, bool isAsync) + { + var returnType = isConvenience ? GetConvenienceReturnType(responses) : typeof(ClientResult); + return isAsync ? new CSharpType(typeof(Task<>), returnType) : returnType; + } + + private static CSharpType GetConvenienceReturnType(IReadOnlyList responses) { var response = responses.FirstOrDefault(r => !r.IsErrorResponse); - if (response is null || response.BodyType is null) - return null; - var returnType = ClientModelPlugin.Instance.TypeFactory.CreateCSharpType(response.BodyType); - if (isAsync) - { - returnType = returnType.WrapInTask(); - } - return returnType; + return response is null || response.BodyType is null + ? typeof(ClientResult) + : new CSharpType(typeof(ClientResult<>), ClientModelPlugin.Instance.TypeFactory.CreateCSharpType(response.BodyType)); } - private static MethodProvider BuildCreateMessageMethod(InputOperation operation, TypeProvider enclosingType) + private MethodProvider BuildCreateMessageMethod() { // TO-DO: properly build method https://github.com/Azure/autorest.csharp/issues/4583 - List methodParameters = new(); - foreach (var inputParam in operation.Parameters) - { - methodParameters.Add(ClientModelPlugin.Instance.TypeFactory.CreateCSharpParam(inputParam)); - } var methodModifier = MethodSignatureModifiers.Internal; - var methodSignatureName = $"Create{operation.Name.ToCleanName()}Request"; - var methodSignature = new MethodSignature(methodSignatureName, FormattableStringHelpers.FromString(operation.Description), methodModifier, null, null, Parameters: methodParameters); + var methodSignature = new MethodSignature( + _createRequestMethodName, + FormattableStringHelpers.FromString(_operation.Description), + methodModifier, + typeof(PipelineMessage), + null, + Parameters: [.. MethodParameters, ScmKnownParameters.RequestOptions]); var methodBody = Throw(New.NotImplementedException(Literal("Method not implemented."))); - return new MethodProvider(methodSignature, methodBody, enclosingType); + return new MethodProvider(methodSignature, methodBody, _enclosingType); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs index 1757392197..2ca0acdd82 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs @@ -170,9 +170,9 @@ private MethodProvider BuildToBase64UrlStringMethodProvider() body.Add(new MethodBodyStatement[] { Declare(outputVar, New.Array(typeof(char), size)), - EmptyLineStatement, + MethodBodyStatement.EmptyLine, Declare("numBase64Chars", new IntSnippet(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.ToBase64CharArray), [value, Int(0), valueLength, output, Int(0)])), out var numBase64Chars), - EmptyLineStatement, + MethodBodyStatement.EmptyLine, Declare("i", Int(0), out var i), new ForStatement(null, i.LessThan(numBase64Chars), new UnaryOperatorExpression("++", i, true)) { @@ -188,7 +188,7 @@ private MethodProvider BuildToBase64UrlStringMethodProvider() Break })) }, - EmptyLineStatement, + MethodBodyStatement.EmptyLine, Return(New.Instance(typeof(string), output, Int(0), i)) }); @@ -234,12 +234,12 @@ private MethodProvider BuildFromBase64UrlString() output[i].Assign(Literal('/')).Terminate() }, output[i].Assign(ch).Terminate())) }, - EmptyLineStatement, + MethodBodyStatement.EmptyLine, new ForStatement(null, i.LessThan(outputLength), new UnaryOperatorExpression("++", i, true)) { output[i].Assign(Literal('=')).Terminate() }, - EmptyLineStatement, + MethodBodyStatement.EmptyLine, Return(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.FromBase64CharArray), new[] { output, Int(0), outputLength })) }); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ClientPipelineSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ClientPipelineSnippet.cs new file mode 100644 index 0000000000..8a732c062c --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ClientPipelineSnippet.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Collections.Generic; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Snippets; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Snippets +{ + internal sealed record ClientPipelineSnippet(ValueExpression Expression) : TypedSnippet(Expression) + { + private const string _processMessageAsync = "ProcessMessageAsync"; + private const string _processMessage = "ProcessMessage"; + private const string _processHeadAsBoolMessageAsync = "ProcessHeadAsBoolMessageAsync"; + private const string _processHeadAsBoolMessage = "ProcessHeadAsBoolMessage"; + + public PipelineMessageSnippet CreateMessage(RequestOptionsSnippet requestOptions, ValueExpression responseClassifier) + => new(Expression.Invoke(nameof(ClientPipeline.CreateMessage), requestOptions, responseClassifier)); + + public PipelineResponseSnippet ProcessMessage(ValueExpression message, RequestOptionsSnippet? requestOptions, bool isAsync) + { + var arguments = new List + { + Expression, + message, + requestOptions ?? Null + }; + + return new(new InvokeStaticMethodExpression(Type, isAsync ? _processMessageAsync : _processMessage, arguments, CallAsExtension: true, CallAsAsync: isAsync)); + } + + public ClientResultSnippet ProcessHeadAsBoolMessage(ValueExpression message, RequestOptionsSnippet? requestContext, bool isAsync) + { + var arguments = new List + { + Expression, + message, + requestContext ?? Null + }; + + return new(new InvokeStaticMethodExpression(Type, isAsync ? _processHeadAsBoolMessageAsync : _processHeadAsBoolMessage, arguments, CallAsExtension: true, CallAsAsync: isAsync)); + } + + public static ClientPipelineSnippet Create() => new(InvokeStatic(nameof(ClientPipeline.Create))); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ErrorResultSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ErrorResultSnippet.cs new file mode 100644 index 0000000000..8762b8e547 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ErrorResultSnippet.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Snippets; + +namespace Microsoft.Generator.CSharp.ClientModel.Snippets +{ + internal sealed record ErrorResultSnippet(ValueExpression Expression) : TypedSnippet(Expression) + { + private static readonly ErrorResultProvider _errorResultProvider = new(); + + public static CSharpType ErrorResultType => _errorResultProvider.Type; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineMessageSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineMessageSnippet.cs index 1248767257..48b02bdc7c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineMessageSnippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineMessageSnippet.cs @@ -14,5 +14,7 @@ internal sealed record PipelineMessageSnippet(ValueExpression Expression) : Type public PipelineResponseSnippet Response => new(Property(nameof(PipelineMessage.Response))); public BoolSnippet BufferResponse => new(Property(nameof(PipelineMessage.BufferResponse))); + + public PipelineResponseSnippet ExtractResponse() => new(Invoke(nameof(PipelineMessage.ExtractResponse), [])); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineResponseSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineResponseSnippet.cs index 5639f15953..9710a1520e 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineResponseSnippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/PipelineResponseSnippet.cs @@ -12,5 +12,7 @@ internal sealed record PipelineResponseSnippet(ValueExpression Expression) : Typ public BinaryDataSnippet Content => new(Property(nameof(PipelineResponse.Content))); public StreamSnippet ContentStream => new(Property(nameof(PipelineResponse.ContentStream))); + + public BoolSnippet IsError => new(Property(nameof(PipelineResponse.IsError))); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockClientTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockClientTypeProvider.cs new file mode 100644 index 0000000000..908a644a22 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockClientTypeProvider.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Input; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests +{ + internal class MockClientTypeProvider : ClientProvider + { + public MockClientTypeProvider() : base(new InputClient("TestClient", "TestClient description", [], true, [], null)) + { + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockTypeFactory.cs index 84a6e9374b..ae440182b3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Mocks/MockTypeFactory.cs @@ -27,10 +27,6 @@ protected override CSharpType CreateCSharpTypeCore(InputType input) public override CSharpType MatchConditionsType() => typeof(int); - public override CSharpType PageResponseType() => typeof(int); - - public override CSharpType RequestConditionsType() => typeof(int); - public override CSharpType TokenCredentialType() => typeof(int); public override CSharpType ListInitializationType => new CSharpType(typeof(List<>), arguments: typeof(int)); public override CSharpType DictionaryInitializationType => new CSharpType(typeof(Dictionary<,>), arguments: [typeof(string), typeof(int)]); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs index 584d64e737..22347da2da 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs @@ -34,14 +34,5 @@ public void TestMatchConditionsParameter() Assert.IsNotNull(result.Type); Assert.IsTrue(result.Type.Equals(new CSharpType(typeof(int)))); } - - [TestCase] - public void TestRequestConditionsParameter() - { - var result = ScmKnownParameters.RequestConditionsParameter; - Assert.IsNotNull(result); - Assert.IsNotNull(result.Type); - Assert.IsTrue(result.Type.Equals(new CSharpType(typeof(int)))); - } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs index d535ec641d..9cc1fbfa46 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs @@ -52,7 +52,7 @@ public void Teardown() [TestCaseSource(nameof(DefaultCSharpMethodCollectionTestCases))] public void TestDefaultCSharpMethodCollection(InputOperation inputOperation) { - var methodCollection = new ScmMethodProviderCollection(inputOperation, new MockTypeProvider()); + var methodCollection = new ScmMethodProviderCollection(inputOperation, new MockClientTypeProvider()); Assert.IsNotNull(methodCollection); Assert.AreEqual(3, methodCollection.Count); @@ -63,7 +63,7 @@ public void TestDefaultCSharpMethodCollection(InputOperation inputOperation) var parameters = signature.Parameters; Assert.IsNotNull(parameters); - Assert.AreEqual(inputOperation.Parameters.Count, parameters.Count); + Assert.AreEqual(inputOperation.Parameters.Count + 1, parameters.Count); } public static IEnumerable DefaultCSharpMethodCollectionTestCases diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/perf/MethodProviderBenchmark.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/perf/MethodProviderBenchmark.cs index a5cc25b37e..5a9bec0e1d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/perf/MethodProviderBenchmark.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/perf/MethodProviderBenchmark.cs @@ -111,7 +111,7 @@ private MethodBodyStatement GetStatementsWithHash(MethodBodyStatement bodyStatem index++; } } - statements[index] = EmptyLineStatement; + statements[index] = MethodBodyStatement.EmptyLine; index++; statements[index] = bodyStatements; @@ -132,7 +132,7 @@ private MethodBodyStatement GetStatementsAsSingleList(MethodBodyStatement origin } } if (wroteValidation) - statements.Add(EmptyLineStatement); + statements.Add(MethodBodyStatement.EmptyLine); statements.Add(original); return statements; @@ -150,7 +150,7 @@ private IEnumerable GetValidationStatementsWithYield() } } if (wroteValidation) - yield return EmptyLineStatement; + yield return MethodBodyStatement.EmptyLine; } private IReadOnlyList GetValidationStatements() @@ -166,7 +166,7 @@ private IReadOnlyList GetValidationStatements() } } if (wroteValidation) - statements.Add(EmptyLineStatement); + statements.Add(MethodBodyStatement.EmptyLine); return statements; } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/BinaryOperatorExpression.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/BinaryOperatorExpression.cs index 4fa063d56f..25f9794cd1 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/BinaryOperatorExpression.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/BinaryOperatorExpression.cs @@ -9,7 +9,9 @@ internal override void Write(CodeWriter writer) { writer.AppendRaw("("); Left.Write(writer); - writer.AppendRaw(" ").AppendRaw(Operator).AppendRaw(" "); + writer.AppendRawIf(" ", !ReferenceEquals(Left, Empty)); + writer.AppendRaw(Operator); + writer.AppendRawIf(" ", !ReferenceEquals(Right, Empty)); Right.Write(writer); writer.AppendRaw(")"); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/ValueExpression.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/ValueExpression.cs index ee6888a477..623ae7c8d3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/ValueExpression.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Expressions/ValueExpression.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Linq; using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; namespace Microsoft.Generator.CSharp.Expressions { @@ -16,6 +15,10 @@ namespace Microsoft.Generator.CSharp.Expressions [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] public record ValueExpression { + public static readonly ValueExpression Empty = new(); + + protected ValueExpression() { } + internal virtual void Write(CodeWriter writer) { } public static implicit operator ValueExpression(Type type) => new TypeReferenceExpression(type); @@ -61,6 +64,7 @@ public InvokeInstanceMethodExpression Invoke(string methodName, IReadOnlyList new CastExpression(this, to); public BoolSnippet GreaterThan(ValueExpression other) => new(new BinaryOperatorExpression(">", this, other)); + public BoolSnippet GreaterThanOrEqual(ValueExpression other) => new(new BinaryOperatorExpression(">=", this, other)); public BoolSnippet LessThan(ValueExpression other) => new(new BinaryOperatorExpression("<", this, other)); @@ -70,7 +74,9 @@ public InvokeInstanceMethodExpression Invoke(string methodName, IReadOnlyList new(new BinaryOperatorExpression("is", this, other)); - public ValueExpression Increment() => new UnaryOperatorExpression("++", this, true); + public ValueExpression Increment() => new UnaryOperatorExpression("++", this, true); + + public ValueExpression AndExpr(ValueExpression other) => new BinaryOperatorExpression("and", this, other); private string GetDebuggerDisplay() { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs index d61a0e3cd2..dc26cf1fab 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs @@ -609,15 +609,5 @@ public CSharpType MakeGenericType(IReadOnlyList arguments) return new CSharpType(Implementation, arguments, IsNullable); } } - - public CSharpType WrapInTask() - { - if (IsFrameworkType && FrameworkType == typeof(Task<>)) - { - return this; - } - - return new CSharpType(typeof(Task<>), this); - } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/ExpressionPropertyBody.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/ExpressionPropertyBody.cs index d39d03778c..4800bb71bb 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/ExpressionPropertyBody.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/ExpressionPropertyBody.cs @@ -5,5 +5,5 @@ namespace Microsoft.Generator.CSharp { - internal record ExpressionPropertyBody(ValueExpression Getter) : PropertyBody(false); + public record ExpressionPropertyBody(ValueExpression Getter) : PropertyBody(false); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs index 365af0ae1c..334e969782 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs @@ -78,7 +78,7 @@ protected override MethodProvider[] BuildConstructors() return [ - new MethodProvider(new ConstructorSignature(Type, null, MethodSignatureModifiers.Public, Array.Empty()), EmptyStatement, this), + new MethodProvider(new ConstructorSignature(Type, null, MethodSignatureModifiers.Public, Array.Empty()), MethodBodyStatement.Empty, this), new MethodProvider(iListSignature, iListBody, this), new MethodProvider(iReadOnlyListSignature, iReadOnlyListBody, this) ]; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs index b53284c650..ea071eeca7 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs @@ -106,7 +106,7 @@ private MethodBodyStatement GetBodyStatementWithValidation(MethodBodyStatement b index++; } } - statements[index] = EmptyLineStatement; + statements[index] = MethodBodyStatement.EmptyLine; index++; statements[index] = bodyStatements; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.cs index c9a8c7daa2..bcfb4b56a1 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.cs @@ -12,17 +12,6 @@ namespace Microsoft.Generator.CSharp.Snippets { public static partial class Snippet { - private class PrivateEmptyLineStatement : MethodBodyStatement - { - internal override void Write(CodeWriter writer) - { - writer.WriteLine(); - } - } - - public static readonly MethodBodyStatement EmptyStatement = new(); - public static readonly MethodBodyStatement EmptyLineStatement = new PrivateEmptyLineStatement(); - public static ValueExpression Identifier(string name) => new MemberExpression(null, name); public static MethodBodyStatement AsStatement(this IEnumerable statements) => statements.ToArray(); @@ -97,5 +86,8 @@ public static InvokeInstanceMethodExpression Invoke(this ParameterProvider param public static ValueExpression Property(this ParameterProvider parameter, string propertyName, bool nullConditional = false) => new MemberExpression(nullConditional ? new NullConditionalExpression(parameter) : parameter, propertyName); + + public static ValueExpression Invoke(this FieldProvider field, string methodName, IEnumerable parameters, bool isAsync, bool configureAwait) + => new InvokeInstanceMethodExpression(field, methodName, [.. parameters], null, isAsync, configureAwait); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/MethodBodyStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/MethodBodyStatement.cs index 40e4ea4af1..341d50aab3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/MethodBodyStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/MethodBodyStatement.cs @@ -13,6 +13,17 @@ internal virtual void Write(CodeWriter writer) { } public static implicit operator MethodBodyStatement(MethodBodyStatement[] statements) => new MethodBodyStatements(statements); public static implicit operator MethodBodyStatement(List statements) => new MethodBodyStatements(statements); + private class PrivateEmptyLineStatement : MethodBodyStatement + { + internal override void Write(CodeWriter writer) + { + writer.WriteLine(); + } + } + + public static readonly MethodBodyStatement Empty = new(); + public static readonly MethodBodyStatement EmptyLine = new PrivateEmptyLineStatement(); + private string GetDebuggerDisplay() { using CodeWriter writer = new CodeWriter(); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocExceptionStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocExceptionStatement.cs index 5131babee0..3de7f9e457 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocExceptionStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocExceptionStatement.cs @@ -22,6 +22,13 @@ public XmlDocExceptionStatement(ParameterValidationType validationType, IReadOnl _reason = GetText(validationType); } + public XmlDocExceptionStatement(Type exceptionType, string reason, IReadOnlyList parameters) + { + ExceptionType = exceptionType; + Parameters = parameters; + _reason = reason; + } + private static Type GetExceptionType(ParameterValidationType validationType) => validationType switch { ParameterValidationType.AssertNotNull => typeof(ArgumentNullException), @@ -42,13 +49,16 @@ internal override void Write(CodeWriter writer) writer.Append($"/// "); - writer.Append($" "); - for (int i = 1; i < Parameters.Count - 1; i++) + if (Parameters.Count > 0) { - writer.Append($", "); + writer.Append($" "); + for (int i = 1; i < Parameters.Count - 1; i++) + { + writer.Append($", "); + } + if (Parameters.Count > 1) + writer.Append($" or "); } - if (Parameters.Count > 1) - writer.Append($" or "); writer.WriteLine($" {_reason} "); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ArgumentSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ArgumentSnippet.cs index b0f99274d0..5e60410983 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ArgumentSnippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ArgumentSnippet.cs @@ -35,7 +35,7 @@ public static MethodBodyStatement AssertNotNullOrWhiteSpace(ValueExpression vari { ParameterValidationType.AssertNotNullOrEmpty => AssertNotNullOrEmpty(parameter), ParameterValidationType.AssertNotNull => AssertNotNull(parameter), - _ => Snippet.EmptyStatement + _ => MethodBodyStatement.Empty }; } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/TypedSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/TypedSnippet.cs index 41e8509925..4bdc85833b 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/TypedSnippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/TypedSnippet.cs @@ -46,6 +46,8 @@ protected static ValueExpression ValidateType(TypedSnippet typed, CSharpType typ public InvokeInstanceMethodExpression Invoke(string methodName, params ValueExpression[] args) => new InvokeInstanceMethodExpression(this, methodName, [..args], null, false); + public ValueExpression AndExpr(ValueExpression other) => new BinaryOperatorExpression("and", this, other); + private string GetDebuggerDisplay() { using CodeWriter writer = new CodeWriter(); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Expressions/KnownValueExpressionsTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Expressions/KnownValueExpressionsTests.cs index ce3a596b04..42af7ae3d4 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Expressions/KnownValueExpressionsTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Expressions/KnownValueExpressionsTests.cs @@ -3,10 +3,8 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; using NUnit.Framework; namespace Microsoft.Generator.CSharp.Tests.Expressions @@ -16,29 +14,29 @@ public class KnownValueExpressionsTests [Test] public void BinaryOperatorExpressionWithOrOperator() { - var left = new ValueExpression(); - var right = new ValueExpression(); + var left = ValueExpression.Empty; + var right = ValueExpression.Empty; var boolExpression = new BoolSnippet(left); var result = boolExpression.Or(right); using var writer = new CodeWriter(); result.Expression.Write(writer); - Assert.AreEqual("( || )", writer.ToString(false)); + Assert.AreEqual("(||)", writer.ToString(false)); } [Test] public void BinaryOperatorExpressionWithAndOperator() { - var left = new ValueExpression(); - var right = new ValueExpression(); + var left = ValueExpression.Empty; + var right = ValueExpression.Empty; var boolExpression = new BoolSnippet(left); var result = boolExpression.And(right); using var writer = new CodeWriter(); result.Expression.Write(writer); - Assert.AreEqual("( && )", writer.ToString(false)); + Assert.AreEqual("(&&)", writer.ToString(false)); } [TestCase(typeof(int))] @@ -57,7 +55,7 @@ public void BinaryOperatorExpressionWithAndOperator() public void ListExpression(Type T) { var itemType = new CSharpType(T); - var untypedValue = new ValueExpression(); + var untypedValue = ValueExpression.Empty; var listExpression = new ListSnippet(itemType, untypedValue); @@ -71,8 +69,8 @@ public void ListExpression(Type T) [Test] public void ListExpressionAddItem() { - var item = new ValueExpression(); - var listExpression = new ListSnippet(new CSharpType(typeof(int)), new ValueExpression()); + var item = ValueExpression.Empty; + var listExpression = new ListSnippet(new CSharpType(typeof(int)), ValueExpression.Empty); var result = listExpression.Add(item); @@ -100,7 +98,7 @@ public void DictionaryExpression(Type t1, Type t2) { var keyType = new CSharpType(t1); var valueType = new CSharpType(t2); - var untypedValue = new ValueExpression(); + var untypedValue = ValueExpression.Empty; var dictionaryExpression = new DictionarySnippet(t1, t2, untypedValue); @@ -114,10 +112,10 @@ public void DictionaryExpressionAddItems() { var keyType = new CSharpType(typeof(int)); var valueType = new CSharpType(typeof(string)); - var dictionaryExpression = new DictionarySnippet(keyType, valueType, new ValueExpression()); + var dictionaryExpression = new DictionarySnippet(keyType, valueType, ValueExpression.Empty); - var key = new ValueExpression(); - var value = new ValueExpression(); + var key = ValueExpression.Empty; + var value = ValueExpression.Empty; var result = dictionaryExpression.Add(key, value); var expectedStatement = dictionaryExpression.Invoke(nameof(Dictionary.Add), key, value).Terminate(); @@ -144,7 +142,7 @@ public void KeyValuePairExpression(Type t1, Type t2) { var keyType = new CSharpType(t1); var valueType = new CSharpType(t2); - var untypedValue = new ValueExpression(); + var untypedValue = ValueExpression.Empty; var keyValuePairExpression = new KeyValuePairSnippet(keyType, valueType, untypedValue); var expectedKey = new MemberExpression(keyValuePairExpression, nameof(KeyValuePair.Key)); @@ -160,7 +158,7 @@ public void KeyValuePairExpression(Type t1, Type t2) public void EnumerableExpressionWithAnyMethodCall() { var itemType = new CSharpType(typeof(int)); - var untypedValue = new ValueExpression(); + var untypedValue = ValueExpression.Empty; var enumerableExpression = new EnumerableSnippet(itemType, untypedValue); var result = enumerableExpression.Any(); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj index 63b357c922..d67c20e28d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj @@ -2,7 +2,10 @@ - + + + + diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs index c9bcf68d65..d57f44d90b 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs @@ -31,9 +31,9 @@ public void Setup() [Test] public void CreateForStatement() { - var assignment = new AssignmentExpression(new DeclarationExpression(new CSharpType(typeof(BinaryData)), "responseParamName"), new ValueExpression()); + var assignment = new AssignmentExpression(new DeclarationExpression(new CSharpType(typeof(BinaryData)), "responseParamName"), ValueExpression.Empty); var condition = True; - var increment = new ValueExpression(); + var increment = ValueExpression.Empty; var forStatement = new ForStatement(assignment, condition, increment); Assert.NotNull(forStatement); @@ -43,9 +43,9 @@ public void CreateForStatement() [Test] public void ForStatementWithAddMethod() { - var assignment = new AssignmentExpression(new DeclarationExpression(new CSharpType(typeof(BinaryData)), "responseParamName"), new ValueExpression()); + var assignment = new AssignmentExpression(new DeclarationExpression(new CSharpType(typeof(BinaryData)), "responseParamName"), ValueExpression.Empty); var condition = True; - var increment = new ValueExpression(); + var increment = ValueExpression.Empty; var forStatement = new ForStatement(assignment, condition, increment); var statementToAdd = new MethodBodyStatement(); @@ -61,7 +61,7 @@ public void CreateForeachStatement() { var itemType = new CSharpType(typeof(int)); var itemName = "item"; - var enumerable = new ValueExpression(); + var enumerable = ValueExpression.Empty; var foreachStatement = new ForeachStatement(itemType, itemName, enumerable, isAsync: false, out var itemReference); @@ -78,7 +78,7 @@ public void CreateForeachStatement() [Test] public void ForeachStatementWithAddMethod() { - var foreachStatement = new ForeachStatement(new CSharpType(typeof(int)), "item", new ValueExpression(), isAsync: false, out var itemReference); + var foreachStatement = new ForeachStatement(new CSharpType(typeof(int)), "item", ValueExpression.Empty, isAsync: false, out var itemReference); var statementToAdd = new MethodBodyStatement(); foreachStatement.Add(statementToAdd); @@ -173,11 +173,11 @@ public void IfElseStatementWithConditionAndStatements() [Test] public void SwitchStatementWithSingleCase() { - var matchExpression = new ValueExpression(); + var matchExpression = ValueExpression.Empty; var switchStatement = new SwitchStatement(matchExpression); var caseStatement = new MethodBodyStatement(); - var switchCase = new SwitchCaseStatement(new ValueExpression(), caseStatement); + var switchCase = new SwitchCaseStatement(ValueExpression.Empty, caseStatement); switchStatement.Add(switchCase); @@ -188,13 +188,13 @@ public void SwitchStatementWithSingleCase() [Test] public void SwitchStatementWithMultipleCases() { - var matchExpression = new ValueExpression(); + var matchExpression = ValueExpression.Empty; var switchStatement = new SwitchStatement(matchExpression); var caseStatements = new List { - new SwitchCaseStatement(new ValueExpression(), new MethodBodyStatement()), - new SwitchCaseStatement(new ValueExpression(), new MethodBodyStatement()) + new SwitchCaseStatement(ValueExpression.Empty, new MethodBodyStatement()), + new SwitchCaseStatement(ValueExpression.Empty, new MethodBodyStatement()) }; foreach (var switchCase in caseStatements) @@ -208,13 +208,13 @@ public void SwitchStatementWithMultipleCases() [Test] public void SwitchStatementEnumeratingCases() { - var matchExpression = new ValueExpression(); + var matchExpression = ValueExpression.Empty; var switchStatement = new SwitchStatement(matchExpression); var caseStatements = new List { - new SwitchCaseStatement(new ValueExpression(), new MethodBodyStatement()), - new SwitchCaseStatement(new ValueExpression(), new MethodBodyStatement()) + new SwitchCaseStatement(ValueExpression.Empty, new MethodBodyStatement()), + new SwitchCaseStatement(ValueExpression.Empty, new MethodBodyStatement()) }; foreach (var switchCase in caseStatements) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ClientPipelineExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ClientPipelineExtensions.cs new file mode 100644 index 0000000000..6ed3aa6f71 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ClientPipelineExtensions.cs @@ -0,0 +1,67 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading.Tasks; + +namespace UnbrandedTypeSpec +{ + internal static partial class ClientPipelineExtensions + { + public static async ValueTask ProcessMessageAsync(this ClientPipeline pipeline, PipelineMessage message, RequestOptions options) + { + await pipeline.SendAsync(message).ConfigureAwait(false); + + if (message.Response.IsError && (options?.ErrorOptions & ClientErrorBehaviors.NoThrow) != ClientErrorBehaviors.NoThrow) + { + throw await ClientResultException.CreateAsync(message.Response).ConfigureAwait(false); + } + + PipelineResponse response = message.BufferResponse ? message.Response : message.ExtractResponse(); + return response; + } + + public static PipelineResponse ProcessMessage(this ClientPipeline pipeline, PipelineMessage message, RequestOptions options) + { + pipeline.Send(message); + + if (message.Response.IsError && (options?.ErrorOptions & ClientErrorBehaviors.NoThrow) != ClientErrorBehaviors.NoThrow) + { + throw new ClientResultException(message.Response); + } + + PipelineResponse response = message.BufferResponse ? message.Response : message.ExtractResponse(); + return response; + } + + public static async ValueTask> ProcessHeadAsBoolMessageAsync(this ClientPipeline pipeline, PipelineMessage message, RequestOptions options) + { + PipelineResponse response = await pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + switch (response.Status) + { + case >= 200 and < 300: + return ClientResult.FromValue(true, response); + case >= 400 and < 500: + return ClientResult.FromValue(false, response); + default: + return new ErrorResult(response, new ClientResultException(response)); + } + } + + public static ClientResult ProcessHeadAsBoolMessage(this ClientPipeline pipeline, PipelineMessage message, RequestOptions options) + { + PipelineResponse response = pipeline.ProcessMessage(message, options); + switch (response.Status) + { + case >= 200 and < 300: + return ClientResult.FromValue(true, response); + case >= 400 and < 500: + return ClientResult.FromValue(false, response); + default: + return new ErrorResult(response, new ClientResultException(response)); + } + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ErrorResult.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ErrorResult.cs new file mode 100644 index 0000000000..a79e6b98e1 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ErrorResult.cs @@ -0,0 +1,24 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace UnbrandedTypeSpec +{ + internal partial class ErrorResult : ClientResult + { + private readonly PipelineResponse _response; + private readonly ClientResultException _exception; + + public ErrorResult(PipelineResponse response, ClientResultException exception): base(default, response) + { + _response = response; + _exception = exception; + } + + /// Gets the value. + public override T Value => throw _exception; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs index e35c2608f5..eabb4bacb6 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs @@ -3,449 +3,795 @@ #nullable disable using System; -using System.Threading; +using System.ClientModel; +using System.ClientModel.Primitives; using System.Threading.Tasks; -using UnbrandedTypeSpec.Models; namespace UnbrandedTypeSpec { /// public partial class UnbrandedTypeSpecClient { - internal void CreateSayHiRequest(Uri unbrandedTypeSpecUrl, string headParameter, string queryParameter, string optionalQuery, string accept) + private ClientPipeline _pipeline; + + /// This is a sample typespec project. + public UnbrandedTypeSpecClient() + { + _pipeline = ClientPipeline.Create(); + } + + internal PipelineMessage CreateSayHiRequest(string headParameter, string queryParameter, string optionalQuery, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Return hi. + /// + /// [Protocol Method] Return hi + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. - public virtual void SayHi(string headParameter, string queryParameter, string optionalQuery, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult SayHi(string headParameter, string queryParameter, string optionalQuery, RequestOptions options) { Argument.AssertNotNull(headParameter, nameof(headParameter)); Argument.AssertNotNull(queryParameter, nameof(queryParameter)); + using PipelineMessage message = CreateSayHiRequest(headParameter, queryParameter, optionalQuery, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// Return hi. + /// + /// [Protocol Method] Return hi + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. - public virtual async void SayHiAsync(string headParameter, string queryParameter, string optionalQuery, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task SayHiAsync(string headParameter, string queryParameter, string optionalQuery, RequestOptions options) { Argument.AssertNotNull(headParameter, nameof(headParameter)); Argument.AssertNotNull(queryParameter, nameof(queryParameter)); - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateSayHiRequest(headParameter, queryParameter, optionalQuery, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateHelloAgainRequest(Uri unbrandedTypeSpecUrl, string p1, string contentType, string p2, RoundTripModel action, string accept) + internal PipelineMessage CreateHelloAgainRequest(string p1, string p2, BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Return hi again. + /// + /// [Protocol Method] Return hi again + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// - /// - /// The cancellation token to use. - /// , or is null. - public virtual void HelloAgain(string p1, string p2, RoundTripModel action, CancellationToken cancellationToken = default) + /// 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 ClientResult HelloAgain(string p1, string p2, BinaryContent content, RequestOptions options) { Argument.AssertNotNull(p1, nameof(p1)); Argument.AssertNotNull(p2, nameof(p2)); - Argument.AssertNotNull(action, nameof(action)); + using PipelineMessage message = CreateHelloAgainRequest(p1, p2, content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// Return hi again. + /// + /// [Protocol Method] Return hi again + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// - /// - /// The cancellation token to use. - /// , or is null. - public virtual async void HelloAgainAsync(string p1, string p2, RoundTripModel action, CancellationToken cancellationToken = default) + /// 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 HelloAgainAsync(string p1, string p2, BinaryContent content, RequestOptions options) { Argument.AssertNotNull(p1, nameof(p1)); Argument.AssertNotNull(p2, nameof(p2)); - Argument.AssertNotNull(action, nameof(action)); - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateHelloAgainRequest(p1, p2, content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateNoContentTypeRequest(Uri unbrandedTypeSpecUrl, string p1, string p2, RoundTripModel action, string accept, string contentType) + internal PipelineMessage CreateNoContentTypeRequest(string p1, string p2, BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Return hi again. + /// + /// [Protocol Method] Return hi again + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// - /// - /// The cancellation token to use. - /// , or is null. - public virtual void NoContentType(string p1, string p2, RoundTripModel action, CancellationToken cancellationToken = default) + /// 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 ClientResult NoContentType(string p1, string p2, BinaryContent content, RequestOptions options) { Argument.AssertNotNull(p1, nameof(p1)); Argument.AssertNotNull(p2, nameof(p2)); - Argument.AssertNotNull(action, nameof(action)); + using PipelineMessage message = CreateNoContentTypeRequest(p1, p2, content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// Return hi again. + /// + /// [Protocol Method] Return hi again + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// /// - /// - /// The cancellation token to use. - /// , or is null. - public virtual async void NoContentTypeAsync(string p1, string p2, RoundTripModel action, CancellationToken cancellationToken = default) + /// 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 NoContentTypeAsync(string p1, string p2, BinaryContent content, RequestOptions options) { Argument.AssertNotNull(p1, nameof(p1)); Argument.AssertNotNull(p2, nameof(p2)); - Argument.AssertNotNull(action, nameof(action)); - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateNoContentTypeRequest(p1, p2, content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateHelloDemo2Request(Uri unbrandedTypeSpecUrl, string accept) + internal PipelineMessage CreateHelloDemo2Request(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Return hi in demo2. - /// The cancellation token to use. - public virtual void HelloDemo2(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] Return hi in demo2 + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult HelloDemo2(RequestOptions options) { + using PipelineMessage message = CreateHelloDemo2Request(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// Return hi in demo2. - /// The cancellation token to use. - public virtual async void HelloDemo2Async(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] Return hi in demo2 + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task HelloDemo2Async(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateHelloDemo2Request(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateCreateLiteralRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal PipelineMessage CreateCreateLiteralRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Create with literal value. - /// - /// The cancellation token to use. - /// is null. - public virtual void CreateLiteral(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - } - - /// Create with literal value. - /// - /// The cancellation token to use. - /// is null. - public virtual async void CreateLiteralAsync(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateHelloLiteralRequest(Uri unbrandedTypeSpecUrl, string p1, int p2, bool p3, string accept) + /// + /// [Protocol Method] Create with literal value + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult CreateLiteral(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateCreateLiteralRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Create with literal value + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task CreateLiteralAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateCreateLiteralRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateHelloLiteralRequest(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Send literal parameters. - /// The cancellation token to use. - public virtual void HelloLiteral(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] Send literal parameters + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult HelloLiteral(RequestOptions options) { + using PipelineMessage message = CreateHelloLiteralRequest(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// Send literal parameters. - /// The cancellation token to use. - public virtual async void HelloLiteralAsync(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] Send literal parameters + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task HelloLiteralAsync(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateHelloLiteralRequest(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateTopActionRequest(Uri unbrandedTypeSpecUrl, DateTimeOffset action, string accept) + internal PipelineMessage CreateTopActionRequest(DateTimeOffset action, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// top level method. + /// + /// [Protocol Method] top level method + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. - public virtual void TopAction(DateTimeOffset action, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult TopAction(DateTimeOffset action, RequestOptions options) { Argument.AssertNotNull(action, nameof(action)); + using PipelineMessage message = CreateTopActionRequest(action, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// top level method. + /// + /// [Protocol Method] top level method + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. - public virtual async void TopActionAsync(DateTimeOffset action, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task TopActionAsync(DateTimeOffset action, RequestOptions options) { Argument.AssertNotNull(action, nameof(action)); - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateTopActionRequest(action, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateTopAction2Request(Uri unbrandedTypeSpecUrl, string accept) + internal PipelineMessage CreateTopAction2Request(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// top level method2. - /// The cancellation token to use. - public virtual void TopAction2(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] top level method2 + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult TopAction2(RequestOptions options) { + using PipelineMessage message = CreateTopAction2Request(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// top level method2. - /// The cancellation token to use. - public virtual async void TopAction2Async(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] top level method2 + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task TopAction2Async(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateTopAction2Request(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreatePatchActionRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal PipelineMessage CreatePatchActionRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// top level patch. - /// - /// The cancellation token to use. - /// is null. - public virtual void PatchAction(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - } - - /// top level patch. - /// - /// The cancellation token to use. - /// is null. - public virtual async void PatchActionAsync(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateAnonymousBodyRequest(Uri unbrandedTypeSpecUrl, Thing Thing, string accept, string contentType) + /// + /// [Protocol Method] top level patch + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult PatchAction(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreatePatchActionRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] top level patch + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task PatchActionAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreatePatchActionRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateAnonymousBodyRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// body parameter without body decorator. - /// A model with a few properties of literal types. - /// The cancellation token to use. - /// is null. - public virtual void AnonymousBody(Thing Thing, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(Thing, nameof(Thing)); - - } - - /// body parameter without body decorator. - /// A model with a few properties of literal types. - /// The cancellation token to use. - /// is null. - public virtual async void AnonymousBodyAsync(Thing Thing, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(Thing, nameof(Thing)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateFriendlyModelRequest(Uri unbrandedTypeSpecUrl, Friend Friend, string accept, string contentType) + /// + /// [Protocol Method] body parameter without body decorator + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult AnonymousBody(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateAnonymousBodyRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] body parameter without body decorator + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task AnonymousBodyAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateAnonymousBodyRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateFriendlyModelRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Model can have its friendly name. - /// this is not a friendly model but with a friendly name. - /// The cancellation token to use. - /// is null. - public virtual void FriendlyModel(Friend Friend, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(Friend, nameof(Friend)); - - } - - /// Model can have its friendly name. - /// this is not a friendly model but with a friendly name. - /// The cancellation token to use. - /// is null. - public virtual async void FriendlyModelAsync(Friend Friend, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(Friend, nameof(Friend)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateAddTimeHeaderRequest(Uri unbrandedTypeSpecUrl, DateTimeOffset repeatabilityFirstSent, string accept) + /// + /// [Protocol Method] Model can have its friendly name + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult FriendlyModel(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateFriendlyModelRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Model can have its friendly name + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task FriendlyModelAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateFriendlyModelRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateAddTimeHeaderRequest(DateTimeOffset repeatabilityFirstSent, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// addTimeHeader. + /// + /// [Protocol Method] addTimeHeader + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. - public virtual void AddTimeHeader(DateTimeOffset repeatabilityFirstSent, CancellationToken cancellationToken = default) - { - } - - /// addTimeHeader. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult AddTimeHeader(DateTimeOffset repeatabilityFirstSent, RequestOptions options) + { + using PipelineMessage message = CreateAddTimeHeaderRequest(repeatabilityFirstSent, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] addTimeHeader + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. - public virtual async void AddTimeHeaderAsync(DateTimeOffset repeatabilityFirstSent, CancellationToken cancellationToken = default) + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task AddTimeHeaderAsync(DateTimeOffset repeatabilityFirstSent, RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateAddTimeHeaderRequest(repeatabilityFirstSent, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateProjectedNameModelRequest(Uri unbrandedTypeSpecUrl, ProjectedModel ProjectedModel, string accept, string contentType) + internal PipelineMessage CreateProjectedNameModelRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// Model can have its projected name. - /// this is a model with a projected name. - /// The cancellation token to use. - /// is null. - public virtual void ProjectedNameModel(ProjectedModel ProjectedModel, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(ProjectedModel, nameof(ProjectedModel)); - - } - - /// Model can have its projected name. - /// this is a model with a projected name. - /// The cancellation token to use. - /// is null. - public virtual async void ProjectedNameModelAsync(ProjectedModel ProjectedModel, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(ProjectedModel, nameof(ProjectedModel)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateReturnsAnonymousModelRequest(Uri unbrandedTypeSpecUrl, string accept) + /// + /// [Protocol Method] Model can have its projected name + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult ProjectedNameModel(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateProjectedNameModelRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Model can have its projected name + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task ProjectedNameModelAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateProjectedNameModelRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateReturnsAnonymousModelRequest(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// return anonymous model. - /// The cancellation token to use. - public virtual void ReturnsAnonymousModel(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] return anonymous model + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult ReturnsAnonymousModel(RequestOptions options) { + using PipelineMessage message = CreateReturnsAnonymousModelRequest(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// return anonymous model. - /// The cancellation token to use. - public virtual async void ReturnsAnonymousModelAsync(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] return anonymous model + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task ReturnsAnonymousModelAsync(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateReturnsAnonymousModelRequest(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateGetUnknownValueRequest(Uri unbrandedTypeSpecUrl, string accept) + internal PipelineMessage CreateGetUnknownValueRequest(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// get extensible enum. - /// The cancellation token to use. - public virtual void GetUnknownValue(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] get extensible enum + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetUnknownValue(RequestOptions options) { + using PipelineMessage message = CreateGetUnknownValueRequest(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// get extensible enum. - /// The cancellation token to use. - public virtual async void GetUnknownValueAsync(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] get extensible enum + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetUnknownValueAsync(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateGetUnknownValueRequest(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateInternalProtocolRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal PipelineMessage CreateInternalProtocolRequest(BinaryContent content, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// When set protocol false and convenient true, then the protocol method should be internal. - /// - /// The cancellation token to use. - /// is null. - public virtual void InternalProtocol(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - } - - /// When set protocol false and convenient true, then the protocol method should be internal. - /// - /// The cancellation token to use. - /// is null. - public virtual async void InternalProtocolAsync(Thing body, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(body, nameof(body)); - - await Task.CompletedTask.ConfigureAwait(false); - } - - internal void CreateStillConvenientRequest(Uri unbrandedTypeSpecUrl, string accept) + /// + /// [Protocol Method] When set protocol false and convenient true, then the protocol method should be internal + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult InternalProtocol(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateInternalProtocolRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] When set protocol false and convenient true, then the protocol method should be internal + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// 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. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task InternalProtocolAsync(BinaryContent content, RequestOptions options) + { + using PipelineMessage message = CreateInternalProtocolRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + internal PipelineMessage CreateStillConvenientRequest(RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one. - /// The cancellation token to use. - public virtual void StillConvenient(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult StillConvenient(RequestOptions options) { + using PipelineMessage message = CreateStillConvenientRequest(options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one. - /// The cancellation token to use. - public virtual async void StillConvenientAsync(CancellationToken cancellationToken = default) + /// + /// [Protocol Method] When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task StillConvenientAsync(RequestOptions options) { - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateStillConvenientRequest(options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal void CreateHeadAsBooleanRequest(Uri unbrandedTypeSpecUrl, string id, string accept) + internal PipelineMessage CreateHeadAsBooleanRequest(string id, RequestOptions options) { throw new NotImplementedException("Method not implemented."); } - /// head as boolean. + /// + /// [Protocol Method] head as boolean. + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. - public virtual void HeadAsBoolean(string id, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult HeadAsBoolean(string id, RequestOptions options) { Argument.AssertNotNull(id, nameof(id)); + using PipelineMessage message = CreateHeadAsBooleanRequest(id, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - /// head as boolean. + /// + /// [Protocol Method] head as boolean. + /// + /// + /// This protocol method</see> allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// /// - /// The cancellation token to use. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. - public virtual async void HeadAsBooleanAsync(string id, CancellationToken cancellationToken = default) + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task HeadAsBooleanAsync(string id, RequestOptions options) { Argument.AssertNotNull(id, nameof(id)); - await Task.CompletedTask.ConfigureAwait(false); + using PipelineMessage message = CreateHeadAsBooleanRequest(id, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } } }