Skip to content

Commit b1389ec

Browse files
authored
Merge pull request #43 from damienbod/dev
.NET 10 APIs sample
2 parents 941f889 + 81cba37 commit b1389ec

File tree

12 files changed

+173
-103
lines changed

12 files changed

+173
-103
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.OpenApi;
3+
using Microsoft.OpenApi;
4+
5+
namespace UserApiOne;
6+
7+
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
8+
{
9+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
10+
{
11+
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
12+
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
13+
{
14+
var requirements = new Dictionary<string, IOpenApiSecurityScheme>
15+
{
16+
["Bearer"] = new OpenApiSecurityScheme
17+
{
18+
Type = SecuritySchemeType.Http,
19+
Scheme = "bearer", // "bearer" refers to the header name here
20+
In = ParameterLocation.Header,
21+
BearerFormat = "Json Web Token"
22+
}
23+
};
24+
document.Components ??= new OpenApiComponents();
25+
document.Components.SecuritySchemes = requirements;
26+
}
27+
document.Info = new()
28+
{
29+
Title = "My API Bearer scheme",
30+
Version = "v1",
31+
Description = "API for Damien"
32+
};
33+
}
34+
}

DownstreamApis/UserApiOne/Program.cs

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Mvc.Authorization;
44
using Microsoft.Identity.Web;
5-
using Microsoft.OpenApi.Models;
5+
using Microsoft.OpenApi;
66
using UserApiOne;
77

88
var builder = WebApplication.CreateBuilder(args);
@@ -17,41 +17,19 @@
1717
.EnableTokenAcquisitionToCallDownstreamApi()
1818
.AddDistributedTokenCaches();
1919

