Skip to content

Commit 1e4f4ab

Browse files
A-Joshiwing328
authored andcommitted
[aspnetcore] Support async tasks and some code cleanups (#2629)
* Add first cutasync support and small cleanups * Add apiPackage, modePacke to use for namespaces, for library don't generate wwwroot and dont make model class partial and default to no swashbuckle, , workarodun empty string cliOption * Update docs * Don't add async for library * Fix generated program for async and task * Default models names space should be <package>.Models * Remove commented out code * Remove unnecessary code, fix a comparison and add an else fo an if statment. * Update docs
1 parent 89eb603 commit 1e4f4ab

File tree

7 files changed

+125
-38
lines changed

7 files changed

+125
-38
lines changed

docs/generators/aspnetcore.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ sidebar_label: aspnetcore
2323
|useCollection|Deserialize array types to Collection&lt;T&gt; instead of List&lt;T&gt;.| |false|
2424
|returnICollection|Return ICollection&lt;T&gt; instead of the concrete type.| |false|
2525
|useSwashbuckle|Uses the Swashbuckle.AspNetCore NuGet package for documentation.| |true|
26+
|isLibrary|Is the build a library| |false|
2627
|classModifier|Class Modifier can be empty, abstract| ||
2728
|operationModifier|Operation Modifier can be virtual, abstract or partial| |virtual|
2829
|buildTarget|Target to build an application or library| |program|
2930
|generateBody|Generates method body.| |true|
31+
|operationIsAsync|Set methods to async or sync.| |false|
32+
|operationResultTask|Set methods result to Task&lt;&gt;.| |false|
33+
|modelClassModifier|Model Class Modifier can be nothing or partial| |partial|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.samskivert.mustache.Mustache;
2121
import io.swagger.v3.oas.models.OpenAPI;
2222
import io.swagger.v3.oas.models.media.Schema;
23+
import io.swagger.v3.parser.util.SchemaTypeUtil;
2324
import org.openapitools.codegen.*;
2425
import org.openapitools.codegen.utils.URLPathUtils;
2526
import org.slf4j.Logger;
@@ -39,13 +40,17 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
3940
public static final String ASPNET_CORE_VERSION = "aspnetCoreVersion";
4041
public static final String CLASS_MODIFIER = "classModifier";
4142
public static final String OPERATION_MODIFIER = "operationModifier";
43+
public static final String OPERATION_IS_ASYNC = "operationIsAsync";
44+
public static final String OPERATION_RESULT_TASK = "operationResultTask";
4245
public static final String GENERATE_BODY = "generateBody";
4346
public static final String BUILD_TARGET = "buildTarget";
47+
public static final String MODEL_CLASS_MODIFIER = "modelClassModifier";
4448

4549
public static final String PROJECT_SDK = "projectSdk";
4650
public static final String SDK_WEB = "Microsoft.NET.Sdk.Web";
4751
public static final String SDK_LIB = "Microsoft.NET.Sdk";
4852
public static final String COMPATIBILITY_VERSION = "compatibilityVersion";
53+
public static final String IS_LIBRARY = "isLibrary";
4954

5055
private String packageGuid = "{" + randomUUID().toString().toUpperCase(Locale.ROOT) + "}";
5156

@@ -55,13 +60,18 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
5560
private boolean useSwashbuckle = true;
5661
protected int serverPort = 8080;
5762
protected String serverHost = "0.0.0.0";
58-
private CliOption aspnetCoreVersion = new CliOption(ASPNET_CORE_VERSION, "ASP.NET Core version: 2.2 (default), 2.1, 2.0 (deprecated)");
63+
protected CliOption aspnetCoreVersion = new CliOption(ASPNET_CORE_VERSION, "ASP.NET Core version: 2.2 (default), 2.1, 2.0 (deprecated)");
64+
; // default to 2.1
5965
private CliOption classModifier = new CliOption(CLASS_MODIFIER, "Class Modifier can be empty, abstract");
6066
private CliOption operationModifier = new CliOption(OPERATION_MODIFIER, "Operation Modifier can be virtual, abstract or partial");
67+
private CliOption modelClassModifier = new CliOption(MODEL_CLASS_MODIFIER, "Model Class Modifier can be nothing or partial");
6168
private boolean generateBody = true;
6269
private CliOption buildTarget = new CliOption("buildTarget", "Target to build an application or library");
6370
private String projectSdk = SDK_WEB;
6471
private String compatibilityVersion = "Version_2_1";
72+
private boolean operationIsAsync = false;
73+
private boolean operationResultTask = false;
74+
private boolean isLibrary = false;
6575

6676
public AspNetCoreServerCodegen() {
6777
super();
@@ -160,6 +170,10 @@ public AspNetCoreServerCodegen() {
160170
"Uses the Swashbuckle.AspNetCore NuGet package for documentation.",
161171
useSwashbuckle);
162172

173+
addSwitch(IS_LIBRARY,
174+
"Is the build a library",
175+
isLibrary);
176+
163177
classModifier.addEnum("", "Keep class default with no modifier");
164178
classModifier.addEnum("abstract", "Make class abstract");
165179
classModifier.setDefault("");
@@ -182,6 +196,21 @@ public AspNetCoreServerCodegen() {
182196
"Generates method body.",
183197
generateBody);
184198

199+
addSwitch(OPERATION_IS_ASYNC,
200+
"Set methods to async or sync.",
201+
operationIsAsync);
202+
203+
addSwitch(OPERATION_RESULT_TASK,
204+
"Set methods result to Task<>.",
205+
operationResultTask);
206+
207+
modelClassModifier.setType("String");
208+
modelClassModifier.addEnum("", "Keep model class default with no modifier");
209+
modelClassModifier.addEnum("partial", "Make model class partial");
210+
modelClassModifier.setDefault("partial");
211+
modelClassModifier.setOptValue(modelClassModifier.getDefault());
212+
addOption(modelClassModifier.getOpt(), modelClassModifier.getDescription(), modelClassModifier.getOptValue());
213+
185214
}
186215

187216
@Override
@@ -210,34 +239,36 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
210239
@Override
211240
public void processOpts() {
212241
super.processOpts();
213-
boolean isLibrary = false;
214242

215243
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_GUID)) {
216244
setPackageGuid((String) additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_GUID));
217245
}
218246
additionalProperties.put("packageGuid", packageGuid);
219247

