Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new settings Sync/AsyncMethodFormat #4817

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Also, since you've come to this repo, we'll assume you want to use NSwag as part
- [OpenAPI Swagger Editor VS Code Extension](https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi) *(optional)* - This Visual Studio Code (VS Code) extension adds rich support for the OpenAPI Specification (OAS) (formerly known as Swagger Specification) in JSON or YAML format. The features include, for example, SwaggerUI and ReDoc preview, IntelliSense, linting, schema enforcement, code navigation, definition links, snippets, static security analysis, and more!
- If in later steps you choose to download the 3rd-Party Service's Open API Spec, this plugin makes it easy visualize

**Notes**:
**Notes**:

- You may need to specify runtime version `nswag version /runtime:Net50` to run nswag on your local machine, since the sample [nswag config](https://github.com/RicoSuter/NSwag/wiki/NSwag-Configuration-Document) we'll use specifies `runtime` as `Net50`.
- If you chose to download NSwag as a ZIP Archive, you may see dotnet version errors when trying to execute commands. If you are not able to resolve the issues, you may opt to install via Chocolatey or the MSI from the install instructions page provided above.
Expand Down Expand Up @@ -73,7 +73,7 @@ nswag run sample.nswag /runtime:Net50
"output": null,
"newLineBehavior": "Auto"
}
},
},
"codeGenerators": {
"openApiToCSharpClient": {
"generateClientClasses": true,
Expand Down Expand Up @@ -121,7 +121,7 @@ nswag run sample.nswag /runtime:Net50
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.ObjectModel.ObservableCollection",
"arrayInstanceType": "System.Collections.ObjectModel.ObservableCollection",
"arrayInstanceType": "System.Collections.ObjectModel.ObservableCollection",
"dictionaryType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.ObservableCollection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
Expand All @@ -132,6 +132,8 @@ nswag run sample.nswag /runtime:Net50
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"asyncMethodFormat": "{0}Async",
"syncMethodFormat": "{0}",
"output": "GENERATEDCODE.cs"
}
}
Expand Down
Binary file modified docs/tutorials/GenerateProxyClientWithCLI/sample.nswag
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
<NSwagServiceSchemes>$(NSwagServiceSchemes)</NSwagServiceSchemes>
<NSwagOutput>$(NSwagOutput)</NSwagOutput>
<NSwagNewLineBehavior>$(NSwagNewLineBehavior)</NSwagNewLineBehavior>
<NSwagAsyncMethodFormat>$(NSwagAsyncMethodFormat)</NSwagAsyncMethodFormat>
<NSwagSyncMethodFormat>$(NSwagSyncMethodFormat)</NSwagSyncMethodFormat>
</OpenApiReference>
<OpenApiProjectReference>
<CodeGenerator>NSwagCSharp</CodeGenerator>
Expand Down Expand Up @@ -177,6 +179,8 @@
<NSwagServiceSchemes>$(NSwagServiceSchemes)</NSwagServiceSchemes>
<NSwagOutput>$(NSwagOutput)</NSwagOutput>
<NSwagNewLineBehavior>$(NSwagNewLineBehavior)</NSwagNewLineBehavior>
<NSwagAsyncMethodFormat>$(NSwagAsyncMethodFormat)</NSwagAsyncMethodFormat>
<NSwagSyncMethodFormat>$(NSwagSyncMethodFormat)</NSwagSyncMethodFormat>
</OpenApiProjectReference>
</ItemDefinitionGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,13 @@
<CurrentOpenApiReference>
<Command Condition="'%(NSwagNewLineBehavior)' != ''">%(Command) /newLineBehavior:%(NSwagNewLineBehavior)</Command>
</CurrentOpenApiReference>

<CurrentOpenApiReference>
<Command Condition="'%(NSwagAsyncMethodFormat)' != ''">%(Command) /asyncMethodFormat:%(NSwagAsyncMethodFormat)</Command>
</CurrentOpenApiReference>
<CurrentOpenApiReference>
<Command Condition="'%(NSwagSyncMethodFormat)' != ''">%(Command) /syncMethodFormat:%(NSwagSyncMethodFormat)</Command>
</CurrentOpenApiReference>

</ItemGroup>

