/
speaker-notes.md
336 lines (297 loc) · 13.1 KB
/
speaker-notes.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# Speaker notes
## 01 Introduction
- Personal introduction - each attendee
- Introduction to .NET Core presentation
- Introduction to ASP.NET Core presentation
- Check if environments are set up correctly:
- Use [Prerequisites](00-prerequisites.md) document as guideline
- Latest Visual Studio 2019 Preview is installed with ASP.NET and .NET Core workloads
- Latest Blazor extension is installed in Visual Studio Extensions
- Latest .NET Core SDK is installed - use `dotnet --info` to check
- Git client is installed - use `git --version` to check
- Latest Blazor templates installed - use `dotnet new` to check
- Postman installed
- Alternative for Visual Studio 2019 Preview:
- Latest Visual Studio Code is installed
- C# for Visual Studio Code extension
- Each attendee should have a GitHub account
- Define individual or team organization
- Add attendees to Slack channel
## 02 Tools and templates
- `dotnet` CLI
- `dotnet --info`
- `dotnet new`
- `dotnet new console`
- `dotnet run`
- `code .` - if Visual Studio Code is installed
- `dotnet new web`
- `dotnet new webapi`
- `dotnet new mvc --auth Individual`
- Visual Studio 2019
- New project dialog
- Filters and options
- Templates
- ASP.NET Core templates
- Templates to analyze
- Console app
- Empty ASP.NET Core
- ASP.NET Web API
- ASP.NET MVC - with Individual auth
- SPA - Angular or React
- Worker
- gRPC
- Server-side Blazor
- Client-side Blazor
- Explain:
- Folder / namespace structure
- Dependencies
- `Program` and `Startup`
- `appsettings.json`
- `wwwroot` folder
- `.csproj` file
- Controllers - base `Controller`, attribute routing, `IActionResult`, `async`, model binding, model validation, view models...
- Entity Framework Core, `DbContext`, migrations
- Views, Razor syntax, `_Layout` file, `_ViewStart`, `_ViewImports`, tag helpers, `ViewData` / `ViewBag`
- ASP.NET Core Identity - scaffold identity, register, login, 2FA
## 03 Choosing a domain
- Discuss about the domain to create
- Choose very simple domain - up to 4-5 entities
- Explain user stories
- Define user stories for the domain
## 04 Project initialization
- Introduction to REST APIs presentation
- Create a new `TimeTracker` ASP.NET Core Web API project
- Reorganize repository folders - move code to `src` sub-folder
- Add to git source control - using Team Explorer
- Git synchronize
- Create an empty GitHub repository
- Don't enable README, .gitignore and LICENSE
- Publish to new repository from VS
- Add `README.md` and `LICENSE` file to root folder - https://choosealicense.com/
- Run the app - F5
- Explain other options
- IIS Express, etc.
- Make a request from Postman to `/weatherforecast`
## 05 Domain models and database
### Domain models
- Revisit selected domain and user stories
- Create `User`, `Client`, `Project` and `TimeEntry` classes with properties
- Add `[Required]` attribute where necessary
### Database and EF Core
- Add a new empty file in the Web API project root - `app.db`
- Modify `appsettings.json` - add connection string `"ConnectionStrings": { "DefaultConnection": "DataSource=app.db" }`
- Explain installing NuGet packages via CLI `dotnet add package ...` and VS NuGet package manager
- Add `Microsoft.EntityFrameworkCore.Sqlite` NuGet package
- Add `Microsoft.EntityFrameworkCore.Tools`
- Add `TimeTrackerDbContext` with necessary `DbSet<T>` properties
### Migrations
- Explain what the db migrations are
- `dotnet-tools.json`
- `dotnet new tool-manifest` from the solution root
- `dotnet tool install dotnet-ef` to install EF Core tools
- From the project folder: `dotnet ef migrations add "InitialMigration" --output-dir "Data/Migrations"`
- Look at the migrations folder content
- `dotnet ef database update` to update the database
- Use [SQLite/SQL Server Compact Toolbox](https://marketplace.visualstudio.com/items?itemName=ErikEJ.SQLServerCompactSQLiteToolbox) VS extension to look at db content
### Data seeding
- Add `OnModelCreating` override to `DbContext`
- Use `modelBuilder.Entity<User>().HasData()` method to seed
- `dotnet ef migrations add "SeedData" --output-dir "Data/Migrations"`
- `dotnet ef database update`
## 06 Controllers and actions
### View Models
- Explain what View Models / Input Models are
- Create `XxModel`, `XxInputModel` pairs
- Add `FromXx` static methods to `XxModel` classes for data mapping
- Add `MapTo` methods to `XxInputModel` classes to map data to existing entity models
- Add `PagedList<T>` for paging
### Validation
- Explain validation and Data Annotations
- Explain Fluent Validation
- Install `FluentValidation.AspNetCore`
- Add validators for all input models
- Modify `Startup` class to initialize Fluent Validation - `services.AddControllers().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<UserInputModelValidator>());`
### Data access
- Explain using `DbContext` classes directly, Repository pattern, CQRS
### Controllers
- Create `UserController`
- Define and explain `[ApiController]`
- Explain attribute routing `[Route("/api/users")]`
- Explain base `Controller` class
- Explain dependency injection
- Explain how logging is done and `ILogger<T>`
- Explain HTTP verbs - GET, POST, PUT, DELETE...
- Add `GetById` method
- Add `GetPage` method with paging parameters
- Add `Delete` method
- Add `Create` POST method
- Add `Update` PUT method
- Add other controllers
### Postman collection
- Explain what are Postman collections
- Get into more details about requests
- Create Postman collection for API
- See how errors look like in Postman
- Define variable for `rootUrl`
### Error handling
- Implement `ErrorHandlingMiddleware` and include it in `Startup`
## 07 Securing APIs
- HTTPS everywhere
- OAuth 2.0 and OpenID Connect
- JWT Token auth
- Add `Tokens:Issuer` and `Tokens:Key` settings to `appsettings.json`
- Install `Microsoft.AspNetCore.Authentication.JwtBearer`
- Create extension method `ServiceCollectionExtensions.AddJwtBearerAuthentication`
- Add to `Startup`
- `services.AddJwtBearerAuthentication(Configuration);`
- `app.UseAuthentication();`
- Add `[Authorize]` and `[Authorize(Roles = "admin")]` to controllers and action methods
- Authorization server
- Mention IdentityServer4, OpenIddict, Auth0, Okta...
- Implement `JwtTokenGenerator`
- Implement `DummyAuthController` with `/get-token` route
- Organize Postman collection into folders - *No Auth* folder
- Duplicate folder into *Bearer Token Auth*
- Define variables for `token` and `adminToken`
- Move admin requests into `Admin` sub-folder
## 08 Testing and documentation
- Explain unit and integration testing
- Add `TimeTracker.Tests` xUnit test project - into `tests` folder
- Unit testing
- Add `UnitTests/UsersControllerTests`
- Add `FakeLogger<T>`
- Initialize `TimeTrackerDbContext` with In Memory database
- Write tests for `GetById` method
- Use VS Test Explorer to run tests
- Write tests for `GetPage` method
- Write tests for `Delete` method
- Integration testing
- Add `IntegrationTests/UsersApiTests`
- Initialize `TestServer` and test `HttpClient`
- Initialize two tokens - admin and non-admin
- Write tests for `Delete` functionality
- Documentation
- Install `NSwag.AspNetCore`
- Install `Microsoft.AspNetCore.Mvc.NewtonsoftJson`
- Implement `ServiceCollectionExtensions.AddOpenApi()` method
- Add to `Startup`
- `services.AddOpenApi();`
- `app.UseOpenApi();`
- `app.UseSwaggerUi3();`
- Change launch URL to `/swagger`
- Run the app and play with the Swagger UI interface - auth, etc.
- Add `[OpenApiIgnore]` for controllers to skip
- Add XML documentation to Controllers and View Models
- Enable XML generation in project properties
- Rebuild and test in Swagger UI
## 09 Versioning, usage limiting and monitoring
- Versioning
- Talk about API versioning
- Different versioning strategies
- Install `Microsoft.AspNetCore.Mvc.Versioning` and `Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer` pre-release
- Create copy of controllers in `Controllers/V1`
- Update controller routes to include `/api/v{version:apiVersion}/`
- Add `[ApiVersion("...")]` attribute to controllers
- Update all `CreatedAtAction` method calls to include `version = "..."` in route parameters
- Create `ServiceCollectionExtensions.AddVersioning` method
- Refactor `AddOpenApi` method to support versioning - add `InitializeOpenApiDocumentOptions` private method
- Call `service.AddVersioning()` from `Startup.ConfigureServices`
- Test swagger UI output in browser
- Modify Postman collection - add new folder for versioned calls
- Fix integration tests in `UserApiTests` to include version number
- Limiting
- Create `LimitingMiddleware`
- Add to `Startup`
- `app.UseMiddleware<LimitingMiddleware>();`
- Logging
- Mention different logging libraries
- Install `Serilog.AspNetCore` and `Serilog.Sinks.File`
- Modify `Program` class to initialize logger
- Run the app, make several requests, check the log file content
- Health checks
- Talk about service status pages
- Add to `Startup`
- `services.AddHealthChecks();`
- `endpoints.MapHealthChecks("/health");` - under `UseEndpoints`
- Install `AspNetCore.HealthChecks.Sqlite`
- Modify `Startup`
- `services.AddHealthChecks().AddSqlite(Configuration.GetConnectionString("DefaultConnection"));`
- Try defining health check SQL query above, see the *Unhealthy* response
- Custom health checks - `IHealthCheck` interface
- Install `AspNetCore.HealthChecks.UI`
- Add to `Startup`
- `services.AddHealthChecksUI();`
- `app.UseHealthChecksUI();`
- `endpoints.MapHealthChecks("/health", new HealthCheckOptions { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse });`
- Add health check settings to `appsettings.json` file
- Browse `/healthchecks-ui`
- Mention Azure and third-party services for monitoring
## 10 Blazor client
- Introduction to Blazor presentation
- Create new Blazor (client-side) app - `TimeTracker.Client`
- Set it up as a startup project
- Authentication
- Mention that this is a preview of Blazor - future breaking changes are possible
- Explain how we are simulating login
- Install `Microsoft.AspNetCore.Components.Authorization` NuGet package
- Add `Models.UserModel` class
- Create `Security.TokenAuthenticationStateProvider`
- Explain what it does
- Add `Extensions.SecurityExtensions`
- Call it from `Startup.ConfigureServices`
- Modify `App.razor` to add `<CascadingAuthenticationState>`
- Explain
- Modify the main `_Imports.razor`
- add `@using System.Net.Http.Headers`
- add `@using Microsoft.AspNetCore.Authorization`
- add `@using Microsoft.AspNetCore.Components.Authorization`
- Add `wwwroot/scripts/localStorage.js`
- Include it in `wwwroot/index.html`
- Add `@attribute [Authorize]` attribute to some pages
- Login page
- Enable CORS in API's `Startup`
- Explain Cors
- `services.AddCors()` before `AddControllers()`
- `appUseCors()` before `UseOpenApi()`
- Modify `MainLayout.razor`
- Use `<AuthorizeView>`
- Add `Login` and `Logout` links
- Implement `Logout` by setting token and user to `null`
- Add `Config` class to hold all the configuration constants (e.g. URLs)
- Add `Services.ApiService` with `GetAsync` method
- Explain `HttpClient` and how we get token
- Register `ApiService` in `Startup` - `services.AddScoped<ApiService>();`
- Implement `Login.razor` page
- Explain `EditForm` component and its `Model` property
- Explain buttons and `onclick` handlers
- Explain `Login` methods
- Explain how errors are displayed
- Preparing for custom pages
- Comment out `LimitingMiddleware`
- Remove `Counter.razor` and `FetchData.razor`
- Modify links in `NavMenu.razor`
- Refactor `ApiService` - add `SendAuthorizedRequest` private method
- Implement create, update and delete methods
- Adding pages for users
- Create `Users.razor`
- Explain routing, DI, `OnInitializedAsync`...
- Implement `Shared/Pager.razor` component
- Explain parameters and how they are passed
- Explain usage of `PagedList<T>`
- Explain `Loader` function
- Add `Models` folder, copy models from API project and clean up
- Add data annotations validation
- Mention how this could be moved to shared project
- Add create and edit page and explain it
- Add delete user page
- Leave attendees to implement all pages for clients and projects, or copy-paste from existing ones
- Explain loading lookups and using `InputSelect` component
- Implement `Models.Lookup` class
- Adding pages for time entries
- Only add/edit and delete
- Explain date selection
- Home page dashboard page
- Explain search
- Add new API endpoint `TimeEntriesController.GetByUserAndMonth` and explain
## Show resources page
## Close up!