Skip to content

Commit 0960a7a

Browse files
authored
Configure OpenAPI as part of webapi project template creation (#25110)
* Configure OpenAPI as part of webapi project template creation Fixes #25080 * Update to default to WebAPI
1 parent 50815ed commit 0960a7a

File tree

9 files changed

+106
-34
lines changed

9 files changed

+106
-34
lines changed

eng/Versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@
274274
<SerilogSinksFilePackageVersion>4.0.0</SerilogSinksFilePackageVersion>
275275
<StackExchangeRedisPackageVersion>2.0.593</StackExchangeRedisPackageVersion>
276276
<SystemReactiveLinqPackageVersion>3.1.1</SystemReactiveLinqPackageVersion>
277+
<SwashbuckleAspNetCorePackageVersion>5.5.1</SwashbuckleAspNetCorePackageVersion>
277278
<XunitAbstractionsPackageVersion>2.0.3</XunitAbstractionsPackageVersion>
278279
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
279280
<XunitVersion>2.4.1</XunitVersion>

src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
MicrosoftNETCoreAppRuntimeVersion=$(MicrosoftNETCoreAppRuntimeVersion);
2424
SystemNetHttpJsonPackageVersion=$(SystemNetHttpJsonPackageVersion);
2525
MicrosoftGraphPackageVersion=$(MicrosoftGraphPackageVersion);
26+
SwashbuckleAspNetCorePackageVersion=$(SwashbuckleAspNetCorePackageVersion);
2627
</GeneratedContentProperties>
2728
</PropertyGroup>
2829

src/ProjectTemplates/Web.ProjectTemplates/WebApi-CSharp.csproj.in

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
<NoDefaultLaunchSettingsFile Condition="'$(ExcludeLaunchSettings)' == 'True'">True</NoDefaultLaunchSettingsFile>
77
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">Company.WebApplication1</RootNamespace>
88
</PropertyGroup>
9-
<!--#if (OrganizationalAuth || IndividualB2CAuth) -->
9+
<!--#if (OrganizationalAuth || IndividualB2CAuth || EnableOpenAPI) -->
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="${MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion}" NoWarn="NU1605" />
13-
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="${MicrosoftAspNetCoreAuthenticationOpenIdConnectPackageVersion}" NoWarn="NU1605" />
14-
<PackageReference Include="Microsoft.Identity.Web" Version="${MicrosoftIdentityWebPackageVersion}" />
15-
<PackageReference Include="Microsoft.Graph" Version="${MicrosoftGraphPackageVersion}" Condition=" '$(GenerateGraph)' == 'True' "/>
12+
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="${MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion}" NoWarn="NU1605" Condition="'$(OrganizationalAuth)' == 'True' OR '$(IndividualB2CAuth)' == 'True'"/>
13+
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="${MicrosoftAspNetCoreAuthenticationOpenIdConnectPackageVersion}" NoWarn="NU1605" Condition="'$(OrganizationalAuth)' == 'True' OR '$(IndividualB2CAuth)' == 'True'"/>
14+
<PackageReference Include="Microsoft.Identity.Web" Version="${MicrosoftIdentityWebPackageVersion}" Condition="'$(OrganizationalAuth)' == 'True' OR '$(IndividualB2CAuth)' == 'True'"/>
15+
<PackageReference Include="Microsoft.Graph" Version="${MicrosoftGraphPackageVersion}" Condition="'$(GenerateGraph)' == 'True'"/>
16+
<PackageReference Include="Swashbuckle.AspNetCore" Version="${SwashbuckleAspNetCorePackageVersion}" Condition="'$(EnableOpenAPI)' == 'True'" />
1617
</ItemGroup>
1718
<!--#endif -->
1819

src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/dotnetcli.host.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,23 @@
5757
"shortName": ""
5858
},
5959
"CalledApiUrl": {
60-
"longName": "called-api-url",
61-
"shortName": ""
60+
"longName": "called-api-url",
61+
"shortName": ""
6262
},
6363
"CalledApiScopes": {
64-
"longName": "called-api-scopes",
65-
"shortName": ""
64+
"longName": "called-api-scopes",
65+
"shortName": ""
6666
},
6767
"CallsMicrosoftGraph": {
68-
"longName": "calls-graph",
69-
"shortName": ""
68+
"longName": "calls-graph",
69+
"shortName": ""
70+
},
71+
"DisableOpenAPI": {
72+
"longName": "no-openapi",
73+
"shortName": ""
7074
}
7175
},
7276
"usageExamples": [
7377
""
7478
]
75-
}
79+
}

