Add support for spread of aliases & models (#4199)

This PR adds support for spread of aliases & models within a client
operation's parameters.

fixes: https://github.com/microsoft/typespec/issues/3831

---------

Co-authored-by: m-nash <64171366+m-nash@users.noreply.github.com>
This commit is contained in:
Jorge Rangel 2024-08-21 18:27:56 -05:00 коммит произвёл GitHub
Родитель e8c493e015
Коммит 371d5c1adb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
12 изменённых файлов: 656 добавлений и 90 удалений

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

@ -33,7 +33,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Primitives
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)) { Validation = ParameterValidationType.AssertNotNull };
public static readonly ParameterProvider BinaryContent = new("content", $"The content to send as the body of the request.", typeof(BinaryContent), location: ParameterLocation.Body) { Validation = ParameterValidationType.AssertNotNull };
// Known header parameters
public static readonly ParameterProvider RepeatabilityRequestId = new("repeatabilityRequestId", FormattableStringHelpers.Empty, typeof(Guid))

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

@ -356,6 +356,43 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
}
}
private static IReadOnlyList<ParameterProvider> BuildSpreadParametersForModel(InputModelType inputModel)
{
var builtParameters = new ParameterProvider[inputModel.Properties.Count];
int index = 0;
foreach (var property in inputModel.Properties)
{
// convert the property to a parameter
var inputParameter = new InputParameter(
property.Name,
property.SerializedName,
property.Description,
property.Type,
RequestLocation.Body,
null,
InputOperationParameterKind.Method,
property.IsRequired,
false,
false,
false,
false,
false,
false,
null,
null);
var paramProvider = ClientModelPlugin.Instance.TypeFactory.CreateParameter(inputParameter);
paramProvider.DefaultValue = !inputParameter.IsRequired ? Default : null;
paramProvider.SpreadSource = ClientModelPlugin.Instance.TypeFactory.CreateModel(inputModel);
paramProvider.Type = paramProvider.Type.InputType;
builtParameters[index++] = paramProvider;
}
return builtParameters;
}
private static bool TryGetSpecialHeaderParam(InputParameter inputParameter, [NotNullWhen(true)] out ParameterProvider? parameterProvider)
{
if (inputParameter.Location == RequestLocation.Header)
@ -375,12 +412,22 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
internal static List<ParameterProvider> GetMethodParameters(InputOperation operation, bool isProtocol = false)
{
List<ParameterProvider> methodParameters = new();
SortedList<int, ParameterProvider> sortedParams = [];
int path = 0;
int required = 100;
int bodyRequired = 200;
int bodyOptional = 300;
int contentType = 400;
int optional = 500;
foreach (InputParameter inputParam in operation.Parameters)
{
if (inputParam.Kind != InputOperationParameterKind.Method || TryGetSpecialHeaderParam(inputParam, out var _))
if ((inputParam.Kind != InputOperationParameterKind.Method && inputParam.Kind != InputOperationParameterKind.Spread)
|| TryGetSpecialHeaderParam(inputParam, out var _))
continue;
var spreadInputModel = inputParam.Kind == InputOperationParameterKind.Spread ? GetSpreadParameterModel(inputParam) : null;
ParameterProvider? parameter = ClientModelPlugin.Instance.TypeFactory.CreateParameter(inputParam);
if (isProtocol)
@ -394,11 +441,66 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
parameter.Type = parameter.Type.IsEnum ? parameter.Type.UnderlyingEnumType : parameter.Type;
}
}
else if (spreadInputModel != null)
{
foreach (var bodyParam in BuildSpreadParametersForModel(spreadInputModel))
{
if (bodyParam.DefaultValue is null)
{
sortedParams.Add(bodyRequired++, bodyParam);
}
else
{
sortedParams.Add(bodyOptional++, bodyParam);
}
}
continue;
}
if (parameter is not null)
methodParameters.Add(parameter);
if (parameter is null)
continue;
switch (parameter.Location)
{
case ParameterLocation.Path:
case ParameterLocation.Uri:
sortedParams.Add(path++, parameter);
break;
case ParameterLocation.Query:
case ParameterLocation.Header:
if (inputParam.IsContentType)
{
sortedParams.Add(contentType++, parameter);
}
else if (parameter.Validation != ParameterValidationType.None)
{
sortedParams.Add(required++, parameter);
}
else
{
sortedParams.Add(optional++, parameter);
}
break;
case ParameterLocation.Body:
sortedParams.Add(bodyRequired++, parameter);
break;
default:
sortedParams.Add(optional++, parameter);
break;
}
}
return methodParameters;
return [.. sortedParams.Values];
}
internal static InputModelType GetSpreadParameterModel(InputParameter inputParam)
{
if (inputParam.Kind.HasFlag(InputOperationParameterKind.Spread) && inputParam.Type is InputModelType model)
{
return model;
}
throw new InvalidOperationException($"inputParam `{inputParam.Name}` is `Spread` but not a model type");
}
}
}

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