20-
builder.Services.AddSwaggerGen(c =>
20+
builder.Services.AddOpenApi(options =>
2121
{
22-
// add JWT Authentication
23-
var securityScheme = new OpenApiSecurityScheme
24-
{
25-
Name = "JWT Authentication",
26-
Description = "Enter JWT Bearer token **_only_**",
27-
In = ParameterLocation.Header,
28-
Type = SecuritySchemeType.Http,
29-
Scheme = "bearer", // must be lower case
30-
BearerFormat = "JWT",
31-
Reference = new OpenApiReference
32-
{
33-
Id = JwtBearerDefaults.AuthenticationScheme,
34-
Type = ReferenceType.SecurityScheme
35-
}
36-
};
37-
c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
38-
c.AddSecurityRequirement(new OpenApiSecurityRequirement
39-
{
40-
{securityScheme, Array.Empty<string>()}
41-
});
42-
43-
c.SwaggerDoc("v1", new OpenApiInfo
44-
{
45-
Title = "User API One",
46-
Version = "v1",
47-
Description = "User API One",
48-
Contact = new OpenApiContact
49-
{
50-
Name = "damienbod",
51-
Email = string.Empty,
52-
Url = new Uri("https://damienbod.com/"),
53-
},
54-
});
22+
//options.UseTransformer((document, context, cancellationToken) =>
23+
//{
24+
// document.Info = new()
25+
// {
26+
// Title = "My API",
27+
// Version = "v1",
28+
// Description = "API for Damien"
29+
// };
30+
// return Task.CompletedTask;
31+
//});
32+
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
5533
});
5634

5735
builder.Services.AddControllers(options =>
@@ -71,13 +49,6 @@
7149
app.UseHsts();
7250
}
7351

74-
app.UseSwagger();
75-
app.UseSwaggerUI(c =>
76-
{
77-
c.SwaggerEndpoint("/swagger/v1/swagger.json", "User API Two");
78-
c.RoutePrefix = string.Empty;
79-
});
80-
8152
app.UseHttpsRedirection();
8253

8354
app.UseRouting();
@@ -87,4 +58,14 @@
8758

8859
app.MapControllers();
8960

61+
app.MapOpenApi("/openapi/v1/openapi.json");
62+
63+
if (app.Environment.IsDevelopment())
64+
{
65+
app.UseSwaggerUI(options =>
66+
{
67+
options.SwaggerEndpoint("/openapi/v1/openapi.json", "v1");
68+
});
69+
}
70+
9071
app.Run();

DownstreamApis/UserApiOne/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"UserApiOne": {
44
"commandName": "Project",
55
"launchBrowser": true,
6-
"launchUrl": "",
6+
"launchUrl": "swagger",
77
"environmentVariables": {
88
"ASPNETCORE_ENVIRONMENT": "Development"
99
},
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net9.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<UserSecretsId>aspnet-UserApiOne-2ba0bbf9-49f5-452e-8333-1e33a467b74e</UserSecretsId>
66
<Nullable>enable</Nullable>
77
<ImplicitUsings>enable</ImplicitUsings>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.Identity.Web" Version="3.7.0" />
12-
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
11+
<PackageReference Include="Microsoft.Identity.Web" Version="4.1.1" />
12+
13+
<PackageReference Include="NetEscapades.AspNetCore.SecurityHeaders" Version="1.3.0" />
14+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
15+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.0.1" />
1316
</ItemGroup>
1417

1518
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.OpenApi;
3+
using Microsoft.OpenApi;
4+
5+
namespace UserApiTwo;
6+
7+
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
8+
{
9+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
10+
{
11+
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
12+
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
13+
{
14+
var requirements = new Dictionary<string, IOpenApiSecurityScheme>
15+
{
16+
["Bearer"] = new OpenApiSecurityScheme
17+
{
18+
Type = SecuritySchemeType.Http,
19+
Scheme = "bearer", // "bearer" refers to the header name here
20+
In = ParameterLocation.Header,
21+
BearerFormat = "Json Web Token"
22+
}
23+
};
24+
document.Components ??= new OpenApiComponents();
25+
document.Components.SecuritySchemes = requirements;
26+
}
27+
document.Info = new()
28+
{
29+
Title = "My API Bearer scheme",
30+
Version = "v1",
31+
Description = "API for Damien"
32+
};
33+
}
34+
}

DownstreamApis/UserApiTwo/Program.cs

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
using Microsoft.AspNetCore.Mvc.Authorization;
44
using Microsoft.Identity.Web;
55
using Microsoft.IdentityModel.JsonWebTokens;
6-
using Microsoft.OpenApi.Models;
6+
using Microsoft.OpenApi;
7+
using UserApiTwo;
78

89
var builder = WebApplication.CreateBuilder(args);
910

@@ -13,41 +14,19 @@
1314
builder.Services.AddMicrosoftIdentityWebApiAuthentication(
1415
builder.Configuration, "AzureAd");
1516

16-
builder.Services.AddSwaggerGen(c =>
17+
builder.Services.AddOpenApi(options =>
1718
{
18-
// add JWT Authentication
19-
var securityScheme = new OpenApiSecurityScheme
20-
{
21-
Name = "JWT Authentication",
22-
Description = "Enter JWT Bearer token **_only_**",
23-
In = ParameterLocation.Header,
24-
Type = SecuritySchemeType.Http,
25-
Scheme = "bearer", // must be lower case
26-
BearerFormat = "JWT",
27-
Reference = new OpenApiReference
28-
{
29-
Id = JwtBearerDefaults.AuthenticationScheme,
30-
Type = ReferenceType.SecurityScheme
31-
}
32-
};
33-
c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
34-
c.AddSecurityRequirement(new OpenApiSecurityRequirement
35-
{
36-
{securityScheme, Array.Empty<string>()}
37-
});
38-
39-
c.SwaggerDoc("v1", new OpenApiInfo
40-
{
41-
Title = "User API Two",
42-
Version = "v1",
43-
Description = "User API Two",
44-
Contact = new OpenApiContact
45-
{
46-
Name = "damienbod",
47-
Email = string.Empty,
48-
Url = new Uri("https://damienbod.com/"),
49-
},
50-
});
19+
//options.UseTransformer((document, context, cancellationToken) =>
20+
//{
21+
// document.Info = new()
22+
// {
23+
// Title = "My API",
24+
// Version = "v1",
25+
// Description = "API for Damien"
26+
// };
27+
// return Task.CompletedTask;
28+
//});
29+
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
5130
});
5231

5332
builder.Services.AddControllers(options =>
@@ -69,13 +48,6 @@
6948
app.UseHsts();
7049
}
7150

72-
app.UseSwagger();
73-
app.UseSwaggerUI(c =>
74-
{
75-
c.SwaggerEndpoint("/swagger/v1/swagger.json", "User API Two");
76-
c.RoutePrefix = string.Empty;
77-
});
78-
7951
app.UseHttpsRedirection();
8052

8153
app.UseRouting();
@@ -85,4 +57,14 @@
8557

8658
app.MapControllers();
8759

60+
app.MapOpenApi("/openapi/v1/openapi.json");
61+
62+
if (app.Environment.IsDevelopment())
63+
{
64+
app.UseSwaggerUI(options =>
65+
{
66+
options.SwaggerEndpoint("/openapi/v1/openapi.json", "v1");
67+
});
68+
}
69+
8870
app.Run();

DownstreamApis/UserApiTwo/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"UserApiTwo": {
44
"commandName": "Project",
55
"launchBrowser": true,
6-
"launchUrl": "",
6+
"launchUrl": "swagger",
77
"environmentVariables": {
88
"ASPNETCORE_ENVIRONMENT": "Development"
99
},
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net9.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Identity.Web" Version="3.7.0" />
11-
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
10+
<PackageReference Include="Microsoft.Identity.Web" Version="4.1.1" />
11+
12+
<PackageReference Include="NetEscapades.AspNetCore.SecurityHeaders" Version="1.3.0" />
13+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
14+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.0.1" />
1215
</ItemGroup>
1316

1417
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.OpenApi;
3+
using Microsoft.OpenApi;
4+
5+
namespace WebAppUserApis;
6+
7+
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
8+
{
9+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
10+
{
11+
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
12+
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
13+
{
14+
var requirements = new Dictionary<string, IOpenApiSecurityScheme>
15+
{
16+
["Bearer"] = new OpenApiSecurityScheme
17+
{
18+
Type = SecuritySchemeType.Http,
19+
Scheme = "bearer", // "bearer" refers to the header name here
20+
In = ParameterLocation.Header,
21+
BearerFormat = "Json Web Token"
22+
}
23+
};
24+
document.Components ??= new OpenApiComponents();
25+
document.Components.SecuritySchemes = requirements;
26+
}
27+
document.Info = new()
28+
{
29+
Title = "My API Bearer scheme",
30+
Version = "v1",
31+
Description = "API for Damien"
32+
};
33+
}
34+
}

DownstreamApis/WebAppUserApis/CallUserApiOne/UserApiOneService.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.Identity.Web;
2-
using Newtonsoft.Json.Linq;
32
using System.Net.Http.Headers;
43

54
namespace WebAppUserApis;
@@ -19,7 +18,7 @@ public UserApiOneService(IHttpClientFactory clientFactory,
1918
_configuration = configuration;
2019
}
2120

22-
public async Task<JArray> GetApiDataAsync()
21+
public async Task<string> GetApiDataAsync()
2322
{
2423

2524
var client = _clientFactory.CreateClient();
@@ -40,9 +39,7 @@ public async Task<JArray> GetApiDataAsync()
4039
if (response.IsSuccessStatusCode)
4140
{
4241
var responseContent = await response.Content.ReadAsStringAsync();
43-
var data = JArray.Parse(responseContent);
44-
45-
return data;
42+
return responseContent;
4643
}
4744

4845
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");

0 commit comments

Comments
 (0)