ASP.NET Core in Action, Third Edition (Final) [3 ed.] 9781633438620

Build professional-grade full-stack web applications using C# and ASP.NET Core. In ASP.NET Core in Action, Third Editio

507 175 34MB

English Pages 984 Year 2023

Report DMCA / Copyright

DOWNLOAD FILE

ASP.NET Core in Action, Third Edition (Final) [3 ed.]
 9781633438620

Table of contents :
inside front cover
ASP.NET Core in Action
Copyright
Praise for the Second Edition
contents
front matter
preface
acknowledgments
about this book
Who should read this book
How this book is organized
About the code
liveBook discussion forum
about the author
about the cover illustration
1 Getting started with ASP.NET Core
1.1 What is ASP.NET Core?
1.2 What types of applications can you build?
1.3 Choosing ASP.NET Core
1.4 How does ASP.NET Core work?
1.4.1 How does an HTTP web request work?
1.4.2 How does ASP.NET Core process a request?
1.5 What you’ll learn in this book
Summary
Part 1 Getting started with minimal APIs
2 Understanding ASP.NET Core
2.1 Using a web framework
2.2 Why ASP.NET Core was created
2.3 Understanding the many paradigms of ASP.NET Core
2.4 When to choose ASP.NET Core
2.4.1 If you’re new to .NET development
2.4.2 If you’re a .NET Framework developer creating a new application
2.4.3 Converting an existing ASP.NET application to ASP.NET Core
Summary
3 Your first application
3.1 A brief overview of an ASP.NET Core application
3.2 Creating your first ASP.NET Core application
3.2.1 Using a template to get started
3.2.2 Building the application
3.3 Running the web application
3.4 Understanding the project layout
3.5 The .csproj project file: Declaring your dependencies
3.6 Program.cs file: Defining your application
3.7 Adding functionality to your application
3.7.1 Adding and configuring services
3.7.2 Defining how requests are handled with middleware and endpoints
Summary
4 Handling requests with the middleware pipeline
4.1 Defining middleware
4.2 Combining middleware in a pipeline
4.2.1 Simple pipeline scenario 1: A holding page
4.2.2 Simple pipeline scenario 2: Handling static files
4.2.3 Simple pipeline scenario 3: A minimal API application
4.3 Handling errors using middleware
4.3.1 Viewing exceptions in development: DeveloperExceptionPage
4.3.2 Handling exceptions in production: ExceptionHandlerMiddleware
Summary
5 Creating a JSON API with minimal APIs
5.1 What is an HTTP API, and when should you use one?
5.2 Defining minimal API endpoints
5.2.1 Extracting values from the URL with routing
5.2.2 Mapping verbs to endpoints
5.2.3 Defining route handlers with functions
5.3 Generating responses with IResult
5.3.1 Returning status codes with Results and TypedResults
5.3.2 Returning useful errors with Problem Details
5.3.3 Converting all your responses to Problem Details
5.3.4 Returning other data types
5.4 Running common code with endpoint filters
5.4.1 Adding multiple filters to an endpoint
5.4.2 Filters or middleware: Which should you choose?
5.4.3 Generalizing your endpoint filters
5.4.4 Implementing the IEndpointFilter interface
5.5 Organizing your APIs with route groups
Summary
6 Mapping URLs to endpoints using routing
6.1 What is routing?
6.2 Endpoint routing in ASP.NET Core
6.3 Exploring the route template syntax
6.3.1 Working with parameters and literal segments
6.3.2 Using optional and default values
6.3.3 Adding additional constraints to route parameters
6.3.4 Matching arbitrary URLs with the catch-all parameter
6.4 Generating URLs from route parameters
6.4.1 Generating URLs for a minimal API endpoint with LinkGenerator
6.4.2 Generating URLs with IResults
6.4.3 Controlling your generated URLs with RouteOptions
Summary
7 Model binding and validation in minimal APIs
7.1 Extracting values from a request with model binding
7.2 Binding simple types to a request
7.3 Binding complex types to the JSON body
7.4 Arrays: Simple types or complex types?
7.5 Making parameters optional with nullables
7.6 Binding services and special types
7.6.1 Injecting well-known types
7.6.2 Injecting services
7.6.3 Binding file uploads with IFormFile and IFormFileCollection
7.7 Custom binding with BindAsync
7.8 Choosing a binding source
7.9 Simplifying handlers with AsParameters
7.10 Handling user input with model validation
7.10.1 The need for validation
7.10.2 Using DataAnnotations attributes for validation
7.10.3 Adding a validation filter to your minimal APIs
Summary
Part 2 Building complete applications
8 An introduction to dependency injection
8.1 Understanding the benefits of dependency injection
8.2 Creating loosely coupled code
8.3 Using dependency injection in ASP.NET Core
8.4 Adding ASP.NET Core framework services to the container
8.5 Using services from the DI container
Summary
9 Registering services with dependency injection
9.1 Registering custom services with the DI container
9.2 Registering services using objects and lambdas
9.3 Registering a service in the container multiple times
9.3.1 Injecting multiple implementations of an interface
9.3.2 Injecting a single implementation when multiple services are registered
9.3.3 Conditionally registering services using TryAdd
9.4 Understanding lifetimes: When are services created?
9.4.1 Transient: Everyone is unique
9.4.2 Scoped: Let’s stick together
9.4.3 Singleton: There can be only one
9.4.4 Keeping an eye out for captive dependencies
9.5 Resolving scoped services outside a request
Summary
10 Configuring an ASP.NET Core application
10.1 Introducing the ASP.NET Core configuration model
10.2 Building a configuration object for your app
10.2.1 Adding a configuration provider in Program.cs
10.2.2 Using multiple providers to override configuration values
10.2.3 Storing configuration secrets safely
10.2.4 Reloading configuration values when they change
10.3 Using strongly typed settings with the options pattern
10.3.1 Introducing the IOptions interface
10.3.2 Reloading strongly typed options with IOptionsSnapshot
10.3.3 Designing your options classes for automatic binding
10.3.4 Binding strongly typed settings without the IOptions interface
10.4 Configuring an application for multiple environments
10.4.1 Identifying the hosting environment
10.4.2 Loading environment-specific configuration files
10.4.3 Setting the hosting environment
Summary
11 Documenting APIs with OpenAPI
11.1 Adding an OpenAPI description to your app
11.2 Testing your APIs with Swagger UI
11.3 Adding metadata to your minimal APIs
11.4 Generating strongly typed clients with NSwag
11.4.1 Generating a client using Visual Studio
11.4.2 Generating a client using the .NET Global tool
11.4.3 Using a generated client to call your API
11.4.4 Customizing the generated code
11.4.5 Refreshing the OpenAPI description
11.5 Adding descriptions and summaries to your endpoints
11.5.1 Using fluent methods to add descriptions
11.5.2 Using attributes to add metadata
11.5.3 Using XML documentation comments to add metadata
11.6 Knowing the limitations of OpenAPI
11.6.1 Not all APIs can be described by OpenAPI
11.6.2 Generated code is opinionated
11.6.3 Tooling often lags the specification
Summary
12 Saving data with Entity Framework Core
12.1 Introducing Entity Framework Core
12.1.1 What is EF Core?
12.1.2 Why use an object-relational mapper?
12.1.3 When should you choose EF Core?
12.1.4 Mapping a database to your application code
12.2 Adding EF Core to an application
12.2.1 Choosing a database provider and installing EF Core
12.2.2 Building a data model
12.2.3 Registering a data context
12.3 Managing changes with migrations
12.3.1 Creating your first migration
12.3.2 Adding a second migration
12.4 Querying data from and saving data to the database
12.4.1 Creating a record
12.4.2 Loading a list of records
12.4.3 Loading a single record
12.4.4 Updating a model with changes
12.5 Using EF Core in production applications
Summary
Part 3 Generating HTML with Razor Pages and MVC
13 Creating a website with Razor Pages
13.1 Your first Razor Pages application
13.1.1 Using the Web Application template
13.1.2 Adding and configuring services
13.1.3 Generating HTML with Razor Pages
13.1.4 Handling request logic with page models and handlers
13.2 Exploring a typical Razor Page
13.3 Understanding the MVC design pattern
13.4 Applying the MVC design pattern to Razor Pages
13.4.1 Directing a request to a Razor Page and building a binding model
13.4.2 Executing a handler using the application model
13.4.3 Building HTML using the view model
13.4.4 Putting it all together: A complete Razor Page request
Summary
14 Mapping URLs to Razor Pages using routing
14.1 Routing in ASP.NET Core
14.2 Convention-based routing vs. explicit routing
14.3 Routing requests to Razor Pages
14.4 Customizing Razor Page route templates
14.4.1 Adding a segment to a Razor Page route template
14.4.2 Replacing a Razor Page route template completely
14.5 Generating URLs for Razor Pages
14.5.1 Generating URLs for a Razor Page
14.5.2 Generating URLs for an MVC controller
14.5.3 Generating URLs with LinkGenerator
14.6 Customizing conventions with Razor Pages
Summary
15 Generating responses with page handlers in Razor Pages
15.1 Razor Pages and page handlers
15.2 Selecting a page handler to invoke
15.3 Accepting parameters to page handlers
15.4 Returning IActionResult responses
15.4.1 PageResult and RedirectToPageResult
15.4.2 NotFoundResult and StatusCodeResult
15.5 Handler status codes with StatusCodePagesMiddleware
Summary
16 Binding and validating requests with Razor Pages
16.1 Understanding the models in Razor Pages and MVC
16.2 From request to binding model: Making the request useful
16.2.1 Binding simple types
16.2.2 Binding complex types
16.2.3 Choosing a binding source
16.3 Validating binding models
16.3.1 Validation in Razor Pages
16.3.2 Validating on the server for safety
16.3.3 Validating on the client for user experience
16.4 Organizing your binding models in Razor Pages
Summary
17 Rendering HTML using Razor views
17.1 Views: Rendering the user interface
17.2 Creating Razor views
17.2.1 Razor views and code-behind
17.2.2 Introducing Razor templates
17.2.3 Passing data to views
17.3 Creating dynamic web pages with Razor
17.3.1 Using C# in Razor templates
17.3.2 Adding loops and conditionals to Razor templates
17.3.3 Rendering HTML with Raw
17.4 Layouts, partial views, and _ViewStart
17.4.1 Using layouts for shared markup
17.4.2 Overriding parent layouts using sections
17.4.3 Using partial views to encapsulate markup
17.4.4 Running code on every view with _ViewStart and _ViewImports
Summary
18 Building forms with Tag Helpers
18.1 Catering to editors with Tag Helpers
18.2 Creating forms using Tag Helpers
18.2.1 The Form Tag Helper
18.2.2 The Label Tag Helper
18.2.3 The Input and Textarea Tag Helpers
18.2.4 The Select Tag Helper
18.2.5 The Validation Message and Validation Summary Tag Helpers
18.3 Generating links with the Anchor Tag Helper
18.4 Cache-busting with the Append Version Tag Helper
18.5 Using conditional markup with the Environment Tag Helper
Summary
19 Creating a website with MVC controllers
19.1 Razor Pages vs. MVC in ASP.NET Core
19.2 Your first MVC web application
19.3 Comparing an MVC controller with a Razor Page PageModel
19.4 Selecting a view from an MVC controller
19.5 Choosing between Razor Pages and MVC controllers
19.5.1 The benefits of Razor Pages
19.5.2 When to choose MVC controllers over Razor Pages
Summary
20 Creating an HTTP API using web API controllers
20.1 Creating your first web API project
20.2 Applying the MVC design pattern to a web API
20.3 Attribute routing: Linking action methods to URLs
20.3.1 Combining route attributes to keep your route templates DRY
20.3.2 Using token replacement to reduce duplication in attribute routing
20.3.3 Handling HTTP verbs with attribute routing
20.4 Using common conventions with [ApiController]
20.5 Generating a response from a model
20.5.1 Customizing the default formatters: Adding XML support
20.5.2 Choosing a response format with content negotiation
20.6 Choosing between web API controllers and minimal APIs
Summary
21 The MVC and Razor Pages filter pipeline
21.1 Understanding the MVC filter pipeline
21.2 The Razor Pages filter pipeline
21.3 Filters or middleware: Which should you choose?
21.4 Creating a simple filter
21.5 Adding filters to your actions and Razor Pages
21.6 Understanding the order of filter execution
21.6.1 The default scope execution order
21.6.2 Overriding the default order of filter execution with IOrderedFilter
Summary
22 Creating custom MVC and Razor Page filters
22.1 Creating custom filters for your application
22.1.1 Authorization filters: Protecting your APIs
22.1.2 Resource filters: Short-circuiting your action methods
22.1.3 Action filters: Customizing model binding and action results
22.1.4 Exception filters: Custom exception handling for your action methods
22.1.5 Result filters: Customizing action results before they execute
22.1.6 Page filters: Customizing model binding for Razor Pages
22.2 Understanding pipeline short-circuiting
22.3 Using dependency injection with filter attributes
Summary
Part 4 Securing and deploying your applications
23 Authentication: Adding users to your application with Identity
23.1 Introducing authentication and authorization
23.1.1 Understanding users and claims in ASP.NET Core
23.1.2 Authentication in ASP.NET Core: Services and middleware
23.2 What is ASP.NET Core Identity?
23.3 Creating a project that uses ASP.NET Core Identity
23.3.1 Creating the project from a template
23.3.2 Exploring the template in Solution Explorer
23.3.3 The ASP.NET Core Identity data model
23.3.4 Interacting with ASP.NET Core Identity
23.4 Adding ASP.NET Core Identity to an existing project
23.4.1 Configuring the ASP.NET Core Identity services
23.4.2 Updating the EF Core data model to support Identity
23.4.3 Updating the Razor views to link to the Identity UI
23.5 Customizing a page in ASP.NET Core Identity’s default UI
23.6 Managing users: Adding custom data to users
Summary
24 Authorization: Securing your application
24.1 Introduction to authorization
24.2 Authorization in ASP.NET Core
24.2.1 Preventing anonymous users from accessing your application
24.2.2 Handling unauthorized requests
24.3 Using policies for claims-based authorization
24.4 Creating custom policies for authorization
24.4.1 Requirements and handlers: The building blocks of a policy
24.4.2 Creating a policy with a custom requirement and handler
24.5 Controlling access with resource-based authorization
24.5.1 Manually authorizing requests with IAuthorizationService
24.5.2 Creating a resource-based AuthorizationHandler
24.6 Hiding HTML elements from unauthorized users
Summary
25 Authentication and authorization for APIs
25.1 Authentication for APIs and distributed applications
25.1.1 Extending authentication to multiple apps
25.1.2 Centralizing authentication in an identity provider
25.1.3 OpenID Connect and OAuth 2.0
25.2 Understanding bearer token authentication
25.3 Adding JWT bearer authentication to minimal APIs
25.4 Using the user-jwts tool for local JWT testing
25.4.1 Creating JWTs with the user-jwts tool
25.4.2 Customizing your JWTs
25.4.3 Managing your local JWTs
25.5 Describing your authentication requirements to OpenAPI
25.6 Applying authorization policies to minimal API endpoints
Summary
26 Monitoring and troubleshooting errors with logging
26.1 Using logging effectively in a production app
26.1.1 Highlighting problems using custom log messages
26.1.2 The ASP.NET Core logging abstractions
26.2 Adding log messages to your application
26.2.1 Log level: How important is the log message?
26.2.2 Log category: Which component created the log?
26.2.3 Formatting messages and capturing parameter values
26.3 Controlling where logs are written using logging providers
26.4 Changing log verbosity with filtering
26.5 Structured logging: Creating searchable, useful logs
26.5.1 Adding a structured logging provider to your app
26.5.2 Using scopes to add properties to your logs
Summary
27 Publishing and deploying your application
27.1 Understanding the ASP.NET Core hosting model
27.1.1 Running vs. publishing an ASP.NET Core app
27.1.2 Choosing a deployment method for your application
27.2 Publishing your app to IIS
27.2.1 Configuring IIS for ASP.NET Core
27.2.2 Preparing and publishing your application to IIS
27.3 Hosting an application in Linux
27.3.1 Running an ASP.NET Core app behind a reverse proxy in Linux
27.3.2 Preparing your app for deployment to Linux
27.4 Configuring the URLs for your application
Summary
28 Adding HTTPS to an application
28.1 Why do I need HTTPS?
28.2 Using the ASP.NET Core HTTPS development certificates
28.3 Configuring Kestrel with a production HTTPS certificate
28.4 Enforcing HTTPS for your whole app
28.4.1 Enforcing HTTPS with HTTP Strict Transport Security headers
28.4.2 Redirecting from HTTP to HTTPS with HTTPS redirection middleware
28.4.3 Rejecting HTTP requests in API applications
Summary
29 Improving your application’s security
29.1 Defending against cross-site scripting (XSS) attacks
29.2 Protecting from cross-site request forgery (CSRF) attacks
29.3 Calling your web APIs from other domains using CORS
29.3.1 Understanding CORS and how it works
29.3.2 Adding a global CORS policy to your whole app
29.3.3 Adding CORS to specific endpoints with EnableCors metadata
29.3.4 Configuring CORS policies
29.4 Exploring other attack vectors
29.4.1 Detecting and avoiding open redirect attacks
29.4.2 Avoiding SQL injection attacks with EF Core and parameterization
29.4.3 Preventing insecure direct object references
29.4.4 Protecting your users’ passwords and data
Summary
Part 5 Going further with ASP.NET Core
30 Building ASP.NET Core apps with the generic host and Startup
30.1 Separating concerns between two files
30.2 The Program class: Building a Web Host
30.3 The Startup class: Configuring your application
30.4 Creating a custom IHostBuilder
30.5 Understanding the complexity of the generic host
30.6 Choosing between the generic host and minimal hosting
Summary
31 Advanced configuration of ASP.NET Core
31.1 Customizing your middleware pipeline
31.1.1 Creating simple apps with the Run extension
31.1.2 Branching middleware pipelines with the Map extension
31.1.3 Adding to the pipeline with the Use extension
31.1.4 Building a custom middleware component
31.1.5 Converting middleware into endpoint routing endpoints
31.2 Using DI with OptionsBuilder and IConfigureOptions
31.3 Using a third-party dependency injection container
Summary
32 Building custom MVC and Razor Pages components
32.1 Creating a custom Razor Tag Helper
32.1.1 Printing environment information with a custom Tag Helper
32.1.2 Creating a custom Tag Helper to conditionally hide elements
32.1.3 Creating a Tag Helper to convert Markdown to HTML
32.2 View components: Adding logic to partial views
32.3 Building a custom validation attribute
32.4 Replacing the validation framework with FluentValidation
32.4.1 Comparing FluentValidation with DataAnnotations attributes
32.4.2 Adding FluentValidation to your application
Summary
33 Calling remote APIs with IHttpClientFactory
33.1 Calling HTTP APIs: The problem with HttpClient
33.2 Creating HttpClients with IHttpClientFactory
33.2.1 Using IHttpClientFactory to manage HttpClientHandler lifetime
33.2.2 Configuring named clients at registration time
33.2.3 Using typed clients to encapsulate HTTP calls
33.3 Handling transient HTTP errors with Polly
33.4 Creating a custom HttpMessageHandler
Summary
34 Building background tasks and ser vices
34.1 Running background tasks with IHostedService
34.1.1 Running background tasks on a timer
34.1.2 Using scoped services in background tasks
34.2 Creating headless worker services using IHost
34.2.1 Creating a worker service from a template
34.2.2 Running worker services in production
34.3 Coordinating background tasks using Quartz.NET
34.3.1 Installing Quartz.NET in an ASP.NET Core application
34.3.2 Configuring a job to run on a schedule with Quartz.NET
34.3.3 Using clustering to add redundancy to your background tasks
Summary
35 Testing applications with xUnit
35.1 An introduction to testing in ASP.NET Core
35.2 Creating your first test project with xUnit
35.3 Running tests with dotnet test
35.4 Referencing your app from your test project
35.5 Adding Fact and Theory unit tests
35.6 Testing failure conditions
Summary
36 Testing ASP.NET Core applications
36.1 Unit testing custom middleware
36.2 Unit testing API controllers and minimal API endpoints
36.3 Integration testing: Testing your whole app in-memory
36.3.1 Creating a TestServer using the Test Host package
36.3.2 Testing your application with WebApplicationFactory
36.3.3 Replacing dependencies in WebApplicationFactory
36.3.4 Reducing duplication by creating a custom WebApplicationFactory
36.4 Isolating the database with an in-memory EF Core provider
Summary
appendix A. Preparing your development environment
A.1 Installing the .NET SDK
A.2 Choosing an IDE or editor
A.2.1 Visual Studio (Windows)
A.2.2 JetBrains Rider (Windows, Linux, macOS)
A.2.3 Visual Studio for Mac (macOS)
A.2.4 Visual Studio Code (Windows, Linux, macOS)
Appendix B. Useful references
B.1 Relevant books
B.2 Announcement blog posts
B.3 Microsoft documentation
B.4 Security-related links
B.5 ASP.NET Core GitHub repositories
B.6 Tooling and services
B.7 ASP.NET Core blogs
B.8 Video links
index
inside back cover

Polecaj historie