@ -64,6 +64,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
methodModifier |= MethodSignatureModifiers.Async;
}
var methodSignature = new MethodSignature(
isAsync ? _cleanOperationName + "Async" : _cleanOperationName,
FormattableStringHelpers.FromString(Operation.Description),
@ -74,12 +75,13 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
var processMessageName = isAsync ? "ProcessMessageAsync" : "ProcessMessage";
MethodBodyStatement[] methodBody;
if (responseBodyType is null)
{
methodBody =
[
.. GetStackVariablesForProtocolParamConversion(ConvenienceMethodParameters, out var paramDeclarations),
Return(This.Invoke(protocolMethod.Signature, [.. GetParamConversions(ConvenienceMethodParameters, paramDeclarations), Null], isAsync))
.. GetStackVariablesForProtocolParamConversion(ConvenienceMethodParameters, out var declarations),
Return(This.Invoke(protocolMethod.Signature, [.. GetParamConversions(ConvenienceMethodParameters, declarations), Null], isAsync))
];
}
else
@ -88,11 +90,11 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
[
.. GetStackVariablesForProtocolParamConversion(ConvenienceMethodParameters, out var paramDeclarations),
Declare("result", This.Invoke(protocolMethod.Signature, [.. GetParamConversions(ConvenienceMethodParameters, paramDeclarations), Null], isAsync).As<ClientResult>(), out ScopedApi<ClientResult> result),
.. GetStackVariablesForReturnValueConversion(result, responseBodyType, isAsync, out var declarations),
.. GetStackVariablesForReturnValueConversion(result, responseBodyType, isAsync, out var resultDeclarations),
Return(Static<ClientResult>().Invoke(
nameof(ClientResult.FromValue),
[
GetResultConversion(result, responseBodyType, declarations),
GetResultConversion(result, responseBodyType, resultDeclarations),
result.Invoke("GetRawResponse")
])),
];
@ -109,6 +111,9 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
declarations = new Dictionary<string, ValueExpression>();
foreach (var parameter in convenienceMethodParameters)
{
if (parameter.SpreadSource is not null)
continue;
if (parameter.Location == ParameterLocation.Body)
{
if (parameter.Type.IsReadOnlyMemory)
@ -136,9 +141,53 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
}
}
}
// add spread parameter model variable declaration
var spreadSource = convenienceMethodParameters.FirstOrDefault(p => p.SpreadSource is not null)?.SpreadSource;
if (spreadSource is not null)
{
statements.Add(Declare("spreadModel", New.Instance(spreadSource.Type, [.. GetSpreadConversion(spreadSource)]).As(spreadSource.Type), out var spread));
declarations["spread"] = spread;
}
return statements;
}
private List<ValueExpression> GetSpreadConversion(TypeProvider spreadSource)
{
var convenienceMethodParams = ConvenienceMethodParameters.ToDictionary(p => p.Name);
List<ValueExpression> expressions = new(spreadSource.Properties.Count);
// we should make this find more deterministic
var ctor = spreadSource.Constructors.First(c => c.Signature.Parameters.Count == spreadSource.Properties.Count + 1 &&
c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal));
foreach (var param in ctor.Signature.Parameters)
{
if (convenienceMethodParams.TryGetValue(param.Name, out var convenienceParam))
{
if (convenienceParam.Type.IsList)
{
var interfaceType = param.Property!.WireInfo?.IsReadOnly == true
? new CSharpType(typeof(IReadOnlyList<>), convenienceParam.Type.Arguments)
: new CSharpType(typeof(IList<>), convenienceParam.Type.Arguments);
expressions.Add(NullCoalescing(
new AsExpression(convenienceParam.NullConditional().ToList(), interfaceType),
New.Instance(convenienceParam.Type.PropertyInitializationType, [])));
}
else
{
expressions.Add(convenienceParam);
}
}
else
{
expressions.Add(Null);
}
}
return expressions;
}
private IEnumerable<MethodBodyStatement> GetStackVariablesForReturnValueConversion(ScopedApi<ClientResult> result, CSharpType responseBodyType, bool isAsync, out Dictionary<string, ValueExpression> declarations)
{
if (responseBodyType.IsList)
@ -216,9 +265,18 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
private IReadOnlyList<ValueExpression> GetParamConversions(IReadOnlyList<ParameterProvider> convenienceMethodParameters, Dictionary<string, ValueExpression> declarations)
{
List<ValueExpression> conversions = new List<ValueExpression>();
bool addedSpreadSource = false;
foreach (var param in convenienceMethodParameters)
{
if (param.Location == ParameterLocation.Body)
if (param.SpreadSource is not null)
{
if (!addedSpreadSource)
{
conversions.Add(declarations["spread"]);
addedSpreadSource = true;
}
}
else if (param.Location == ParameterLocation.Body)
{
if (param.Type.IsReadOnlyMemory || param.Type.IsList)
{

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

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Linq;
@ -25,6 +26,13 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName);
private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name);
private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name);
private static readonly InputModelType _spreadModel = InputFactory.Model(
"spreadModel",
usage: InputModelTypeUsage.Spread,
properties:
[
InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true),
]);
[SetUp]
public void SetUp()
@ -365,6 +373,33 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
Assert.AreEqual(Helpers.GetExpectedFromFile(), codeFile.Content);
}
[TestCaseSource(nameof(ValidateClientWithSpreadTestCases))]
public void ValidateClientWithSpread(InputClient inputClient)
{
var clientProvider = new ClientProvider(inputClient);
var methods = clientProvider.Methods;
Assert.AreEqual(4, methods.Count);
var protocolMethods = methods.Where(m => m.Signature.Parameters.Any(p => p.Type.Equals(typeof(BinaryContent)))).ToList();
Assert.AreEqual(2, protocolMethods.Count);
Assert.AreEqual(2, protocolMethods[0].Signature.Parameters.Count);
Assert.AreEqual(2, protocolMethods[1].Signature.Parameters.Count);
Assert.AreEqual(new CSharpType(typeof(BinaryContent)), protocolMethods[0].Signature.Parameters[0].Type);
Assert.AreEqual(new CSharpType(typeof(RequestOptions)), protocolMethods[0].Signature.Parameters[1].Type);
Assert.AreEqual(new CSharpType(typeof(BinaryContent)), protocolMethods[1].Signature.Parameters[0].Type);
Assert.AreEqual(new CSharpType(typeof(RequestOptions)), protocolMethods[1].Signature.Parameters[1].Type);
var convenienceMethods = methods.Where(m => m.Signature.Parameters.Any(p => p.Type.Equals(typeof(string)))).ToList();
Assert.AreEqual(2, convenienceMethods.Count);
Assert.AreEqual(1, convenienceMethods[0].Signature.Parameters.Count);
Assert.AreEqual(new CSharpType(typeof(string)), convenienceMethods[0].Signature.Parameters[0].Type);
Assert.AreEqual("p1", convenienceMethods[0].Signature.Parameters[0].Name);
}
private static InputClient GetEnumQueryParamClient()
=> InputFactory.Client(
TestClientName,
@ -386,6 +421,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
InputFactory.EnumMember.String("value1", "value1"),
InputFactory.EnumMember.String("value2", "value2")
]),
isRequired: true,
location: RequestLocation.Query)
])
]);
@ -469,6 +505,29 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
}
}
public static IEnumerable<TestCaseData> ValidateClientWithSpreadTestCases
{
get
{
yield return new TestCaseData(InputFactory.Client(
TestClientName,
operations:
[
InputFactory.Operation(
"CreateMessage",
parameters:
[
InputFactory.Parameter(
"spread",
_spreadModel,
location: RequestLocation.Body,
isRequired: true,
kind: InputOperationParameterKind.Spread),
])
]));
}
}
public static IEnumerable<TestCaseData> BuildConstructorsTestCases
{
get

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

@ -4,17 +4,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Tests.Common;
using NUnit.Framework;
using Microsoft.Generator.CSharp.Snippets;
namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
{
public class RestClientProviderTests
{
private static readonly InputModelType _spreadModel = InputFactory.Model(
"spreadModel",
usage: InputModelTypeUsage.Spread,
properties:
[
InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true),
InputFactory.Property("optionalProp", InputPrimitiveType.String, isRequired: false)
]);
public RestClientProviderTests()
{
MockHelpers.LoadMockPlugin();
@ -120,6 +131,58 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
p.Name.Equals("repeatabilityFirstSent", StringComparison.OrdinalIgnoreCase) &&
p.Name.Equals("repeatabilityRequestId", StringComparison.OrdinalIgnoreCase)));
}
var spreadInputParameter = inputOperation.Parameters.FirstOrDefault(p => p.Kind == InputOperationParameterKind.Spread);
if (spreadInputParameter != null)
{
Assert.AreEqual(_spreadModel.Properties.Count + 1, methodParameters.Count);
// validate path parameter
Assert.AreEqual(inputOperation.Parameters[1].Name, methodParameters[0].Name);
// validate spread parameters
Assert.AreEqual(_spreadModel.Properties[0].Name, methodParameters[1].Name);
Assert.IsNull(methodParameters[1].DefaultValue);
// validate optional parameter
Assert.AreEqual(_spreadModel.Properties[1].Name, methodParameters[2].Name);
Assert.AreEqual(Snippet.Default, methodParameters[2].DefaultValue);
}
}
[TestCase]
public void TestGetMethodParameters_ProperOrdering()
{
var methodParameters = RestClientProvider.GetMethodParameters(OperationWithMixedParamOrdering);
Assert.AreEqual(OperationWithMixedParamOrdering.Parameters.Count, methodParameters.Count);
// validate ordering
Assert.AreEqual("requiredPath", methodParameters[0].Name);
Assert.AreEqual("requiredQuery", methodParameters[1].Name);
Assert.AreEqual("requiredHeader", methodParameters[2].Name);
Assert.AreEqual("body", methodParameters[3].Name);
Assert.AreEqual("contentType", methodParameters[4].Name);
Assert.AreEqual("optionalQuery", methodParameters[5].Name);
Assert.AreEqual("optionalHeader", methodParameters[6].Name);
var orderedPathParams = RestClientProvider.GetMethodParameters(OperationWithOnlyPathParams);
Assert.AreEqual(OperationWithOnlyPathParams.Parameters.Count, orderedPathParams.Count);
Assert.AreEqual("c", orderedPathParams[0].Name);
Assert.AreEqual("a", orderedPathParams[1].Name);
Assert.AreEqual("b", orderedPathParams[2].Name);
}
[TestCaseSource(nameof(GetSpreadParameterModelTestCases))]
public void TestGetSpreadParameterModel(InputParameter inputParameter)
{
if (inputParameter.Kind == InputOperationParameterKind.Spread)
{
var model = RestClientProvider.GetSpreadParameterModel(inputParameter);
Assert.AreEqual(_spreadModel, model);
}
else
{
// assert throws
Assert.Throws<InvalidOperationException>(() => RestClientProvider.GetSpreadParameterModel(inputParameter));
}
}
[Test]
@ -151,6 +214,103 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true)
]);
private readonly static InputOperation OperationWithSpreadParam = InputFactory.Operation(
"CreateMessageWithSpread",
parameters:
[
InputFactory.Parameter(
"spread",
_spreadModel,
location: RequestLocation.Body,
isRequired: true,
kind: InputOperationParameterKind.Spread),
InputFactory.Parameter(
"p2",
InputPrimitiveType.Boolean,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method)
]);
private static readonly InputOperation OperationWithMixedParamOrdering = InputFactory.Operation(
"CreateMessage",
parameters:
[
// require query param
InputFactory.Parameter(
"requiredQuery",
InputPrimitiveType.String,
location: RequestLocation.Query,
isRequired: true,
kind: InputOperationParameterKind.Method),
// optional query param
InputFactory.Parameter(
"optionalQuery",
InputPrimitiveType.String,
location: RequestLocation.Query,
isRequired: false,
kind: InputOperationParameterKind.Method),
// required path param
InputFactory.Parameter(
"requiredPath",
InputPrimitiveType.String,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method),
// required header param
InputFactory.Parameter(
"requiredHeader",
InputPrimitiveType.String,
location: RequestLocation.Header,
isRequired: true,
kind: InputOperationParameterKind.Method),
// optional header param
InputFactory.Parameter(
"optionalHeader",
InputPrimitiveType.String,
location: RequestLocation.Header,
isRequired: false,
kind: InputOperationParameterKind.Method),
// content type param
InputFactory.Parameter(
"contentType",
InputPrimitiveType.String,
location: RequestLocation.Header,
isContentType: true,
kind: InputOperationParameterKind.Method),
// body param
InputFactory.Parameter(
"body",
InputPrimitiveType.String,
location: RequestLocation.Body,
isRequired: true,
kind: InputOperationParameterKind.Method)
]);
private static readonly InputOperation OperationWithOnlyPathParams = InputFactory.Operation(
"CreateMessage",
parameters:
[
InputFactory.Parameter(
"c",
InputPrimitiveType.String,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method),
InputFactory.Parameter(
"a",
InputPrimitiveType.String,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method),
InputFactory.Parameter(
"b",
InputPrimitiveType.String,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method)
]);
private readonly static InputClient SingleOpInputClient = InputFactory.Client("TestClient", operations: [BasicOperation]);
private static IEnumerable<TestCaseData> DefaultCSharpMethodCollectionTestCases =>
@ -160,7 +320,18 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders
private static IEnumerable<TestCaseData> GetMethodParametersTestCases =>
[
new TestCaseData(BasicOperation)
new TestCaseData(OperationWithSpreadParam),
new TestCaseData(BasicOperation),
new TestCaseData(OperationWithMixedParamOrdering)
];
private static IEnumerable<TestCaseData> GetSpreadParameterModelTestCases =>
[
// spread param
new TestCaseData(InputFactory.Parameter("spread", _spreadModel, location: RequestLocation.Body, kind: InputOperationParameterKind.Spread, isRequired: true)),
// non spread param
new TestCaseData(InputFactory.Parameter("p1", InputPrimitiveType.Boolean, location: RequestLocation.Path, isRequired: true, kind: InputOperationParameterKind.Method))
];
private class MockClientProvider : RestClientProvider

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

