Two clients using shared `ClientOptions` class results in duplicate 2-param constructors on each client
See original GitHub issueThe DPG-generated clients have 2 sets of constructors like so:
public partial class ConversationAnalysisAuthoringClient
{
private const string AuthorizationHeader = "Ocp-Apim-Subscription-Key";
private readonly AzureKeyCredential _keyCredential;
private const string AuthorizationHeader0 = "Ocp-Apim-Subscription-Key";
private readonly AzureKeyCredential _keyCredential0;
private readonly HttpPipeline _pipeline;
private readonly Uri _endpoint;
private readonly string _apiVersion;
/// <summary> The ClientDiagnostics is used to provide tracing support for the client library. </summary>
internal ClientDiagnostics ClientDiagnostics { get; }
/// <summary> The HTTP pipeline for sending and receiving REST requests and responses. </summary>
public virtual HttpPipeline Pipeline => _pipeline;
/// <summary> Initializes a new instance of ConversationAnalysisAuthoringClient for mocking. </summary>
protected ConversationAnalysisAuthoringClient()
{
}
/// <summary> Initializes a new instance of ConversationAnalysisAuthoringClient. </summary>
/// <param name="endpoint"> Supported Cognitive Services endpoint (e.g., https://<resource-name>.api.cognitiveservices.azure.com). </param>
/// <param name="credential"> A credential used to authenticate to an Azure Service. </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> or <paramref name="credential"/> is null. </exception>
public ConversationAnalysisAuthoringClient(Uri endpoint, AzureKeyCredential credential) : this(endpoint, credential, new ConversationAnalysisClientOptions())
{
}
/// <summary> Initializes a new instance of ConversationAnalysisAuthoringClient. </summary>
/// <param name="endpoint"> Supported Cognitive Services endpoint (e.g., https://<resource-name>.api.cognitiveservices.azure.com). </param>
/// <param name="credential"> A credential used to authenticate to an Azure Service. </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> or <paramref name="credential"/> is null. </exception>
public ConversationAnalysisAuthoringClient(Uri endpoint, AzureKeyCredential credential) : this(endpoint, credential, new ConversationAnalysisClientOptions())
{
}
/// <summary> Initializes a new instance of ConversationAnalysisAuthoringClient. </summary>
/// <param name="endpoint"> Supported Cognitive Services endpoint (e.g., https://<resource-name>.api.cognitiveservices.azure.com). </param>
/// <param name="credential"> A credential used to authenticate to an Azure Service. </param>
/// <param name="options"> The options for configuring the client. </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> or <paramref name="credential"/> is null. </exception>
public ConversationAnalysisAuthoringClient(Uri endpoint, AzureKeyCredential credential, ConversationAnalysisClientOptions options)
{
Argument.AssertNotNull(endpoint, nameof(endpoint));
Argument.AssertNotNull(credential, nameof(credential));
options ??= new ConversationAnalysisClientOptions();
ClientDiagnostics = new ClientDiagnostics(options, true);
_keyCredential0 = credential;
_pipeline = HttpPipelineBuilder.Build(options, Array.Empty<HttpPipelinePolicy>(), new HttpPipelinePolicy[] { new AzureKeyCredentialPolicy(_keyCredential0, AuthorizationHeader0) }, new ResponseClassifier());
_endpoint = endpoint;
_apiVersion = options.Version;
}
/// <summary> Initializes a new instance of ConversationAnalysisAuthoringClient. </summary>
/// <param name="endpoint"> Supported Cognitive Services endpoint (e.g., https://<resource-name>.api.cognitiveservices.azure.com). </param>
/// <param name="credential"> A credential used to authenticate to an Azure Service. </param>
/// <param name="options"> The options for configuring the client. </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> or <paramref name="credential"/> is null. </exception>
public ConversationAnalysisAuthoringClient(Uri endpoint, AzureKeyCredential credential, ConversationAnalysisClientOptions options)
{
Argument.AssertNotNull(endpoint, nameof(endpoint));
Argument.AssertNotNull(credential, nameof(credential));
options ??= new ConversationAnalysisClientOptions();
ClientDiagnostics = new ClientDiagnostics(options, true);
_keyCredential0 = credential;
_pipeline = HttpPipelineBuilder.Build(options, Array.Empty<HttpPipelinePolicy>(), new HttpPipelinePolicy[] { new AzureKeyCredentialPolicy(_keyCredential0, AuthorizationHeader0) }, new ResponseClassifier());
_endpoint = endpoint;
_apiVersion = options.Version;
}
You can also see two sets of authorization headers. This happens when I have an autorest.md file like so:
# Generated code configuration
Run `dotnet build /t:GenerateCode` to generate code.
``` yaml
# The title here is used to generate the single ClientOptions class name.
title: Conversations
license-header: MICROSOFT_MIT_NO_VERSION
input-file:
- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/e7f37e4e43b1d12fd1988fda3ed39624c4b23303/specification/cognitiveservices/data-plane/Language/preview/2022-05-15-preview/analyzeconversations.json
- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/e7f37e4e43b1d12fd1988fda3ed39624c4b23303/specification/cognitiveservices/data-plane/Language/preview/2022-05-15-preview/analyzeconversations-authoring.json
data-plane: true
model-namespace: false
clear-output-folder: true
modelerfour:
lenient-model-deduplication: true
Customizations
Customizations that should eventually be added to central autorest configuration.
General customizations
Support automatically generating code for key credentials.
directive:
- from: swagger-document
where: $.securityDefinitions
transform: |
$["AzureKey"] = $["apim_key"];
delete $["apim_key"];
- from: swagger-document
where: $.security
transform: |
$ = [
{
"AzureKey": []
}
];
```
This would result in 2 separate client classes by design - a ConversationAnalysisClient
and ConversationAnalysisAuthoringClient
. Just like we shipped the Question Answering SDK, we want to use 1 ConversationAnalysisClientOptions
, so I added a class like so:
[CodeGenModel("ConversationsClientOptions")]
public partial class ConversationAnalysisClientOptions : ClientOptions
If I process these input-file
s in a batch I can probably work around this, but I imagine this wasn’t by design. I also don’t know how the DPG generator came up with ConversationsClientOptions
- this isn’t evident from either of the swaggers - but it’s not the name we want. It seems from some minimal testing that this was a big cause of the duplication error.
Issue Analytics
- State:
- Created a year ago
- Comments:17 (17 by maintainers)
Top GitHub Comments
Thanks for all the effort you put into this, @heaths! Since you are not blocked on this, I have moved the ask to DPG v1.1.
I do think it makes sense to make this easier for DPG library authors 😃
Is it correct to summarize the ask as “Enable generation of a single ClientOptions type for a library”? If so, I will update the title of this issue to reflect that.
@annelo-msft: Would you please be so kind as to triage?