diff --git a/docs/generators/aspnetcore.md b/docs/generators/aspnetcore.md index 63c1d810c112..f2445f7a427e 100644 --- a/docs/generators/aspnetcore.md +++ b/docs/generators/aspnetcore.md @@ -16,13 +16,13 @@ sidebar_label: aspnetcore |packageVersion|C# package version.| |1.0.0| |packageGuid|The GUID that will be associated with the C# project| |null| |sourceFolder|source folder for generated code| |src| -|aspnetCoreVersion|ASP.NET Core version: 2.1 (default), 2.0 (deprecated)| |2.1| +|aspnetCoreVersion|ASP.NET Core version: 2.2 (default), 2.1, 2.0 (deprecated)| |2.2| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false| |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| -|classModifier|Class modifiers such as abstract or partial| || -|operationModifier|Operation modifiers such as virtual or abstract.| |virtual| +|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| -|buildTarget|Target the build for a program or library.| |program| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CliOption.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CliOption.java index 0854b2e8593c..b6d95b4fa6f2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CliOption.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CliOption.java @@ -28,6 +28,7 @@ public class CliOption { private String description; private String type; private String defaultValue; + private String optValue; private Map enumValues; public CliOption(String opt, String description) { @@ -73,6 +74,15 @@ public CliOption defaultValue(String defaultValue) { return this; } + public String getOptValue() { return this.optValue;} + public void setOptValue(String optValue) { + if (this.enumValues!=null && this.enumValues.containsKey(optValue)) { + this.optValue = optValue; + } else { + this.optValue = null; + } + } + public CliOption addEnum(String value, String description) { if (this.enumValues == null) { this.enumValues = new LinkedHashMap(); 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 fe4bce79ae39..c308d74729e1 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 @@ -19,10 +19,7 @@ import com.samskivert.mustache.Mustache; import io.swagger.v3.oas.models.OpenAPI; -import org.openapitools.codegen.CodegenConstants; -import org.openapitools.codegen.CodegenOperation; -import org.openapitools.codegen.CodegenType; -import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.*; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,12 +53,11 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen { private boolean useSwashbuckle = true; protected int serverPort = 8080; protected String serverHost = "0.0.0.0"; - protected String aspnetCoreVersion= "2.1"; // default to 2.1 - // TODO Make next two enums toensure fixed list. - private String classModifier = ""; - private String operationModifier = "virtual"; + 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 boolean generateBody = true; - private String buildTarget = "program"; + private CliOption buildTarget = new CliOption("buildTarget", "Target to build an application or library"); private String projectSdk = SDK_WEB; public AspNetCoreServerCodegen() { @@ -119,9 +115,12 @@ public AspNetCoreServerCodegen() { CodegenConstants.SOURCE_FOLDER_DESC, sourceFolder); - addOption(ASPNET_CORE_VERSION, - "ASP.NET Core version: 2.1 (default), 2.0 (deprecated)", - aspnetCoreVersion); + aspnetCoreVersion.addEnum("2.0", "ASP.NET COre V2.0"); + aspnetCoreVersion.addEnum("2.1", "ASP.NET COre V2.1"); + aspnetCoreVersion.addEnum("2.2", "ASP.NET COre V2.2"); + aspnetCoreVersion.setDefault("2.2"); + aspnetCoreVersion.setOptValue(aspnetCoreVersion.getDefault()); + addOption(aspnetCoreVersion.getOpt(),aspnetCoreVersion.getDescription(),aspnetCoreVersion.getOptValue()); // CLI Switches addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, @@ -144,22 +143,28 @@ public AspNetCoreServerCodegen() { "Uses the Swashbuckle.AspNetCore NuGet package for documentation.", useSwashbuckle); - addOption(CLASS_MODIFIER, - "Class modifiers such as abstract or partial", - classModifier); + classModifier.addEnum("", "Keep class default with no modifier"); + classModifier.addEnum("abstract", "Make class abstract"); + classModifier.setDefault(""); + classModifier.setOptValue(classModifier.getDefault()); + addOption(classModifier.getOpt(),classModifier.getDescription(),classModifier.getOptValue()); - addOption(OPERATION_MODIFIER, - "Operation modifiers such as virtual or abstract.", - operationModifier); + operationModifier.addEnum("virtual", "Keep method virtual "); + operationModifier.addEnum("abstract", "Make method abstract"); + operationModifier.setDefault("virtual"); + operationModifier.setOptValue(operationModifier.getDefault()); + addOption(operationModifier.getOpt(),operationModifier.getDescription(),operationModifier.getOptValue()); + + buildTarget.addEnum("program", "Generate code for standalone server"); + buildTarget.addEnum("library", "Generate code for a server abstract class lbrary"); + buildTarget.setDefault("program"); + buildTarget.setOptValue(buildTarget.getDefault()); + addOption(buildTarget.getOpt(),buildTarget.getDescription(),buildTarget.getOptValue()); addSwitch(GENERATE_BODY, "Generates method body.", generateBody); - addOption(BUILD_TARGET, - "Target the build for a program or library.", - buildTarget); - } @Override @@ -201,53 +206,15 @@ public void processOpts() { additionalProperties.put(USE_SWASHBUCKLE, useSwashbuckle); } - // determine the ASP.NET core version setting - if (additionalProperties.containsKey(ASPNET_CORE_VERSION)) { - setAspnetCoreVersion((String) additionalProperties.get(ASPNET_CORE_VERSION)); - } - - // CHeck for class modifier if not present set the default value. - if (additionalProperties.containsKey(CLASS_MODIFIER)) { - classModifier = additionalProperties.get(CLASS_MODIFIER).toString(); - } else { - additionalProperties.put(CLASS_MODIFIER, classModifier); - } - - // TODO Validate modifier values - // If class modifierier is abstract then the methods need to be abstrat too. - if ("abstract".equals(classModifier)) { - operationModifier = classModifier; - additionalProperties.put(OPERATION_MODIFIER, operationModifier); - } - if (additionalProperties.containsKey(OPERATION_MODIFIER)) { - operationModifier = additionalProperties.get(OPERATION_MODIFIER).toString(); - } else { - additionalProperties.put(OPERATION_MODIFIER, operationModifier); - } + // CHeck for the modifiers etc. + // The order of the checks is important. + isLibrary = setBuildTarget(); + setClassModifier(); + setOperationModifier(); - // TODO Validate modifier values - // If operation modifier is abstract then dont generate any body - if ("abstract".equals(operationModifier)) { - generateBody = false; - additionalProperties.put(GENERATE_BODY, generateBody); - } - if (additionalProperties.containsKey(GENERATE_BODY)) { - generateBody = convertPropertyToBooleanAndWriteBack(GENERATE_BODY); - } else { - additionalProperties.put(GENERATE_BODY, generateBody); - } // CHeck for class modifier if not present set the default value. - if (additionalProperties.containsKey(BUILD_TARGET)) { - buildTarget = additionalProperties.get(BUILD_TARGET).toString(); - } else { - additionalProperties.put(BUILD_TARGET, buildTarget); - } - if ("library".equals(buildTarget)) { - isLibrary = true; - projectSdk = SDK_LIB; - } additionalProperties.put(PROJECT_SDK, projectSdk); additionalProperties.put("dockerTag", packageName.toLowerCase(Locale.ROOT)); @@ -257,17 +224,8 @@ public void processOpts() { String packageFolder = sourceFolder + File.separator + packageName; - if ("2.0".equals(aspnetCoreVersion)) { - embeddedTemplateDir = templateDir = "aspnetcore/2.0"; - supportingFiles.add(new SupportingFile("web.config", packageFolder, "web.config")); - LOGGER.info("ASP.NET core version: 2.0"); - } else if ("2.1".equals(aspnetCoreVersion)) { - // default, do nothing - LOGGER.info("ASP.NET core version: 2.1"); - } else { - throw new IllegalArgumentException("aspnetCoreVersion must be '2.1', '2.0' but found " + aspnetCoreVersion); - } - + // determine the ASP.NET core version setting + setAspnetCoreVersion(packageFolder); supportingFiles.add(new SupportingFile("build.sh.mustache", "", "build.sh")); supportingFiles.add(new SupportingFile("build.bat.mustache", "", "build.bat")); @@ -328,10 +286,6 @@ public void setPackageGuid(String packageGuid) { this.packageGuid = packageGuid; } - public void setAspnetCoreVersion(String aspnetCoreVersion) { - this.aspnetCoreVersion= aspnetCoreVersion; - } - @Override public String apiFileFolder() { return outputFolder + File.separator + sourceFolder + File.separator + packageName + File.separator + "Controllers"; @@ -375,4 +329,69 @@ public Mustache.Compiler processCompiler(Mustache.Compiler compiler) { public String toRegularExpression(String pattern) { return escapeText(pattern); } + + private void setCliOption(CliOption cliOption) throws IllegalArgumentException { + if (additionalProperties.containsKey(cliOption.getOpt())) { + cliOption.setOptValue(additionalProperties.get(cliOption.getOpt()).toString()); + if (classModifier.getOptValue() == null) { + cliOption.setOptValue(cliOption.getDefault()); + throw new IllegalArgumentException(cliOption.getOpt() + ": Invalid value '" + additionalProperties.get(cliOption.getOpt()).toString() + "'" + + ". " + cliOption.getDescription()); + } + } else { + additionalProperties.put(cliOption.getOpt(), cliOption.getOptValue()); + } + } + + private void setClassModifier() { + // CHeck for class modifier if not present set the default value. + setCliOption(classModifier); + + // If class modifier is abstract then the methods need to be abstract too. + if ("abstract".equals(classModifier.getOptValue())) { + 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); + } + } + + private void setOperationModifier() { + setCliOption(operationModifier); + + // If operation modifier is abstract then dont generate any body + if ("abstract".equals(operationModifier.getOptValue())) { + generateBody = false; + additionalProperties.put(GENERATE_BODY, generateBody); + LOGGER.warn("operationModifier is " + operationModifier.getOptValue() + " so forcing generateBody to "+ generateBody); + } else if (additionalProperties.containsKey(GENERATE_BODY)) { + generateBody = convertPropertyToBooleanAndWriteBack(GENERATE_BODY); + } else { + additionalProperties.put(GENERATE_BODY, generateBody); + } + } + + private boolean setBuildTarget() { + boolean isLibrary = false; + setCliOption(buildTarget); + if ("library".equals(buildTarget)) { + isLibrary = true; + projectSdk = SDK_LIB; + additionalProperties.put(CLASS_MODIFIER, "abstract"); + } + return isLibrary; + } + + private void setAspnetCoreVersion(String packageFolder) { + setCliOption(aspnetCoreVersion); + if ("2.0".equals(aspnetCoreVersion.getOptValue())) { + embeddedTemplateDir = templateDir = "aspnetcore/2.0"; + supportingFiles.add(new SupportingFile("web.config", packageFolder, "web.config")); + LOGGER.info("ASP.NET core version: 2.0"); + } else { + // default, do nothing + LOGGER.info("ASP.NET core version: " + aspnetCoreVersion.getOptValue()); + } + } } diff --git a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Dockerfile.mustache b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Dockerfile.mustache index 391e85846b8d..aa3f404bdce6 100644 --- a/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Dockerfile.mustache +++ b/modules/openapi-generator/src/main/resources/aspnetcore/2.1/Dockerfile.mustache @@ -1,4 +1,4 @@ -FROM microsoft/dotnet:2.1-sdk AS build-env +FROM microsoft/dotnet:{{aspnetCoreVersion}}-sdk AS build-env WORKDIR /app ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 @@ -12,7 +12,7 @@ COPY . ./ RUN dotnet publish -c Release -o out # build runtime image -FROM microsoft/dotnet:2.1-aspnetcore-runtime +FROM microsoft/dotnet:{{aspnetCoreVersion}}-aspnetcore-runtime WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "{{packageName}}.dll"] 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 0430f24a4a46..296a332ecd97 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 @@ -2,7 +2,7 @@ {{packageName}} {{packageName}} - netcoreapp2.1 + netcoreapp{{aspnetCoreVersion}} true true {{packageName}} 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 7a488bfcf170..8c2af4dc41a2 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 @@ -43,7 +43,7 @@ namespace {{packageName}} // Add framework services. services .AddMvc() - .SetCompatibilityVersion (CompatibilityVersion.Version_2_1) + .SetCompatibilityVersion ((String.Compare("2.1","{{aspnetCoreVersion}}") == 0)?CompatibilityVersion.Version_2_1:CompatibilityVersion.Version_2_2) .AddJsonOptions(opts => { opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 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 57a4f545f4ba..381d16aabef2 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 @@ -28,7 +28,7 @@ namespace {{packageName}}.Controllers [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}}) + public {{operationModifier}} IActionResult {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{^generateBody}};{{/generateBody}} {{#generateBody}} { {{#responses}} {{#dataType}} @@ -51,9 +51,6 @@ namespace {{packageName}}.Controllers throw new NotImplementedException();{{/returnType}} } {{/generateBody}} - {{^generateBody}} - ; - {{/generateBody}} {{/operation}} } {{/operations}}