<Message Importance="high" Text="%0AGenerateNSwagCSharp:" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NJsonSchema.Generation;
using NJsonSchema.NewtonsoftJson.Generation;
using NSwag.Generation.WebApi;
using Xunit;
Expand Down Expand Up @@ -249,5 +249,52 @@ public async Task When_client_interface_generation_is_enabled_and_suppressed_the
Assert.DoesNotContain("public partial interface IFooClient", code);
Assert.Contains("public partial class FooClient : IFooClient", code);
}

[Fact]
public async Task When_async_method_format_specified_then_methods_use_it()
{
// Arrange
var swaggerGenerator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings
{
SchemaSettings = new NewtonsoftJsonSchemaGeneratorSettings()
});

var document = await swaggerGenerator.GenerateForControllerAsync<FooController>();
var generator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings
{
GenerateClientInterfaces = true,
AsyncMethodFormat = "{0}Asynchronous"
});

// Act
var code = generator.GenerateFile();

// Assert
Assert.Equal(4, Regex.Matches(code, @"Task<object> GetPersonAsynchronous\(").Count);
}

[Fact]
public async Task When_sync_method_format_specified_then_methods_use_it()
{
// Arrange
var swaggerGenerator = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings
{
SchemaSettings = new NewtonsoftJsonSchemaGeneratorSettings()
});

var document = await swaggerGenerator.GenerateForControllerAsync<FooController>();
var generator = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings
{
GenerateClientInterfaces = true,
GenerateSyncMethods = true,
SyncMethodFormat = "{0}Synchronous"
});

// Act
var code = generator.GenerateFile();

