├── .github
└── workflows
│ └── dotnet.yml
├── .gitignore
├── MinimalApiDemo.AWSLambdaHosting
├── 6.MinimalApiDemo.AWSLambdaHosting.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── appsettings.Development.json
└── appsettings.json
├── MinimalApiDemo.BasicJWT
├── 1.MinimalApiDemo.BasicJWT.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── appsettings.Development.json
└── appsettings.json
├── MinimalApiDemo.DIExample
├── 2.MinimalApiDemo.DIExample.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Services
│ ├── ITokenService.cs
│ └── TokenService.cs
├── appsettings.Development.json
└── appsettings.json
├── MinimalApiDemo.EndpointsRespones
├── 4.MinimalApiDemo.MinimalApiDemo.EndpointsResponses.csproj
├── Endpoints
│ ├── AppointmentEndpoints.cs
│ └── TokenEndpoints.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Services
│ ├── ITokenService.cs
│ └── TokenService.cs
├── appsettings.Development.json
├── appsettings.json
└── test_image.png
├── MinimalApiDemo.Logging
├── 5.MinimalApiDemo.MinimalApiDemo.Logging.csproj
├── Endpoints
│ ├── AppointmentEndpoints.cs
│ └── TokenEndpoints.cs
├── Extensions
│ ├── SimpleFileLogger.cs
│ ├── SimpleFileLoggerExtension.cs
│ └── SimpleFileLoggerProvider.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Services
│ ├── ITokenService.cs
│ └── TokenService.cs
├── appsettings.Development.json
├── appsettings.json
└── test_image.png
├── MinimalApiDemo.Slicing
├── 3.MinimalApiDemo.SlicingEndpoints.csproj
├── Endpoints
│ ├── AppointmentEndpoints.cs
│ └── TokenEndpoints.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Services
│ ├── ITokenService.cs
│ └── TokenService.cs
├── appsettings.Development.json
└── appsettings.json
├── MinimalApiDemo.sln
└── README.md
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v2
18 | with:
19 | dotnet-version: 6.0.x
20 | - name: Restore dependencies
21 | run: dotnet restore
22 | - name: Build
23 | run: dotnet build --no-restore
24 | - name: Test
25 | run: dotnet test --no-build --verbosity normal
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # globs
2 | Makefile.in
3 | *.userprefs
4 | *.usertasks
5 | config.make
6 | config.status
7 | aclocal.m4
8 | install-sh
9 | autom4te.cache/
10 | *.tar.gz
11 | tarballs/
12 | test-results/
13 |
14 | # Mac bundle stuff
15 | *.dmg
16 | *.app
17 |
18 | # content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
19 | # General
20 | .DS_Store
21 | .AppleDouble
22 | .LSOverride
23 |
24 | # Icon must end with two \r
25 | Icon
26 |
27 |
28 | # Thumbnails
29 | ._*
30 |
31 | # Files that might appear in the root of a volume
32 | .DocumentRevisions-V100
33 | .fseventsd
34 | .Spotlight-V100
35 | .TemporaryItems
36 | .Trashes
37 | .VolumeIcon.icns
38 | .com.apple.timemachine.donotpresent
39 |
40 | # Directories potentially created on remote AFP share
41 | .AppleDB
42 | .AppleDesktop
43 | Network Trash Folder
44 | Temporary Items
45 | .apdisk
46 |
47 | # content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
48 | # Windows thumbnail cache files
49 | Thumbs.db
50 | ehthumbs.db
51 | ehthumbs_vista.db
52 |
53 | # Dump file
54 | *.stackdump
55 |
56 | # Folder config file
57 | [Dd]esktop.ini
58 |
59 | # Recycle Bin used on file shares
60 | $RECYCLE.BIN/
61 |
62 | # Windows Installer files
63 | *.cab
64 | *.msi
65 | *.msix
66 | *.msm
67 | *.msp
68 |
69 | # Windows shortcuts
70 | *.lnk
71 |
72 | # content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
73 | ## Ignore Visual Studio temporary files, build results, and
74 | ## files generated by popular Visual Studio add-ons.
75 | ##
76 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
77 |
78 | # User-specific files
79 | *.suo
80 | *.user
81 | *.userosscache
82 | *.sln.docstates
83 |
84 | # User-specific files (MonoDevelop/Xamarin Studio)
85 | *.userprefs
86 |
87 | # Build results
88 | [Dd]ebug/
89 | [Dd]ebugPublic/
90 | [Rr]elease/
91 | [Rr]eleases/
92 | x64/
93 | x86/
94 | bld/
95 | [Bb]in/
96 | [Oo]bj/
97 | [Ll]og/
98 |
99 | # Visual Studio 2015/2017 cache/options directory
100 | .vs/
101 | # Uncomment if you have tasks that create the project's static files in wwwroot
102 | #wwwroot/
103 |
104 | # Visual Studio 2017 auto generated files
105 | Generated\ Files/
106 |
107 | # MSTest test Results
108 | [Tt]est[Rr]esult*/
109 | [Bb]uild[Ll]og.*
110 |
111 | # NUNIT
112 | *.VisualState.xml
113 | TestResult.xml
114 |
115 | # Build Results of an ATL Project
116 | [Dd]ebugPS/
117 | [Rr]eleasePS/
118 | dlldata.c
119 |
120 | # Benchmark Results
121 | BenchmarkDotNet.Artifacts/
122 |
123 | # .NET Core
124 | project.lock.json
125 | project.fragment.lock.json
126 | artifacts/
127 |
128 | # StyleCop
129 | StyleCopReport.xml
130 |
131 | # Files built by Visual Studio
132 | *_i.c
133 | *_p.c
134 | *_h.h
135 | *.ilk
136 | *.meta
137 | *.obj
138 | *.iobj
139 | *.pch
140 | *.pdb
141 | *.ipdb
142 | *.pgc
143 | *.pgd
144 | *.rsp
145 | *.sbr
146 | *.tlb
147 | *.tli
148 | *.tlh
149 | *.tmp
150 | *.tmp_proj
151 | *_wpftmp.csproj
152 | *.log
153 | *.vspscc
154 | *.vssscc
155 | .builds
156 | *.pidb
157 | *.svclog
158 | *.scc
159 |
160 | # Chutzpah Test files
161 | _Chutzpah*
162 |
163 | # Visual C++ cache files
164 | ipch/
165 | *.aps
166 | *.ncb
167 | *.opendb
168 | *.opensdf
169 | *.sdf
170 | *.cachefile
171 | *.VC.db
172 | *.VC.VC.opendb
173 |
174 | # Visual Studio profiler
175 | *.psess
176 | *.vsp
177 | *.vspx
178 | *.sap
179 |
180 | # Visual Studio Trace Files
181 | *.e2e
182 |
183 | # TFS 2012 Local Workspace
184 | $tf/
185 |
186 | # Guidance Automation Toolkit
187 | *.gpState
188 |
189 | # ReSharper is a .NET coding add-in
190 | _ReSharper*/
191 | *.[Rr]e[Ss]harper
192 | *.DotSettings.user
193 |
194 | # JustCode is a .NET coding add-in
195 | .JustCode
196 |
197 | # TeamCity is a build add-in
198 | _TeamCity*
199 |
200 | # DotCover is a Code Coverage Tool
201 | *.dotCover
202 |
203 | # AxoCover is a Code Coverage Tool
204 | .axoCover/*
205 | !.axoCover/settings.json
206 |
207 | # Visual Studio code coverage results
208 | *.coverage
209 | *.coveragexml
210 |
211 | # NCrunch
212 | _NCrunch_*
213 | .*crunch*.local.xml
214 | nCrunchTemp_*
215 |
216 | # MightyMoose
217 | *.mm.*
218 | AutoTest.Net/
219 |
220 | # Web workbench (sass)
221 | .sass-cache/
222 |
223 | # Installshield output folder
224 | [Ee]xpress/
225 |
226 | # DocProject is a documentation generator add-in
227 | DocProject/buildhelp/
228 | DocProject/Help/*.HxT
229 | DocProject/Help/*.HxC
230 | DocProject/Help/*.hhc
231 | DocProject/Help/*.hhk
232 | DocProject/Help/*.hhp
233 | DocProject/Help/Html2
234 | DocProject/Help/html
235 |
236 | # Click-Once directory
237 | publish/
238 |
239 | # Publish Web Output
240 | *.[Pp]ublish.xml
241 | *.azurePubxml
242 | # Note: Comment the next line if you want to checkin your web deploy settings,
243 | # but database connection strings (with potential passwords) will be unencrypted
244 | *.pubxml
245 | *.publishproj
246 |
247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
248 | # checkin your Azure Web App publish settings, but sensitive information contained
249 | # in these scripts will be unencrypted
250 | PublishScripts/
251 |
252 | # NuGet Packages
253 | *.nupkg
254 | # The packages folder can be ignored because of Package Restore
255 | **/[Pp]ackages/*
256 | # except build/, which is used as an MSBuild target.
257 | !**/[Pp]ackages/build/
258 | # Uncomment if necessary however generally it will be regenerated when needed
259 | #!**/[Pp]ackages/repositories.config
260 | # NuGet v3's project.json files produces more ignorable files
261 | *.nuget.props
262 | *.nuget.targets
263 |
264 | # Microsoft Azure Build Output
265 | csx/
266 | *.build.csdef
267 |
268 | # Microsoft Azure Emulator
269 | ecf/
270 | rcf/
271 |
272 | # Windows Store app package directories and files
273 | AppPackages/
274 | BundleArtifacts/
275 | Package.StoreAssociation.xml
276 | _pkginfo.txt
277 | *.appx
278 |
279 | # Visual Studio cache files
280 | # files ending in .cache can be ignored
281 | *.[Cc]ache
282 | # but keep track of directories ending in .cache
283 | !*.[Cc]ache/
284 |
285 | # Others
286 | ClientBin/
287 | ~$*
288 | *~
289 | *.dbmdl
290 | *.dbproj.schemaview
291 | *.jfm
292 | *.pfx
293 | *.publishsettings
294 | orleans.codegen.cs
295 |
296 | # Including strong name files can present a security risk
297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
298 | #*.snk
299 |
300 | # Since there are multiple workflows, uncomment next line to ignore bower_components
301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
302 | #bower_components/
303 |
304 | # RIA/Silverlight projects
305 | Generated_Code/
306 |
307 | # Backup & report files from converting an old project file
308 | # to a newer Visual Studio version. Backup files are not needed,
309 | # because we have git ;-)
310 | _UpgradeReport_Files/
311 | Backup*/
312 | UpgradeLog*.XML
313 | UpgradeLog*.htm
314 | ServiceFabricBackup/
315 | *.rptproj.bak
316 |
317 | # SQL Server files
318 | *.mdf
319 | *.ldf
320 | *.ndf
321 |
322 | # Business Intelligence projects
323 | *.rdl.data
324 | *.bim.layout
325 | *.bim_*.settings
326 | *.rptproj.rsuser
327 |
328 | # Microsoft Fakes
329 | FakesAssemblies/
330 |
331 | # GhostDoc plugin setting file
332 | *.GhostDoc.xml
333 |
334 | # Node.js Tools for Visual Studio
335 | .ntvs_analysis.dat
336 | node_modules/
337 |
338 | # Visual Studio 6 build log
339 | *.plg
340 |
341 | # Visual Studio 6 workspace options file
342 | *.opt
343 |
344 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
345 | *.vbw
346 |
347 | # Visual Studio LightSwitch build output
348 | **/*.HTMLClient/GeneratedArtifacts
349 | **/*.DesktopClient/GeneratedArtifacts
350 | **/*.DesktopClient/ModelManifest.xml
351 | **/*.Server/GeneratedArtifacts
352 | **/*.Server/ModelManifest.xml
353 | _Pvt_Extensions
354 |
355 | # Paket dependency manager
356 | .paket/paket.exe
357 | paket-files/
358 |
359 | # FAKE - F# Make
360 | .fake/
361 |
362 | # JetBrains Rider
363 | .idea/
364 | *.sln.iml
365 |
366 | # CodeRush personal settings
367 | .cr/personal
368 |
369 | # Python Tools for Visual Studio (PTVS)
370 | __pycache__/
371 | *.pyc
372 |
373 | # Cake - Uncomment if you are using it
374 | # tools/**
375 | # !tools/packages.config
376 |
377 | # Tabs Studio
378 | *.tss
379 |
380 | # Telerik's JustMock configuration file
381 | *.jmconfig
382 |
383 | # BizTalk build output
384 | *.btp.cs
385 | *.btm.cs
386 | *.odx.cs
387 | *.xsd.cs
388 |
389 | # OpenCover UI analysis results
390 | OpenCover/
391 |
392 | # Azure Stream Analytics local run output
393 | ASALocalRun/
394 |
395 | # MSBuild Binary and Structured Log
396 | *.binlog
397 |
398 | # NVidia Nsight GPU debugger configuration file
399 | *.nvuser
400 |
401 | # MFractors (Xamarin productivity tool) working folder
402 | .mfractor/
403 |
404 | # Local History for Visual Studio
405 | .localhistory/
--------------------------------------------------------------------------------
/MinimalApiDemo.AWSLambdaHosting/6.MinimalApiDemo.AWSLambdaHosting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | _6.MinimalApiDemo.AWSLambdaHosting
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/MinimalApiDemo.AWSLambdaHosting/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);
4 |
5 | var app = builder.Build();
6 |
7 | app.MapGet("/", () => "Hello Lambda");
8 |
9 | app.Run();
--------------------------------------------------------------------------------
/MinimalApiDemo.AWSLambdaHosting/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:34138",
8 | "sslPort": 0
9 | }
10 | },
11 | "profiles": {
12 | "_6.MinimalApiDemo.AWSLambdaHosting": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "weatherforecast",
17 | "applicationUrl": "http://localhost:5149",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "weatherforecast",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
32 |
33 |
34 |
--------------------------------------------------------------------------------
/MinimalApiDemo.AWSLambdaHosting/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/MinimalApiDemo.AWSLambdaHosting/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/MinimalApiDemo.BasicJWT/1.MinimalApiDemo.BasicJWT.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/MinimalApiDemo.BasicJWT/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authentication.JwtBearer;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.IdentityModel.Tokens;
4 | using Microsoft.OpenApi.Models;
5 | using System.IdentityModel.Tokens.Jwt;
6 | using System.Security.Claims;
7 | using System.Text;
8 |
9 | var builder = WebApplication.CreateBuilder(args);
10 |
11 | const string _issuer = "pp";
12 | const string _audience = "pp";
13 | const string _secret = "supersecretkey :)";
14 |
15 | builder.Services.AddEndpointsApiExplorer();
16 | builder.Services.AddSwaggerGen(s =>
17 | {
18 | s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
19 | {
20 | Name = "Authorization",
21 | Type = SecuritySchemeType.ApiKey,
22 | Scheme = "Bearer",
23 | BearerFormat = "JWT",
24 | In = ParameterLocation.Header,
25 | Description = "JSON Web Token",
26 | });
27 |
28 | s.AddSecurityRequirement(new OpenApiSecurityRequirement() {{new OpenApiSecurityScheme {Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty()}});
29 | });
30 |
31 | builder.Services.AddAuthorization();
32 | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
33 | {
34 | options.TokenValidationParameters = new TokenValidationParameters()
35 | {
36 | ValidateActor = true,
37 | ValidateAudience = true,
38 | ValidateLifetime = true,
39 | ValidateIssuerSigningKey = true,
40 | ValidIssuer = _issuer,
41 | ValidAudience = _audience,
42 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret))
43 | };
44 | });
45 | var app = builder.Build();
46 |
47 | if (app.Environment.IsDevelopment())
48 | {
49 | app.UseSwagger();
50 | app.UseSwaggerUI();
51 | }
52 |
53 | app.UseHttpsRedirection();
54 | app.UseAuthentication();
55 | app.UseAuthorization();
56 |
57 |
58 | app.MapGet("/login", (string login, string password, HttpContext http) =>
59 | {
60 | //checking login & password - for demo open for all users :)
61 | var claims = new[] {
62 | new Claim(ClaimTypes.Actor, login),
63 | new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString())
64 | };
65 |
66 | var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret));
67 | var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
68 | var tokenDescriptor = new JwtSecurityToken(_issuer, _audience, claims,
69 | expires: DateTime.Now.Add(new TimeSpan(0, 5, 0)), signingCredentials: credentials);
70 | return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
71 | })
72 | .WithName("GetToken");
73 |
74 |
75 | app.MapGet("/dashboard", [Authorize] () => "Welcome to the secret Dashboard");
76 |
77 | app.Run();
--------------------------------------------------------------------------------
/MinimalApiDemo.BasicJWT/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:21500",
8 | "sslPort": 44395
9 | }
10 | },
11 | "profiles": {
12 | "MinimalApiDemo.EndpointsResponses": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "https://localhost:7123;http://localhost:5198",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "swagger",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
32 |
33 |
34 |
--------------------------------------------------------------------------------
/MinimalApiDemo.BasicJWT/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "SecurityKey": "My Super Secret",
9 | "Issuer": "pp",
10 | "Audience": "pp"
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/MinimalApiDemo.BasicJWT/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/2.MinimalApiDemo.DIExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | MinimalApiDemo.DIExample
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Authentication.JwtBearer;
3 | using Microsoft.AspNetCore.Authorization;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.OpenApi.Models;
6 | using MinimalApiDemo;
7 |
8 | var builder = WebApplication.CreateBuilder(args);
9 |
10 | var tokenSettingsSection = builder.Configuration.GetSection("TokenSettings");
11 |
12 | builder.Services.Configure(tokenSettingsSection);
13 | // or if you like AddOptions
14 |
15 | builder.Services.AddOptions().BindConfiguration("TokenSettings");
16 |
17 | var tokenSettings = tokenSettingsSection.Get();
18 | string issuer = tokenSettings.Issuer;
19 | string audience = tokenSettings.Audience;
20 | string secret = tokenSettings.SecurityKey;
21 |
22 |
23 | builder.Services.AddEndpointsApiExplorer();
24 | builder.Services.AddSwaggerGen(s =>
25 | {
26 | s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
27 | {
28 | Name = "Authorization",
29 | Type = SecuritySchemeType.ApiKey,
30 | Scheme = "Bearer",
31 | BearerFormat = "JWT",
32 | In = ParameterLocation.Header,
33 | Description = "JSON Web Token",
34 | });
35 |
36 | s.AddSecurityRequirement(new OpenApiSecurityRequirement() {
37 | {new OpenApiSecurityScheme {Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty()}}
38 | );
39 | });
40 |
41 |
42 | builder.Services.AddScoped();
43 |
44 | builder.Services.AddAuthorization();
45 | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
46 | {
47 | options.TokenValidationParameters = new TokenValidationParameters()
48 | {
49 | ValidateActor = true,
50 | ValidateAudience = true,
51 | ValidateLifetime = true,
52 | ValidateIssuerSigningKey = true,
53 | ValidIssuer = issuer,
54 | ValidAudience = audience,
55 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
56 | };
57 | });
58 | var app = builder.Build();
59 |
60 | if (app.Environment.IsDevelopment())
61 | {
62 | app.UseSwagger();
63 | app.UseSwaggerUI();
64 | }
65 |
66 |
67 | app.UseHttpsRedirection();
68 | app.UseAuthentication();
69 | app.UseAuthorization();
70 |
71 |
72 | app.MapGet("/login", (string login, ITokenService tokenService) =>
73 | {
74 | return tokenService.CreateToken(login);
75 | })
76 | .WithName("GetToken");
77 |
78 |
79 | app.MapGet("/dashboard", [Authorize] () => "Welcome to the secret Dashboard");
80 |
81 | app.Run();
82 |
83 | public class TokenSettings
84 | {
85 | public string SecurityKey { get; set; }
86 | public string Issuer { get; set; }
87 | public string Audience { get; set; }
88 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:39905",
8 | "sslPort": 44355
9 | }
10 | },
11 | "profiles": {
12 | "MinimalApiDemo.DIExample": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "https://localhost:7085;http://localhost:5017",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "swagger",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/Services/ITokenService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 | public interface ITokenService
4 | {
5 | public string CreateToken(string login);
6 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/Services/TokenService.cs:
--------------------------------------------------------------------------------
1 | using System.IdentityModel.Tokens.Jwt;
2 | using System.Security.Claims;
3 | using System.Text;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.Extensions.Options;
6 | namespace MinimalApiDemo;
7 |
8 | public class TokenService : ITokenService
9 | {
10 | private readonly IOptions _tokenSettings;
11 |
12 | public TokenService(IOptions tokenSettings)
13 | {
14 | _tokenSettings = tokenSettings;
15 | }
16 |
17 | public string CreateToken(string login)
18 | {
19 | var claims = new[] {
20 | new Claim(ClaimTypes.Actor, login)
21 | };
22 |
23 | // Get Token Settings using IOption
24 | var key = _tokenSettings.Value.SecurityKey;
25 | var issuer = _tokenSettings.Value.Issuer;
26 | var audience = _tokenSettings.Value.Audience;
27 |
28 | var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
29 | var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
30 | var tokenDescriptor = new JwtSecurityToken(issuer, audience, claims,
31 | expires: DateTime.Now.Add(new TimeSpan(0, 5, 0)), signingCredentials: credentials);
32 |
33 | return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.DIExample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/4.MinimalApiDemo.MinimalApiDemo.EndpointsResponses.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | MinimalApiDemo.EndpointsRespones
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Endpoints/AppointmentEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using Microsoft.AspNetCore.Authorization;
4 |
5 | namespace MinimalApiDemo;
6 |
7 | public static class AppointmentEndpoints
8 | {
9 | public static void UseAppointmentEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
10 | {
11 | endpointRouteBuilder.MapPost("/appointments", (Appointment? appointment) =>
12 | {
13 | if (appointment != null)
14 | return Results.Ok();
15 | else
16 | return Results.Problem();
17 | }).WithTags("Appointments");
18 |
19 | endpointRouteBuilder.MapGet("/html-template", () => Results.Extensions.HtmlResponse(@"
20 |
21 |
22 | Minimal API Template
23 |
24 | This is HTML response
25 |
26 |
27 | "));
28 |
29 | endpointRouteBuilder.MapGet("/file", () =>
30 | {
31 | return Results.File($"{Environment.CurrentDirectory}/test_image.png", contentType: "image/png");
32 | });
33 |
34 |
35 | endpointRouteBuilder.MapGet("/json", () => new { PatientName = "Piotr", Age=99 });
36 |
37 | endpointRouteBuilder.MapGet("/appointments/{id}", [Authorize] () => "Welcome to the secret appointments by id").WithTags("Appointments"); ;
38 | }
39 |
40 | record Appointment(string patientName);
41 |
42 | }
43 |
44 |
45 | public class HtmlResult : IResult
46 | {
47 | private readonly string? code;
48 |
49 | public HtmlResult(string htmlCode) => code = htmlCode;
50 |
51 | public async Task ExecuteAsync(HttpContext httpContext)
52 | {
53 | httpContext.Response.ContentType = MediaTypeNames.Text.Html;
54 | httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(code);
55 | await httpContext.Response.WriteAsync(code);
56 | }
57 | }
58 |
59 | public static class AdditionalResults
60 | {
61 | public static IResult HtmlResponse(this IResultExtensions extensions, string code) => new HtmlResult(code);
62 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Endpoints/TokenEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 |
4 | public static class TokenEndpoints
5 | {
6 | public static void UseTokenEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
7 | {
8 | endpointRouteBuilder.MapGet("/login", (string login, ITokenService tokenService) =>
9 | {
10 | return tokenService.CreateToken(login);
11 | });
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Authentication.JwtBearer;
3 | using Microsoft.AspNetCore.Authorization;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.OpenApi.Models;
6 | using MinimalApiDemo;
7 |
8 | var builder = WebApplication.CreateBuilder(args);
9 |
10 | var tokenSettingsSection = builder.Configuration.GetSection("TokenSettings");
11 |
12 | builder.Services.Configure(tokenSettingsSection);
13 | // or if you like AddOptions
14 |
15 | //builder.Services.AddOptions().BindConfiguration("TokenSettings");
16 |
17 | var tokenSettings = tokenSettingsSection.Get();
18 | string issuer = tokenSettings.Issuer;
19 | string audience = tokenSettings.Audience;
20 | string secret = tokenSettings.SecurityKey;
21 |
22 |
23 | builder.Services.AddEndpointsApiExplorer();
24 | builder.Services.AddSwaggerGen(s =>
25 | {
26 | s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
27 | {
28 | Name = "Authorization",
29 | Type = SecuritySchemeType.ApiKey,
30 | Scheme = "Bearer",
31 | BearerFormat = "JWT",
32 | In = ParameterLocation.Header,
33 | Description = "JSON Web Token",
34 | });
35 |
36 | s.AddSecurityRequirement(new OpenApiSecurityRequirement() {
37 | {new OpenApiSecurityScheme {Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty()}}
38 | );
39 | });
40 |
41 |
42 | builder.Services.AddScoped();
43 |
44 | builder.Services.AddAuthorization();
45 | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
46 | {
47 | options.TokenValidationParameters = new TokenValidationParameters()
48 | {
49 | ValidateActor = true,
50 | ValidateAudience = true,
51 | ValidateLifetime = true,
52 | ValidateIssuerSigningKey = true,
53 | ValidIssuer = issuer,
54 | ValidAudience = audience,
55 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
56 | };
57 | });
58 | var app = builder.Build();
59 |
60 | if (app.Environment.IsDevelopment())
61 | {
62 | app.UseSwagger();
63 | app.UseSwaggerUI();
64 | }
65 |
66 |
67 | app.UseHttpsRedirection();
68 | app.UseAuthentication();
69 | app.UseAuthorization();
70 |
71 | app.UseTokenEndpoints();
72 | app.UseAppointmentEndpoints();
73 |
74 | app.MapGet("/dashboard", [Authorize] () => "Welcome to the secret Dashboard");
75 |
76 | app.Run();
77 |
78 | public class TokenSettings
79 | {
80 | public string SecurityKey { get; set; }
81 | public string Issuer { get; set; }
82 | public string Audience { get; set; }
83 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:39905",
8 | "sslPort": 44355
9 | }
10 | },
11 | "profiles": {
12 | "MinimalApiDemo.SlicingEndpoints": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "https://localhost:7085;http://localhost:5017",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "swagger",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Services/ITokenService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 | public interface ITokenService
4 | {
5 | public string CreateToken(string login);
6 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/Services/TokenService.cs:
--------------------------------------------------------------------------------
1 | using System.IdentityModel.Tokens.Jwt;
2 | using System.Security.Claims;
3 | using System.Text;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.Extensions.Options;
6 | namespace MinimalApiDemo;
7 |
8 | public class TokenService : ITokenService
9 | {
10 | private readonly IOptions _tokenSettings;
11 |
12 | public TokenService(
13 | IOptions tokenSettings)
14 | {
15 | _tokenSettings = tokenSettings;
16 | }
17 |
18 | public string CreateToken(string login)
19 | {
20 | var claims = new[] {
21 | new Claim(ClaimTypes.Actor, login)
22 | };
23 |
24 | var key = _tokenSettings.Value.SecurityKey;
25 | var issuer = _tokenSettings.Value.Issuer;
26 | var audience = _tokenSettings.Value.Audience;
27 |
28 | var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
29 | var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
30 | var tokenDescriptor = new JwtSecurityToken(issuer, audience, claims,
31 | expires: DateTime.Now.Add(new TimeSpan(0, 5, 0)), signingCredentials: credentials);
32 |
33 | return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
34 | }
35 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.EndpointsRespones/test_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rh8512/csharp-minimalapi/297ad4a28528828b5d1ea1cbeff697e233d5d49f/MinimalApiDemo.EndpointsRespones/test_image.png
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/5.MinimalApiDemo.MinimalApiDemo.Logging.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | MinimalApiDemo.Logging
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Endpoints/AppointmentEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mime;
2 | using System.Text;
3 | using Microsoft.AspNetCore.Authorization;
4 |
5 | namespace MinimalApiDemo;
6 |
7 | public static class AppointmentEndpoints
8 | {
9 | public static void UseAppointmentEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
10 | {
11 | endpointRouteBuilder.MapPost("/appointments", (Appointment? appointment) =>
12 | {
13 | if (appointment != null)
14 | return Results.Ok();
15 | else
16 | return Results.Problem();
17 | }).WithTags("Appointments");
18 |
19 | endpointRouteBuilder.MapGet("/html-template", () => Results.Extensions.HtmlResponse(@"
20 |
21 |
22 | Minimal API Template
23 |
24 | This is HTML response
25 |
26 |
27 | "));
28 |
29 | endpointRouteBuilder.MapGet("/file", () =>
30 | {
31 | return Results.File($"{Environment.CurrentDirectory}/test_image.png", contentType: "image/png");
32 | });
33 |
34 |
35 | endpointRouteBuilder.MapGet("/json", () => new { PatientName = "Piotr", Age=99 });
36 |
37 | endpointRouteBuilder.MapGet("/appointments/{id}", [Authorize] () => "Welcome to the secret appointments by id").WithTags("Appointments"); ;
38 | }
39 |
40 | record Appointment(string patientName);
41 |
42 | }
43 |
44 |
45 | public class HtmlResult : IResult
46 | {
47 | private readonly string? code;
48 |
49 | public HtmlResult(string htmlCode) => code = htmlCode;
50 |
51 | public async Task ExecuteAsync(HttpContext httpContext)
52 | {
53 | httpContext.Response.ContentType = MediaTypeNames.Text.Html;
54 | httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(code);
55 | await httpContext.Response.WriteAsync(code);
56 | }
57 | }
58 |
59 | public static class AdditionalResults
60 | {
61 | public static IResult HtmlResponse(this IResultExtensions extensions, string code) => new HtmlResult(code);
62 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Endpoints/TokenEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 |
4 | public static class TokenEndpoints
5 | {
6 | public static void UseTokenEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
7 | {
8 | endpointRouteBuilder.MapGet("/login", (string login, ITokenService tokenService) =>
9 | {
10 | return tokenService.CreateToken(login);
11 | });
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Extensions/SimpleFileLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | public class SimpleFileLogger : ILogger
4 | {
5 | public IDisposable BeginScope(TState state)=> default!;
6 |
7 |
8 | public bool IsEnabled(LogLevel logLevel) => true;
9 |
10 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter)
11 | {
12 | var message = formatter(state, exception);
13 |
14 | if (string.IsNullOrEmpty(message) && exception is null) return;
15 |
16 | Console.WriteLine("My custom logger: " + message);
17 |
18 | using StreamWriter w = File.AppendText("logs.txt");
19 |
20 | w.WriteLine(message);
21 | }
22 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Extensions/SimpleFileLoggerExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | public static class LoggingBuilderExtensions
4 | {
5 | public static ILoggingBuilder AddFileLogger(this ILoggingBuilder builder)
6 | {
7 | builder.AddProvider(SimpleFileLoggerProvider.Instance);
8 |
9 | return builder;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Extensions/SimpleFileLoggerProvider.cs:
--------------------------------------------------------------------------------
1 | public class SimpleFileLoggerProvider : ILoggerProvider
2 | {
3 | public static SimpleFileLoggerProvider Instance { get; } = new();
4 |
5 | public ILogger CreateLogger(string categoryName)
6 | {
7 | return new SimpleFileLogger();
8 | }
9 |
10 | void IDisposable.Dispose() { }
11 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Authentication.JwtBearer;
3 | using Microsoft.AspNetCore.Authorization;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.OpenApi.Models;
6 | using MinimalApiDemo;
7 |
8 | var builder = WebApplication.CreateBuilder(args);
9 |
10 | var tokenSettingsSection = builder.Configuration.GetSection("TokenSettings");
11 |
12 | builder.Services.Configure(tokenSettingsSection);
13 |
14 | var tokenSettings = tokenSettingsSection.Get();
15 | string issuer = tokenSettings.Issuer;
16 | string audience = tokenSettings.Audience;
17 | string secret = tokenSettings.SecurityKey;
18 |
19 | builder.Services.AddEndpointsApiExplorer();
20 | builder.Services.AddSwaggerGen(s =>
21 | {
22 | s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
23 | {
24 | Name = "Authorization",
25 | Type = SecuritySchemeType.ApiKey,
26 | Scheme = "Bearer",
27 | BearerFormat = "JWT",
28 | In = ParameterLocation.Header,
29 | Description = "JSON Web Token",
30 | });
31 |
32 | s.AddSecurityRequirement(new OpenApiSecurityRequirement() {
33 | {new OpenApiSecurityScheme {Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty()}}
34 | );
35 | });
36 |
37 | builder.Logging.AddFileLogger();
38 |
39 | builder.Services.AddHttpLogging(logging =>
40 | {
41 | logging.LoggingFields = Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.All;
42 | /*
43 | logging.LoggingFields = Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.RequestQuery |
44 | Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.RequestHeaders |
45 | Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.RequestProtocol |
46 | Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.RequestMethod |
47 | */
48 | });
49 |
50 |
51 | builder.Services.AddScoped();
52 |
53 | builder.Services.AddAuthorization();
54 | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
55 | {
56 | options.TokenValidationParameters = new TokenValidationParameters()
57 | {
58 | ValidateActor = true,
59 | ValidateAudience = true,
60 | ValidateLifetime = true,
61 | ValidateIssuerSigningKey = true,
62 | ValidIssuer = issuer,
63 | ValidAudience = audience,
64 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
65 | };
66 | });
67 |
68 | var app = builder.Build();
69 |
70 |
71 | app.Logger.LogInformation("Application started");
72 |
73 | app.UseHttpLogging();
74 |
75 | if (app.Environment.IsDevelopment())
76 | {
77 | app.UseSwagger();
78 | app.UseSwaggerUI();
79 | }
80 |
81 | app.UseHttpsRedirection();
82 | app.UseAuthentication();
83 | app.UseAuthorization();
84 |
85 | app.UseTokenEndpoints();
86 | app.UseAppointmentEndpoints();
87 |
88 | app.MapGet("/dashboard", [Authorize] () => "Welcome to the secret Dashboard");
89 |
90 | app.Run();
91 |
92 | public class TokenSettings
93 | {
94 | public string SecurityKey { get; set; }
95 | public string Issuer { get; set; }
96 | public string Audience { get; set; }
97 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:39905",
8 | "sslPort": 44355
9 | }
10 | },
11 | "profiles": {
12 | "MinimalApiDemo.SlicingEndpoints": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "https://localhost:7085;http://localhost:5017",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "swagger",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Services/ITokenService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 | public interface ITokenService
4 | {
5 | public string CreateToken(string login);
6 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/Services/TokenService.cs:
--------------------------------------------------------------------------------
1 | using System.IdentityModel.Tokens.Jwt;
2 | using System.Security.Claims;
3 | using System.Text;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.Extensions.Options;
6 | namespace MinimalApiDemo;
7 |
8 | public class TokenService : ITokenService
9 | {
10 | private readonly IOptions _tokenSettings;
11 |
12 | public TokenService(
13 | IOptions tokenSettings)
14 | {
15 | _tokenSettings = tokenSettings;
16 | }
17 |
18 | public string CreateToken(string login)
19 | {
20 | var claims = new[] {
21 | new Claim(ClaimTypes.Actor, login)
22 | };
23 |
24 | var key = _tokenSettings.Value.SecurityKey;
25 | var issuer = _tokenSettings.Value.Issuer;
26 | var audience = _tokenSettings.Value.Audience;
27 |
28 | var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
29 | var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
30 | var tokenDescriptor = new JwtSecurityToken(issuer, audience, claims,
31 | expires: DateTime.Now.Add(new TimeSpan(0, 5, 0)), signingCredentials: credentials);
32 |
33 | return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
34 | }
35 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Information"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Information"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Logging/test_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rh8512/csharp-minimalapi/297ad4a28528828b5d1ea1cbeff697e233d5d49f/MinimalApiDemo.Logging/test_image.png
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/3.MinimalApiDemo.SlicingEndpoints.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | MinimalApiDemo.SlicingEndpoints
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Endpoints/AppointmentEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Authorization;
3 |
4 | namespace MinimalApiDemo;
5 |
6 | public static class AppointmentEndpoints
7 | {
8 | public static void UseAppointmentEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
9 | {
10 | endpointRouteBuilder.MapGet("/appointments", [Authorize] () => "Welcome to the secret appointments");
11 | endpointRouteBuilder.MapGet("/appointments/{id}", [Authorize] () => "Welcome to the secret appointments by id");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Endpoints/TokenEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 |
4 | public static class TokenEndpoints
5 | {
6 | public static void UseTokenEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
7 | {
8 | endpointRouteBuilder.MapGet("/login", (string login, ITokenService tokenService) =>
9 | {
10 | return tokenService.CreateToken(login);
11 | });
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Microsoft.AspNetCore.Authentication.JwtBearer;
3 | using Microsoft.AspNetCore.Authorization;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.OpenApi.Models;
6 | using MinimalApiDemo;
7 |
8 | var builder = WebApplication.CreateBuilder(args);
9 |
10 | var tokenSettingsSection = builder.Configuration.GetSection("TokenSettings");
11 |
12 | builder.Services.Configure(tokenSettingsSection);
13 | // or if you like AddOptions
14 |
15 | //builder.Services.AddOptions().BindConfiguration("TokenSettings");
16 |
17 | var tokenSettings = tokenSettingsSection.Get();
18 | string issuer = tokenSettings.Issuer;
19 | string audience = tokenSettings.Audience;
20 | string secret = tokenSettings.SecurityKey;
21 |
22 |
23 | builder.Services.AddEndpointsApiExplorer();
24 | builder.Services.AddSwaggerGen(s =>
25 | {
26 | s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
27 | {
28 | Name = "Authorization",
29 | Type = SecuritySchemeType.ApiKey,
30 | Scheme = "Bearer",
31 | BearerFormat = "JWT",
32 | In = ParameterLocation.Header,
33 | Description = "JSON Web Token",
34 | });
35 |
36 | s.AddSecurityRequirement(new OpenApiSecurityRequirement() {
37 | {new OpenApiSecurityScheme {Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty()}}
38 | );
39 | });
40 |
41 |
42 | builder.Services.AddScoped();
43 |
44 | builder.Services.AddAuthorization();
45 | builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
46 | {
47 | options.TokenValidationParameters = new TokenValidationParameters()
48 | {
49 | ValidateActor = true,
50 | ValidateAudience = true,
51 | ValidateLifetime = true,
52 | ValidateIssuerSigningKey = true,
53 | ValidIssuer = issuer,
54 | ValidAudience = audience,
55 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
56 | };
57 | });
58 | var app = builder.Build();
59 |
60 | if (app.Environment.IsDevelopment())
61 | {
62 | app.UseSwagger();
63 | app.UseSwaggerUI();
64 | }
65 |
66 |
67 | app.UseHttpsRedirection();
68 | app.UseAuthentication();
69 | app.UseAuthorization();
70 |
71 | app.UseTokenEndpoints();
72 | app.UseAppointmentEndpoints();
73 |
74 | app.MapGet("/dashboard", [Authorize] () => "Welcome to the secret Dashboard");
75 |
76 | app.Run();
77 |
78 | public class TokenSettings
79 | {
80 | public string SecurityKey { get; set; }
81 | public string Issuer { get; set; }
82 | public string Audience { get; set; }
83 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:39905",
8 | "sslPort": 44355
9 | }
10 | },
11 | "profiles": {
12 | "MinimalApiDemo.SlicingEndpoints": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "https://localhost:7085;http://localhost:5017",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "IIS Express": {
23 | "commandName": "IISExpress",
24 | "launchBrowser": true,
25 | "launchUrl": "swagger",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Services/ITokenService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MinimalApiDemo;
3 | public interface ITokenService
4 | {
5 | public string CreateToken(string login);
6 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/Services/TokenService.cs:
--------------------------------------------------------------------------------
1 | using System.IdentityModel.Tokens.Jwt;
2 | using System.Security.Claims;
3 | using System.Text;
4 | using Microsoft.IdentityModel.Tokens;
5 | using Microsoft.Extensions.Options;
6 | namespace MinimalApiDemo;
7 |
8 | public class TokenService : ITokenService
9 | {
10 | private readonly IOptions _tokenSettings;
11 |
12 | public TokenService(
13 | IOptions tokenSettings)
14 | {
15 | _tokenSettings = tokenSettings;
16 | }
17 |
18 | public string CreateToken(string login)
19 | {
20 | var claims = new[] {
21 | new Claim(ClaimTypes.Actor, login)
22 | };
23 |
24 | var key = _tokenSettings.Value.SecurityKey;
25 | var issuer = _tokenSettings.Value.Issuer;
26 | var audience = _tokenSettings.Value.Audience;
27 |
28 | var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
29 | var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
30 | var tokenDescriptor = new JwtSecurityToken(issuer, audience, claims,
31 | expires: DateTime.Now.Add(new TimeSpan(0, 5, 0)), signingCredentials: credentials);
32 |
33 | return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
34 | }
35 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.Slicing/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "TokenSettings": {
9 | "SecurityKey": "My Super Secret-My Super Secret",
10 | "Issuer": "pp",
11 | "Audience": "pp"
12 | }
13 | }
--------------------------------------------------------------------------------
/MinimalApiDemo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 25.0.1700.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3.MinimalApiDemo.SlicingEndpoints", "MinimalApiDemo.Slicing\3.MinimalApiDemo.SlicingEndpoints.csproj", "{4A0A4EA4-7060-4730-B033-6540814B4330}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1.MinimalApiDemo.BasicJWT", "MinimalApiDemo.BasicJWT\1.MinimalApiDemo.BasicJWT.csproj", "{E1BC9912-6B68-445A-8AB3-D7DA0E8B0DED}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2.MinimalApiDemo.DIExample", "MinimalApiDemo.DIExample\2.MinimalApiDemo.DIExample.csproj", "{01729775-F0E5-49CB-A652-D0F4A411F5AC}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "4.MinimalApiDemo.MinimalApiDemo.EndpointsResponses", "MinimalApiDemo.EndpointsRespones\4.MinimalApiDemo.MinimalApiDemo.EndpointsResponses.csproj", "{A5177827-0B12-4D1D-930F-312C9FE02DF3}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5.MinimalApiDemo.MinimalApiDemo.Logging", "MinimalApiDemo.Logging\5.MinimalApiDemo.MinimalApiDemo.Logging.csproj", "{9DBBA7A3-EB26-4FE7-BA99-45E196794012}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6.MinimalApiDemo.AWSLambdaHosting", "MinimalApiDemo.AWSLambdaHosting\6.MinimalApiDemo.AWSLambdaHosting.csproj", "{A9F4DF9D-F889-4A2A-B7A5-1B111D6D2FD0}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {4A0A4EA4-7060-4730-B033-6540814B4330}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {4A0A4EA4-7060-4730-B033-6540814B4330}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {4A0A4EA4-7060-4730-B033-6540814B4330}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {4A0A4EA4-7060-4730-B033-6540814B4330}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {2FC7DCC2-DF1A-4D9F-AFBA-BD0EE36EB4C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {2FC7DCC2-DF1A-4D9F-AFBA-BD0EE36EB4C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {2FC7DCC2-DF1A-4D9F-AFBA-BD0EE36EB4C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {2FC7DCC2-DF1A-4D9F-AFBA-BD0EE36EB4C7}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {E1BC9912-6B68-445A-8AB3-D7DA0E8B0DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {E1BC9912-6B68-445A-8AB3-D7DA0E8B0DED}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {E1BC9912-6B68-445A-8AB3-D7DA0E8B0DED}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {E1BC9912-6B68-445A-8AB3-D7DA0E8B0DED}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {01729775-F0E5-49CB-A652-D0F4A411F5AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {01729775-F0E5-49CB-A652-D0F4A411F5AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {01729775-F0E5-49CB-A652-D0F4A411F5AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {01729775-F0E5-49CB-A652-D0F4A411F5AC}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {A5177827-0B12-4D1D-930F-312C9FE02DF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {A5177827-0B12-4D1D-930F-312C9FE02DF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {A5177827-0B12-4D1D-930F-312C9FE02DF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {A5177827-0B12-4D1D-930F-312C9FE02DF3}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {9DBBA7A3-EB26-4FE7-BA99-45E196794012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {9DBBA7A3-EB26-4FE7-BA99-45E196794012}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {9DBBA7A3-EB26-4FE7-BA99-45E196794012}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {9DBBA7A3-EB26-4FE7-BA99-45E196794012}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {A9F4DF9D-F889-4A2A-B7A5-1B111D6D2FD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {A9F4DF9D-F889-4A2A-B7A5-1B111D6D2FD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {A9F4DF9D-F889-4A2A-B7A5-1B111D6D2FD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {A9F4DF9D-F889-4A2A-B7A5-1B111D6D2FD0}.Release|Any CPU.Build.0 = Release|Any CPU
52 | EndGlobalSection
53 | GlobalSection(SolutionProperties) = preSolution
54 | HideSolutionNode = FALSE
55 | EndGlobalSection
56 | GlobalSection(ExtensibilityGlobals) = postSolution
57 | SolutionGuid = {7E17703E-9522-48AA-A8CE-E8365D37A4C1}
58 | EndGlobalSection
59 | EndGlobal
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # csharp-minimalapi
2 | Minimal Api Demo:
3 |
4 | **1.MinimalApiDemo.BasicJWT** - simple example, no databases, even without checking the login and password, it's supposed to be a minimum, just pure token creation
5 |
6 | **2.MinimalApiDemo.DIExample** - simple as above, but I introduced here TokenService and used IConfiguration & IOptions to access appsettings.json settings
7 |
8 | **3.MinimalApiDemo.SlicingEndpoints** - simple as above, but I extracted endpoints to external files using extension methods
9 |
10 | **4.MinimalApiDemo.EndpointsResponses** - custom result type (HTML result) using IResult interface
11 |
12 | **5.MinimalApiDemo.Logging** - custom file logger, build using ILogger & ILoggerProvider
13 |
14 | **6.MinimalApiDemo.AWSLambdaHosting** - how to host Minimal API using AWS Lambda Service
15 |
--------------------------------------------------------------------------------