Skip to content

Commit 435783f

Browse files
CopilotmeaghanlewisCopilotgewarren
authored
Freshness pass for Q2FY26: Update 44 .NET Fundamentals articles with style improvements and current dates (#49392)
* Initial plan * Apply freshness edits to logging.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to dependency-injection.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to tutorials/index.md and get-started.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to clr.md and commandline/index.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to collections/thread-safe/index.md and io/how-to-write-text-to-a-file.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to assembly/index.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to task-parallel-library-tpl.md, httpclient-guidelines.md, and socket-services.md Co-authored-by: meaghanlewis <[email protected]> * Apply freshness edits to ignore-properties.md, testing/index.md, dependency-injection-usage.md, and regular-expressions.md Co-authored-by: meaghanlewis <[email protected]> * Complete freshness pass for all core/extensions articles Co-authored-by: meaghanlewis <[email protected]> * Complete freshness pass for core/tools and core/testing articles Co-authored-by: meaghanlewis <[email protected]> * Complete freshness pass for all 45 existing articles (2 desktop articles not found in repo) Co-authored-by: meaghanlewis <[email protected]> * Second editing pass: Apply more aggressive present tense and contraction transformations (batch 1) Co-authored-by: meaghanlewis <[email protected]> * Second editing pass: Apply systematic present tense and contraction transformations across all 45 articles Co-authored-by: meaghanlewis <[email protected]> * Second editing pass: Fix remaining would/should instances and apply additional contractions Co-authored-by: meaghanlewis <[email protected]> * edit pass * fix invalid link * Update docs/core/extensions/logging.md Co-authored-by: Copilot <[email protected]> * Update docs/core/extensions/logging-providers.md Co-authored-by: Copilot <[email protected]> * Update docs/core/deploying/native-aot/index.md Co-authored-by: Genevieve Warren <[email protected]> * Update docs/core/deploying/single-file/overview.md Co-authored-by: Genevieve Warren <[email protected]> * Update docs/core/extensions/caching.md Co-authored-by: Genevieve Warren <[email protected]> * Update docs/standard/parallel-programming/task-based-asynchronous-programming.md Co-authored-by: Genevieve Warren <[email protected]> * Update docs/standard/garbage-collection/fundamentals.md Co-authored-by: Genevieve Warren <[email protected]> * address review feedback --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: meaghanlewis <[email protected]> Co-authored-by: Meaghan Osagie <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Genevieve Warren <[email protected]>
1 parent 895fe13 commit 435783f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+326
-285
lines changed

docs/core/deploying/native-aot/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
title: Native AOT deployment overview
33
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.
44
author: lakshanf
5-
ms.date: 06/12/2023
5+
ms.date: 10/22/2025
6+
ai-usage: ai-assisted
67
---
78

89
# Native AOT deployment
@@ -134,7 +135,7 @@ Native AOT apps have the following limitations:
134135
- Implies compilation into a single file, which has known [incompatibilities](../single-file/overview.md#api-incompatibility).
135136
- Apps include required runtime libraries (just like [self-contained apps](../index.md#self-contained-deployment), increasing their size as compared to framework-dependent apps).
136137
- <xref:System.Linq.Expressions> always use their interpreted form, which is slower than run-time generated compiled code.
137-
- 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.
138+
- 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.
138139
- 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.
139140
- [Diagnostic support for debugging and profiling](./diagnostics.md) with some limitations.
140141
- Support for some ASP.NET Core features. For more information, see [ASP.NET Core support for Native AOT](/aspnet/core/fundamentals/native-aot/).

docs/core/deploying/single-file/overview.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
title: Create a single file for application deployment
33
description: Learn what single file application is and why you should consider using this application deployment model.
44
author: lakshanf
5-
ms.date: 06/21/2022
5+
ms.date: 10/22/2025
66
ms.custom: kr2b-contr-experiment
7+
ai-usage: ai-assisted
78
---
89

910
# Single-file deployment
@@ -209,11 +210,11 @@ We have some recommendations for fixing common scenarios:
209210
210211
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:
211212
212-
- A target `PrepareForBundle` that will be called before `GenerateSingleFileBundle`
213-
- An `<ItemGroup><FilesToBundle /></ItemGroup>` containing all files that will be bundled
213+
- A target `PrepareForBundle` that is called before `GenerateSingleFileBundle`
214+
- An `<ItemGroup><FilesToBundle /></ItemGroup>` containing all files that are to be bundled
214215
- A Property `AppHostFile` that will specify the apphost template. Post-processing might want to exclude the apphost from processing.
215216
216-
To plug into this involves creating a target that will be executed between `PrepareForBundle` and `GenerateSingleFileBundle`.
217+
To plug into this involves creating a target that is executed between `PrepareForBundle` and `GenerateSingleFileBundle`.
217218
218219
Consider the following .NET project `Target` node example:
219220
@@ -225,7 +226,7 @@ It's possible that tooling will need to copy files in the process of signing. Th
225226

226227
### Compress assemblies in single-file apps
227228

228-
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.
229+
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.
229230

230231
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.
231232

docs/core/extensions/caching.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ title: Caching in .NET
33
description: Discover effective ways to implement in-memory and distributed caching in .NET. Boost app performance and scalability with .NET caching.
44
author: IEvangelist
55
ms.author: dapine
6-
ms.date: 04/11/2024
6+
ms.date: 10/22/2025
7+
ai-usage: ai-assisted
78
---
89

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

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

98-
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.
99+
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.
99100

100101
#### Additional extension methods
101102

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

262263
### Distributed caching API
263264

264-
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.
265+
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.
265266

266267
#### Create values
267268

docs/core/extensions/channels.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ title: Channels
33
description: Learn the official synchronization data structures in System.Threading.Channels for producers and consumers with .NET.
44
author: IEvangelist
55
ms.author: dapine
6-
ms.date: 06/26/2023
6+
ms.date: 10/22/2025
7+
ai-usage: ai-assisted
78
---
89

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

1516
## Producer/consumer conceptual programming model
1617

17-
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.
18+
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.
1819

1920
## Bounding strategies
2021

@@ -23,7 +24,7 @@ Depending on how a `Channel<T>` is created, its reader and writer behave differe
2324
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.
2425

2526
> [!NOTE]
26-
> 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.
27+
> Regardless of the bounding strategy, a channel always throws a <xref:System.Threading.Channels.ChannelClosedException> when it's used after it's been closed.
2728
2829
### Unbounded channels
2930

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

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

143-
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.
144+
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.
144145

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

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

157158
> [!NOTE]
158-
> This code will throw an exception if the channel is closed.
159+
> This code throws an exception if the channel is closed.
159160
160161
An alternative consumer could avoid this concern by using a nested while loop, as shown in the following code:
161162

docs/core/extensions/dependency-injection-guidelines.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ title: Dependency injection guidelines
33
description: Discover effective dependency injection guidelines and best practices for developing .NET apps. Deepen your understanding of inversion of control.
44
author: IEvangelist
55
ms.author: dapine
6-
ms.date: 07/18/2024
6+
ms.date: 10/22/2025
77
ms.topic: concept-article
8+
ai-usage: ai-assisted
89
---
910

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

9293
**Solution**
9394

94-
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:
95+
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:
9596

9697
- Receive an <xref:System.IServiceProvider> in its constructor.
9798
- 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.
@@ -158,8 +159,8 @@ The factory method of a singleton service, such as the second argument to [AddSi
158159
- **Coupling**: It can couple otherwise unrelated requests.
159160
- **Testing challenges**: Shared state and coupling can make unit testing more difficult.
160161
- **Memory impact**: A singleton may keep a large object graph alive in memory for the lifetime of the application.
161-
- **Fault tolerance**: If a singleton or any part of its dependency tree fails, it cannot easily recover.
162-
- **Configuration reloading**: Singletons generally cannot support "hot reload" of configuration values.
162+
- **Fault tolerance**: If a singleton or any part of its dependency tree fails, it can't easily recover.
163+
- **Configuration reloading**: Singletons generally can't support "hot reload" of configuration values.
163164
- **Scope leakage**: A singleton can inadvertently capture scoped or transient dependencies, effectively promoting them to singletons and causing unintended side effects.
164165
- **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.
165166

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

181182
:::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!":::
182183

183-
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.
184+
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.
184185

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

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

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

211-
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'.".
212+
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'.".
212213

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

docs/core/extensions/dependency-injection-usage.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ title: Use dependency injection
33
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#.
44
author: IEvangelist
55
ms.author: dapine
6-
ms.date: 07/18/2024
6+
ms.date: 10/22/2025
77
ms.topic: tutorial
88
no-loc: [Transient, Scoped, Singleton, Example]
9+
ai-usage: ai-assisted
910
---
1011

1112
# Tutorial: Use dependency injection in .NET
@@ -39,7 +40,7 @@ Your new console app project file should resemble the following:
3940
4041
## Add interfaces
4142

42-
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:
43+
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:
4344

4445
*IReportServiceLifetime.cs*
4546

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

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

83-
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`.
84+
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`.
8485

8586
## Add a service that requires DI
8687

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

101102
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:
102103

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

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

121122
From the app output, you can see that:
122123

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

127128
## See also
128129

0 commit comments

Comments
 (0)