@ -2,10 +2,10 @@
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Tests.Common;
using NUnit.Framework;
@ -13,6 +13,14 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
{
internal class ScmMethodProviderCollectionTests
{
private static readonly InputModelType _spreadModel = InputFactory.Model(
"spreadModel",
usage: InputModelTypeUsage.Spread,
properties:
[
InputFactory.Property("p2", InputPrimitiveType.String, isRequired: true),
]);
// Validate that the default method collection consists of the expected method kind(s)
[TestCaseSource(nameof(DefaultCSharpMethodCollectionTestCases))]
public void TestDefaultCSharpMethodCollection(InputOperation inputOperation)
@ -20,8 +28,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
var inputClient = InputFactory.Client("TestClient", operations: [inputOperation]);
MockHelpers.LoadMockPlugin(
createCSharpTypeCore: (inputType) => new CSharpType(typeof(bool)),
createParameterCore: (inputParameter) => new ParameterProvider("mockParam", $"mock description", typeof(bool), null));
createCSharpTypeCore: (inputType) => new CSharpType(typeof(bool)));
var methodCollection = new ScmMethodProviderCollection(inputOperation, ClientModelPlugin.Instance.TypeFactory.CreateClient(inputClient));
Assert.IsNotNull(methodCollection);
@ -35,6 +42,23 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
var parameters = signature.Parameters;
Assert.IsNotNull(parameters);
Assert.AreEqual(inputOperation.Parameters.Count + 1, parameters.Count);
var convenienceMethod = methodCollection.FirstOrDefault(m
=> !m.Signature.Parameters.Any(p => p.Name == "content")
&& m.Signature.Name == $"{inputOperation.Name.ToCleanName()}");
Assert.IsNotNull(convenienceMethod);
var convenienceMethodParams = convenienceMethod!.Signature.Parameters;
Assert.IsNotNull(convenienceMethodParams);
var spreadInputParameter = inputOperation.Parameters.FirstOrDefault(p => p.Kind == InputOperationParameterKind.Spread);
if (spreadInputParameter != null)
{
var spreadModelProperties = _spreadModel.Properties;
Assert.AreEqual(spreadModelProperties.Count + 1, convenienceMethodParams.Count);
Assert.AreEqual("p1", convenienceMethodParams[0].Name);
Assert.AreEqual(spreadModelProperties[0].Name, convenienceMethodParams[1].Name);
}
}
public static IEnumerable<TestCaseData> DefaultCSharpMethodCollectionTestCases
@ -50,6 +74,25 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
InputPrimitiveType.Boolean,
isRequired: true)
]));
// Operation with spread parameter
yield return new TestCaseData(InputFactory.Operation(
"CreateMessage",
parameters:
[
InputFactory.Parameter(
"spread",
_spreadModel,
location: RequestLocation.Body,
isRequired: true,
kind: InputOperationParameterKind.Spread),
InputFactory.Parameter(
"p1",
InputPrimitiveType.Boolean,
location: RequestLocation.Path,
isRequired: true,
kind: InputOperationParameterKind.Method)
]));
}
}
}

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