// Assert
Assert.Equal(2, Regex.Matches(code, @"object GetPersonSynchronous\(").Count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,11 @@ public CSharpClientGeneratorSettings()

/// <summary>Gets or sets a value indicating whether to expose the JsonSerializerSettings property (default: false).</summary>
public bool ExposeJsonSerializerSettings { get; set; }

/// <summary>Gets or sets the format for asynchronous methods (default: "{0}Async").</summary>
public string AsyncMethodFormat { get; set; } = "{0}Async";

/// <summary>Gets or sets the format for synchronous methods (default: "{0}").</summary>
public string SyncMethodFormat { get; set; } = "{0}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ public CSharpClientTemplateModel(
/// </summary>
public bool GeneratePrepareRequestAndProcessResponseAsAsyncMethods => _settings.GeneratePrepareRequestAndProcessResponseAsAsyncMethods;

/// <summary>Gets the format for asynchronous methods.</summary>
public string AsyncMethodFormat => _settings.AsyncMethodFormat;

/// <summary>Gets the format for synchronous methods.</summary>
public string SyncMethodFormat => _settings.SyncMethodFormat;

/// <summary>Gets the JSON serializer parameter code.</summary>
public string JsonSerializerParameterCode
{
Expand Down
10 changes: 5 additions & 5 deletions src/NSwag.CodeGeneration.CSharp/Templates/Client.Class.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,25 @@
{% if GenerateOptionalParameters == false -%}
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.MethodAccessModifier }} virtual {{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
{{ operation.MethodAccessModifier }} virtual {{ operation.ResultType }} {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
{
return {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None);
return {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None);
}

{% endif -%}
{% if GenerateSyncMethods -%}
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.MethodAccessModifier }} virtual {{ operation.SyncResultType }} {{ operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
{{ operation.MethodAccessModifier }} virtual {{ operation.SyncResultType }} {{ SyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
{
{% if operation.HasResult or operation.WrapResponse %}return {% endif %}System.Threading.Tasks.Task.Run(async () => await {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
{% if operation.HasResult or operation.WrapResponse %}return {% endif %}System.Threading.Tasks.Task.Run(async () => await {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
}

{% endif -%}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.MethodAccessModifier }} virtual async {{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}, {% endfor %}System.Threading.CancellationToken cancellationToken{% if GenerateOptionalParameters %} = default(System.Threading.CancellationToken){% endif %})
{{ operation.MethodAccessModifier }} virtual async {{ operation.ResultType }} {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}, {% endfor %}System.Threading.CancellationToken cancellationToken{% if GenerateOptionalParameters %} = default(System.Threading.CancellationToken){% endif %})
{
{% for parameter in operation.PathParameters -%}
{% if parameter.IsNullable == false and parameter.IsRequired -%}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ public partial interface I{{ Class }}{% if HasClientBaseInterface %} : {{ Client
{% if GenerateOptionalParameters == false -%}
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %});
{{ operation.ResultType }} {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %});

{% endif -%}
{% if GenerateSyncMethods -%}
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.SyncResultType }} {{ operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %});
{{ operation.SyncResultType }} {{ SyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %});

{%- endif %}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
{% template Client.Method.Documentation %}
{% template Client.Method.Annotations %}
{{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}, {% endfor %}System.Threading.CancellationToken cancellationToken{% if GenerateOptionalParameters %} = default(System.Threading.CancellationToken){% endif %});
{{ operation.ResultType }} {{ AsyncMethodFormat | format_string: operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}, {% endfor %}System.Threading.CancellationToken cancellationToken{% if GenerateOptionalParameters %} = default(System.Threading.CancellationToken){% endif %});

{% endfor -%}
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,22 @@ public string QueryNullValue
set { Settings.QueryNullValue = value; }
}

[Argument(Name = "AsyncMethodFormat", IsRequired = false,
Description = "Specifies the format for asynchronous methods (default: '{0}Async').")]
public string AsyncMethodFormat
{
get { return Settings.AsyncMethodFormat; }
set { Settings.AsyncMethodFormat = value; }
}

[Argument(Name = "SyncMethodFormat", IsRequired = false,
Description = "Specifies the format for synchronous methods (default: '{0}').")]
public string SyncMethodFormat
{
get { return Settings.SyncMethodFormat; }
set { Settings.SyncMethodFormat = value; }
}

public override async Task<object> RunAsync(CommandLineProcessor processor, IConsoleHost host)
{
var result = await RunAsync();
Expand Down
10 changes: 7 additions & 3 deletions src/NSwag.Sample.NET70Minimal/nswag.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@
"serviceHost": null,
"serviceSchemes": null,
"output": "GeneratedClientsCs.gen",
"newLineBehavior": "Auto"
"newLineBehavior": "Auto",
"asyncMethodFormat": "{0}Async",
"syncMethodFormat": "{0}"
},
"openApiToCSharpController": {
"controllerBaseClass": null,
Expand Down Expand Up @@ -225,7 +227,9 @@
"serviceHost": null,
"serviceSchemes": null,
"output": "GeneratedControllersCs.gen",
"newLineBehavior": "Auto"
"newLineBehavior": "Auto",
"asyncMethodFormat": "{0}Async",
"syncMethodFormat": "{0}"
}
}
}
}
10 changes: 7 additions & 3 deletions src/NSwag.Sample.NET80Minimal/nswag.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@
"serviceHost": null,
"serviceSchemes": null,
"output": "GeneratedClientsCs.gen",
"newLineBehavior": "Auto"
"newLineBehavior": "Auto",
"asyncMethodFormat": "{0}Async",
"syncMethodFormat": "{0}"
},
"openApiToCSharpController": {
"controllerBaseClass": null,
Expand Down Expand Up @@ -225,7 +227,9 @@
"serviceHost": null,
"serviceSchemes": null,
"output": "GeneratedControllersCs.gen",
"newLineBehavior": "Auto"
"newLineBehavior": "Auto",
"asyncMethodFormat": "{0}Async",
"syncMethodFormat": "{0}"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@
<TextBox Text="{Binding Command.QueryNullValue, Mode=TwoWay}"
ToolTip="QueryNullValue" Margin="0,0,0,12" />

<TextBlock Text="Format for asynchronous methods" FontWeight="Bold" Margin="0,0,0,6" />
<TextBox Text="{Binding Command.AsyncMethodFormat, Mode=TwoWay}" ToolTip="AsyncMethodFormat" Margin="0,0,0,12" />

<TextBlock Text="Format for synchronous methods" FontWeight="Bold" Margin="0,0,0,6" />
<TextBox Text="{Binding Command.SyncMethodFormat, Mode=TwoWay}" ToolTip="SyncMethodFormat" Margin="0,0,0,12" />

<GroupBox Header="Base Class and Configuration Class" Margin="0,0,0,12">
<StackPanel Margin="4,8,4,-8">
<TextBlock Text="Base Class Name (optional)" FontWeight="Bold" Margin="0,0,0,6" />
Expand Down
Loading