Skip to content

Commit 8239f58

Browse files
committed
Added support for .NetCore 3 & Swashbuckle 5
1 parent ec3bc36 commit 8239f58

File tree

8 files changed

+464
-8
lines changed

8 files changed

+464
-8
lines changed

src/main/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegen.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
3535
private static final String ASP_NET_CORE_VERSION_OPTION = "--aspnet-core-version";
3636
private static final String INTERFACE_ONLY_OPTION = "--interface-only";
3737
private static final String INTERFACE_CONTROLLER_OPTION = "--interface-controller";
38-
private final String DEFAULT_ASP_NET_CORE_VERSION = "2.2";
38+
private final String DEFAULT_ASP_NET_CORE_VERSION = "3.0";
3939
private String aspNetCoreVersion;
4040

4141
@SuppressWarnings("hiding")
@@ -151,13 +151,33 @@ public void processOpts() {
151151
supportingFiles.add(new SupportingFile("Program.mustache", packageFolder, "Program.cs"));
152152
supportingFiles.add(new SupportingFile("Project.csproj.mustache", packageFolder, this.packageName + ".csproj"));
153153
supportingFiles.add(new SupportingFile("Dockerfile.mustache", packageFolder, "Dockerfile"));
154-
} else{
154+
supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs"));
155+
156+
supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs"));
157+
supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs"));
158+
159+
} else if (aspNetCoreVersion.equals("2.1")) {
155160
apiTemplateFiles.put("2.1/controller.mustache", ".cs");
156161
addInterfaceControllerTemplate();
157162

158163
supportingFiles.add(new SupportingFile("2.1/Program.mustache", packageFolder, "Program.cs"));
159164
supportingFiles.add(new SupportingFile("2.1/Project.csproj.mustache", packageFolder, this.packageName + ".csproj"));
160165
supportingFiles.add(new SupportingFile("2.1/Dockerfile.mustache", packageFolder, "Dockerfile"));
166+
supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs"));
167+
168+
supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs"));
169+
supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs"));
170+
} else {
171+
apiTemplateFiles.put("3.0/controller.mustache", ".cs");
172+
addInterfaceControllerTemplate();
173+
174+
supportingFiles.add(new SupportingFile("3.0/Program.mustache", packageFolder, "Program.cs"));
175+
supportingFiles.add(new SupportingFile("3.0/Project.csproj.mustache", packageFolder, this.packageName + ".csproj"));
176+
supportingFiles.add(new SupportingFile("3.0/Dockerfile.mustache", packageFolder, "Dockerfile"));
177+
supportingFiles.add(new SupportingFile("3.0/Startup.mustache", packageFolder, "Startup.cs"));
178+
179+
supportingFiles.add(new SupportingFile("3.0" + File.separator + "Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs"));
180+
supportingFiles.add(new SupportingFile("3.0" + File.separator + "Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs"));
161181
}
162182

