Update ClientPipelineApi, HttpMessageApi abstraction (#4816)

- Remove unused `ClientPipelineApi.CreateMessage`
- Add `HttpRequestOptionsApi` to `ClientPipelineApi.Send(Async)`
- Replace `HttpMessageApi.ResponseClassifier` with
`HttpMessageApi.ApplyResponseClassifier`
- Make abstraction more generic

This fix is needed for below issues of Azure plugin:
https://github.com/Azure/azure-sdk-for-net/issues/46899
https://github.com/Azure/azure-sdk-for-net/issues/46900
https://github.com/Azure/azure-sdk-for-net/issues/46901
https://github.com/Azure/azure-sdk-for-net/issues/46902
This commit is contained in:
Wei Hu 2024-10-31 12:24:33 +08:00 коммит произвёл GitHub
Родитель 9c95ccda8c
Коммит fe8f3f1bbc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
12 изменённых файлов: 102 добавлений и 54 удалений

Просмотреть файл

@ -4,7 +4,9 @@
using System;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;
using Microsoft.Generator.CSharp.Statements;
namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
@ -18,13 +20,11 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
}
public abstract HttpMessageApi CreateMessage();
public abstract ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier);
public abstract InvokeMethodExpression Send(HttpMessageApi message);
public abstract MethodBodyStatement Send(HttpMessageApi message, HttpRequestOptionsApi options);
public abstract InvokeMethodExpression SendAsync(HttpMessageApi message);
public abstract MethodBodyStatement SendAsync(HttpMessageApi message, HttpRequestOptionsApi options);
public abstract ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies);

Просмотреть файл

@ -21,9 +21,9 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
public abstract ValueExpression BufferResponse();
public abstract ValueExpression ResponseClassifier();
public abstract MethodBodyStatement ApplyResponseClassifier(StatusCodeClassifierApi statusCodeClassifier);
public abstract MethodBodyStatement Apply(ValueExpression options);
public abstract MethodBodyStatement ApplyRequestOptions(HttpRequestOptionsApi options);
public abstract MethodBodyStatement[] ExtractResponse();

Просмотреть файл