src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/template.json

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939
},
4040
{
4141
"condition": "(!GenerateApi)",
42-
"exclude": [
43-
"Services/DownstreamWebApi.cs"
44-
]
42+
"exclude": [
43+
"Services/DownstreamWebApi.cs"
44+
]
4545
},
4646
{
4747
"condition": "(!GenerateGraph)",
4848
"exclude": [
49-
"Services/MicrosoftGraphServiceExtensions.cs",
49+
"Services/MicrosoftGraphServiceExtensions.cs",
5050
"Services/TokenAcquisitionCredentialProvider.cs"
5151
]
5252
}
@@ -244,35 +244,45 @@
244244
"defaultValue": "false"
245245
},
246246
"CalledApiUrl": {
247-
"type": "parameter",
248-
"datatype": "string",
249-
"replaces": "[WebApiUrl]",
250-
"defaultValue" : "https://graph.microsoft.com/v1.0",
251-
"description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
247+
"type": "parameter",
248+
"datatype": "string",
249+
"replaces": "[WebApiUrl]",
250+
"defaultValue": "https://graph.microsoft.com/v1.0",
251+
"description": "URL of the API to call from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
252252
},
253253
"CallsMicrosoftGraph": {
254-
"type": "parameter",
255-
"datatype": "bool",
256-
"defaultValue": "false",
257-
"description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified."
254+
"type": "parameter",
255+
"datatype": "bool",
256+
"defaultValue": "false",
257+
"description": "Specifies if the web app calls Microsoft Graph. This option only applies if --auth SingleOrg is specified."
258258
},
259259
"CalledApiScopes": {
260260
"type": "parameter",
261261
"datatype": "string",
262-
"replaces" : "user.read",
262+
"replaces": "user.read",
263263
"description": "Scopes to request to call the API from the web app. This option only applies if --auth SingleOrg or --auth IndividualB2C is specified."
264264
},
265265
"GenerateApi": {
266-
"type": "computed",
267-
"value": "((IndividualB2CAuth || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/v1.0\" || CalledApiScopes != \"user.read\"))"
266+
"type": "computed",
267+
"value": "((IndividualB2CAuth || OrganizationalAuth) && (CalledApiUrl != \"https://graph.microsoft.com/v1.0\" || CalledApiScopes != \"user.read\"))"
268268
},
269269
"GenerateGraph": {
270-
"type": "computed",
271-
"value": "(OrganizationalAuth && CallsMicrosoftGraph)"
270+
"type": "computed",
271+
"value": "(OrganizationalAuth && CallsMicrosoftGraph)"
272272
},
273273
"GenerateApiOrGraph": {
274-
"type": "computed",
275-
"value": "(GenerateApi || GenerateGraph)"
274+
"type": "computed",
275+
"value": "(GenerateApi || GenerateGraph)"
276+
},
277+
"DisableOpenAPI": {
278+
"type": "parameter",
279+
"dataType": "bool",
280+
"defaultValue": "false",
281+
"description": "Disable OpenAPI (Swagger) support"
282+
},
283+
"EnableOpenAPI": {
284+
"type": "computed",
285+
"value": "(!DisableOpenAPI)"
276286
}
277287
},
278288
"primaryOutputs": [
@@ -294,4 +304,4 @@
294304
"continueOnError": true
295305
}
296306
]
297-
}
307+
}

src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/.template.config/vs-2017.3.host.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@
4949
"useHttps": true
5050
}
5151
],
52+
"symbolInfo": [
53+
{
54+
"id": "DisableOpenAPI",
55+
"name": {
56+
"text": "Enable _OpenAPI support"
57+
},
58+
"invertBoolean": true,
59+
"isVisible": true,
60+
"defaultValue": true
61+
}
62+
],
5263
"excludeLaunchSettings": false,
5364
"azureReplyUrlPortName": "HttpsPort",
5465
"minFullFrameworkVersion": "4.6.1",