@ -8,5 +8,8 @@ namespace Microsoft.Generator.CSharp.Primitives
Unknown,
Body,
Uri,
Path,
Query,
Header,
}
}

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

@ -23,7 +23,7 @@ namespace Microsoft.Generator.CSharp.Providers
/// <summary>
/// The default value of the parameter.
/// </summary>
public ValueExpression? DefaultValue { get; init; }
public ValueExpression? DefaultValue { get; set; }
public ValueExpression? InitializationValue { get; init; }
public ParameterValidationType Validation { get; init; } = ParameterValidationType.None;
public bool IsRef { get; }
@ -50,8 +50,15 @@ namespace Microsoft.Generator.CSharp.Providers
{
Name = inputParameter.Name;
Description = FormattableStringHelpers.FromString(inputParameter.Description) ?? FormattableStringHelpers.Empty;
Type = CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(inputParameter.Type) ?? throw new InvalidOperationException($"Failed to create CSharpType for {inputParameter.Type}");
Validation = inputParameter.IsRequired && !Type.IsValueType ? ParameterValidationType.AssertNotNull : ParameterValidationType.None;
var type = CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(inputParameter.Type) ?? throw new InvalidOperationException($"Failed to create CSharpType for {inputParameter.Type}");
if (!inputParameter.IsRequired && !type.IsCollection)
{
type = type.WithNullable(true);
}
Type = type;
Validation = inputParameter.IsRequired && !Type.IsValueType && !Type.IsNullable
? ParameterValidationType.AssertNotNull
: ParameterValidationType.None;
WireInfo = new WireInformation(CodeModelPlugin.Instance.TypeFactory.GetSerializationFormat(inputParameter.Type), inputParameter.NameInRequest);
Location = inputParameter.Location.ToParameterLocation();
}
@ -66,7 +73,8 @@ namespace Microsoft.Generator.CSharp.Providers
IReadOnlyList<AttributeStatement>? attributes = null,
PropertyProvider? property = null,
FieldProvider? field = null,
ValueExpression? initializationValue = null)
ValueExpression? initializationValue = null,
ParameterLocation? location = null)
{
Debug.Assert(!(property is not null && field is not null), "A parameter cannot be both a property and a field");
@ -82,6 +90,7 @@ namespace Microsoft.Generator.CSharp.Providers
Validation = GetParameterValidation();
InitializationValue = initializationValue;
WireInfo = new WireInformation(SerializationFormat.Default, name);
Location = location ?? ParameterLocation.Unknown;
}
private ParameterProvider? _inputParameter;
@ -162,6 +171,8 @@ namespace Microsoft.Generator.CSharp.Providers
private VariableExpression? _asVariable;
public VariableExpression AsExpression => _asVariable ??= this;
public TypeProvider? SpreadSource { get; set; }
private ParameterValidationType GetParameterValidation()
{
if (Field is not null && !Field.Type.IsNullable)

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

@ -13,6 +13,9 @@ namespace Microsoft.Generator.CSharp
{
RequestLocation.Body => ParameterLocation.Body,
RequestLocation.Uri => ParameterLocation.Uri,
RequestLocation.Path => ParameterLocation.Path,
RequestLocation.Query => ParameterLocation.Query,
RequestLocation.Header => ParameterLocation.Header,
_ => ParameterLocation.Unknown,
};
}

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