@ -6,6 +6,7 @@ using System.Collections.Generic;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Snippets;
using Microsoft.Generator.CSharp.Statements;
namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
@ -15,11 +16,11 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
}
public abstract AssignmentExpression SetMethod(string httpMethod);
public abstract MethodBodyStatement SetMethod(string httpMethod);
public abstract AssignmentExpression SetUri(ValueExpression uri);
public abstract MethodBodyStatement SetUri(ValueExpression uri);
public abstract InvokeMethodExpression SetHeaders(IReadOnlyList<ValueExpression> arguments);
public abstract MethodBodyStatement SetHeaders(IReadOnlyList<ValueExpression> arguments);
public abstract ValueExpression Content();
public abstract HttpRequestApi FromExpression(ValueExpression original);

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;
namespace Microsoft.Generator.CSharp.ClientModel.Providers
@ -33,5 +34,55 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
throw new InvalidOperationException($"Invalid type {typeof(T)}");
}
}
public static T ToApi<T>(this ParameterProvider valueExpression) where T : ScopedApi
{
switch (typeof(T).Name)
{
case nameof(ClientResponseApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.ClientResponseApi.FromExpression(valueExpression);
case nameof(HttpResponseApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpResponseApi.FromExpression(valueExpression);
case nameof(HttpRequestOptionsApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.FromExpression(valueExpression);
case nameof(HttpMessageApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpMessageApi.FromExpression(valueExpression);
case nameof(HttpRequestApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpRequestApi.FromExpression(valueExpression);
case nameof(ClientPipelineApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.FromExpression(valueExpression);
case nameof(StatusCodeClassifierApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.FromExpression(valueExpression);
case nameof(RequestContentApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.RequestContentApi.FromExpression(valueExpression);
default:
throw new InvalidOperationException($"Invalid type {typeof(T)}");
}
}
public static T ToApi<T>(this PropertyProvider valueExpression) where T : ScopedApi
{
switch (typeof(T).Name)
{
case nameof(ClientResponseApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.ClientResponseApi.FromExpression(valueExpression);
case nameof(HttpResponseApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpResponseApi.FromExpression(valueExpression);
case nameof(HttpRequestOptionsApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.FromExpression(valueExpression);
case nameof(HttpMessageApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpMessageApi.FromExpression(valueExpression);
case nameof(HttpRequestApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.HttpRequestApi.FromExpression(valueExpression);
case nameof(ClientPipelineApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.FromExpression(valueExpression);
case nameof(StatusCodeClassifierApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.FromExpression(valueExpression);
case nameof(RequestContentApi):
return (T)(object)ClientModelPlugin.Instance.TypeFactory.RequestContentApi.FromExpression(valueExpression);
default:
throw new InvalidOperationException($"Invalid type {typeof(T)}");
}
}
}
}

Просмотреть файл

@ -27,10 +27,10 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
_pipelineParam = new ParameterProvider("pipeline", FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.ClientPipelineType);
_messageParam = new ParameterProvider("message", FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.HttpMessageApi.HttpMessageType);
_requestOptionsParam = new ParameterProvider("options", FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.HttpRequestOptionsType);
_pipeline = _pipelineParam.AsExpression.ToApi<ClientPipelineApi>();
_message = _messageParam.AsExpression.ToApi<HttpMessageApi>();
_options = _requestOptionsParam.AsExpression.ToApi<HttpRequestOptionsApi>();
_requestOptionsParam = new ParameterProvider(ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.ParameterName, FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.HttpRequestOptionsType);
_pipeline = _pipelineParam.ToApi<ClientPipelineApi>();
_message = _messageParam.ToApi<HttpMessageApi>();
_options = _requestOptionsParam.ToApi<HttpRequestOptionsApi>();
}
protected override TypeSignatureModifiers GetDeclarationModifiers()
@ -124,7 +124,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
var clientErrorNoThrow = _options.NoThrow();
return new MethodProvider(signature, new MethodBodyStatement[]
{
_pipeline.Send(_message).Terminate(),
_pipeline.Send(_message, _options),
MethodBodyStatement.EmptyLine,
new IfStatement(_message.Response().IsError().And(new BinaryOperatorExpression("&", _options.NullConditional().Property("ErrorOptions"), clientErrorNoThrow).NotEqual(clientErrorNoThrow)))
{
@ -167,7 +167,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
var clientErrorNoThrow = _options.NoThrow();
return new MethodProvider(signature, new MethodBodyStatement[]
{
_pipeline.SendAsync(_message).Terminate(),
_pipeline.SendAsync(_message, _options),
MethodBodyStatement.EmptyLine,
new IfStatement(_message.Response().IsError().And(new BinaryOperatorExpression("&", _options.NullConditional().Property("ErrorOptions"), clientErrorNoThrow).NotEqual(clientErrorNoThrow)))
{

Просмотреть файл

@ -4,6 +4,7 @@
using System.ClientModel.Primitives;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Statements;
using static Microsoft.Generator.CSharp.Snippets.Snippet;
namespace Microsoft.Generator.CSharp.ClientModel.Providers
@ -26,11 +27,8 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies)
=> Static<ClientPipeline>().Invoke(nameof(ClientPipeline.Create), [options, New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType), perRetryPolicies, New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType)]).As<ClientPipeline>();
public override HttpMessageApi CreateMessage()
=> new PipelineMessageProvider(Original.Invoke(nameof(ClientPipeline.CreateMessage)));
public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier)
=> Original.Invoke(nameof(ClientPipeline.CreateMessage), requestOptions, responseClassifier).As<PipelineMessage>();
=> new PipelineMessageProvider(Original.Invoke(nameof(ClientPipeline.CreateMessage)));
public override ClientPipelineApi FromExpression(ValueExpression expression)
=> new ClientPipelineProvider(expression);
@ -38,11 +36,11 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
public override ValueExpression PerRetryPolicy(params ValueExpression[] arguments)
=> Static<ApiKeyAuthenticationPolicy>().Invoke(nameof(ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy), arguments).As<ApiKeyAuthenticationPolicy>();
public override InvokeMethodExpression Send(HttpMessageApi message)
=> Original.Invoke(nameof(ClientPipeline.Send), [message]);
public override MethodBodyStatement Send(HttpMessageApi message, HttpRequestOptionsApi options)
=> Original.Invoke(nameof(ClientPipeline.Send), [message]).Terminate();
public override InvokeMethodExpression SendAsync(HttpMessageApi message)
=> Original.Invoke(nameof(ClientPipeline.SendAsync), [message], true);
public override MethodBodyStatement SendAsync(HttpMessageApi message, HttpRequestOptionsApi options)
=> Original.Invoke(nameof(ClientPipeline.SendAsync), [message], true).Terminate();
public override ClientPipelineApi ToExpression() => this;
}

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.ClientModel.Primitives;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Statements;
@ -27,10 +28,10 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
public override HttpResponseApi Response()
=> new PipelineResponseProvider(Original.Property(nameof(PipelineMessage.Response)));
public override ValueExpression ResponseClassifier()
=> Original.Property(nameof(PipelineMessage.ResponseClassifier));
public override MethodBodyStatement ApplyResponseClassifier(StatusCodeClassifierApi statusCodeClassifier)
=> Original.Property(nameof(PipelineMessage.ResponseClassifier)).Assign(statusCodeClassifier).Terminate();
public override MethodBodyStatement Apply(ValueExpression options)
public override MethodBodyStatement ApplyRequestOptions(HttpRequestOptionsApi options)
=> Original.Invoke(nameof(PipelineMessage.Apply), options).Terminate();
public override MethodBodyStatement[] ExtractResponse()

Просмотреть файл

@ -6,6 +6,7 @@ using System.Collections.Generic;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.ClientModel.Snippets;
using static Microsoft.Generator.CSharp.Snippets.Snippet;
using Microsoft.Generator.CSharp.Statements;
namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
@ -24,14 +25,14 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
public override HttpRequestApi FromExpression(ValueExpression original)
=> new PipelineRequestProvider(original);
public override InvokeMethodExpression SetHeaders(IReadOnlyList<ValueExpression> arguments)
=> Original.Property(nameof(PipelineRequest.Headers)).Invoke(nameof(PipelineRequestHeaders.Set), arguments);
public override MethodBodyStatement SetHeaders(IReadOnlyList<ValueExpression> arguments)
=> Original.Property(nameof(PipelineRequest.Headers)).Invoke(nameof(PipelineRequestHeaders.Set), arguments).Terminate();
public override AssignmentExpression SetMethod(string httpMethod)
=> Original.Property(nameof(PipelineRequest.Method)).Assign(Literal(httpMethod));
public override MethodBodyStatement SetMethod(string httpMethod)
=> Original.Property(nameof(PipelineRequest.Method)).Assign(Literal(httpMethod)).Terminate();
public override AssignmentExpression SetUri(ValueExpression value)
=> Original.Property("Uri").Assign(value.As<ClientUriBuilderDefinition>().ToUri());
public override MethodBodyStatement SetUri(ValueExpression value)
=> Original.Property("Uri").Assign(value.As<ClientUriBuilderDefinition>().ToUri()).Terminate();
public override HttpRequestApi ToExpression() => this;
}

Просмотреть файл

@ -131,7 +131,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
private MethodProvider BuildCreateRequestMethod(InputOperation operation)
{
var pipelineField = ((MemberExpression)ClientProvider.PipelineProperty).ToApi<ClientPipelineApi>();
var pipelineField = ClientProvider.PipelineProperty.ToApi<ClientPipelineApi>();
var options = ScmKnownParameters.RequestOptions;
var signature = new MethodSignature(
@ -165,18 +165,18 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
signature,
new MethodBodyStatements(
[
Declare("message", pipelineField.CreateMessage().ToApi<HttpMessageApi>(), out HttpMessageApi message),
message.ResponseClassifier().Assign(classifier).Terminate(),
Declare("request", message.Request().ToApi<HttpRequestApi>(), out HttpRequestApi request), // ScopedApi<PipelineRequest>
request.SetMethod(operation.HttpMethod).Terminate(),
Declare("message", pipelineField.CreateMessage(options.ToApi<HttpRequestOptionsApi>(), classifier).ToApi<HttpMessageApi>(), out HttpMessageApi message),
message.ApplyResponseClassifier(classifier.ToApi<StatusCodeClassifierApi>()),
Declare("request", message.Request().ToApi<HttpRequestApi>(), out HttpRequestApi request),
request.SetMethod(operation.HttpMethod),
Declare("uri", New.Instance<ClientUriBuilderDefinition>(), out ScopedApi<ClientUriBuilderDefinition> uri),
uri.Reset(ClientProvider.EndpointField).Terminate(),
.. AppendPathParameters(uri, operation, paramMap),
.. AppendQueryParameters(uri, operation, paramMap),
request.SetUri(uri).Terminate(),
request.SetUri(uri),
.. AppendHeaderParameters(request, operation, paramMap),
.. GetSetContent(request, signature.Parameters),
message.Apply(options),
message.ApplyRequestOptions(options.ToApi<HttpRequestOptionsApi>()),
Return(message)
]),
this);
@ -231,7 +231,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
}
else
{
statement = request.SetHeaders([Literal(inputParameter.NameInRequest), toStringExpression.As<string>()]).Terminate();
statement = request.SetHeaders([Literal(inputParameter.NameInRequest), toStringExpression.As<string>()]);
}
statements.Add(statement);
}

Просмотреть файл

@ -2,6 +2,7 @@ using System.Linq;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Statements;
using Microsoft.Generator.CSharp.Tests.Common;
using NUnit.Framework;
@ -28,7 +29,6 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
Assert.NotNull(method);
Assert.NotNull(method!.BodyStatements);
var test = method?.BodyStatements?.ToDisplayString();
Assert.AreEqual(Helpers.GetExpectedFromFile(), method!.BodyStatements!.ToDisplayString());
}
@ -58,9 +58,6 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies)
=> Original.Invoke("GetFakeCreate", [options, perRetryPolicies]);
public override HttpMessageApi CreateMessage()
=> Original.Invoke("GetFakeCreateMessage").ToApi<HttpMessageApi>();
public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier)
=> Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]);
@ -70,11 +67,11 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
public override ValueExpression PerRetryPolicy(params ValueExpression[] arguments)
=> Original.Invoke("GetFakePerRetryPolicy", arguments);
public override InvokeMethodExpression Send(HttpMessageApi message)
=> Original.Invoke("GetFakeSend", message);
public override MethodBodyStatement Send(HttpMessageApi message, HttpRequestOptionsApi options)
=> Original.Invoke("GetFakeSend", [message, options]).Terminate();
public override InvokeMethodExpression SendAsync(HttpMessageApi message)
=> Original.Invoke("GetFakeSendAsync", message);
public override MethodBodyStatement SendAsync(HttpMessageApi message, HttpRequestOptionsApi options)
=> Original.Invoke("GetFakeSendAsync", [message, options]).Terminate();
public override ClientPipelineApi ToExpression() => this;
}

Просмотреть файл

@ -32,7 +32,6 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
Assert.IsNotNull(method);
Assert.IsNotNull(method!.BodyStatements);
var test = method!.BodyStatements!.ToDisplayString();
Assert.AreEqual(Helpers.GetExpectedFromFile(), method!.BodyStatements!.ToDisplayString());
}
@ -55,8 +54,8 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
public override CSharpType HttpMessageType => typeof(string);
public override MethodBodyStatement Apply(ValueExpression options)
=> Original.Invoke("GetFakeApply", [options]).Terminate();
public override MethodBodyStatement ApplyRequestOptions(HttpRequestOptionsApi options)
=> Original.Invoke("GetFakeSetRequestContext", [options]).Terminate();
public override ValueExpression BufferResponse()
=> Original.Invoke("GetFakeBufferResponse");
@ -73,8 +72,8 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Abstractions
public override HttpResponseApi Response()
=> Original.Invoke("GetFakeResponse").ToApi<HttpResponseApi>();
public override ValueExpression ResponseClassifier()
=> Original.Invoke("GetFakeResponseClassifier");
public override MethodBodyStatement ApplyResponseClassifier(StatusCodeClassifierApi statusCodeClassifier)
=> Original.Invoke("GetFakeAssignResponseClassifier", [statusCodeClassifier]).Terminate();
public override HttpMessageApi ToExpression() => this;
}

Просмотреть файл

@ -1,4 +1,4 @@
global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.GetFakeCreateMessage();
global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.GetFakeCreateMessage(options, PipelineMessageClassifier200);
message.ResponseClassifier = PipelineMessageClassifier200;
global::System.ClientModel.Primitives.PipelineRequest request = message.Request;
request.Method = "GET";