220-
if (additionalProperties.containsKey(USE_SWASHBUCKLE)) {
221-
useSwashbuckle = convertPropertyToBooleanAndWriteBack(USE_SWASHBUCKLE);
222-
} else {
223-
additionalProperties.put(USE_SWASHBUCKLE, useSwashbuckle);
224-
}
225-
226248

227249
// CHeck for the modifiers etc.
228250
// The order of the checks is important.
229-
isLibrary = setBuildTarget();
251+
setBuildTarget();
230252
setClassModifier();
231253
setOperationModifier();
232-
254+
setModelClassModifier();
255+
setUseSwashbuckle();
256+
setOperationIsAsync();
233257

234258
// CHeck for class modifier if not present set the default value.
235259
additionalProperties.put(PROJECT_SDK, projectSdk);
236260

237261
additionalProperties.put("dockerTag", packageName.toLowerCase(Locale.ROOT));
238262

239-
apiPackage = packageName + ".Controllers";
240-
modelPackage = packageName + ".Models";
263+
if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
264+
apiPackage = packageName + ".Controllers";
265+
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
266+
}
267+
268+
if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
269+
modelPackage = packageName + ".Models";
270+
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
271+
}
241272

242273
String packageFolder = sourceFolder + File.separator + packageName;
243274

@@ -259,15 +290,15 @@ public void processOpts() {
259290
supportingFiles.add(new SupportingFile("Program.mustache", packageFolder, "Program.cs"));
260291
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json",
261292
packageFolder + File.separator + "Properties", "launchSettings.json"));
262-
} else {
263-
supportingFiles.add(new SupportingFile("Project.nuspec.mustache", packageFolder, packageName + ".nuspec"));
264293
// wwwroot files.
265294
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
266295
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
267296
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "web.config", packageFolder + File.separator + "wwwroot", "web.config"));
268297

269298
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "openapi-original.mustache",
270299
packageFolder + File.separator + "wwwroot", "openapi-original.json"));
300+
} else {
301+
supportingFiles.add(new SupportingFile("Project.nuspec.mustache", packageFolder, packageName + ".nuspec"));
271302
}
272303

273304

