Skip to content
Closed
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 @@ -160,6 +160,9 @@ public class CodegenConstants {
public static final String NETCORE_PROJECT_FILE = "netCoreProjectFile";
public static final String NETCORE_PROJECT_FILE_DESC = "Use the new format (.NET Core) for .NET project files (.csproj).";

public static final String OVERRIDE_CONTROLLERS = "overrideControllers";
public static final String OVERRIDE_CONTROLLERS_DESC = "Make generated controllers for AspNetCoreLibrary abstract and not automatically bound";

public static final String USE_COLLECTION = "useCollection";
public static final String USE_COLLECTION_DESC = "Deserialize array types to Collection<T> instead of List<T>.";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openapitools.codegen.languages;

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.utils.URLPathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;

public class AspNetCoreServerLibraryCodegen extends AbstractCSharpCodegen {

public static final String ASPNET_CORE_VERSION = "aspnetCoreVersion";

@SuppressWarnings("hiding")
protected Logger LOGGER = LoggerFactory.getLogger(AspNetCoreServerLibraryCodegen.class);

protected int serverPort = 8080;
protected String serverHost = "0.0.0.0";
protected String aspnetCoreVersion= "2.1"; // default to 2.1

public AspNetCoreServerLibraryCodegen() {
super();

outputFolder = "generated-code" + File.separator + getName();

modelTemplateFiles.put("model.mustache", ".cs");
apiTemplateFiles.put("controller.mustache", ".cs");

embeddedTemplateDir = templateDir = "aspnetcorelib/2.1";

// contextually reserved words
// NOTE: C# uses camel cased reserved words, while models are title cased. We don't want lowercase comparisons.
reservedWords.addAll(
Arrays.asList("var", "async", "await", "dynamic", "yield")
);

cliOptions.clear();

// CLI options
addOption(CodegenConstants.PACKAGE_NAME,
"C# package name (convention: Title.Case).",
packageName);

addOption(CodegenConstants.PACKAGE_VERSION,
"C# package version.",
packageVersion);

addOption(CodegenConstants.OPTIONAL_PROJECT_GUID,
CodegenConstants.OPTIONAL_PROJECT_GUID_DESC,
null);

addOption(CodegenConstants.SOURCE_FOLDER,
CodegenConstants.SOURCE_FOLDER_DESC,
sourceFolder);

addOption(ASPNET_CORE_VERSION,
"ASP.NET Core version: 2.1 (default), 2.0 (deprecated)",
aspnetCoreVersion);

// CLI Switches
addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG,
CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC,
sortParamsByRequiredFlag);

addSwitch(CodegenConstants.USE_DATETIME_OFFSET,
CodegenConstants.USE_DATETIME_OFFSET_DESC,
useDateTimeOffsetFlag);

addSwitch(CodegenConstants.USE_COLLECTION,
CodegenConstants.USE_COLLECTION_DESC,
useCollection);

addSwitch(CodegenConstants.RETURN_ICOLLECTION,
CodegenConstants.RETURN_ICOLLECTION_DESC,
returnICollection);


addSwitch(CodegenConstants.OVERRIDE_CONTROLLERS,
CodegenConstants.OVERRIDE_CONTROLLERS_DESC,
true);
}

@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}

@Override
public String getName() {
return "aspnetcorelib";
}

@Override
public String getHelp() {
return "Generates an ASP.NET Core Web API Library.";
}

@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
super.preprocessOpenAPI(openAPI);
URL url = URLPathUtils.getServerURL(openAPI);
additionalProperties.put("serverHost", url.getHost());
additionalProperties.put("serverPort", URLPathUtils.getPort(url, 8080));
}

@Override
public void processOpts() {
super.processOpts();

// determine the ASP.NET core version setting
if (additionalProperties.containsKey(ASPNET_CORE_VERSION)) {
setAspnetCoreVersion((String) additionalProperties.get(ASPNET_CORE_VERSION));
}

apiPackage = packageName + ".Controllers";
modelPackage = packageName + ".Models";

String packageFolder = sourceFolder + File.separator + packageName;

supportingFiles.add(new SupportingFile("README.mustache", packageFolder, "README.md"));
supportingFiles.add(new SupportingFile("gitignore", packageFolder, ".gitignore"));

supportingFiles.add(new SupportingFile("validateModel.mustache", packageFolder + File.separator + "Attributes", "ValidateModelStateAttribute.cs"));
supportingFiles.add(new SupportingFile("Project.csproj.mustache", packageFolder, packageName + ".csproj"));
}

public void setAspnetCoreVersion(String aspnetCoreVersion) {
this.aspnetCoreVersion= aspnetCoreVersion;
}

@Override
public String apiFileFolder() {
return outputFolder + File.separator + sourceFolder + File.separator + packageName + File.separator + "Controllers";
}

@Override
public String modelFileFolder() {
return outputFolder + File.separator + sourceFolder + File.separator + packageName + File.separator + "Models";
}