@ -61,7 +61,8 @@ namespace Microsoft.Generator.CSharp.Tests.Common
bool isRequired = false,
InputOperationParameterKind kind = InputOperationParameterKind.Method,
bool isEndpoint = false,
bool isResourceParameter = false)
bool isResourceParameter = false,
bool isContentType = false)
{
return new InputParameter(
name,
@ -74,7 +75,7 @@ namespace Microsoft.Generator.CSharp.Tests.Common
isRequired,
false,
isResourceParameter,
false,
isContentType,
isEndpoint,
false,
false,

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

@ -42,7 +42,7 @@ namespace UnbrandedTypeSpec
return message;
}
internal PipelineMessage CreateHelloAgainRequest(string p1, string p2, BinaryContent content, RequestOptions options)
internal PipelineMessage CreateHelloAgainRequest(string p2, string p1, BinaryContent content, RequestOptions options)
{
PipelineMessage message = Pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
@ -61,7 +61,7 @@ namespace UnbrandedTypeSpec
return message;
}
internal PipelineMessage CreateNoContentTypeRequest(string p1, string p2, BinaryContent content, RequestOptions options)
internal PipelineMessage CreateNoContentTypeRequest(string p2, string p1, BinaryContent content, RequestOptions options)
{
PipelineMessage message = Pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
@ -178,7 +178,7 @@ namespace UnbrandedTypeSpec
return message;
}
internal PipelineMessage CreateAnonymousBodyRequest(RequestOptions options)
internal PipelineMessage CreateAnonymousBodyRequest(BinaryContent content, RequestOptions options)
{
PipelineMessage message = Pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
@ -190,11 +190,12 @@ namespace UnbrandedTypeSpec
request.Uri = uri.ToUri();
request.Headers.Set("Content-Type", "application/json");
request.Headers.Set("Accept", "application/json");
request.Content = content;
message.Apply(options);
return message;
}
internal PipelineMessage CreateFriendlyModelRequest(RequestOptions options)
internal PipelineMessage CreateFriendlyModelRequest(BinaryContent content, RequestOptions options)
{
PipelineMessage message = Pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
@ -206,6 +207,7 @@ namespace UnbrandedTypeSpec
request.Uri = uri.ToUri();
request.Headers.Set("Content-Type", "application/json");
request.Headers.Set("Accept", "application/json");
request.Content = content;
message.Apply(options);
return message;
}
@ -225,7 +227,7 @@ namespace UnbrandedTypeSpec
return message;
}
internal PipelineMessage CreateProjectedNameModelRequest(RequestOptions options)
internal PipelineMessage CreateProjectedNameModelRequest(BinaryContent content, RequestOptions options)
{
PipelineMessage message = Pipeline.CreateMessage();
message.ResponseClassifier = PipelineMessageClassifier200;
@ -237,6 +239,7 @@ namespace UnbrandedTypeSpec
request.Uri = uri.ToUri();
request.Headers.Set("Content-Type", "application/json");
request.Headers.Set("Accept", "application/json");
request.Content = content;
message.Apply(options);
return message;
}

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

