Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7c06e15
Initial plan
Copilot Oct 21, 2025
6b54358
Apply freshness edits to logging.md
Copilot Oct 21, 2025
e07d910
Apply freshness edits to dependency-injection.md
Copilot Oct 21, 2025
d4509cc
Apply freshness edits to tutorials/index.md and get-started.md
Copilot Oct 21, 2025
f7ed958
Apply freshness edits to clr.md and commandline/index.md
Copilot Oct 21, 2025
f19c105
Apply freshness edits to collections/thread-safe/index.md and io/how-…
Copilot Oct 21, 2025
3d634e5
Apply freshness edits to assembly/index.md
Copilot Oct 21, 2025
58e8532
Apply freshness edits to task-parallel-library-tpl.md, httpclient-gui…
Copilot Oct 22, 2025
719003c
Apply freshness edits to ignore-properties.md, testing/index.md, depe…
Copilot Oct 22, 2025
ec77bdd
Complete freshness pass for all core/extensions articles
Copilot Oct 22, 2025
efede64
Complete freshness pass for core/tools and core/testing articles
Copilot Oct 22, 2025
161ecd3
Complete freshness pass for all 45 existing articles (2 desktop artic…
Copilot Oct 22, 2025
a1ca5d5
Second editing pass: Apply more aggressive present tense and contract…
Copilot Oct 22, 2025
4ae376a
Second editing pass: Apply systematic present tense and contraction t…
Copilot Oct 22, 2025
19ace24
Second editing pass: Fix remaining would/should instances and apply a…
Copilot Oct 22, 2025
72d56f4
edit pass
meaghanlewis Oct 23, 2025
e5c7c2e
fix invalid link
meaghanlewis Oct 23, 2025
46b92f7
Update docs/core/extensions/logging.md
meaghanlewis Oct 23, 2025
f785287
Update docs/core/extensions/logging-providers.md
meaghanlewis Oct 23, 2025
b85e6e6
Merge branch 'main' into copilot/update-stale-dotnet-docs
meaghanlewis Oct 27, 2025
eac076e
Update docs/core/deploying/native-aot/index.md
meaghanlewis Oct 27, 2025
966cd42
Update docs/core/deploying/single-file/overview.md
meaghanlewis Oct 27, 2025
39221d8
Update docs/core/extensions/caching.md
meaghanlewis Oct 27, 2025
502339e
Update docs/standard/parallel-programming/task-based-asynchronous-pro…
meaghanlewis Oct 27, 2025
31480f6
Update docs/standard/garbage-collection/fundamentals.md
meaghanlewis Oct 27, 2025
6a1d702
address review feedback
meaghanlewis Oct 27, 2025
8d71a13
Update docs/core/extensions/logging.md
meaghanlewis Oct 27, 2025
39c35d8
Update docs/core/extensions/logging.md
meaghanlewis Oct 27, 2025
1ad3f83
Update docs/core/extensions/logging.md
meaghanlewis Oct 27, 2025
f3eeae2
Update docs/core/versions/selection.md
meaghanlewis Oct 27, 2025
3636ee8
Update docs/standard/base-types/formatting-types.md
meaghanlewis Oct 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/core/deploying/native-aot/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
title: Native AOT deployment overview
description: Learn what Native AOT deployments are and why you should consider using it as part of the publishing your app with .NET 7 and later.
author: lakshanf
ms.date: 06/12/2023
ms.date: 10/22/2025
ai-usage: ai-assisted
---

# Native AOT deployment
Expand Down Expand Up @@ -134,7 +135,7 @@ Native AOT apps have the following limitations:
- Implies compilation into a single file, which has known [incompatibilities](../single-file/overview.md#api-incompatibility).
- Apps include required runtime libraries (just like [self-contained apps](../index.md#self-contained-deployment), increasing their size as compared to framework-dependent apps).
- <xref:System.Linq.Expressions> always use their interpreted form, which is slower than run-time generated compiled code.
- Generic parameters substituted with struct type arguments will have specialized code generated for each instantiation. In the dynamic runtime, many instantiations are generated on-demand. In Native AOT, all instantiations are pre-generated. This can have significant impact to the disk size of the application. Generic virtual methods and generic instance methods will also have an instantiation for every implementing or overriding type.
- Generic parameters substituted with struct type arguments have specialized code generated for each instantiation. In the dynamic runtime, many instantiations are generated on-demand. In Native AOT, all instantiations are pre-generated. This can have significant impact to the disk size of the application. Generic virtual methods and generic instance methods will also have an instantiation for every implementing or overriding type.
- Not all the runtime libraries are fully annotated to be Native AOT compatible. That is, some warnings in the runtime libraries aren't actionable by end developers.
- [Diagnostic support for debugging and profiling](./diagnostics.md) with some limitations.
- Support for some ASP.NET Core features. For more information, see [ASP.NET Core support for Native AOT](/aspnet/core/fundamentals/native-aot/).
Expand Down
11 changes: 6 additions & 5 deletions docs/core/deploying/single-file/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
title: Create a single file for application deployment
description: Learn what single file application is and why you should consider using this application deployment model.
author: lakshanf
ms.date: 06/21/2022
ms.date: 10/22/2025
ms.custom: kr2b-contr-experiment
ai-usage: ai-assisted
---

# Single-file deployment
Expand Down Expand Up @@ -209,11 +210,11 @@ We have some recommendations for fixing common scenarios:

Some workflows require post-processing of binaries before bundling. A common example is signing. The dotnet SDK provides MSBuild extension points to allow processing binaries just before single-file bundling. The available APIs are:

- A target `PrepareForBundle` that will be called before `GenerateSingleFileBundle`
- An `<ItemGroup><FilesToBundle /></ItemGroup>` containing all files that will be bundled
- A target `PrepareForBundle` that is called before `GenerateSingleFileBundle`
- An `<ItemGroup><FilesToBundle /></ItemGroup>` containing all files that are to be bundled
- A Property `AppHostFile` that will specify the apphost template. Post-processing might want to exclude the apphost from processing.

To plug into this involves creating a target that will be executed between `PrepareForBundle` and `GenerateSingleFileBundle`.
To plug into this involves creating a target that is executed between `PrepareForBundle` and `GenerateSingleFileBundle`.

Consider the following .NET project `Target` node example:

Expand All @@ -225,7 +226,7 @@ It's possible that tooling will need to copy files in the process of signing. Th

### Compress assemblies in single-file apps

Single-file apps can be created with compression enabled on the embedded assemblies. Set the `EnableCompressionInSingleFile` property to `true`. The single file that's produced will have all of the embedded assemblies compressed, which can significantly reduce the size of the executable.
Single-file apps can be created with compression enabled on the embedded assemblies. Set the `EnableCompressionInSingleFile` property to `true`. The single file that's produced has all of the embedded assemblies compressed, which can significantly reduce the size of the executable.

Compression comes with a performance cost. On application start, the assemblies must be decompressed into memory, which takes some time. We recommend that you measure both the size change and startup cost of enabling compression before using it. The impact can vary significantly between different applications.

Expand Down
7 changes: 4 additions & 3 deletions docs/core/extensions/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ title: Caching in .NET
description: Discover effective ways to implement in-memory and distributed caching in .NET. Boost app performance and scalability with .NET caching.
author: IEvangelist
ms.author: dapine
ms.date: 04/11/2024
ms.date: 10/22/2025
ai-usage: ai-assisted
---

# Caching in .NET
Expand Down Expand Up @@ -95,7 +96,7 @@ Now that the cache is populated, another call to `IterateAlphabetAsync` is await

:::code source="snippets/caching/memory-apis/Program.cs" range="56-66":::

If the `cache` contains the `letter` key, and the `value` is an instance of an `AlphabetLetter` it's written to the console. When the `letter` key is not in the cache, it was evicted and its post eviction callback was invoked.
If the `cache` contains the `letter` key, and the `value` is an instance of an `AlphabetLetter` it's written to the console. When the `letter` key isn't in the cache, it was evicted and its post eviction callback was invoked.

#### Additional extension methods

Expand Down Expand Up @@ -261,7 +262,7 @@ Consider any of the available implementations of the `IDistributedCache` from th

### Distributed caching API

The distributed caching APIs are a bit more primitive than their in-memory caching API counterparts. The key-value pairs are a bit more basic. In-memory caching keys are based on an `object`, whereas the distributed keys are a `string`. With in-memory caching, the value can be any strongly-typed generic, whereas values in distributed caching are persisted as `byte[]`. That's not to say that various implementations don't expose strongly-typed generic values but that would be an implementation detail.
The distributed caching APIs are a bit more primitive than their in-memory caching API counterparts. The key-value pairs are a bit more basic. In-memory caching keys are based on an `object`, whereas the distributed keys are a `string`. With in-memory caching, the value can be any strongly typed generic, whereas values in distributed caching are persisted as `byte[]`. That's not to say that various implementations don't expose strongly typed generic values, but that's an implementation detail.

#### Create values

Expand Down
11 changes: 6 additions & 5 deletions docs/core/extensions/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ title: Channels
description: Learn the official synchronization data structures in System.Threading.Channels for producers and consumers with .NET.
author: IEvangelist
ms.author: dapine
ms.date: 06/26/2023
ms.date: 10/22/2025
ai-usage: ai-assisted
---

# System.Threading.Channels library
Expand All @@ -14,7 +15,7 @@ This library is available in the [System.Threading.Channels](https://www.nuget.o

## Producer/consumer conceptual programming model

Channels are an implementation of the producer/consumer conceptual programming model. In this programming model, producers asynchronously produce data, and consumers asynchronously consume that data. In other words, this model passes data from one party to another through a first-in first-out ("FIFO") queue. Try to think of channels as you would any other common generic collection type, such as a `List<T>`. The primary difference is that this collection manages synchronization and provides various consumption models through factory creation options. These options control the behavior of the channels, such as how many elements they're allowed to store and what happens if that limit is reached, or whether the channel is accessed by multiple producers or multiple consumers concurrently.
Channels are an implementation of the producer/consumer conceptual programming model. In this programming model, producers asynchronously produce data, and consumers asynchronously consume that data. In other words, this model passes data from one party to another through a first-in first-out ("FIFO") queue. Think of channels as any other common generic collection type, such as a `List<T>`. The primary difference is that this collection manages synchronization and provides various consumption models through factory creation options. These options control the behavior of the channels, such as how many elements they're allowed to store and what happens if that limit is reached, or whether the channel is accessed by multiple producers or multiple consumers concurrently.

## Bounding strategies

Expand All @@ -23,7 +24,7 @@ Depending on how a `Channel<T>` is created, its reader and writer behave differe
To create a channel that specifies a maximum capacity, call <xref:System.Threading.Channels.Channel.CreateBounded%2A?displayProperty=nameWithType>. To create a channel that is used by any number of readers and writers concurrently, call <xref:System.Threading.Channels.Channel.CreateUnbounded%2A?displayProperty=nameWithType>. Each bounding strategy exposes various creator-defined options, either <xref:System.Threading.Channels.BoundedChannelOptions> or <xref:System.Threading.Channels.UnboundedChannelOptions> respectively.

> [!NOTE]
> Regardless of the bounding strategy, a channel will always throw a <xref:System.Threading.Channels.ChannelClosedException> when it's used after it's been closed.
> Regardless of the bounding strategy, a channel always throws a <xref:System.Threading.Channels.ChannelClosedException> when it's used after it's been closed.

### Unbounded channels

Expand Down Expand Up @@ -140,7 +141,7 @@ An alternative producer might use the `WriteAsync` method:

:::code language="csharp" source="snippets/channels/Program.Producer.cs" id="whilewrite":::

Again, the `Channel<Coordinates>.Writer` is used within a `while` loop. But this time, the <xref:System.Threading.Channels.ChannelWriter%601.WriteAsync%2A> method is called. The method will continue only after the coordinates have been written. When the `while` loop exits, a call to <xref:System.Threading.Channels.ChannelWriter%601.Complete%2A> is made, which signals that no more data is written to the channel.
Again, the `Channel<Coordinates>.Writer` is used within a `while` loop. But this time, the <xref:System.Threading.Channels.ChannelWriter%601.WriteAsync%2A> method is called. The method continues only after the coordinates have been written. When the `while` loop exits, a call to <xref:System.Threading.Channels.ChannelWriter%601.Complete%2A> is made, which signals that no more data is written to the channel.

Another producer pattern is to use the <xref:System.Threading.Channels.ChannelWriter%601.WaitToWriteAsync%2A> method, consider the following code:

Expand All @@ -155,7 +156,7 @@ There are several common channel consumer patterns. When a channel is never endi
:::code language="csharp" source="snippets/channels/Program.Consumer.cs" id="whiletrue":::

> [!NOTE]
> This code will throw an exception if the channel is closed.
> This code throws an exception if the channel is closed.

An alternative consumer could avoid this concern by using a nested while loop, as shown in the following code:

Expand Down
13 changes: 7 additions & 6 deletions docs/core/extensions/dependency-injection-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ title: Dependency injection guidelines
description: Discover effective dependency injection guidelines and best practices for developing .NET apps. Deepen your understanding of inversion of control.
author: IEvangelist
ms.author: dapine
ms.date: 07/18/2024
ms.date: 10/22/2025
ms.topic: concept-article
ai-usage: ai-assisted
---

# Dependency injection guidelines
Expand Down Expand Up @@ -91,7 +92,7 @@ The app requires an <xref:System.IDisposable> instance with a transient lifetime

**Solution**

Use the factory pattern to create an instance outside of the parent scope. In this situation, the app would generally have a `Create` method that calls the final type's constructor directly. If the final type has other dependencies, the factory can:
Use the factory pattern to create an instance outside of the parent scope. In this situation, the app generally has a `Create` method that calls the final type's constructor directly. If the final type has other dependencies, the factory can:

- Receive an <xref:System.IServiceProvider> in its constructor.
- Use <xref:Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance%2A?displayProperty=nameWithType> to instantiate the instance outside of the container, while using the container for its dependencies.
Expand Down Expand Up @@ -158,8 +159,8 @@ The factory method of a singleton service, such as the second argument to [AddSi
- **Coupling**: It can couple otherwise unrelated requests.
- **Testing challenges**: Shared state and coupling can make unit testing more difficult.
- **Memory impact**: A singleton may keep a large object graph alive in memory for the lifetime of the application.
- **Fault tolerance**: If a singleton or any part of its dependency tree fails, it cannot easily recover.
- **Configuration reloading**: Singletons generally cannot support "hot reload" of configuration values.
- **Fault tolerance**: If a singleton or any part of its dependency tree fails, it can't easily recover.
- **Configuration reloading**: Singletons generally can't support "hot reload" of configuration values.
- **Scope leakage**: A singleton can inadvertently capture scoped or transient dependencies, effectively promoting them to singletons and causing unintended side effects.
- **Initialization overhead**: When resolving a service, the IoC container needs to look up the singleton instance. If it doesn't already exist, it needs to create it in a thread-safe manner. In contrast, a stateless transient service is very cheap to create and destroy.

Expand All @@ -180,7 +181,7 @@ When you register *Transient* services that implement <xref:System.IDisposable>,

:::image type="content" source="media/transient-disposables-without-dispose.png" lightbox="media/transient-disposables-without-dispose.png" alt-text="Anti-pattern: Transient disposables without dispose. Do not copy!":::

In the preceding anti-pattern, 1,000 `ExampleDisposable` objects are instantiated and rooted. They will not be disposed of until the `serviceProvider` instance is disposed.
In the preceding anti-pattern, 1,000 `ExampleDisposable` objects are instantiated and rooted. They won't be disposed of until the `serviceProvider` instance is disposed.

For more information on debugging memory leaks, see [Debug a memory leak in .NET](../diagnostics/debug-memory-leak.md).

Expand Down Expand Up @@ -208,7 +209,7 @@ In the preceding code, `Foo` is registered as a singleton and `Bar` is scoped -

:::code language="csharp" source="snippets/configuration/di-anti-patterns/Foo.cs":::

The `Foo` object requires a `Bar` object, and since `Foo` is a singleton, and `Bar` is scoped - this is a misconfiguration. As is, `Foo` would only be instantiated once, and it would hold onto `Bar` for its lifetime, which is longer than the intended scoped lifetime of `Bar`. You should consider validating scopes, by passing `validateScopes: true` to the <xref:Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Boolean)>. When you validate the scopes, you'd get an <xref:System.InvalidOperationException> with a message similar to "Cannot consume scoped service 'Bar' from singleton 'Foo'.".
The `Foo` object requires a `Bar` object, and since `Foo` is a singleton, and `Bar` is scoped - this is a misconfiguration. As is, `Foo` is only instantiated once, and it holds onto `Bar` for its lifetime, which is longer than the intended scoped lifetime of `Bar`. Consider validating scopes by passing `validateScopes: true` to the <xref:Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Boolean)>. When you validate the scopes, you get an <xref:System.InvalidOperationException> with a message similar to "Cannot consume scoped service 'Bar' from singleton 'Foo'.".

For more information, see [Scope validation](dependency-injection.md#scope-validation).

Expand Down
13 changes: 7 additions & 6 deletions docs/core/extensions/dependency-injection-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ title: Use dependency injection
description: Learn how to use dependency injection in your .NET apps with this comprehensive tutorial. Follow along with this pragmatic guide to understand DI in C#.
author: IEvangelist
ms.author: dapine
ms.date: 07/18/2024
ms.date: 10/22/2025
ms.topic: tutorial
no-loc: [Transient, Scoped, Singleton, Example]
ai-usage: ai-assisted
---

# Tutorial: Use dependency injection in .NET
Expand Down Expand Up @@ -39,7 +40,7 @@ Your new console app project file should resemble the following:

## Add interfaces

In this sample app, you'll learn how dependency injection handles service lifetime. You'll create several interfaces that represent different service lifetimes. Add the following interfaces to the project root directory:
In this sample app, you learn how dependency injection handles service lifetime. You create several interfaces that represent different service lifetimes. Add the following interfaces to the project root directory:

*IReportServiceLifetime.cs*

Expand Down Expand Up @@ -80,7 +81,7 @@ The example implementations all initialize their `Id` property with the result o

:::code source="snippets/configuration/console-di/ExampleSingletonService.cs":::

Each implementation is defined as `internal sealed` and implements its corresponding interface. They're not required to be `internal` or `sealed`, however, it's common to treat implementations as `internal` to avoid leaking implementation types to external consumers. Furthermore, since each type will not be extended, it's marked as `sealed`. For example, `ExampleSingletonService` implements `IExampleSingletonService`.
Each implementation is defined as `internal sealed` and implements its corresponding interface. They're not required to be `internal` or `sealed`, however, it's common to treat implementations as `internal` to avoid leaking implementation types to external consumers. Furthermore, since each type isn't extended, it's marked as `sealed`. For example, `ExampleSingletonService` implements `IExampleSingletonService`.

## Add a service that requires DI

Expand All @@ -100,7 +101,7 @@ Update *Program.cs* with the following code:

Each `services.Add{LIFETIME}<{SERVICE}>` extension method adds (and potentially configures) services. We recommend that apps follow this convention. Don't place extension methods in the <xref:Microsoft.Extensions.DependencyInjection?displayProperty=fullName> namespace unless you're authoring an official Microsoft package. Extension methods that are defined within the `Microsoft.Extensions.DependencyInjection` namespace:

- Are displayed in [IntelliSense](/visualstudio/ide/using-intellisense) without requiring additional `using` directives.
- Are displayed in [IntelliSense](/visualstudio/ide/using-intellisense) without requiring more `using` directives.
- Reduce the number of required `using` directives in the `Program` or `Startup` classes where these extension methods are typically called.

The app:
Expand All @@ -120,9 +121,9 @@ When you run the app, it displays output similar to the following:

From the app output, you can see that:

- Transient services are always different, a new instance is created with every retrieval of the service.
- Transient services are always different. A new instance is created with every retrieval of the service.
- Scoped services change only with a new scope, but are the same instance within a scope.
- Singleton services are always the same, a new instance is only created once.
- Singleton services are always the same. A new instance is only created once.

## See also

Expand Down
Loading