@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateJSONSpecFile(objs);
return super.postProcessSupportingFileData(objs);
}

@Override
protected void processOperation(CodegenOperation operation) {
super.processOperation(operation);

// HACK: Unlikely in the wild, but we need to clean operation paths for MVC Routing
if (operation.path != null) {
String original = operation.path;
operation.path = operation.path.replace("?", "/");
if (!original.equals(operation.path)) {
LOGGER.warn("Normalized " + original + " to " + operation.path + ". Please verify generated source.");
}
}

// Converts, for example, PUT to HttpPut for controller attributes
operation.httpMethod = "Http" + operation.httpMethod.substring(0, 1) + operation.httpMethod.substring(1).toLowerCase(Locale.ROOT);
}

@Override
public Mustache.Compiler processCompiler(Mustache.Compiler compiler) {
// To avoid unexpected behaviors when options are passed programmatically such as { "useCollection": "" }
return super.processCompiler(compiler).emptyStringIsFalse(true);
}

@Override
public String toRegularExpression(String pattern) {
return escapeText(pattern);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ org.openapitools.codegen.languages.AndroidClientCodegen
org.openapitools.codegen.languages.Apache2ConfigCodegen
org.openapitools.codegen.languages.ApexClientCodegen
org.openapitools.codegen.languages.AspNetCoreServerCodegen
org.openapitools.codegen.languages.AspNetCoreServerLibraryCodegen
org.openapitools.codegen.languages.BashClientCodegen
org.openapitools.codegen.languages.CLibcurlClientCodegen
org.openapitools.codegen.languages.ClojureClientCodegen
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>{{packageName}}</Description>
<Copyright>{{packageName}}</Copyright>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>{{packageName}}</AssemblyName>
<PackageId>{{packageName}}</PackageId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>

</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# {{packageName}} - ASP.NET Core 2.0 Server

{{#appDescription}}
{{{appDescription}}}
{{/appDescription}}

## Run

Linux/OS X:

```
sh build.sh
```

Windows:

```
build.bat
```

## Run in Docker

```
cd {{sourceFolder}}/{{packageName}}
docker build -t {{dockerTag}} .
docker run -p 5000:5000 {{dockerTag}}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{classname}}{{#overrideControllers}}Abstract{{/overrideControllers}}Controller
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{#isBodyParam}}[FromBody]{{&dataType}} {{paramName}}{{/isBodyParam}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{{>partial_header}}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Threading.Tasks;
using {{packageName}}.Attributes;
using {{packageName}}.Models;
using Microsoft.AspNetCore.Mvc;

namespace {{packageName}}.Controllers
{ {{#operations}}

/// <summary>
/// {{description}}
/// </summary>{{#description}}
[Description("{{description}}")]{{/description}}
public interface I{{classname}}Implementation
{
{{#operation}}
/// <summary>
/// {{#summary}}{{summary}}{{/summary}}
/// </summary>{{#notes}}
/// <remarks>{{notes}}</remarks>{{/notes}}{{#allParams}}
/// <param name="{{paramName}}">{{description}}</param>{{/allParams}}{{#responses}}
/// <response code="{{code}}">{{message}}</response>{{/responses}}
Task<(HttpStatusCode statusCode, object response)> {{operationId}}({{#allParams}}{{&dataType}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
{{/operation}}
}

/// <summary>
/// {{description}}
/// </summary>{{#description}}
[Description("{{description}}")]{{/description}}
public {{#overrideControllers}}abstract {{/overrideControllers}}class {{>abstractConcreteClassName}} : ControllerBase
{
private readonly I{{classname}}Implementation _impl;

/// <summary>
/// The IOC injected implementation
/// <param name="impl">Controller's implementation</param>
/// </summary>
public {{>abstractConcreteClassName}}(I{{classname}}Implementation impl)
{
_impl = impl;
}

{{#operation}}
/// <summary>
/// {{#summary}}{{summary}}{{/summary}}
/// </summary>{{#notes}}
/// <remarks>{{notes}}</remarks>{{/notes}}{{#allParams}}
/// <param name="{{paramName}}">{{description}}</param>{{/allParams}}{{#responses}}
/// <response code="{{code}}">{{message}}</response>{{/responses}}
[{{httpMethod}}]
[Route("{{{basePathWithoutHost}}}{{{path}}}")]
[ValidateModelState]
public virtual async Task<IActionResult> {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
{
{{>tupleReturn}}
}
{{/operation}}
}
{{/operations}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

/// <summary>
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}}
/// </summary>
{{#description}}
/// <value>{{{description}}}</value>
{{/description}}
{{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}}[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]{{/isString}}{{/-first}}{{/enumVars}}{{/allowableValues}}
public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}
{
{{#allowableValues}}{{#enumVars}}
/// <summary>
/// Enum {{name}} for {{{value}}}
/// </summary>
{{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
{{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}},
{{/-last}}{{/enumVars}}{{/allowableValues}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{#isFormParam}}[FromForm]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isFormParam}}
Loading