@ -5,6 +5,8 @@
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnbrandedTypeSpec.Models;
@ -137,20 +139,20 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult HelloAgain(string p1, string p2, BinaryContent content, RequestOptions options)
public virtual ClientResult HelloAgain(string p2, string p1, BinaryContent content, RequestOptions options)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateHelloAgainRequest(p1, p2, content, options);
using PipelineMessage message = CreateHelloAgainRequest(p2, p1, content, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}
@ -162,52 +164,52 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> HelloAgainAsync(string p1, string p2, BinaryContent content, RequestOptions options)
public virtual async Task<ClientResult> HelloAgainAsync(string p2, string p1, BinaryContent content, RequestOptions options)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateHelloAgainRequest(p1, p2, content, options);
using PipelineMessage message = CreateHelloAgainRequest(p2, p1, content, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}
/// <summary> Return hi again. </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="action"></param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual ClientResult<RoundTripModel> HelloAgain(string p1, string p2, RoundTripModel action)
public virtual ClientResult<RoundTripModel> HelloAgain(string p2, string p1, RoundTripModel action)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(action, nameof(action));
ClientResult result = HelloAgain(p1, p2, action, null);
ClientResult result = HelloAgain(p2, p1, action, null);
return ClientResult.FromValue((RoundTripModel)result, result.GetRawResponse());
}
/// <summary> Return hi again. </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="action"></param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual async Task<ClientResult<RoundTripModel>> HelloAgainAsync(string p1, string p2, RoundTripModel action)
public virtual async Task<ClientResult<RoundTripModel>> HelloAgainAsync(string p2, string p1, RoundTripModel action)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(action, nameof(action));
ClientResult result = await HelloAgainAsync(p1, p2, action, null).ConfigureAwait(false);
ClientResult result = await HelloAgainAsync(p2, p1, action, null).ConfigureAwait(false);
return ClientResult.FromValue((RoundTripModel)result, result.GetRawResponse());
}
@ -219,20 +221,20 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult NoContentType(string p1, string p2, BinaryContent content, RequestOptions options)
public virtual ClientResult NoContentType(string p2, string p1, BinaryContent content, RequestOptions options)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateNoContentTypeRequest(p1, p2, content, options);
using PipelineMessage message = CreateNoContentTypeRequest(p2, p1, content, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}
@ -244,52 +246,52 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> NoContentTypeAsync(string p1, string p2, BinaryContent content, RequestOptions options)
public virtual async Task<ClientResult> NoContentTypeAsync(string p2, string p1, BinaryContent content, RequestOptions options)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateNoContentTypeRequest(p1, p2, content, options);
using PipelineMessage message = CreateNoContentTypeRequest(p2, p1, content, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}
/// <summary> Return hi again. </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="action"></param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual ClientResult<RoundTripModel> NoContentType(string p1, string p2, RoundTripModel action)
public virtual ClientResult<RoundTripModel> NoContentType(string p2, string p1, RoundTripModel action)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(action, nameof(action));
ClientResult result = NoContentType(p1, p2, action, null);
ClientResult result = NoContentType(p2, p1, action, null);
return ClientResult.FromValue((RoundTripModel)result, result.GetRawResponse());
}
/// <summary> Return hi again. </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p1"></param>
/// <param name="action"></param>
/// <exception cref="ArgumentNullException"> <paramref name="p1"/>, <paramref name="p2"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ArgumentNullException"> <paramref name="p2"/>, <paramref name="p1"/> or <paramref name="action"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual async Task<ClientResult<RoundTripModel>> NoContentTypeAsync(string p1, string p2, RoundTripModel action)
public virtual async Task<ClientResult<RoundTripModel>> NoContentTypeAsync(string p2, string p1, RoundTripModel action)
{
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(p2, nameof(p2));
Argument.AssertNotNull(p1, nameof(p1));
Argument.AssertNotNull(action, nameof(action));
ClientResult result = await NoContentTypeAsync(p1, p2, action, null).ConfigureAwait(false);
ClientResult result = await NoContentTypeAsync(p2, p1, action, null).ConfigureAwait(false);
return ClientResult.FromValue((RoundTripModel)result, result.GetRawResponse());
}
@ -637,12 +639,16 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult AnonymousBody(RequestOptions options)
public virtual ClientResult AnonymousBody(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateAnonymousBodyRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateAnonymousBodyRequest(content, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}
@ -654,28 +660,98 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> AnonymousBodyAsync(RequestOptions options)
public virtual async Task<ClientResult> AnonymousBodyAsync(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateAnonymousBodyRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateAnonymousBodyRequest(content, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}
/// <summary> body parameter without body decorator. </summary>
/// <param name="name"> name of the Thing. </param>
/// <param name="requiredUnion"> required Union. </param>
/// <param name="requiredLiteralString"> required literal string. </param>
/// <param name="requiredLiteralInt"> required literal int. </param>
/// <param name="requiredLiteralFloat"> required literal float. </param>
/// <param name="requiredLiteralBool"> required literal bool. </param>
/// <param name="requiredBadDescription"> description with xml &lt;|endoftext|&gt;. </param>
/// <param name="requiredNullableList"> required nullable collection. </param>
/// <param name="optionalLiteralString"> optional literal string. </param>
/// <param name="optionalLiteralInt"> optional literal int. </param>
/// <param name="optionalLiteralFloat"> optional literal float. </param>
/// <param name="optionalLiteralBool"> optional literal bool. </param>
/// <param name="optionalNullableList"> optional nullable collection. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/>, <paramref name="requiredUnion"/> or <paramref name="requiredBadDescription"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual ClientResult<Thing> AnonymousBody()
public virtual ClientResult<Thing> AnonymousBody(string name, BinaryData requiredUnion, AnonymousBodyRequestRequiredLiteralString requiredLiteralString, AnonymousBodyRequestRequiredLiteralInt requiredLiteralInt, AnonymousBodyRequestRequiredLiteralFloat requiredLiteralFloat, bool requiredLiteralBool, string requiredBadDescription, IEnumerable<int> requiredNullableList, AnonymousBodyRequestOptionalLiteralString? optionalLiteralString = default, AnonymousBodyRequestOptionalLiteralInt? optionalLiteralInt = default, AnonymousBodyRequestOptionalLiteralFloat? optionalLiteralFloat = default, bool? optionalLiteralBool = default, IEnumerable<int> optionalNullableList = default)
{
ClientResult result = AnonymousBody(null);
Argument.AssertNotNull(name, nameof(name));
Argument.AssertNotNull(requiredUnion, nameof(requiredUnion));
Argument.AssertNotNull(requiredBadDescription, nameof(requiredBadDescription));
AnonymousBodyRequest spreadModel = new AnonymousBodyRequest(
name,
requiredUnion,
requiredLiteralString,
requiredLiteralInt,
requiredLiteralFloat,
requiredLiteralBool,
optionalLiteralString,
optionalLiteralInt,
optionalLiteralFloat,
optionalLiteralBool,
requiredBadDescription,
optionalNullableList?.ToList() as IList<int> ?? new ChangeTrackingList<int>(),
requiredNullableList?.ToList() as IList<int> ?? new ChangeTrackingList<int>(),
null);
ClientResult result = AnonymousBody(spreadModel, null);
return ClientResult.FromValue((Thing)result, result.GetRawResponse());
}
/// <summary> body parameter without body decorator. </summary>
/// <param name="name"> name of the Thing. </param>
/// <param name="requiredUnion"> required Union. </param>
/// <param name="requiredLiteralString"> required literal string. </param>
/// <param name="requiredLiteralInt"> required literal int. </param>
/// <param name="requiredLiteralFloat"> required literal float. </param>
/// <param name="requiredLiteralBool"> required literal bool. </param>
/// <param name="requiredBadDescription"> description with xml &lt;|endoftext|&gt;. </param>
/// <param name="requiredNullableList"> required nullable collection. </param>
/// <param name="optionalLiteralString"> optional literal string. </param>
/// <param name="optionalLiteralInt"> optional literal int. </param>
/// <param name="optionalLiteralFloat"> optional literal float. </param>
/// <param name="optionalLiteralBool"> optional literal bool. </param>
/// <param name="optionalNullableList"> optional nullable collection. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/>, <paramref name="requiredUnion"/> or <paramref name="requiredBadDescription"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual async Task<ClientResult<Thing>> AnonymousBodyAsync()
public virtual async Task<ClientResult<Thing>> AnonymousBodyAsync(string name, BinaryData requiredUnion, AnonymousBodyRequestRequiredLiteralString requiredLiteralString, AnonymousBodyRequestRequiredLiteralInt requiredLiteralInt, AnonymousBodyRequestRequiredLiteralFloat requiredLiteralFloat, bool requiredLiteralBool, string requiredBadDescription, IEnumerable<int> requiredNullableList, AnonymousBodyRequestOptionalLiteralString? optionalLiteralString = default, AnonymousBodyRequestOptionalLiteralInt? optionalLiteralInt = default, AnonymousBodyRequestOptionalLiteralFloat? optionalLiteralFloat = default, bool? optionalLiteralBool = default, IEnumerable<int> optionalNullableList = default)
{
ClientResult result = await AnonymousBodyAsync(null).ConfigureAwait(false);
Argument.AssertNotNull(name, nameof(name));
Argument.AssertNotNull(requiredUnion, nameof(requiredUnion));
Argument.AssertNotNull(requiredBadDescription, nameof(requiredBadDescription));
AnonymousBodyRequest spreadModel = new AnonymousBodyRequest(
name,
requiredUnion,
requiredLiteralString,
requiredLiteralInt,
requiredLiteralFloat,
requiredLiteralBool,
optionalLiteralString,
optionalLiteralInt,
optionalLiteralFloat,
optionalLiteralBool,
requiredBadDescription,
optionalNullableList?.ToList() as IList<int> ?? new ChangeTrackingList<int>(),
requiredNullableList?.ToList() as IList<int> ?? new ChangeTrackingList<int>(),
null);
ClientResult result = await AnonymousBodyAsync(spreadModel, null).ConfigureAwait(false);
return ClientResult.FromValue((Thing)result, result.GetRawResponse());
}
@ -687,12 +763,16 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult FriendlyModel(RequestOptions options)
public virtual ClientResult FriendlyModel(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateFriendlyModelRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateFriendlyModelRequest(content, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}
@ -704,28 +784,42 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> FriendlyModelAsync(RequestOptions options)
public virtual async Task<ClientResult> FriendlyModelAsync(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateFriendlyModelRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateFriendlyModelRequest(content, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}
/// <summary> Model can have its friendly name. </summary>
/// <param name="name"> name of the NotFriend. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual ClientResult<Friend> FriendlyModel()
public virtual ClientResult<Friend> FriendlyModel(string name)
{
ClientResult result = FriendlyModel(null);
Argument.AssertNotNull(name, nameof(name));
FriendlyModelRequest spreadModel = new FriendlyModelRequest(name, null);
ClientResult result = FriendlyModel(spreadModel, null);
return ClientResult.FromValue((Friend)result, result.GetRawResponse());
}
/// <summary> Model can have its friendly name. </summary>
/// <param name="name"> name of the NotFriend. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual async Task<ClientResult<Friend>> FriendlyModelAsync()
public virtual async Task<ClientResult<Friend>> FriendlyModelAsync(string name)
{
ClientResult result = await FriendlyModelAsync(null).ConfigureAwait(false);
Argument.AssertNotNull(name, nameof(name));
FriendlyModelRequest spreadModel = new FriendlyModelRequest(name, null);
ClientResult result = await FriendlyModelAsync(spreadModel, null).ConfigureAwait(false);
return ClientResult.FromValue((Friend)result, result.GetRawResponse());
}
@ -785,12 +879,16 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual ClientResult ProjectedNameModel(RequestOptions options)
public virtual ClientResult ProjectedNameModel(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateProjectedNameModelRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateProjectedNameModelRequest(content, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}
@ -802,28 +900,42 @@ namespace UnbrandedTypeSpec
/// </item>
/// </list>
/// </summary>
/// <param name="content"> The content to send as the body of the request. </param>
/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> ProjectedNameModelAsync(RequestOptions options)
public virtual async Task<ClientResult> ProjectedNameModelAsync(BinaryContent content, RequestOptions options)
{
using PipelineMessage message = CreateProjectedNameModelRequest(options);
Argument.AssertNotNull(content, nameof(content));
using PipelineMessage message = CreateProjectedNameModelRequest(content, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}
/// <summary> Model can have its projected name. </summary>
/// <param name="name"> name of the ModelWithProjectedName. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual ClientResult<ProjectedModel> ProjectedNameModel()
public virtual ClientResult<ProjectedModel> ProjectedNameModel(string name)
{
ClientResult result = ProjectedNameModel(null);
Argument.AssertNotNull(name, nameof(name));
ProjectedNameModelRequest spreadModel = new ProjectedNameModelRequest(name, null);
ClientResult result = ProjectedNameModel(spreadModel, null);
return ClientResult.FromValue((ProjectedModel)result, result.GetRawResponse());
}
/// <summary> Model can have its projected name. </summary>
/// <param name="name"> name of the ModelWithProjectedName. </param>
/// <exception cref="ArgumentNullException"> <paramref name="name"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
public virtual async Task<ClientResult<ProjectedModel>> ProjectedNameModelAsync()
public virtual async Task<ClientResult<ProjectedModel>> ProjectedNameModelAsync(string name)
{
ClientResult result = await ProjectedNameModelAsync(null).ConfigureAwait(false);
Argument.AssertNotNull(name, nameof(name));
ProjectedNameModelRequest spreadModel = new ProjectedNameModelRequest(name, null);
ClientResult result = await ProjectedNameModelAsync(spreadModel, null).ConfigureAwait(false);
return ClientResult.FromValue((ProjectedModel)result, result.GetRawResponse());
}