src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Properties/launchSettings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
"IIS Express": {
2222
"commandName": "IISExpress",
2323
"launchBrowser": true,
24+
//#if(EnableOpenAPI)
25+
"launchUrl": "swagger",
26+
//#else
2427
"launchUrl": "weatherforecast",
28+
//#endif
2529
"environmentVariables": {
2630
"ASPNETCORE_ENVIRONMENT": "Development"
2731
}
@@ -30,7 +34,11 @@
3034
"commandName": "Project",
3135
"dotnetRunMessages": "true",
3236
"launchBrowser": true,
37+
//#if(EnableOpenAPI)
38+
"launchUrl": "swagger",
39+
//#else
3340
"launchUrl": "weatherforecast",
41+
//#endif
3442
//#if(RequiresHttps)
3543
"applicationUrl": "https://localhost:5001;http://localhost:5000",
3644
//#else

src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
#if (GenerateGraph)
2727
using Microsoft.Graph;
2828
#endif
29+
#if (EnableOpenAPI)
30+
using Microsoft.OpenApi.Models;
31+
#endif
32+
2933
namespace Company.WebApplication1
3034
{
3135
public class Startup
@@ -71,6 +75,12 @@ public void ConfigureServices(IServiceCollection services)
7175
#endif
7276

7377
services.AddControllers();
78+
#if (EnableOpenAPI)
79+
services.AddSwaggerGen(c =>
80+
{
81+
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Company.WebApplication1", Version = "v1" });
82+
});
83+
#endif
7484
}
7585

7686
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -79,12 +89,15 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
7989
if (env.IsDevelopment())
8090
{
8191
app.UseDeveloperExceptionPage();
92+
#if (EnableOpenAPI)
93+
app.UseSwagger();
94+
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Company.WebApplication1 v1"));
95+
#endif
8296
}
8397
#if (RequiresHttps)
8498

8599
app.UseHttpsRedirection();
86100
#endif
87-
88101
app.UseRouting();
89102

90103
#if (OrganizationalAuth || IndividualAuth)

src/ProjectTemplates/test/WebApiTemplateTest.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ public WebApiTemplateTest(ProjectFactoryFixture factoryFixture, ITestOutputHelpe
3939
[SkipOnHelix("Cert failures", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")]
4040
public Task WebApiTemplateCSharp() => WebApiTemplateCore(languageOverride: null);
4141

42+
[ConditionalFact]
43+
[SkipOnHelix("Cert failures", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")]
44+
public async Task WebApiTemplateCSharp_WithoutOpenAPI()
45+
{
46+
Project = await FactoryFixture.GetOrCreateProject("webapinoopenapi", Output);
47+
48+
var createResult = await Project.RunDotNetNewAsync("webapi", args: new[] { "--no-openapi" });
49+
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
50+
51+
var buildResult = await Project.RunDotNetBuildAsync();
52+
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
53+
54+
using var aspNetProcess = Project.StartBuiltProjectAsync();
55+
Assert.False(
56+
aspNetProcess.Process.HasExited,
57+
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
58+
59+
await aspNetProcess.AssertNotFound("swagger");
60+
}
61+
4262
private async Task PublishAndBuildWebApiTemplate(string languageOverride, string auth, string[] args)
4363
{
4464
Project = await FactoryFixture.GetOrCreateProject("webapi" + (languageOverride == "F#" ? "fsharp" : "csharp") + Guid.NewGuid().ToString().Substring(0, 10).ToLower(), Output);
@@ -80,6 +100,7 @@ private async Task WebApiTemplateCore(string languageOverride)
80100
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
81101

82102
await aspNetProcess.AssertOk("weatherforecast");
103+
await aspNetProcess.AssertOk("swagger");
83104
await aspNetProcess.AssertNotFound("/");
84105
}
85106

@@ -91,6 +112,8 @@ private async Task WebApiTemplateCore(string languageOverride)
91112

92113

93114
await aspNetProcess.AssertOk("weatherforecast");
115+
// Swagger is only available in Development
116+
await aspNetProcess.AssertNotFound("swagger");
94117
await aspNetProcess.AssertNotFound("/");
95118
}
96119
}

0 commit comments

Comments
 (0)