preface |
|
xix | |
acknowledgments |
|
xxi | |
About this book |
|
xxiii | |
About the author |
|
xxviii | |
About the cover illustration |
|
xxix | |
|
Part 1 Getting started with ASP.NET Core |
|
|
1 | (288) |
|
1 Getting started with ASP.NET Core |
|
|
3 | (22) |
|
1.1 An introduction to ASP.NET Core |
|
|
4 | (5) |
|
|
5 | (2) |
|
|
7 | (2) |
|
1.2 When to choose ASP.NET Core |
|
|
9 | (10) |
|
What type of applications can you build? |
|
|
9 | (3) |
|
If you're new to NET development |
|
|
12 | (2) |
|
If you're a NET Framework developer creating a new application |
|
|
14 | (4) |
|
Converting an existing ASP.NET application to ASP.NET Core |
|
|
18 | (1) |
|
1.3 How does ASP.NET Core work? |
|
|
19 | (4) |
|
How does an HTTP web request work? |
|
|
19 | (2) |
|
How does ASP.NET Core process a request? |
|
|
21 | (2) |
|
1.4 What you will learn in this book |
|
|
23 | (2) |
|
|
25 | (33) |
|
2.1 A brief overview of an ASP.NET Core application |
|
|
26 | (3) |
|
2.2 Creating your first ASP.NET Core application |
|
|
29 | (5) |
|
Using a template to get started |
|
|
29 | (3) |
|
|
32 | (2) |
|
2.3 Running the web application |
|
|
34 | (1) |
|
2.4 Understanding the project layout |
|
|
35 | (2) |
|
2.5 The .csproj project file: Defining your dependencies |
|
|
37 | (2) |
|
2.6 The Program class: Building a web host |
|
|
39 | (3) |
|
2.7 The Startup class: Configuring your application |
|
|
42 | (8) |
|
Adding and configuring services |
|
|
44 | (1) |
|
Defining how requests are handled with middleware |
|
|
45 | (5) |
|
2.8 Generating responses with Razor Pages |
|
|
50 | (8) |
|
Generating HTML with Razor Pages |
|
|
51 | (2) |
|
Handling request logic with PageModels and handlers |
|
|
53 | (5) |
|
3 Handling requests with the middleware pipeline |
|
|
58 | (33) |
|
|
60 | (4) |
|
3.2 Combining middleware in a pipeline |
|
|
64 | (13) |
|
Simple pipeline scenario 1 A holding page |
|
|
6 | (62) |
|
Simple pipeline scenario 2 Handling static files |
|
|
68 | (4) |
|
Simple pipeline scenario 3 A Razor Pages application |
|
|
72 | (5) |
|
3.3 Handling errors using middleware |
|
|
77 | (14) |
|
Viewing exceptions in development: DeveloperExceptionPage |
|
|
78 | (2) |
|
Handling exceptions in production: ExceptionHandlerMiddleware |
|
|
80 | (4) |
|
Handling other errors: StatusCodePagesMiddleware |
|
|
84 | (5) |
|
Error handling middleware and Web APIs |
|
|
89 | (2) |
|
4 A Creating a website with Razor Pages |
|
|
91 | (31) |
|
4.1 An introduction to Razor Pages |
|
|
93 | (14) |
|
Exploring a typical Razor Page |
|
|
93 | (1) |
|
|
94 | (3) |
|
Applying the MVC design pattern to Razor Pages |
|
|
97 | (7) |
|
Adding Razor Pages to your application |
|
|
104 | (3) |
|
4.2 Razor Pages vs. MVC in ASP.NET Core |
|
|
107 | (6) |
|
MVC controllers in ASP.NET Core |
|
|
108 | (2) |
|
The benefits of Razor Pages |
|
|
110 | (2) |
|
When to choose MVC controllers over Razor Pages |
|
|
112 | (1) |
|
4.3 Razor Pages and page handlers |
|
|
113 | (9) |
|
Accepting parameters to page handlers |
|
|
115 | (2) |
|
Returning responses with ActionResults |
|
|
117 | (5) |
|
5 Mapping URLs to Razor Pages using routing |
|
|
122 | (34) |
|
|
123 | (3) |
|
5.2 Routing in ASP.NET Core |
|
|
126 | (8) |
|
Using endpoint routing in ASP.NET Core |
|
|
127 | (3) |
|
Convention-based routing vs. attribute routing |
|
|
130 | (2) |
|
|
132 | (2) |
|
5.3 Customizing Razor Page route templates |
|
|
134 | (4) |
|
Adding a segment to a Razor Page route template |
|
|
136 | (1) |
|
Replacing a Razor Page route template completely |
|
|
137 | (1) |
|
5.4 Exploring the route template syntax |
|
|
138 | (5) |
|
Using optional and default values |
|
|
138 | (1) |
|
Adding additional constraints to route parameters |
|
|
139 | (3) |
|
Matching arbitrary URLs with the catch-all parameter |
|
|
142 | (1) |
|
5.5 Generating URLs from route parameters |
|
|
143 | (6) |
|
Generating URLs for a Razor Page |
|
|
144 | (1) |
|
Generating URLs for an MVC controller |
|
|
145 | (1) |
|
Generating URLs with ActionResults |
|
|
146 | (1) |
|
Generating URLs from other parts of your application |
|
|
147 | (2) |
|
5.6 Selecting a page handler to invoke |
|
|
149 | (2) |
|
5.7 Customizing conventions with Razor Pages |
|
|
151 | (5) |
|
6 The binding model: Retrieving and validating user input |
|
|
156 | (99) |
|
6.1 Understanding the models in Razor Pages and MVC |
|
|
157 | (3) |
|
6.2 From request to model: Making the request useful |
|
|
160 | (14) |
|
|
164 | (4) |
|
|
168 | (4) |
|
Choosing a binding source |
|
|
172 | (2) |
|
6.3 Handling user input with model validation |
|
|
174 | (10) |
|
|
174 | (2) |
|
Using Data Annotations attributes for validation |
|
|
176 | (2) |
|
Validating on the server for safety |
|
|
178 | (4) |
|
Validating on the client for user experience |
|
|
182 | (2) |
|
6.4 Organizing your binding models in Razor Pages |
|
|
184 | (5) |
|
Rendering HTML using Razor views |
|
|
188 | (1) |
|
7.1 Views: Rendering the user interface |
|
|
189 | (4) |
|
|
193 | (6) |
|
Razor views and code-behind |
|
|
194 | (1) |
|
Introducing Razor templates |
|
|
195 | (2) |
|
|
197 | (2) |
|
7.3 Creating dynamic web pages with Razor |
|
|
199 | (7) |
|
Using C# in Razor templates |
|
|
200 | (1) |
|
Adding loops and conditionals to Razor templates |
|
|
201 | (3) |
|
|
204 | (2) |
|
7.4 Layouts, partial views, and _ViewStart |
|
|
206 | (9) |
|
Using layouts for shared markup |
|
|
207 | (2) |
|
Overriding parent layouts using sections |
|
|
209 | (2) |
|
Using partial views to encapsulate markup |
|
|
211 | (2) |
|
Running code on every view with _ViewStart and _ViewImports |
|
|
213 | (2) |
|
7.5 Selecting a view from an MVC controller |
|
|
215 | (10) |
|
Building forms with Tag Helpers |
|
|
223 | (2) |
|
8.1 Catering to editors with Tag Helpers |
|
|
225 | (3) |
|
8.2 Creating forms using Tag Helpers |
|
|
228 | (20) |
|
|
233 | (2) |
|
|
235 | (1) |
|
The Input and Textarea Tag Helpers |
|
|
236 | (4) |
|
|
240 | (5) |
|
The Validation Message and Validation Summary Tag Helpers |
|
|
245 | (3) |
|
8.3 Generating links with the Anchor Tag Helper |
|
|
248 | (2) |
|
8.4 Cache-busting with the Append Version Tag Helper |
|
|
250 | (1) |
|
8.5 Using conditional markup with the Environment Tag Helper |
|
|
251 | (4) |
|
9 Creating a Web API for mobile and client applications using MVC |
|
|
255 | (34) |
|
9.1 What is a Web API and when should you use one? |
|
|
256 | (3) |
|
9.2 Creating your first Web API project |
|
|
259 | (7) |
|
9.3 Applying the MVC design pattern to a Web API |
|
|
266 | (4) |
|
9.4 Attribute routing: Linking action methods to URLs |
|
|
270 | (6) |
|
Combining route attributes to keep your route templates DRY 2 |
|
|
72 | (202) |
|
Using token replacement to reduce duplication in attribute routing |
|
|
274 | (1) |
|
Handling HTTP verbs with attribute routing |
|
|
274 | (2) |
|
9.5 Using common conventions with the [ ApiController] attribute |
|
|
276 | (4) |
|
9.6 Generating a response from a model |
|
|
280 | (9) |
|
Customizing the default formatters: Adding XML support |
|
|
282 | (2) |
|
Choosing a response format with content negotiation |
|
|
284 | (5) |
|
Part 2 Building complete applications |
|
|
289 | (248) |
|
10 Service configuration with dependency injection |
|
|
291 | (39) |
|
10.1 Introduction to dependency injection |
|
|
292 | (10) |
|
Understanding the benefits of dependency injection |
|
|
293 | (5) |
|
Creating loosely coupled code |
|
|
298 | (2) |
|
Dependency injection in ASP.NET Core |
|
|
300 | (2) |
|
10.2 Using the dependency injection container |
|
|
302 | (16) |
|
AddingASP.NET Core framework services to the container |
|
|
302 | (2) |
|
Registering your own services with the container |
|
|
304 | (3) |
|
Registering services using objects and lambdas |
|
|
307 | (4) |
|
Registering a service in the container multiple times |
|
|
311 | (4) |
|
Injecting services into action methods, page handlers, and views |
|
|
315 | (3) |
|
10.3 Understanding lifetimes: When are services created? |
|
|
318 | (12) |
|
Transient: Everyone is unique |
|
|
321 | (1) |
|
Scoped: Let's stick together |
|
|
322 | (1) |
|
Singleton: There can be only one |
|
|
323 | (1) |
|
Keeping an eye out for captured dependencies |
|
|
324 | (6) |
|
11 Configuring an ASP.NET Core application |
|
|
330 | (34) |
|
11.1 Introducing the ASP.NET Core configuration model |
|
|
331 | (2) |
|
11.2 Configuring your application with CreateDefaultBuilder |
|
|
333 | (2) |
|
11.3 Building a configuration object for your app |
|
|
335 | (12) |
|
Adding a configuration provider in Program.cs |
|
|
338 | (2) |
|
Using multiple providers to override configuration values |
|
|
340 | (2) |
|
Storing configuration secrets safely |
|
|
342 | (4) |
|
Reloading configuration values when they change |
|
|
346 | (1) |
|
11.4 Using strongly typed settings with the options pattern |
|
|
347 | (7) |
|
Introducing the IOptions interface |
|
|
349 | (1) |
|
Reloading strongly typed options with IOptionsSnapshot |
|
|
350 | (1) |
|
Designing your options classes for automatic binding |
|
|
351 | (2) |
|
Binding strongly typed settings without the IOptions interface |
|
|
353 | (1) |
|
11.5 Configuring an application for multiple environments |
|
|
354 | (10) |
|
Identifying the hosting environment |
|
|
355 | (1) |
|
Loading environment-specific configuration files |
|
|
356 | (2) |
|
Setting the hosting environment |
|
|
358 | (6) |
|
12 Saving data with Entity Framework Core |
|
|
364 | (34) |
|
12.1 Introducing Entity Framework Core |
|
|
366 | (6) |
|
|
366 | (1) |
|
Why use an object-relational mapper? |
|
|
367 | (2) |
|
When should you choose EF Core? |
|
|
369 | (1) |
|
Mapping a database to your application code |
|
|
370 | (2) |
|
12.2 Adding EF Core to an application |
|
|
372 | (6) |
|
Choosing a database provider and installing EF Core |
|
|
373 | (2) |
|
|
375 | (2) |
|
Registering a data context |
|
|
377 | (1) |
|
12.3 Managing changes with migrations |
|
|
378 | (6) |
|
Creating your first migration |
|
|
379 | (3) |
|
Adding a second migration |
|
|
382 | (2) |
|
12.4 Querying data from and saving data to the database |
|
|
384 | (10) |
|
|
385 | (2) |
|
Loading a list of records |
|
|
387 | (2) |
|
|
389 | (1) |
|
Updating a model with changes |
|
|
390 | (4) |
|
12.5 Using EF Core in production applications |
|
|
394 | (4) |
|
13 The MVC and Razor Pages filter pipeline |
|
|
398 | (38) |
|
13.1 Understanding filters and when to use them |
|
|
399 | (14) |
|
|
401 | (2) |
|
The Razor Pages filter pipeline |
|
|
403 | (1) |
|
Filters or middleware: Which should you choose? |
|
|
404 | (2) |
|
|
406 | (2) |
|
Adding filters to your actions, controllers, Razor Pages, and globally |
|
|
408 | (3) |
|
Understanding the order of filter execution |
|
|
411 | (2) |
|
13.2 Creating custom filters for your application |
|
|
413 | (16) |
|
Authorization filters: Protecting your APIs |
|
|
415 | (1) |
|
Resource filters: Short-circuiting your action methods |
|
|
416 | (3) |
|
Action filters: Customizing model binding and action results |
|
|
419 | (4) |
|
Exception filters: Custom exception handling for your action methods |
|
|
423 | (2) |
|
Result filters: Customizing action results before they execute |
|
|
425 | (2) |
|
Page filters: Customizing model binding for Razor Pages |
|
|
427 | (2) |
|
13.3 Understanding pipeline short-circuiting |
|
|
429 | (2) |
|
13.4 Using dependency injection with filter attributes |
|
|
431 | (5) |
|
14 Authentication: Adding users to your application with Identity |
|
|
436 | (34) |
|
14.1 Introducing authentication and authorization |
|
|
437 | (9) |
|
Understanding users and claims in ASP.NET Core |
|
|
438 | (1) |
|
Authentication in ASP.NET Core: Services and middleware |
|
|
439 | (3) |
|
Authentication for APIs and distributed applications |
|
|
442 | (4) |
|
14.2 What is ASP.NET Core Identity? |
|
|
446 | (2) |
|
14.3 Creating a project that uses ASP.NET Core Identity |
|
|
448 | (10) |
|
Creating the project from a template |
|
|
448 | (2) |
|
Exploring the template in Solution Explorer |
|
|
450 | (3) |
|
The ASP.NET Core Identity data model |
|
|
453 | (2) |
|
Interacting with ASP.NET Core Identity |
|
|
455 | (3) |
|
14.4 Adding ASP.NET Core Identity to an existing project |
|
|
458 | (5) |
|
Configuring the ASP.NET Core Identity services and middleware |
|
|
459 | (1) |
|
Updating the EF Core data model to support Identity |
|
|
460 | (1) |
|
Updating the Razor views to link to the Identity UI |
|
|
461 | (2) |
|
14.5 Customizing a page in ASP.NET Core Identity's default UI |
|
|
463 | (3) |
|
14.6 Managing users: Adding custom data to users |
|
|
466 | (4) |
|
15 Authorization: Securing your application |
|
|
470 | (33) |
|
15.1 Introduction to authorization |
|
|
471 | (3) |
|
15.2 Authorization in ASP.NET Core |
|
|
474 | (7) |
|
Preventing anonymous users from accessing your application |
|
|
476 | (2) |
|
Handling unauthorized requests |
|
|
478 | (3) |
|
15.3 Using policies for claims-based authorization |
|
|
481 | (3) |
|
15.4 Creating custom policies for authorization |
|
|
484 | (8) |
|
Requirements and handlers: The building blocks of a policy |
|
|
484 | (2) |
|
Creating a policy with a custom requirement and handler |
|
|
486 | (6) |
|
15.5 Controlling access with resource-based authorization |
|
|
492 | (6) |
|
Manually authorizing requests with IAuthorizationService |
|
|
493 | (2) |
|
Creating a resource-based AuthorizationHandler |
|
|
495 | (3) |
|
15.6 Hiding elements in Razor templates from unauthorized users |
|
|
498 | (5) |
|
16 Publishing and deploying your application |
|
|
503 | (34) |
|
16.1 Understanding the ASP.NET Core hosting model |
|
|
504 | (7) |
|
Running vs. publishing an ASP.NET Core app |
|
|
506 | (4) |
|
Choosing a deployment method for your application |
|
|
510 | (1) |
|
16.2 Publishing your app to IIS |
|
|
511 | (6) |
|
Configuring IIS for ASP.NET Core |
|
|
512 | (2) |
|
Preparing and publishing your application to IIS |
|
|
514 | (3) |
|
16.3 Hosting an application on Linux |
|
|
517 | (5) |
|
Running an ASP.NET Core app behind a reverse proxy on Linux |
|
|
517 | (3) |
|
Preparing your app for deployment to Linux |
|
|
520 | (2) |
|
16.4 Configuring the URLs for your application |
|
|
522 | (3) |
|
16.5 Optimizing your client-side assets using BundlerMinifier |
|
|
525 | (12) |
|
Speeding up an app using bundling and minification |
|
|
527 | (2) |
|
Adding BundlerMinifier to your application |
|
|
529 | (3) |
|
Using minified files in production with the Environment Tag Helper |
|
|
532 | (1) |
|
Serving common files from a CDN |
|
|
533 | (4) |
|
Part 3 Extending your applications |
|
|
537 | (214) |
|
17 Monitoring and troubleshooting errors with logging |
|
|
539 | (33) |
|
17.1 Using logging effectively in a production app |
|
|
541 | (4) |
|
Highlighting problems using custom log messages |
|
|
542 | (1) |
|
The ASP.NET Core logging abstractions |
|
|
543 | (2) |
|
17.2 Adding log messages to your application |
|
|
545 | (7) |
|
Log level: How important is the log message? |
|
|
547 | (2) |
|
Log category: Which component created the log |
|
|
549 | (1) |
|
Formatting messages and capturing parameter values |
|
|
550 | (2) |
|
17.3 Controlling where logs are written using logging providers |
|
|
552 | (7) |
|
Adding a new logging provider to your application |
|
|
553 | (3) |
|
Replacing the default ILoggerFactory with Serilog |
|
|
556 | (3) |
|
17.4 Changing log verbosity with filtering |
|
|
559 | (5) |
|
17.5 Structured logging: Creating searchable, useful logs |
|
|
564 | (8) |
|
Adding a structured logging provider to your app |
|
|
565 | (3) |
|
Using scopes to add additional properties to your logs |
|
|
568 | (4) |
|
18 Improving your application's security |
|
|
572 | (37) |
|
18.1 Adding HTTPS to an application |
|
|
573 | (11) |
|
Using the ASP.NET Core HTTPS development certificates |
|
|
576 | (3) |
|
Configuring Kestrel with a production HTTPS certificate |
|
|
579 | (1) |
|
Enforcing HTTPS for your whole app |
|
|
580 | (4) |
|
18.2 Defending against cross-site scripting (XSS) attacks |
|
|
584 | (4) |
|
18.3 Protecting from cross-site request forgery (CSRF) attacks |
|
|
588 | (5) |
|
18.4 Calling your web APIs from other domains using CORS |
|
|
593 | (8) |
|
Understanding CORS and how it works |
|
|
594 | (2) |
|
Adding a global CORS policy to your whole app |
|
|
596 | (2) |
|
Adding CORS to specific Web API actions with EnableCorsAttribute |
|
|
598 | (1) |
|
Configuring CORS policies |
|
|
599 | (2) |
|
18.5 Exploring other attack vectors |
|
|
601 | (8) |
|
Detecting and avoiding open redirect attacks |
|
|
601 | (2) |
|
Avoiding SQL injection attacks with EF Core and parameterization |
|
|
603 | (2) |
|
Preventing insecure direct object references |
|
|
605 | (1) |
|
Protecting your users `passwords and data' |
|
|
605 | (4) |
|
19 Building custom components |
|
|
609 | (31) |
|
19.1 Customizing your middleware pipeline |
|
|
610 | (11) |
|
Creating simple endpoints with the Run extension |
|
|
611 | (1) |
|
Branching middleware pipelines with the Map extension |
|
|
612 | (4) |
|
Adding to the pipeline with the Use extension |
|
|
616 | (3) |
|
Building a custom middleware component |
|
|
619 | (2) |
|
19.2 Creating custom endpoints with endpoint routing |
|
|
621 | (8) |
|
Creating a custom endpoint routing component |
|
|
622 | (3) |
|
Creating simple endpoints with MapGet and WritefsonAsync |
|
|
625 | (2) |
|
Applying authorization to endpoints |
|
|
627 | (2) |
|
19.3 Handling complex configuration requirements |
|
|
629 | (6) |
|
Partially building configuration to configure additional providers |
|
|
630 | (2) |
|
Using services to configure IOptions with IConfigureOptions |
|
|
632 | (3) |
|
19.4 Using a third-party dependency injection container |
|
|
635 | (5) |
|
20 Building custom MVC and Razor Pages components |
|
|
640 | (27) |
|
20.1 Creating a custom Razor Tag Helper |
|
|
641 | (8) |
|
Printing environment information with a custom Tag Helper |
|
|
642 | (3) |
|
Creating a custom Tag Helper to conditionally hide elements |
|
|
645 | (2) |
|
Creating a Tag Helper to convert Markdown to HTML |
|
|
647 | (2) |
|
20.2 View components: Adding logic to partial views |
|
|
649 | (5) |
|
20.3 Building a custom validation attribute |
|
|
654 | (5) |
|
20.4 Replacing the validation framework with FluentValidation |
|
|
659 | (8) |
|
Comparing FluentValidation to DataAnnotations attributes |
|
|
660 | (3) |
|
Adding FluentValidation to your application |
|
|
663 | (4) |
|
21 Calling remote APIs with IHttpClientFactory |
|
|
667 | (22) |
|
21.1 Calling HTTP APIs: The problem with HttpClient |
|
|
668 | (6) |
|
21.2 Creating HttpClients with IHttpClientFactory |
|
|
674 | (7) |
|
Using IHttpClientFactory to manage HttpClientHandler lifetime |
|
|
674 | (3) |
|
Configuring named clients at registration time |
|
|
677 | (2) |
|
Using typed clients to encapsulate HTTP calls |
|
|
679 | (2) |
|
21.3 Handling transient HTTP errors with Polly |
|
|
681 | (3) |
|
21.4 Creating a custom HttpMessageHandler |
|
|
684 | (5) |
|
22 Building background tasks and services |
|
|
689 | (25) |
|
22.1 Running background tasks with IHostedService |
|
|
690 | (6) |
|
Running background tasks on a timer |
|
|
691 | (3) |
|
Using scoped services in background tasks |
|
|
694 | (2) |
|
22.2 Creating headless worker services using IHost |
|
|
696 | (7) |
|
Creating a worker service from a template |
|
|
698 | (2) |
|
Running worker services in production |
|
|
700 | (3) |
|
22.3 Coordinating background tasks using Quartz.NET |
|
|
703 | (11) |
|
Installing Quartz.NET in an ASP.NET Core application |
|
|
704 | (2) |
|
Configuring a job to run on a schedule with Quartz.NET |
|
|
706 | (2) |
|
Using clustering to add redundancy to your background tasks |
|
|
708 | (6) |
|
23 Testing your application |
|
|
714 | (37) |
|
23.1 An introduction to testing in ASP.NET Core |
|
|
716 | (1) |
|
23.2 Unit testing with xUnit |
|
|
717 | (11) |
|
Creating your first test project |
|
|
718 | (2) |
|
Running tests with dotnet test |
|
|
720 | (1) |
|
Referencing your app from your test project |
|
|
721 | (3) |
|
Adding Fact and Theory unit tests |
|
|
724 | (3) |
|
Testing failure conditions |
|
|
727 | (1) |
|
23.3 Unit testing custom middleware |
|
|
728 | (3) |
|
23.4 Unit testing API controllers |
|
|
731 | (3) |
|
23.5 Integration testing: Testing your whole app in-memory |
|
|
734 | (10) |
|
Creating a TestServer using the Test Host package |
|
|
735 | (3) |
|
Testing your application with WebApplicationFactory |
|
|
738 | (2) |
|
Replacing dependencies in WebApplicationFactory |
|
|
740 | (2) |
|
Reducing duplication by creating a custom WebApplicationFactory |
|
|
742 | (2) |
|
23.6 Isolating the database with an in-memory EF Core provider |
|
|
744 | (7) |
Appendix A Preparing your development environment |
|
751 | (7) |
Appendix B Understanding the NET ecosystem |
|
758 | (18) |
Appendix C Useful references |
|
776 | (7) |
index |
|
783 | |