diff --git a/eng/Versions.props b/eng/Versions.props
index f7b99d3cd9..f1b77d9fd1 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -274,6 +274,7 @@
4.0.0
2.0.593
3.1.1
+ 5.5.1
2.0.3
0.10.0
2.4.1
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
index 2d8969ece5..9aa8755e9f 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
+++ b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
@@ -23,6 +23,7 @@
MicrosoftNETCoreAppRuntimeVersion=$(MicrosoftNETCoreAppRuntimeVersion);
SystemNetHttpJsonPackageVersion=$(SystemNetHttpJsonPackageVersion);
MicrosoftGraphPackageVersion=$(MicrosoftGraphPackageVersion);
+ SwashbuckleAspNetCorePackageVersion=$(SwashbuckleAspNetCorePackageVersion);
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/WebApi-CSharp.csproj.in b/src/ProjectTemplates/Web.ProjectTemplates/WebApi-CSharp.csproj.in
index 1573dbfe37..44619a1663 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/WebApi-CSharp.csproj.in
+++ b/src/ProjectTemplates/Web.ProjectTemplates/WebApi-CSharp.csproj.in
@@ -6,13 +6,14 @@
True
Company.WebApplication1
-
+
-
-
-
-
+
+
+
+
+
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
index 36f8f5bf5c..af0458974c 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json
@@ -57,19 +57,23 @@
"shortName": ""
},
"CalledApiUrl": {
- "longName": "called-api-url",
- "shortName": ""
+ "longName": "called-api-url",
+ "shortName": ""
},
"CalledApiScopes": {
- "longName": "called-api-scopes",
- "shortName": ""
+ "longName": "called-api-scopes",
+ "shortName": ""
},
"CallsMicrosoftGraph": {
- "longName": "calls-graph",
- "shortName": ""
+ "longName": "calls-graph",
+ "shortName": ""
+ },
+ "DisableOpenAPI": {
+ "longName": "no-openapi",
+ "shortName": ""
}
},
"usageExamples": [
""
]
-}
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
index 1990a4e711..f11b772861 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json
@@ -39,14 +39,14 @@
},
{
"condition": "(!GenerateApi)",
- "exclude": [
- "Services/DownstreamWebApi.cs"
- ]
+ "exclude": [
+ "Services/DownstreamWebApi.cs"
+ ]
},
{
"condition": "(!GenerateGraph)",
"exclude": [
- "Services/MicrosoftGraphServiceExtensions.cs",
+ "Services/MicrosoftGraphServiceExtensions.cs",
"Services/TokenAcquisitionCredentialProvider.cs"
]
}
@@ -244,35 +244,45 @@
"defaultValue": "false"
},
"CalledApiUrl": {
- "type": "parameter",
- "datatype": "string",
- "replaces": "[WebApiUrl]",
- "defaultValue" : "https://graph.microsoft.com/v1.0",
- "description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
+ "type": "parameter",
+ "datatype": "string",
+ "replaces": "[WebApiUrl]",
+ "defaultValue": "https://graph.microsoft.com/v1.0",
+ "description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
},
"CallsMicrosoftGraph": {
- "type": "parameter",
- "datatype": "bool",
- "defaultValue": "false",
- "description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified."
+ "type": "parameter",
+ "datatype": "bool",
+ "defaultValue": "false",
+ "description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified."
},
"CalledApiScopes": {
"type": "parameter",
"datatype": "string",
- "replaces" : "user.read",
+ "replaces": "user.read",
"description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
},
"GenerateApi": {
- "type": "computed",
- "value": "((IndividualB2CAuth || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/v1.0\" || CalledApiScopes != \"user.read\"))"
+ "type": "computed",
+ "value": "((IndividualB2CAuth || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/v1.0\" || CalledApiScopes != \"user.read\"))"
},
"GenerateGraph": {
- "type": "computed",
- "value": "(OrganizationalAuth && CallsMicrosoftGraph)"
+ "type": "computed",
+ "value": "(OrganizationalAuth && CallsMicrosoftGraph)"
},
"GenerateApiOrGraph": {
- "type": "computed",
- "value": "(GenerateApi || GenerateGraph)"
+ "type": "computed",
+ "value": "(GenerateApi || GenerateGraph)"
+ },
+ "DisableOpenAPI": {
+ "type": "parameter",
+ "dataType": "bool",
+ "defaultValue": "false",
+ "description": "Disable OpenAPI (Swagger) support"
+ },
+ "EnableOpenAPI": {
+ "type": "computed",
+ "value": "(!DisableOpenAPI)"
}
},
"primaryOutputs": [
@@ -294,4 +304,4 @@
"continueOnError": true
}
]
-}
+}
\ No newline at end of file
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/vs-2017.3.host.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/vs-2017.3.host.json
index 9e71ead6d7..e2241ce31a 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/vs-2017.3.host.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/vs-2017.3.host.json
@@ -49,6 +49,17 @@
"useHttps": true
}
],
+ "symbolInfo": [
+ {
+ "id": "DisableOpenAPI",
+ "name": {
+ "text": "Enable _OpenAPI support"
+ },
+ "invertBoolean": true,
+ "isVisible": true,
+ "defaultValue": true
+ }
+ ],
"excludeLaunchSettings": false,
"azureReplyUrlPortName": "HttpsPort",
"minFullFrameworkVersion": "4.6.1",
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Properties/launchSettings.json b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Properties/launchSettings.json
index c01e1f6b98..c346e6c26c 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Properties/launchSettings.json
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Properties/launchSettings.json
@@ -21,7 +21,11 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
+ //#if(EnableOpenAPI)
+ "launchUrl": "swagger",
+ //#else
"launchUrl": "weatherforecast",
+ //#endif
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@@ -30,7 +34,11 @@
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
+ //#if(EnableOpenAPI)
+ "launchUrl": "swagger",
+ //#else
"launchUrl": "weatherforecast",
+ //#endif
//#if(RequiresHttps)
"applicationUrl": "https://localhost:5001;http://localhost:5000",
//#else
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs
index 71568e5da0..0e935d107a 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs
@@ -26,6 +26,10 @@ using Microsoft.Extensions.Logging;
#if (GenerateGraph)
using Microsoft.Graph;
#endif
+#if (EnableOpenAPI)
+using Microsoft.OpenApi.Models;
+#endif
+
namespace Company.WebApplication1
{
public class Startup
@@ -71,6 +75,12 @@ namespace Company.WebApplication1
#endif
services.AddControllers();
+#if (EnableOpenAPI)
+ services.AddSwaggerGen(c =>
+ {
+ c.SwaggerDoc("v1", new OpenApiInfo { Title = "Company.WebApplication1", Version = "v1" });
+ });
+#endif
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -79,12 +89,15 @@ namespace Company.WebApplication1
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
+ #if (EnableOpenAPI)
+ app.UseSwagger();
+ app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Company.WebApplication1 v1"));
+ #endif
}
#if (RequiresHttps)
app.UseHttpsRedirection();
#endif
-
app.UseRouting();
#if (OrganizationalAuth || IndividualAuth)
diff --git a/src/ProjectTemplates/test/WebApiTemplateTest.cs b/src/ProjectTemplates/test/WebApiTemplateTest.cs
index 6ae0b1d450..3ed7ed94f4 100644
--- a/src/ProjectTemplates/test/WebApiTemplateTest.cs
+++ b/src/ProjectTemplates/test/WebApiTemplateTest.cs
@@ -39,6 +39,26 @@ namespace Templates.Test
[SkipOnHelix("Cert failures", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")]
public Task WebApiTemplateCSharp() => WebApiTemplateCore(languageOverride: null);
+ [ConditionalFact]
+ [SkipOnHelix("Cert failures", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")]
+ public async Task WebApiTemplateCSharp_WithoutOpenAPI()
+ {
+ Project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output);
+
+ var createResult = await Project.RunDotNetNewAsync("webapi", args: new[] { "--no-openapi" });
+ Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
+
+ var buildResult = await Project.RunDotNetBuildAsync();
+ Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
+
+ using var aspNetProcess = Project.StartBuiltProjectAsync();
+ Assert.False(
+ aspNetProcess.Process.HasExited,
+ ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
+
+ await aspNetProcess.AssertNotFound("swagger");
+ }
+
private async Task PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args)
{
Project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp") + Guid.NewGuid().ToString().Substring(0, 10).ToLower(), Output);
@@ -80,6 +100,7 @@ namespace Templates.Test
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
await aspNetProcess.AssertOk("weatherforecast");
+ await aspNetProcess.AssertOk("swagger");
await aspNetProcess.AssertNotFound("/");
}
@@ -91,6 +112,8 @@ namespace Templates.Test
await aspNetProcess.AssertOk("weatherforecast");
+ // Swagger is only available in Development
+ await aspNetProcess.AssertNotFound("swagger");
await aspNetProcess.AssertNotFound("/");
}
}