@@ -342,15 +373,23 @@ public String getNullableType(Schema p, String type) {
342373

343374
private void setCliOption(CliOption cliOption) throws IllegalArgumentException {
344375
if (additionalProperties.containsKey(cliOption.getOpt())) {
345-
cliOption.setOptValue(additionalProperties.get(cliOption.getOpt()).toString());
346-
if (cliOption.getOptValue() == null) {
347-
cliOption.setOptValue(cliOption.getDefault());
348-
throw new IllegalArgumentException(cliOption.getOpt() + ": Invalid value '" + additionalProperties.get(cliOption.getOpt()).toString() + "'" +
349-
". " + cliOption.getDescription());
376+
// TODO Hack - not sure why the empty strings become boolean.
377+
Object obj = additionalProperties.get(cliOption.getOpt());
378+
if (!SchemaTypeUtil.BOOLEAN_TYPE.equals(cliOption.getType())) {
379+
if (obj instanceof Boolean) {
380+
obj = "";
381+
additionalProperties.put(cliOption.getOpt(), obj);
382+
}
350383
}
384+
cliOption.setOptValue(obj.toString());
351385
} else {
352386
additionalProperties.put(cliOption.getOpt(), cliOption.getOptValue());
353387
}
388+
if (cliOption.getOptValue() == null) {
389+
cliOption.setOptValue(cliOption.getDefault());
390+
throw new IllegalArgumentException(cliOption.getOpt() + ": Invalid value '" + additionalProperties.get(cliOption.getOpt()).toString() + "'" +
391+
". " + cliOption.getDescription());
392+
}
354393
}
355394

356395
private void setClassModifier() {
@@ -362,8 +401,6 @@ private void setClassModifier() {
362401
operationModifier.setOptValue(classModifier.getOptValue());
363402
additionalProperties.put(OPERATION_MODIFIER, operationModifier.getOptValue());
364403
LOGGER.warn("classModifier is " + classModifier.getOptValue() + " so forcing operatonModifier to " + operationModifier.getOptValue());
365-
} else {
366-
setCliOption(operationModifier);
367404
}
368405
}
369406

@@ -382,15 +419,28 @@ private void setOperationModifier() {
382419
}
383420
}
384421

385-
private boolean setBuildTarget() {
386-
boolean isLibrary = false;
422+
private void setModelClassModifier() {
423+
setCliOption(modelClassModifier);
424+
425+
// If operation modifier is abstract then dont generate any body
426+
if (isLibrary) {
427+
modelClassModifier.setOptValue("");
428+
additionalProperties.put(MODEL_CLASS_MODIFIER, modelClassModifier.getOptValue());
429+
LOGGER.warn("buildTarget is " + buildTarget.getOptValue() + " so removing any modelClassModifier ");
430+
}
431+
}
432+
433+
private void setBuildTarget() {
387434
setCliOption(buildTarget);
388435
if ("library".equals(buildTarget.getOptValue())) {
389436
isLibrary = true;
390437
projectSdk = SDK_LIB;
391438
additionalProperties.put(CLASS_MODIFIER, "abstract");
439+
} else {
440+
isLibrary = false;
441+
projectSdk = SDK_WEB;
392442
}
393-
return isLibrary;
443+
additionalProperties.put(IS_LIBRARY, isLibrary);
394444
}
395445

396446
private void setAspnetCoreVersion(String packageFolder) {
@@ -407,4 +457,29 @@ private void setAspnetCoreVersion(String packageFolder) {
407457
}
408458
additionalProperties.put(COMPATIBILITY_VERSION, compatibilityVersion);
409459
}
460+
461+
private void setUseSwashbuckle() {
462+
if (isLibrary) {
463+
LOGGER.warn("buildTarget is " + buildTarget.getOptValue() + " so changing default isLibrary to false ");
464+
useSwashbuckle = false;
465+
} else {
466+
useSwashbuckle = true;
467+
}
468+
if (additionalProperties.containsKey(USE_SWASHBUCKLE)) {
469+
useSwashbuckle = convertPropertyToBooleanAndWriteBack(USE_SWASHBUCKLE);
470+
} else {
471+
additionalProperties.put(USE_SWASHBUCKLE, useSwashbuckle);
472+
}
473+
}
474+
475+
private void setOperationIsAsync() {
476+
if (isLibrary) {
477+
operationIsAsync = false;
478+
additionalProperties.put(OPERATION_IS_ASYNC, operationIsAsync);
479+
} else if (additionalProperties.containsKey(OPERATION_IS_ASYNC)) {
480+
operationIsAsync = convertPropertyToBooleanAndWriteBack(OPERATION_IS_ASYNC);
481+
} else {
482+
additionalProperties.put(OPERATION_IS_ASYNC, operationIsAsync);
483+
}
484+
}
410485
}

modules/openapi-generator/src/main/resources/aspnetcore/2.1/Project.csproj.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
<TargetFramework>netcoreapp{{aspnetCoreVersion}}</TargetFramework>
66
<GenerateDocumentationFile>true</GenerateDocumentationFile>
77
<PreserveCompilationContext>true</PreserveCompilationContext>
8+
{{#isLibrary}}
9+
<OutputType>Library</OutputType>
10+
{{/isLibrary}}
811
<AssemblyName>{{packageName}}</AssemblyName>
912
<PackageId>{{packageName}}</PackageId>
1013
</PropertyGroup>

modules/openapi-generator/src/main/resources/aspnetcore/2.1/README.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ Windows:
1717
```
1818
build.bat
1919
```
20-
20+
{{^isLibrary}}
2121
## Run in Docker
2222

2323
```
2424
cd {{sourceFolder}}/{{packageName}}
2525
docker build -t {{dockerTag}} .
2626
docker run -p 5000:8080 {{dockerTag}}
2727
```
28+
{{/isLibrary}}

modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace {{packageName}}
4444
services
4545
.AddMvc()
4646
{{#compatibilityVersion}}
47-
.SetCompatibilityVersion(CompatibilityVersion.{{compatibilityVersion}})
47+
.SetCompatibilityVersion (CompatibilityVersion.{{compatibilityVersion}})
4848
{{/compatibilityVersion}}
4949
.AddJsonOptions(opts =>
5050
{
@@ -109,7 +109,7 @@ namespace {{packageName}}
109109
// c.SwaggerEndpoint("/openapi-original.json", "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}} Original");
110110
}){{/useSwashbuckle}};
111111
112-
if (env.IsDevelopment())
112+
if (env.IsDevelopment())
113113
{
114114
app.UseDeveloperExceptionPage();
115115
}

modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
{{>partial_header}}
22
using System;
3-
using System.Collections.Generic;
3+
using System.Collections.Generic;{{#operationResultTask}}
4+
using System.Threading.Tasks;
5+
{{/operationResultTask}}
46
using Microsoft.AspNetCore.Mvc;{{#useSwashbuckle}}
57
using Swashbuckle.AspNetCore.Annotations;
6-
using Swashbuckle.AspNetCore.SwaggerGen;{{/useSwashbuckle}}
7-
using Newtonsoft.Json;
8+
using Swashbuckle.AspNetCore.SwaggerGen;{{/useSwashbuckle}}{{^isLibrary}}
9+
using Newtonsoft.Json;{{/isLibrary}}
810
using System.ComponentModel.DataAnnotations;
911
using {{packageName}}.Attributes;
10-
using {{packageName}}.Models;
12+
using {{modelPackage}};
1113

12-
namespace {{packageName}}.Controllers
14+
namespace {{apiPackage}}
1315
{ {{#operations}}
1416
/// <summary>
1517
/// {{description}}
1618
/// </summary>{{#description}}
1719
[Description("{{description}}")]{{/description}}
18-
public {{classModifier}} class {{classname}}Controller : ControllerBase
20+
[ApiController]
21+
public {{#classModifier}}{{classModifier}} {{/classModifier}}class {{classname}}Controller : ControllerBase
1922
{ {{#operation}}
2023
/// <summary>
2124
/// {{#summary}}{{summary}}{{/summary}}
@@ -27,8 +30,9 @@ namespace {{packageName}}.Controllers
2730
[Route("{{{basePathWithoutHost}}}{{{path}}}")]
2831
[ValidateModelState]{{#useSwashbuckle}}
2932
[SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}}
30-
[SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}
31-
public {{operationModifier}} IActionResult {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
33+
[SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}{{^useSwashbuckle}}{{#responses}}{{#dataType}}
34+
[ProducesResponseType(statusCode: {{code}}, type: typeof({{&dataType}}))]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}
35+
public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
3236
{{#generateBody}}
3337
{ {{#responses}}
3438
{{#dataType}}
@@ -47,7 +51,7 @@ namespace {{packageName}}.Controllers
4751
{{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMapContainer}}{{>mapReturn}}{{/isMapContainer}}{{^isMapContainer}}{{>objectReturn}}{{/isMapContainer}}{{/isListCollection}}
4852
{{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}}
4953
//TODO: Change the data returned
50-
return new ObjectResult(example);{{/returnType}}{{^returnType}}
54+
return {{#operationResultTask}}Task.FromResult<IActionResult>({{/operationResultTask}}new ObjectResult(example){{#operationResultTask}}){{/operationResultTask}};{{/returnType}}{{^returnType}}
5155
throw new NotImplementedException();{{/returnType}}
5256
}
5357
{{/generateBody}}

modules/openapi-generator/src/main/resources/aspnetcore/2.1/model.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ using Newtonsoft.Json;
99

1010
{{#models}}
1111
{{#model}}
12-
namespace {{packageName}}.Models
12+
namespace {{modelPackage}}
1313
{ {{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}}
1414
/// <summary>
1515
/// {{description}}
1616
/// </summary>
1717
[DataContract]
18-
public partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}>
18+
public {{#modelClassModifier}}{{modelClassModifier}} {{/modelClassModifier}} class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}>
1919
{ {{#vars}}{{#isEnum}}{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}}{{>enumClass}}{{/items}}{{/items.isEnum}}
2020
/// <summary>
2121
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}

0 commit comments

Comments
 (0)