diff --git a/docs/generators/aspnetcore.md b/docs/generators/aspnetcore.md
index fdb73387f3f7..64a0b8d9a3a9 100644
--- a/docs/generators/aspnetcore.md
+++ b/docs/generators/aspnetcore.md
@@ -23,7 +23,11 @@ sidebar_label: aspnetcore
|useCollection|Deserialize array types to Collection<T> instead of List<T>.| |false|
|returnICollection|Return ICollection<T> instead of the concrete type.| |false|
|useSwashbuckle|Uses the Swashbuckle.AspNetCore NuGet package for documentation.| |true|
+|isLibrary|Is the build a library| |false|
|classModifier|Class Modifier can be empty, abstract| ||
|operationModifier|Operation Modifier can be virtual, abstract or partial| |virtual|
|buildTarget|Target to build an application or library| |program|
|generateBody|Generates method body.| |true|
+|operationIsAsync|Set methods to async or sync.| |false|
+|operationResultTask|Set methods result to Task<>.| |false|
+|modelClassModifier|Model Class Modifier can be nothing or partial| |partial|
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
index 842d7b023388..962da0f3d91b 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AspNetCoreServerCodegen.java
@@ -20,6 +20,7 @@
import com.samskivert.mustache.Mustache;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.openapitools.codegen.*;
import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger;
@@ -39,13 +40,17 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
public static final String ASPNET_CORE_VERSION = "aspnetCoreVersion";
public static final String CLASS_MODIFIER = "classModifier";
public static final String OPERATION_MODIFIER = "operationModifier";
+ public static final String OPERATION_IS_ASYNC = "operationIsAsync";
+ public static final String OPERATION_RESULT_TASK = "operationResultTask";
public static final String GENERATE_BODY = "generateBody";
public static final String BUILD_TARGET = "buildTarget";
+ public static final String MODEL_CLASS_MODIFIER = "modelClassModifier";
public static final String PROJECT_SDK = "projectSdk";
public static final String SDK_WEB = "Microsoft.NET.Sdk.Web";
public static final String SDK_LIB = "Microsoft.NET.Sdk";
public static final String COMPATIBILITY_VERSION = "compatibilityVersion";
+ public static final String IS_LIBRARY = "isLibrary";
private String packageGuid = "{" + randomUUID().toString().toUpperCase(Locale.ROOT) + "}";
@@ -55,13 +60,18 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
private boolean useSwashbuckle = true;
protected int serverPort = 8080;
protected String serverHost = "0.0.0.0";
- private CliOption aspnetCoreVersion = new CliOption(ASPNET_CORE_VERSION, "ASP.NET Core version: 2.2 (default), 2.1, 2.0 (deprecated)");
+ protected CliOption aspnetCoreVersion = new CliOption(ASPNET_CORE_VERSION, "ASP.NET Core version: 2.2 (default), 2.1, 2.0 (deprecated)");
+ ; // default to 2.1
private CliOption classModifier = new CliOption(CLASS_MODIFIER, "Class Modifier can be empty, abstract");
private CliOption operationModifier = new CliOption(OPERATION_MODIFIER, "Operation Modifier can be virtual, abstract or partial");
+ private CliOption modelClassModifier = new CliOption(MODEL_CLASS_MODIFIER, "Model Class Modifier can be nothing or partial");
private boolean generateBody = true;
private CliOption buildTarget = new CliOption("buildTarget", "Target to build an application or library");
private String projectSdk = SDK_WEB;
private String compatibilityVersion = "Version_2_1";
+ private boolean operationIsAsync = false;
+ private boolean operationResultTask = false;
+ private boolean isLibrary = false;
public AspNetCoreServerCodegen() {
super();
@@ -160,6 +170,10 @@ public AspNetCoreServerCodegen() {
"Uses the Swashbuckle.AspNetCore NuGet package for documentation.",
useSwashbuckle);
+ addSwitch(IS_LIBRARY,
+ "Is the build a library",
+ isLibrary);
+
classModifier.addEnum("", "Keep class default with no modifier");
classModifier.addEnum("abstract", "Make class abstract");
classModifier.setDefault("");
@@ -182,6 +196,21 @@ public AspNetCoreServerCodegen() {
"Generates method body.",
generateBody);
+ addSwitch(OPERATION_IS_ASYNC,
+ "Set methods to async or sync.",
+ operationIsAsync);
+
+ addSwitch(OPERATION_RESULT_TASK,
+ "Set methods result to Task<>.",
+ operationResultTask);
+
+ modelClassModifier.setType("String");
+ modelClassModifier.addEnum("", "Keep model class default with no modifier");
+ modelClassModifier.addEnum("partial", "Make model class partial");
+ modelClassModifier.setDefault("partial");
+ modelClassModifier.setOptValue(modelClassModifier.getDefault());
+ addOption(modelClassModifier.getOpt(), modelClassModifier.getDescription(), modelClassModifier.getOptValue());
+
}
@Override
@@ -210,34 +239,36 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
@Override
public void processOpts() {
super.processOpts();
- boolean isLibrary = false;
if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_GUID)) {
setPackageGuid((String) additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_GUID));
}
additionalProperties.put("packageGuid", packageGuid);
- if (additionalProperties.containsKey(USE_SWASHBUCKLE)) {
- useSwashbuckle = convertPropertyToBooleanAndWriteBack(USE_SWASHBUCKLE);
- } else {
- additionalProperties.put(USE_SWASHBUCKLE, useSwashbuckle);
- }
-
// CHeck for the modifiers etc.
// The order of the checks is important.
- isLibrary = setBuildTarget();
+ setBuildTarget();
setClassModifier();
setOperationModifier();
-
+ setModelClassModifier();
+ setUseSwashbuckle();
+ setOperationIsAsync();
// CHeck for class modifier if not present set the default value.
additionalProperties.put(PROJECT_SDK, projectSdk);
additionalProperties.put("dockerTag", packageName.toLowerCase(Locale.ROOT));
- apiPackage = packageName + ".Controllers";
- modelPackage = packageName + ".Models";
+ if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
+ apiPackage = packageName + ".Controllers";
+ additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
+ }
+
+ if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
+ modelPackage = packageName + ".Models";
+ additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
+ }
String packageFolder = sourceFolder + File.separator + packageName;
@@ -259,8 +290,6 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("Program.mustache", packageFolder, "Program.cs"));
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json",
packageFolder + File.separator + "Properties", "launchSettings.json"));
- } else {
- supportingFiles.add(new SupportingFile("Project.nuspec.mustache", packageFolder, packageName + ".nuspec"));
// wwwroot files.
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
@@ -268,6 +297,8 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "openapi-original.mustache",
packageFolder + File.separator + "wwwroot", "openapi-original.json"));
+ } else {
+ supportingFiles.add(new SupportingFile("Project.nuspec.mustache", packageFolder, packageName + ".nuspec"));
}
@@ -342,15 +373,23 @@ public String getNullableType(Schema p, String type) {
private void setCliOption(CliOption cliOption) throws IllegalArgumentException {
if (additionalProperties.containsKey(cliOption.getOpt())) {
- cliOption.setOptValue(additionalProperties.get(cliOption.getOpt()).toString());
- if (cliOption.getOptValue() == null) {
- cliOption.setOptValue(cliOption.getDefault());
- throw new IllegalArgumentException(cliOption.getOpt() + ": Invalid value '" + additionalProperties.get(cliOption.getOpt()).toString() + "'" +
- ". " + cliOption.getDescription());
+ // TODO Hack - not sure why the empty strings become boolean.
+ Object obj = additionalProperties.get(cliOption.getOpt());
+ if (!SchemaTypeUtil.BOOLEAN_TYPE.equals(cliOption.getType())) {
+ if (obj instanceof Boolean) {
+ obj = "";
+ additionalProperties.put(cliOption.getOpt(), obj);
+ }
}
+ cliOption.setOptValue(obj.toString());
} else {
additionalProperties.put(cliOption.getOpt(), cliOption.getOptValue());
}
+ if (cliOption.getOptValue() == null) {
+ cliOption.setOptValue(cliOption.getDefault());
+ throw new IllegalArgumentException(cliOption.getOpt() + ": Invalid value '" + additionalProperties.get(cliOption.getOpt()).toString() + "'" +
+ ". " + cliOption.getDescription());
+ }
}
private void setClassModifier() {
@@ -362,8 +401,6 @@ private void setClassModifier() {
operationModifier.setOptValue(classModifier.getOptValue());
additionalProperties.put(OPERATION_MODIFIER, operationModifier.getOptValue());
LOGGER.warn("classModifier is " + classModifier.getOptValue() + " so forcing operatonModifier to " + operationModifier.getOptValue());
- } else {
- setCliOption(operationModifier);
}
}
@@ -382,15 +419,28 @@ private void setOperationModifier() {
}
}
- private boolean setBuildTarget() {
- boolean isLibrary = false;
+ private void setModelClassModifier() {
+ setCliOption(modelClassModifier);
+
+ // If operation modifier is abstract then dont generate any body
+ if (isLibrary) {
+ modelClassModifier.setOptValue("");
+ additionalProperties.put(MODEL_CLASS_MODIFIER, modelClassModifier.getOptValue());
+ LOGGER.warn("buildTarget is " + buildTarget.getOptValue() + " so removing any modelClassModifier ");
+ }
+ }
+
+ private void setBuildTarget() {
setCliOption(buildTarget);
if ("library".equals(buildTarget.getOptValue())) {
isLibrary = true;
projectSdk = SDK_LIB;
additionalProperties.put(CLASS_MODIFIER, "abstract");
+ } else {
+ isLibrary = false;
+ projectSdk = SDK_WEB;
}
- return isLibrary;
+ additionalProperties.put(IS_LIBRARY, isLibrary);
}
private void setAspnetCoreVersion(String packageFolder) {
@@ -407,4 +457,29 @@ private void setAspnetCoreVersion(String packageFolder) {
}
additionalProperties.put(COMPATIBILITY_VERSION, compatibilityVersion);
}
+
+ private void setUseSwashbuckle() {
+ if (isLibrary) {
+ LOGGER.warn("buildTarget is " + buildTarget.getOptValue() + " so changing default isLibrary to false ");
+ useSwashbuckle = false;
+ } else {
+ useSwashbuckle = true;
+ }
+ if (additionalProperties.containsKey(USE_SWASHBUCKLE)) {
+ useSwashbuckle = convertPropertyToBooleanAndWriteBack(USE_SWASHBUCKLE);
+ } else {
+ additionalProperties.put(USE_SWASHBUCKLE, useSwashbuckle);
+ }
+ }
+
+ private void setOperationIsAsync() {
+ if (isLibrary) {
+ operationIsAsync = false;
+ additionalProperties.put(OPERATION_IS_ASYNC, operationIsAsync);
+ } else if (additionalProperties.containsKey(OPERATION_IS_ASYNC)) {
+ operationIsAsync = convertPropertyToBooleanAndWriteBack(OPERATION_IS_ASYNC);
+ } else {
+ additionalProperties.put(OPERATION_IS_ASYNC, operationIsAsync);
+ }
+ }
}
diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Project.csproj.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Project.csproj.mustache
index 296a332ecd97..3714e878dc47 100644
--- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Project.csproj.mustache
+++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Project.csproj.mustache
@@ -5,6 +5,9 @@
netcoreapp{{aspnetCoreVersion}}
true
true
+{{#isLibrary}}
+ Library
+{{/isLibrary}}
{{packageName}}
{{packageName}}
diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/README.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/README.mustache
index f2b4ce6f7b59..3dda0f304b5d 100644
--- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/README.mustache
+++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/README.mustache
@@ -17,7 +17,7 @@ Windows:
```
build.bat
```
-
+{{^isLibrary}}
## Run in Docker
```
@@ -25,3 +25,4 @@ cd {{sourceFolder}}/{{packageName}}
docker build -t {{dockerTag}} .
docker run -p 5000:8080 {{dockerTag}}
```
+{{/isLibrary}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache
index ee628b34ca77..f7d0e084937a 100644
--- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache
+++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Startup.mustache
@@ -44,7 +44,7 @@ namespace {{packageName}}
services
.AddMvc()
{{#compatibilityVersion}}
- .SetCompatibilityVersion(CompatibilityVersion.{{compatibilityVersion}})
+ .SetCompatibilityVersion (CompatibilityVersion.{{compatibilityVersion}})
{{/compatibilityVersion}}
.AddJsonOptions(opts =>
{
@@ -109,7 +109,7 @@ namespace {{packageName}}
// c.SwaggerEndpoint("/openapi-original.json", "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}} Original");
}){{/useSwashbuckle}};
- if (env.IsDevelopment())
+if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache
index 381d16aabef2..eb6430150c2a 100644
--- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache
+++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/controller.mustache
@@ -1,21 +1,24 @@
{{>partial_header}}
using System;
-using System.Collections.Generic;
+using System.Collections.Generic;{{#operationResultTask}}
+using System.Threading.Tasks;
+{{/operationResultTask}}
using Microsoft.AspNetCore.Mvc;{{#useSwashbuckle}}
using Swashbuckle.AspNetCore.Annotations;
-using Swashbuckle.AspNetCore.SwaggerGen;{{/useSwashbuckle}}
-using Newtonsoft.Json;
+using Swashbuckle.AspNetCore.SwaggerGen;{{/useSwashbuckle}}{{^isLibrary}}
+using Newtonsoft.Json;{{/isLibrary}}
using System.ComponentModel.DataAnnotations;
using {{packageName}}.Attributes;
-using {{packageName}}.Models;
+using {{modelPackage}};
-namespace {{packageName}}.Controllers
+namespace {{apiPackage}}
{ {{#operations}}
///
/// {{description}}
/// {{#description}}
[Description("{{description}}")]{{/description}}
- public {{classModifier}} class {{classname}}Controller : ControllerBase
+ [ApiController]
+ public {{#classModifier}}{{classModifier}} {{/classModifier}}class {{classname}}Controller : ControllerBase
{ {{#operation}}
///
/// {{#summary}}{{summary}}{{/summary}}
@@ -27,8 +30,9 @@ namespace {{packageName}}.Controllers
[Route("{{{basePathWithoutHost}}}{{{path}}}")]
[ValidateModelState]{{#useSwashbuckle}}
[SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}}
- [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}
- public {{operationModifier}} IActionResult {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
+ [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}{{^useSwashbuckle}}{{#responses}}{{#dataType}}
+ [ProducesResponseType(statusCode: {{code}}, type: typeof({{&dataType}}))]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}}{{/useSwashbuckle}}
+ public {{operationModifier}} {{#operationResultTask}}{{#operationIsAsync}}async {{/operationIsAsync}}Task<{{/operationResultTask}}IActionResult{{#operationResultTask}}>{{/operationResultTask}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}}
{{#generateBody}}
{ {{#responses}}
{{#dataType}}
@@ -47,7 +51,7 @@ namespace {{packageName}}.Controllers
{{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMapContainer}}{{>mapReturn}}{{/isMapContainer}}{{^isMapContainer}}{{>objectReturn}}{{/isMapContainer}}{{/isListCollection}}
{{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}}
//TODO: Change the data returned
- return new ObjectResult(example);{{/returnType}}{{^returnType}}
+ return {{#operationResultTask}}Task.FromResult({{/operationResultTask}}new ObjectResult(example){{#operationResultTask}}){{/operationResultTask}};{{/returnType}}{{^returnType}}
throw new NotImplementedException();{{/returnType}}
}
{{/generateBody}}
diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/model.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/model.mustache
index 670e24f4136e..ee6e5e2db771 100644
--- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/model.mustache
+++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/model.mustache
@@ -9,13 +9,13 @@ using Newtonsoft.Json;
{{#models}}
{{#model}}
-namespace {{packageName}}.Models
+namespace {{modelPackage}}
{ {{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}}
///
/// {{description}}
///
[DataContract]
- public partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}>
+ public {{#modelClassModifier}}{{modelClassModifier}} {{/modelClassModifier}} class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}>
{ {{#vars}}{{#isEnum}}{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}}{{>enumClass}}{{/items}}{{/items.isEnum}}
///
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}