Chapter 26: Monitoring and troubleshooting errors with logging
This introduction explains why production logging matters and previews ASP.NET Core’s logging abstractions, providers, filtering, and structured logging features.
After this chapter you will be able to
- Purpose of application logging. Explain logging as recording application events or activities for later diagnosis, especially when a problem appears only in production. Distinguish informational events from warnings and errors or unexpected conditions.
- ASP.NET Core logging framework. Describe how ASP.NET Core’s generic logging interface gives applications, framework code, and third-party libraries a common way to create logs. Explain that dependency injection supports creating log messages and that the framework can control verbosity by component and send output to pluggable destinations.
- Production logging purposes. Describe the three main reasons to add logging to an application: auditing or analytics, recording errors, and recording nonerror events as a breadcrumb trail for later diagnosis.
- Diagnostic context from logs. Explain how error details and the events or conditions leading up to an error give developers context to diagnose a production problem when reproducing it from a customer report is difficult.
- Diagnostic custom log messages. Explain why custom log messages can be more useful than infrastructure logs for diagnosing an application problem. Describe that an effective message explicitly identifies the problem and includes the relevant parameter or variable value, such as a requested recipe ID that does not exist.
- Logging abstraction roles. Describe the roles of ILogger, ILoggerProvider, and ILoggerFactory in the ASP.NET Core logging framework. Explain that application code writes messages through ILogger and that providers create loggers for particular destinations such as the console or a file.
- Provider fan-out and decoupling. Explain that providers are registered with ILoggerFactory and that the ILogger it creates wraps the registered providers, so one Log() call writes to every provider. Explain that this design lets an application add or change log destinations through configuration without changing its application logging code.
- ILogger injection and message writing. Describe how to add logging to an application service by injecting ILogger<T> through dependency injection and using an extension method such as LogInformation() to write a message. State that the logger sends the message to every configured ILoggerProvider.
- Log record elements. Explain that every log message has a log level, category, and message, while parameters, an exception, and an EventId are optional record elements. Describe the purpose of the level as importance, the category as the producing component—typically the class name for ILogger<T>—and EventId as an optional integer for finding similar events.
- Message placeholders and parameters. Describe how a logging message can use brace-delimited placeholders and separate parameter values, with placeholders matched to parameters by position. Explain why placeholders are preferred over string interpolation: loggers can retain the named parameter values for structured logging.
- Log level purpose and ordering. Explain that every ILogger log message has a log level indicating its seriousness or importance, and order the six levels from most to least serious: Critical, Error, Warning, Information, Debug, and Trace.
- Severity-based message selection. Describe what kinds of events fit Critical, Error, Warning, Information, Debug, and Trace, including the distinction between an unhandled failure, a recoverable unexpected condition, normal application flow, and increasingly detailed diagnostics.
- Production verbosity filtering. Justify filtering out lower-level Debug and Trace logs in production: lower levels occur more frequently, can overwhelm searches and fill disk space, while Trace can leak sensitive data; development can retain all levels when detailed diagnosis is needed.
- Log category purpose. Explain that every log message has a category, set when its ILogger instance is created, and that categories are written with log entries and can be used for filtering.
- Category creation patterns. Describe the conventional category and the two ways shown to create it: inject ILogger<T> so T supplies the category, or use ILoggerFactory.CreateLogger with an explicit string or a generic type. State that ILogger<T> is preferred unless customized categories are needed.
- Message templates and parameters. Describe how brace-delimited placeholders in a log message are paired with arguments to produce both a formatted message and named key-value data. Explain that multiple placeholders map to arguments by position and that every placeholder needs a supplied parameter.
- Searchable structured log properties. Explain that structured, or semantic, logging stores contextual values as key-value pairs in addition to message text, making logs searchable and filterable by values such as UserId or RecipeId. Distinguish this from providers that only render a plain text message.
- Logging provider responsibilities. Explain that logging providers consume messages created through ILogger and write them to provider-specific output destinations. Describe how a single ILogger log message is sent to every provider configured for the application.
- Third-party provider configuration. Describe the process for adding a third-party logging provider: install its NuGet package and call its extension method on WebApplicationBuilder.Logging in Program.cs. Use the rolling file example to explain that AddFile() adds a file destination while the existing console and debug providers remain unless ClearProviders() is called.
- Production log destinations. Justify using a centralized log destination separate from the application for production, especially when multiple application instances run. Contrast this with console logging, which is useful during debugging, and local file logging, which persists messages but can require remote-server access, collecting files from many servers, and handling disk or permission problems.
- Logging filter dimensions. Explain how ASP.NET Core decides whether to write a log message by considering its log level, logger category, and logging provider. Describe how default, category-prefix, and provider-specific rules can reduce noise differently for different outputs.
- Most-specific rule selection. Trace the algorithm that selects a single filtering rule for a log message: prefer rules for the current provider, otherwise providerless rules; choose the longest matching category prefix or Default; then use the last matching rule, falling back to the global default level. State that rules are not merged and provider-specific rules can override global category rules.
- Structured versus text logs. Distinguish unstructured text logs from structured logs, explaining that structured logs expose log properties as key-value pairs, commonly represented as JSON.
- Structured log investigation. Explain how key-value properties in structured logs support querying and filtering, such as finding events by EventLevel or recipe ID, instead of relying only on text searches.
- Seq structured logging provider. Describe how to add Seq as a structured logging provider to an ASP.NET Core application. State that the app registers it with AddSeq(), which sends logs to Seq’s default local URL for a local installation, while production can use overloads for additional configuration.
- Structured log properties. Explain that ASP.NET Core treats captured parameters in a log message format string as named key-value properties on a structured log. Describe how Seq displays those properties when an individual log entry is expanded.
- Structured error investigation. Explain how structured properties make production troubleshooting easier by allowing logs to be filtered or queried by fields such as EventId.Id and RecipeId. Trace the example in which 13 warnings with EventId.Id 12 all identify RecipeId 3245, suggesting that the specific recipe is the likely source of the problem.
- Logging scope lifetime. Explain how an ILogger logging scope groups related operations by attaching the same state data to log messages written within a using block. State that a scope is created with ILogger.BeginScope<T>(state), and messages outside that block do not receive the scope data.
- Dictionary scope properties. Describe how the object passed as scope state is handled and why a Dictionary<string, object> is commonly used with Seq. Explain that providers decide how to handle state, often serializing ordinary state with ToString(), whereas dictionary key-value pairs become individual structured log properties that are easier to filter.
What it builds on
- Using dependency injection in ASP.NET Core (chapter 8) · The use of dependency injection in ASP.NET Core to obtain framework services.
- Combining middleware in a pipeline (chapter 4) · The idea that ASP.NET Core processes requests through application components.
- Querying data from and saving data to the database (chapter 12) · EF Core database commands issued while loading and saving application data.
- Loading a single record (chapter 12) · Loading a single record by an identifier, such as a recipe ID, and handling the case where it is absent.
- Using services from the DI container (chapter 8) · Using services resolved from the dependency injection container.
- Program.cs file: Defining your application (chapter 3) · Program.cs as the place where an ASP.NET Core application is configured.
- Using multiple providers to override configuration values (chapter 10) · Layered configuration providers and later values overriding earlier configuration.
- Loading environment-specific configuration files (chapter 10) · Loading environment-specific configuration files.
Section by section
Introduction
This introduction explains why production logging matters and previews ASP.NET Core’s logging abstractions, providers, filtering, and structured logging features.
- Purpose of application logging: Explain logging as recording application events or activities for later diagnosis, especially when a problem appears only in production. Distinguish informational events from warnings and errors or unexpected conditions.
Why it matters: Useful logs provide the evidence needed to understand and troubleshoot production problems. - ASP.NET Core logging framework: Describe how ASP.NET Core’s generic logging interface gives applications, framework code, and third-party libraries a common way to create logs. Explain that dependency injection supports creating log messages and that the framework can control verbosity by component and send output to pluggable destinations.
Why it matters: A common logging abstraction avoids incompatible library-specific log formats and lets an application manage logs consistently. - Logging strategy chapter roadmap: Describe the chapter’s logging workflow: write messages with levels, categories, and parameter values; use providers to select output locations; filter verbosity differently by environment; and use structured key-value data to make logs searchable.
Why it matters: These capabilities let you collect enough diagnostic information without drowning production logs in irrelevant data.
Key terms: logging, informational messages, warnings, errors, generic logging interface, ASP.NET Core logging framework, dependency injection, ILogger, logging providers, verbosity
26.1 Using logging effectively in a production app
This section explains why production logging is essential for diagnosing problems, auditing behavior, and tracing the events that lead to errors.
- Production logging purposes: Describe the three main reasons to add logging to an application: auditing or analytics, recording errors, and recording nonerror events as a breadcrumb trail for later diagnosis.
Why it matters: Knowing the purpose of a log helps you decide which application events are worth recording. - Diagnostic context from logs: Explain how error details and the events or conditions leading up to an error give developers context to diagnose a production problem when reproducing it from a customer report is difficult.
Why it matters: Useful context can turn an otherwise vague customer-reported failure into a diagnosable problem. - Monitoring and framework breadcrumbs: State that teams must review logs or use monitoring services to discover problems promptly, and that ASP.NET Core already provides substantial breadcrumb logging so developers can focus on high-value custom messages.
Why it matters: Automatic framework logs and alerting reduce the chance that important production problems remain unnoticed.
Key terms: logging, auditing, analytics, breadcrumb trail, errors, nonerror events, production, error, context, breadcrumb logging
26.1.1 Highlighting problems using custom log messages
This section contrasts ASP.NET Core’s built-in infrastructure logs with targeted custom messages that make application problems and important events easier to diagnose.
- Infrastructure logging visibility: Describe the request-level information ASP.NET Core framework logging can provide without adding messages to application code, including the requested URL, invoked Razor Page handler, EF Core command, executed action result, and response.
Why it matters: Built-in logs provide a useful trace of what the framework did while processing a request. - Diagnostic custom log messages: Explain why custom log messages can be more useful than infrastructure logs for diagnosing an application problem. Describe that an effective message explicitly identifies the problem and includes the relevant parameter or variable value, such as a requested recipe ID that does not exist.
Why it matters: Clear, contextual application logs make failures and important events much faster to understand.
Key terms: infrastructure logging, ASP.NET Core Framework libraries, EF Core, Razor Page, page handler, custom log message, RecipeId, parameters, variables
26.1.2 The ASP.NET Core logging abstractions
This section explains how ASP.NET Core’s logging interfaces connect application log calls to one or more configurable output providers.
- Logging abstraction roles: Describe the roles of ILogger, ILoggerProvider, and ILoggerFactory in the ASP.NET Core logging framework. Explain that application code writes messages through ILogger and that providers create loggers for particular destinations such as the console or a file.
Why it matters: These abstractions let you write logging code without tying the application to a particular log destination. - Provider fan-out and decoupling: Explain that providers are registered with ILoggerFactory and that the ILogger it creates wraps the registered providers, so one Log() call writes to every provider. Explain that this design lets an application add or change log destinations through configuration without changing its application logging code.
Why it matters: You can redirect or add logging outputs as operational needs change while keeping the code that reports problems unchanged. - Default console provider: State that WebApplicationBuilder adds the console logger by default, while custom provider configuration is performed on WebApplicationBuilder rather than by directly using ILoggerProvider instances in normal application code.
Why it matters: Knowing the default explains why console logs appear before you explicitly add a console provider.
Key terms: ILogger, ILoggerProvider, ILoggerFactory, Log(), CreateLogger(), WebApplicationBuilder, console logger
26.2 Adding log messages to your application
This section introduces creating application log messages through injected ILogger and explains the common information carried by each log record.
- ILogger injection and message writing: Describe how to add logging to an application service by injecting ILogger<T> through dependency injection and using an extension method such as LogInformation() to write a message. State that the logger sends the message to every configured ILoggerProvider.
Why it matters: Injecting ILogger lets application code report useful operational information without being coupled to a particular log destination. - Log record elements: Explain that every log message has a log level, category, and message, while parameters, an exception, and an EventId are optional record elements. Describe the purpose of the level as importance, the category as the producing component—typically the class name for ILogger<T>—and EventId as an optional integer for finding similar events.
Why it matters: Knowing what a log record contains makes it easier to identify the source, significance, and recurring type of a production problem. - Message placeholders and parameters: Describe how a logging message can use brace-delimited placeholders and separate parameter values, with placeholders matched to parameters by position. Explain why placeholders are preferred over string interpolation: loggers can retain the named parameter values for structured logging.
Why it matters: Placeholders preserve useful data alongside the rendered text so later logging tools can search and analyze it. - Optional logging source generator: State that the optional ILogger source generator uses a partial method decorated with LoggerMessage, with the attribute defining the event ID, level, and message and method parameters substituted at runtime. Describe its benefits as analyzer guidance and generated code that can avoid allocations.
Why it matters: The source-generator pattern can make repeated logging safer and more efficient while remaining optional.
Key terms: ILogger<T>, ILogger, ILoggerFactory, ILoggerProvider, LogInformation, dependency injection, LogLevel, log level, category, message
26.2.1 Log level: How important is the log message?
This section explains how to assign ILogger log levels to convey a message’s severity and use those levels to control useful logging in development and production.
- Log level purpose and ordering: Explain that every ILogger log message has a log level indicating its seriousness or importance, and order the six levels from most to least serious: Critical, Error, Warning, Information, Debug, and Trace.
Why it matters: Log levels let you communicate how urgent a message is and later decide which messages are worth recording. - Severity-based message selection: Describe what kinds of events fit Critical, Error, Warning, Information, Debug, and Trace, including the distinction between an unhandled failure, a recoverable unexpected condition, normal application flow, and increasingly detailed diagnostics.
Why it matters: Choosing a level that matches the event makes failures stand out without losing the context needed to investigate them. - ILogger level extension methods: State that ILogger extension methods such as LogInformation and LogWarning set the corresponding log level when creating a message, and describe the example of logging recipe viewing as Information and a missing recipe as Warning.
Why it matters: The extension methods are the practical way application code attaches an intended severity to each log entry. - Production verbosity filtering: Justify filtering out lower-level Debug and Trace logs in production: lower levels occur more frequently, can overwhelm searches and fill disk space, while Trace can leak sensitive data; development can retain all levels when detailed diagnosis is needed.
Why it matters: Filtering prevents production logs from becoming expensive, noisy, and potentially unsafe while retaining meaningful failures and warnings.
Key terms: ILogger, log level, Critical, Error, Warning, Information, Debug, Trace, LogInformation, LogWarning
26.2.2 Log category: Which component created the log?
This section explains how log categories identify the component that created a log entry and how to create categorized ILogger instances.
- Log category purpose: Explain that every log message has a category, set when its ILogger instance is created, and that categories are written with log entries and can be used for filtering.
Why it matters: Categories let you identify the source of a message and control logging for particular parts of an application. - Category creation patterns: Describe the conventional category and the two ways shown to create it: inject ILogger<T> so T supplies the category, or use ILoggerFactory.CreateLogger with an explicit string or a generic type. State that ILogger<T> is preferred unless customized categories are needed.
Why it matters: Using the conventional type-based category makes log sources consistent while retaining an option for deliberately custom categories.
Key terms: category, ILogger, log level, filtering, ILogger<T>, ILoggerFactory, CreateLogger(), fully qualified name, RecipeController, RecipeService
26.2.3 Formatting messages and capturing parameter values
This section explains how message templates and parameter values create searchable structured log data instead of only formatted text.
- Message templates and parameters: Describe how brace-delimited placeholders in a log message are paired with arguments to produce both a formatted message and named key-value data. Explain that multiple placeholders map to arguments by position and that every placeholder needs a supplied parameter.
Why it matters: Template-based messages preserve the values behind a log entry, so providers can make them useful for diagnosis. - Searchable structured log properties: Explain that structured, or semantic, logging stores contextual values as key-value pairs in addition to message text, making logs searchable and filterable by values such as UserId or RecipeId. Distinguish this from providers that only render a plain text message.
Why it matters: Searching for a particular user, recipe, or other recorded value is far more reliable than searching arbitrary rendered text. - Provider-aware logging style: Justify using explicit placeholders and separate parameters rather than C# interpolated strings when logging variable values. Describe why this style is recommended even before a structured provider is installed, and note that the default console provider renders placeholders as text rather than retaining searchable key-value data.
Why it matters: Writing templates from the start avoids losing diagnostic values and lets a later structured provider use them without rewriting log calls.
Key terms: placeholders, format string, parameters, key-value pair, RecipeCount, structured logging, semantic logging, key-value pairs, JSON, UserId
26.3 Controlling where logs are written using logging providers
This section explains how logging providers route ILogger messages to multiple destinations and how to add a third-party rolling file provider or choose centralized production logging.
- Logging provider responsibilities: Explain that logging providers consume messages created through ILogger and write them to provider-specific output destinations. Describe how a single ILogger log message is sent to every provider configured for the application.
Why it matters: Providers let the same application logging code write to consoles, files, operating-system logs, or external services without changing each log call. - Third-party provider configuration: Describe the process for adding a third-party logging provider: install its NuGet package and call its extension method on WebApplicationBuilder.Logging in Program.cs. Use the rolling file example to explain that AddFile() adds a file destination while the existing console and debug providers remain unless ClearProviders() is called.
Why it matters: You can retain convenient local-development outputs while adding a persistent or external destination for production diagnostics. - Production log destinations: Justify using a centralized log destination separate from the application for production, especially when multiple application instances run. Contrast this with console logging, which is useful during debugging, and local file logging, which persists messages but can require remote-server access, collecting files from many servers, and handling disk or permission problems.
Why it matters: Centralized logs make production failures easier to investigate without depending on access to individual servers or their local disks.
Key terms: ILogger, ILoggerProvider, logging provider, WebApplicationBuilder.Logging, NuGet package, AddFile(), ClearProviders(), console provider, debug provider, rolling file provider
26.4 Changing log verbosity with filtering
This section explains how ASP.NET Core logging filters reduce production log noise by selecting one most-specific rule based on provider, category, and log level.
- Logging filter dimensions: Explain how ASP.NET Core decides whether to write a log message by considering its log level, logger category, and logging provider. Describe how default, category-prefix, and provider-specific rules can reduce noise differently for different outputs.
Why it matters: Filtering lets you retain useful diagnostics without drowning production logs in framework and library messages. - Most-specific rule selection: Trace the algorithm that selects a single filtering rule for a log message: prefer rules for the current provider, otherwise providerless rules; choose the longest matching category prefix or Default; then use the last matching rule, falling back to the global default level. State that rules are not merged and provider-specific rules can override global category rules.
Why it matters: Knowing that one rule wins prevents surprising gaps or excess verbosity when provider and category rules overlap. - Configuration-based verbosity strategy: Describe how logging rules are normally placed in the IConfiguration "Logging" section and layered through appsettings.json plus environment-specific overrides such as appsettings.Development.json. Explain the practical strategy of keeping application logs at Debug in development and Information in production while limiting ASP.NET Core infrastructure and referenced libraries to Warning or above.
Why it matters: Environment-specific configuration provides detailed local diagnostics while keeping production output manageable.
Key terms: log level, log category, logging provider, filtering rule, Default, Microsoft namespace, provider-specific rule, category prefix, global minimum level, LogLevel:Default
26.5 Structured logging: Creating searchable, useful logs
This section introduces structured logging as a way to store log properties as searchable key-value pairs and previews using Seq and scopes to analyze them effectively.
- Structured versus text logs: Distinguish unstructured text logs from structured logs, explaining that structured logs expose log properties as key-value pairs, commonly represented as JSON.
Why it matters: Searchable properties make production log investigation faster and less error-prone than manually searching text. - Structured log investigation: Explain how key-value properties in structured logs support querying and filtering, such as finding events by EventLevel or recipe ID, instead of relying only on text searches.
Why it matters: When a customer reports a production problem, properties let you investigate whether it affects a particular customer, recipe, or pattern of events. - Structured logging providers: Describe why a logging provider is required to create and store structured logs, and identify Seq as a more user-friendly structured logging option than a production-scale Elasticsearch setup.
Why it matters: Choosing an appropriate provider determines whether application log properties can be stored centrally and explored conveniently.
Key terms: structured logging, unstructured text, key-value pairs, JSON, query, filter, analytics, EventLevel, recipe ID, logging provider
26.5.1 Adding a structured logging provider to your app
This section shows how to send ASP.NET Core structured logs to Seq and use their captured properties to investigate production errors.
- Seq structured logging provider: Describe how to add Seq as a structured logging provider to an ASP.NET Core application. State that the app registers it with AddSeq(), which sends logs to Seq’s default local URL for a local installation, while production can use overloads for additional configuration.
Why it matters: Adding a structured logging provider lets an application send searchable log data somewhere more useful than plain console output. - Structured log properties: Explain that ASP.NET Core treats captured parameters in a log message format string as named key-value properties on a structured log. Describe how Seq displays those properties when an individual log entry is expanded.
Why it matters: Named log properties preserve data that can later be filtered and analyzed instead of leaving it embedded only in rendered text. - Structured error investigation: Explain how structured properties make production troubleshooting easier by allowing logs to be filtered or queried by fields such as EventId.Id and RecipeId. Trace the example in which 13 warnings with EventId.Id 12 all identify RecipeId 3245, suggesting that the specific recipe is the likely source of the problem.
Why it matters: Searching structured fields helps narrow a broad production symptom to the affected data or component quickly.
Key terms: Seq, structured logging provider, AddSeq(), logging provider, structured logging, message format string, captured parameter, key-value pair, RecipeCount, filtering
26.5.2 Using scopes to add properties to your logs
This section explains how logging scopes attach shared contextual data to every log message within a group of operations, especially as searchable structured properties.
- Logging scope lifetime: Explain how an ILogger logging scope groups related operations by attaching the same state data to log messages written within a using block. State that a scope is created with ILogger.BeginScope<T>(state), and messages outside that block do not receive the scope data.
Why it matters: Scopes let you correlate related log entries, such as several operations for one transaction, user, or recipe. - Dictionary scope properties: Describe how the object passed as scope state is handled and why a Dictionary<string, object> is commonly used with Seq. Explain that providers decide how to handle state, often serializing ordinary state with ToString(), whereas dictionary key-value pairs become individual structured log properties that are easier to filter.
Why it matters: Using named scope properties makes related log entries searchable and filterable by values such as a user, recipe, or transaction ID.
Key terms: logging scopes, ILogger.BeginScope<T>(), scope state, using block, Dictionary<string, object>, Seq, structured logging properties, Scope property, ToString()
26.6 Summary
This summary recaps how to configure, write, filter, store, and structure ASP.NET Core logs for diagnosing production problems.
Where this is used later
- Creating a custom IHostBuilder (chapter 30) · Logging providers and their role in determining where application logs are written.
- Summary (chapter 27) · Deployment requires production-oriented application configuration, including appropriate logging settings.
- Summary (chapter 33) · Cross-cutting logging and metrics information for diagnosing application behavior.
Concepts explained in this chapter
- ILoggerProviderILoggerProvider is a logging abstraction that creates logger instances configured to write messages to a particular destination or system.
- monitoringLogging is the recording of diagnostic or operational messages generated by an application.
- logA structured log is a log record whose message details are represented as named fields, commonly as key-value pairs.
- logging levelThe Information log level records normal application flow and contextual events that help explain subsequent behavior.
- LoggerILogger is a .NET logging abstraction whose methods record application diagnostic messages through configured providers.
- log categoryA log category is a string identifier associated with a logger that identifies the component or type creating a log message.
- ILoggerFactoryILoggerFactory is a .NET logging abstraction that registers logging providers and creates loggers associated with those providers.
- log filteringA logging filter is a configuration rule that selects log messages for output according to criteria such as severity and namespace.
- placeholderA log placeholder is a named brace-delimited marker in a logging message template whose value is supplied by a corresponding runtime parameter.
- LogInformationLogInformation is an ILogger extension method that records a message at the Information severity level.
- SeqSeq is a structured log server and analysis tool for collecting, storing, searching, and filtering application log events.
- centralized logging systemCentralized logging is a logging arrangement in which application instances send their logs to a shared location separate from the applications.
- rolling file providerA rolling file provider is a logging provider that writes messages to files and starts a new file according to a rolling policy such as a daily interval.
- Logging sectionThe Logging section is the standard ASP.NET Core configuration section containing logging provider and filtering settings.
- category-specific ruleA category-specific rule is a filtering rule whose applicability is determined by the logger category or its prefix.
- filtering ruleA filtering rule is a logging configuration rule that determines whether messages meeting specified provider, category, and severity criteria are written.
- provider-specific ruleA provider-specific rule is a filtering rule whose applicability is restricted to a named logging provider.
- logging scopeA logging scope is a contextual logging construct that associates additional data with log messages emitted during a bounded execution context.
- LoggerMessageLoggerMessage is a .NET attribute that declares logging event metadata and a message template for source-generated logging methods.
- event idEventId is a .NET logging value that identifies a category or kind of log event.
- source generatorA source generator is a compiler extension that inspects program code during compilation and emits additional source files included in that compilation.
- ASP.NET CoreASP.NET Core is Microsoft's cross-platform, open-source web framework for building web applications and services on .NET.
- logging moduleA logging library provides APIs for recording and routing diagnostic and operational messages from an application.
- scopeA scope is a named permission describing an operation or resource that a client or user has been granted or consented to access.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