163183
if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
@@ -178,16 +198,11 @@ public void processOpts() {
178198
supportingFiles.add(new SupportingFile("gitignore", packageFolder, ".gitignore"));
179199
supportingFiles.add(new SupportingFile("appsettings.json", packageFolder, "appsettings.json"));
180200

181-
supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs"));
182-
183201
supportingFiles.add(new SupportingFile("validateModel.mustache", packageFolder + File.separator + "Attributes", "ValidateModelStateAttribute.cs"));
184202
supportingFiles.add(new SupportingFile("web.config", packageFolder, "web.config"));
185203

186204
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json"));
187205

188-
supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs"));
189-
supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs"));
190-
191206
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
192207
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
193208
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "web.config", packageFolder + File.separator + "wwwroot", "web.config"));
@@ -361,7 +376,7 @@ private void setAspNetCoreVersion() {
361376
} else {
362377
this.aspNetCoreVersion = optionValue;
363378
}
364-
if (!this.aspNetCoreVersion.equals("2.0") && !this.aspNetCoreVersion.equals("2.1") && !this.aspNetCoreVersion.equals("2.2")) {
379+
if (!this.aspNetCoreVersion.equals("2.0") && !this.aspNetCoreVersion.equals("2.1") && !this.aspNetCoreVersion.equals("2.2") && !this.aspNetCoreVersion.equals("3.0")) {
365380
LOGGER.error("version '" + this.aspNetCoreVersion + "' is not supported, switching to default version: '" + DEFAULT_ASP_NET_CORE_VERSION + "'");
366381
this.aspNetCoreVersion = DEFAULT_ASP_NET_CORE_VERSION;
367382
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM mcr.microsoft.com/dotnet/core/sdk:{{aspNetCoreVersion}} AS build-env
2+
WORKDIR /app
3+
4+
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
5+
6+
# copy csproj and restore as distinct layers
7+
COPY *.csproj ./
8+
RUN dotnet restore
9+
10+
# copy everything else and build
11+
COPY . ./
12+
RUN dotnet publish -c Release -o out
13+
14+
# build runtime image
15+
FROM mcr.microsoft.com/dotnet/core/aspnet:{{aspNetCoreVersion}}
16+
WORKDIR /app
17+
COPY --from=build-env /app/out .
18+
ENTRYPOINT ["dotnet", "{{packageName}}.dll"]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System.Linq;
2+
using System.Text.RegularExpressions;
3+
using Swashbuckle.AspNetCore.Swagger;
4+
using Swashbuckle.AspNetCore.SwaggerGen;
5+
using Microsoft.OpenApi.Models;
6+
7+
namespace {{packageName}}.Filters
8+
{
9+
/// <summary>
10+
/// BasePath Document Filter sets BasePath property of Swagger and removes it from the individual URL paths
11+
/// </summary>
12+
public class BasePathFilter : IDocumentFilter
13+
{
14+
/// <summary>
15+
/// Constructor
16+
/// </summary>
17+
/// <param name="basePath">BasePath to remove from Operations</param>
18+
public BasePathFilter(string basePath)
19+
{
20+
BasePath = basePath;
21+
}
22+
23+
/// <summary>
24+
/// Gets the BasePath of the Swagger Doc
25+
/// </summary>
26+
/// <returns>The BasePath of the Swagger Doc</returns>
27+
public string BasePath { get; }
28+
29+
/// <summary>
30+
/// Apply the filter
31+
/// </summary>
32+
/// <param name="swaggerDoc">OpenApiDocument</param>
33+
/// <param name="context">FilterContext</param>
34+
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
35+
{
36+
swaggerDoc.Servers.Add(new OpenApiServer() { Url = this.BasePath });
37+
38+
var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList();
39+
40+
foreach (var path in pathsToModify)
41+
{
42+
if (path.Key.StartsWith(this.BasePath))
43+
{
44+
string newKey = Regex.Replace(path.Key, $"^{this.BasePath}", string.Empty);
45+
swaggerDoc.Paths.Remove(path.Key);
46+
swaggerDoc.Paths.Add(newKey, path.Value);
47+
}
48+
}
49+
}
50+
}
51+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.Linq;
3+
using Microsoft.AspNetCore.Mvc.Controllers;
4+
using Swashbuckle.AspNetCore.Swagger;
5+
using Swashbuckle.AspNetCore.SwaggerGen;
6+
using Microsoft.OpenApi.Models;
7+
8+
namespace {{packageName}}.Filters
9+
{
10+
/// <summary>
11+
/// Path Parameter Validation Rules Filter
12+
/// </summary>
13+
public class GeneratePathParamsValidationFilter : IOperationFilter
14+
{
15+
/// <summary>
16+
/// Constructor
17+
/// </summary>
18+
/// <param name="operation">Operation</param>
19+
/// <param name="context">OperationFilterContext</param>
20+
public void Apply(OpenApiOperation operation, OperationFilterContext context)
21+
{
22+
var pars = context.ApiDescription.ParameterDescriptions;
23+
24+
foreach (var par in pars)
25+
{
26+
var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
27+
28+
var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes;
29+
30+
if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
31+
{
32+
// Required - [Required]
33+
var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
34+
if (requiredAttr != null)
35+
{
36+
swaggerParam.Required = true;
37+
}
38+
39+
// Regex Pattern [RegularExpression]
40+
var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
41+
if (regexAttr != null)
42+
{
43+
string regex = (string)regexAttr.ConstructorArguments[0].Value;
44+
if (swaggerParam is OpenApiParameter)
45+
{
46+
((OpenApiParameter)swaggerParam).Schema.Pattern = regex;
47+
}
48+
}
49+
50+
// String Length [StringLength]
51+
int? minLenght = null, maxLength = null;
52+
var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
53+
if (stringLengthAttr != null)
54+
{
55+
if (stringLengthAttr.NamedArguments.Count == 1)
56+
{
57+
minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
58+
}
59+
maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
60+
}
61+
62+
var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
63+
if (minLengthAttr != null)
64+
{
65+
minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
66+
}
67+
68+
var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
69+
if (maxLengthAttr != null)
70+
{
71+
maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
72+
}
73+
74+
if (swaggerParam is OpenApiParameter)
75+
{
76+
((OpenApiParameter)swaggerParam).Schema.MinLength = minLenght;
77+
((OpenApiParameter)swaggerParam).Schema.MaxLength = maxLength;
78+
}
79+
80+
// Range [Range]
81+
var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
82+
if (rangeAttr != null)
83+
{
84+
int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
85+
int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;
86+
87+
if (swaggerParam is OpenApiParameter)
88+
{
89+
((OpenApiParameter)swaggerParam).Schema.Minimum = rangeMin;
90+
((OpenApiParameter)swaggerParam).Schema.Maximum = rangeMax;
91+
}
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Microsoft.AspNetCore.Hosting;
2+
using Microsoft.AspNetCore;
3+
4+
namespace {{packageName}}
5+
{
6+
/// <summary>
7+
/// Program
8+
/// </summary>
9+
public class Program
10+
{
11+
/// <summary>
12+
/// Main
13+
/// </summary>
14+
/// <param name="args"></param>
15+
public static void Main(string[] args)
16+
{
17+
CreateWebHostBuilder(args).Build().Run();
18+
}
19+
20+
/// <summary>
21+
/// Create the web host builder.
22+
/// </summary>
23+
/// <param name="args"></param>
24+
/// <returns>IWebHostBuilder</returns>
25+
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
26+
WebHost.CreateDefaultBuilder(args)
27+
.UseStartup<Startup>();
28+
}
29+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<Description>{{packageName}}</Description>
4+
<Copyright>{{packageName}}</Copyright>
5+
<TargetFramework>netcoreapp{{aspNetCoreVersion}}</TargetFramework>
6+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
7+
<PreserveCompilationContext>true</PreserveCompilationContext>
8+
<AssemblyName>{{packageName}}</AssemblyName>
9+
<PackageId>{{packageName}}</PackageId>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc4"/>
13+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0-rc4"/>
14+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.0.0-rc4"/>
15+
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.0.0-rc4" />
16+
</ItemGroup>
17+
<ItemGroup>
18+
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
19+
</ItemGroup>
20+
</Project>

0 commit comments

Comments
 (0)