diff --git a/.github/workflows/profanity-filter.yml b/.github/workflows/profanity-filter.yml
deleted file mode 100644
index 98c942595f4b5..0000000000000
--- a/.github/workflows/profanity-filter.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: Profanity filter
-
-on:
- issue_comment:
- types: [created, edited]
- issues:
- types: [opened, edited, reopened]
- pull_request:
- types: [opened, edited, reopened]
-
-permissions:
- issues: write
- pull-requests: write
-
-jobs:
- apply-filter:
- name: Apply profanity filter
- runs-on: ubuntu-latest
-
- steps:
- - name: Harden Runner
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
- with:
- egress-policy: audit
-
- - name: Profanity filter
- if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'github-actions[bot]' }}
- uses: IEvangelist/profanity-filter@4655e7a15cd4a13a5c9b13affed04a487f556083 # main
- id: profanity-filter
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- replacement-strategy: redacted-rectangle
diff --git a/.github/workflows/snippets5000.yml b/.github/workflows/snippets5000.yml
index 634c62a42df91..8cbaf70631d0a 100644
--- a/.github/workflows/snippets5000.yml
+++ b/.github/workflows/snippets5000.yml
@@ -41,7 +41,7 @@ jobs:
# Get the latest preview SDK (or sdk not installed by the runner)
- name: Setup .NET
if: ${{ env.DOTNET_DO_INSTALL == 'true' }}
- uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 #@5.3.0
+ uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 #@5.4.0
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
dotnet-quality: ${{ env.DOTNET_QUALITY }}
diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json
index 29128b703ea02..25c1563e1f38b 100644
--- a/.openpublishing.redirection.csharp.json
+++ b/.openpublishing.redirection.csharp.json
@@ -1,605 +1,5 @@
{
"redirections": [
- {
- "source_path_from_root": "/docs/csharp/how-to/compare-strings.md",
- "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/compare",
- "redirect_document_id": true
- },
- {
- "source_path_from_root": "/docs/csharp/how-to/concatenate-multiple-strings.md",
- "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/concatenate",
- "redirect_document_id": true
- },
- {
- "source_path_from_root": "/docs/csharp/how-to/modify-string-contents.md",
- "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/modify",
- "redirect_document_id": true
- },
- {
- "source_path_from_root": "/docs/csharp/tutorials/string-interpolation.md",
- "redirect_url": "/dotnet/csharp/fundamentals/tutorials/string-interpolation",
- "redirect_document_id": true
- },
- {
- "source_path_from_root": "/docs/csharp/fundamentals/null-safety/migration-strategies.md",
- "redirect_url": "/dotnet/csharp/advanced-topics/update-applications/nullable-migration-strategies"
- },
- {
- "source_path_from_root": "/docs/csharp/fundamentals/types/anonymous-types.md",
- "redirect_url": "/dotnet/csharp/fundamentals/types/tuples"
- },
- {
- "source_path_from_root": "/docs/csharp/fundamentals/types/namespaces.md",
- "redirect_url": "/dotnet/csharp/fundamentals/program-structure/namespaces"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0006.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0007.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0016.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1564.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1616.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1763.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs2032.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0017.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0028.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0031.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0059.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0123.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0144.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0148.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0220.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0221.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0273.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0274.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0275.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0276.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0406.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0409.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0410.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0411.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0442.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0452.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0453.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0456.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0463.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0543.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0544.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0546.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0547.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0548.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0594.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0610.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0644.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0652.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0659.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0693.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0699.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0701.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0704.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0712.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0718.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1021.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0080.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0081.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0305.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0306.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0307.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0308.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0312.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0313.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0314.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0315.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0401.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0402.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0403.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0405.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0407.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0412.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0449.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0450.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0451.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0454.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0455.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0694.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0695.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0698.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0706.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0717.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0104.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0104"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0434.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0434"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0435.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0435"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0436.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0436"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0437.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0437"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs0438.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0438"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1022.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs1022"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1526.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1555.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1556.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1557.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1558.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1559.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1599.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1617.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1638.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1664.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1668.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1715.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1719.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1720.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1948.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs1958.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs2008.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs2017.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs2019.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs2029.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs2036.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs3012.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs3013.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs3024.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs5001.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0304.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0310.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0311.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0413.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0417.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0467.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0702.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0703.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
- },
- {
- "source_path_from_root": "/docs/csharp/misc/cs8500.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/binary-literals.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/digit-separators.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/local-functions.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/statements#1364-local-function-declarations"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/throw-expression.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1215-the-throw-expression-operator"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/out-var.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1217-declaration-expressions"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/pattern-matching.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/patterns"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.0/task-types.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#15152-task-type-builder-pattern"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.1/async-main.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/basic-concepts#71-application-startup"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.1/target-typed-default.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12719-default-value-expressions"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.1/infer-tuple-names.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/types#8311-tuple-types"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.1/generics-pattern-match.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/patterns"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/conditional-ref.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1219-conditional-operator"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/non-trailing-named-arguments.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12621-general"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/private-protected.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#1536-access-modifiers"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/readonly-ref.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/readonly-struct.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/structs#1624-struct-interfaces"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.2/span-safety.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/auto-prop-field-attrs.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/attributes#223-attribute-specification"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/blittable.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#1525-type-parameter-constraints"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/expression-variables-in-initializers.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1217-declaration-expressions"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/improved-overload-candidates.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12642-applicable-function-member"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/indexing-movable-fixed-fields.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/unsafe-code#2383-fixed-size-buffers-in-expressions"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/leading-digit-separator.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/pattern-based-fixed.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/unsafe-code#247-the-fixed-statement"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/ref-local-reassignment.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/stackalloc-array-initializers.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12821-stack-allocation"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-7.3/tuple-equality.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#121211-tuple-equality-operators"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-9.0/nullable-reference-types-specification.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/types#893-nullable-reference-types"
- },
- {
- "source_path_from_root": "/redirections/proposals/csharp-10.0/generic-attributes.md",
- "redirect_url": "/dotnet/csharp/language-reference/language-specification/attributes#232-attribute-classes"
- },
{
"source_path_from_root": "/docs/csharp/async.md",
"redirect_url": "/dotnet/csharp/asynchronous-programming"
@@ -676,10 +76,22 @@
"source_path_from_root": "/docs/csharp/features.md",
"redirect_url": "/dotnet/csharp/programming-guide/concepts"
},
+ {
+ "source_path_from_root": "/docs/csharp/fundamentals/null-safety/migration-strategies.md",
+ "redirect_url": "/dotnet/csharp/advanced-topics/update-applications/nullable-migration-strategies"
+ },
{
"source_path_from_root": "/docs/csharp/fundamentals/null-safety/resolve-warnings.md",
"redirect_url": "/dotnet/csharp/fundamentals/null-safety/common-tasks/resolve-warnings"
},
+ {
+ "source_path_from_root": "/docs/csharp/fundamentals/types/anonymous-types.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/types/tuples"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/fundamentals/types/namespaces.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/program-structure/namespaces"
+ },
{
"source_path_from_root": "/docs/csharp/generics.md",
"redirect_url": "/dotnet/csharp/fundamentals/types/generics"
@@ -751,6 +163,21 @@
"source_path_from_root": "/docs/csharp/getting-started/with-visual-studio.md",
"redirect_url": "/dotnet/core/tutorials/with-visual-studio"
},
+ {
+ "source_path_from_root": "/docs/csharp/how-to/compare-strings.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/compare",
+ "redirect_document_id": true
+ },
+ {
+ "source_path_from_root": "/docs/csharp/how-to/concatenate-multiple-strings.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/concatenate",
+ "redirect_document_id": true
+ },
+ {
+ "source_path_from_root": "/docs/csharp/how-to/modify-string-contents.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/strings/common-tasks/modify",
+ "redirect_document_id": true
+ },
{
"source_path_from_root": "/docs/csharp/how-to/parse-strings-using-split.md",
"redirect_url": "/dotnet/csharp/fundamentals/strings/split"
@@ -803,6 +230,18 @@
"source_path_from_root": "/docs/csharp/language-reference/builtin-types/nint-nuint.md",
"redirect_url": "/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#native-sized-integers"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0006.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0007.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0016.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0034.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overload-resolution"
@@ -851,6 +290,30 @@
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0270.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0304.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0310.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0311.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0413.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0417.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0467.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0518.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0518"
@@ -891,6 +354,14 @@
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0686.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0702.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0703.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0767.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/ref-modifiers-errors"
@@ -963,10 +434,18 @@
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1502.md",
"redirect_url": "/dotnet/csharp/misc/cs1503"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1564.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1614.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1616.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1656.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
@@ -1015,6 +494,10 @@
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1751.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1763.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1919.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
@@ -1051,6 +534,10 @@
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1997.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/async-await-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs2032.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs3007.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
@@ -2253,10 +1740,22 @@
"source_path_from_root": "/docs/csharp/misc/cs0012.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/assembly-references"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0017.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0022.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0028.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0031.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0035.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
@@ -2269,6 +1768,22 @@
"source_path_from_root": "/docs/csharp/misc/cs0057.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0059.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0080.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0081.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0104.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0104"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0105.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
@@ -2281,6 +1796,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0121.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overload-resolution"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0123.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0132.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/constructor-errors#static-constructors"
@@ -2289,6 +1808,14 @@
"source_path_from_root": "/docs/csharp/misc/cs0138.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0144.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0148.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0171.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors"
@@ -2369,6 +1896,14 @@
"source_path_from_root": "/docs/csharp/misc/cs0218.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0220.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0221.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0225.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
@@ -2433,6 +1968,22 @@
"source_path_from_root": "/docs/csharp/misc/cs0267.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/partial-declarations"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0273.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0274.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0275.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0276.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0277.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors"
@@ -2441,14 +1992,86 @@
"source_path_from_root": "/docs/csharp/misc/cs0282.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/partial-declarations"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0305.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0306.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0307.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0308.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0312.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0313.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0314.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0315.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0400.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/assembly-references"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0401.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0402.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0403.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0404.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0405.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0406.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0407.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0409.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0410.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0411.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0412.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0415.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
@@ -2477,6 +2100,26 @@
"source_path_from_root": "/docs/csharp/misc/cs0432.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0434.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0434"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0435.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0435"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0436.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0436"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0437.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0437"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0438.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs0438"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0439.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
@@ -2485,6 +2128,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0440.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0442.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0447.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
@@ -2493,6 +2140,38 @@
"source_path_from_root": "/docs/csharp/misc/cs0448.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0449.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0450.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0451.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0452.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0453.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0454.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0455.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0456.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0457.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overload-resolution"
@@ -2505,6 +2184,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0460.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0463.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0466.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
@@ -2569,6 +2252,26 @@
"source_path_from_root": "/docs/csharp/misc/cs0541.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0543.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0544.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0546.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0547.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0548.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0550.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors"
@@ -2653,6 +2356,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0591.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/parameter-argument-mismatch"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0594.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0599.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/parameter-argument-mismatch"
@@ -2661,6 +2368,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0609.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0610.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0611.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
@@ -2705,6 +2416,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0643.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/parameter-argument-mismatch"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0644.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0646.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
@@ -2713,6 +2428,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0647.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0652.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0653.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
@@ -2729,6 +2448,10 @@
"source_path_from_root": "/docs/csharp/misc/cs0658.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0659.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0660.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
@@ -2750,21 +2473,65 @@
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
},
{
- "source_path_from_root": "/docs/csharp/misc/cs0685.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
+ "source_path_from_root": "/docs/csharp/misc/cs0685.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0687.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0693.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0694.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0695.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0698.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0699.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0701.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0704.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
},
{
- "source_path_from_root": "/docs/csharp/misc/cs0687.md",
- "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
+ "source_path_from_root": "/docs/csharp/misc/cs0706.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
},
{
"source_path_from_root": "/docs/csharp/misc/cs0710.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/constructor-errors#constructor-declarations"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0712.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0715.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0717.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs0718.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs0719.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
@@ -2921,6 +2688,14 @@
"source_path_from_root": "/docs/csharp/misc/cs1020.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overload-resolution"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1021.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1022.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors#cs1022"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1024.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/preprocessor-errors"
@@ -3013,6 +2788,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1517.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/preprocessor-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1526.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/new-object-creation-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1529.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
@@ -3041,6 +2820,26 @@
"source_path_from_root": "/docs/csharp/misc/cs1554.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overloaded-operator-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1555.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1556.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1557.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1558.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1559.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1560.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/preprocessor-errors"
@@ -3057,6 +2856,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1586.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1599.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1605.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/ref-modifiers-errors"
@@ -3069,6 +2872,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1611.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1617.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1618.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
@@ -3133,6 +2940,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1637.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/iterator-yield"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1638.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/feature-version-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1641.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
@@ -3177,6 +2988,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1663.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1664.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1665.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
@@ -3189,6 +3004,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1667.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1668.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1670.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays"
@@ -3265,6 +3084,18 @@
"source_path_from_root": "/docs/csharp/misc/cs1714.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/assembly-references"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1715.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1719.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1720.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1730.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
@@ -3309,6 +3140,10 @@
"source_path_from_root": "/docs/csharp/misc/cs1945.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/expression-tree-restrictions"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1948.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs1950.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
@@ -3329,22 +3164,66 @@
"source_path_from_root": "/docs/csharp/misc/cs1954.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs1958.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/delegate-function-pointer-diagnostics"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs2008.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs2017.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs2019.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs2029.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs2034.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/using-directive-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs2036.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs3006.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/overload-resolution"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs3012.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs3013.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs3016.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/array-declaration-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs3024.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/CS4009.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/async-await-errors"
},
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs5001.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/entry-point-errors"
+ },
+ {
+ "source_path_from_root": "/docs/csharp/misc/cs8500.md",
+ "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors"
+ },
{
"source_path_from_root": "/docs/csharp/misc/cs8506.md",
"redirect_url": "/dotnet/csharp/language-reference/compiler-messages/pattern-matching-warnings"
@@ -5603,6 +5482,11 @@
"source_path_from_root": "/docs/csharp/tutorials/records.md",
"redirect_url": "/dotnet/csharp/fundamentals/tutorials/records"
},
+ {
+ "source_path_from_root": "/docs/csharp/tutorials/string-interpolation.md",
+ "redirect_url": "/dotnet/csharp/fundamentals/tutorials/string-interpolation",
+ "redirect_document_id": true
+ },
{
"source_path_from_root": "/docs/csharp/tutorials/upgrade-to-nullable-references.md",
"redirect_url": "/dotnet/csharp/advanced-topics/update-applications/nullable-migration-strategies"
@@ -5712,6 +5596,122 @@
{
"source_path_from_root": "/docs/csharp/write-safe-efficient-code.md",
"redirect_url": "/dotnet/csharp/advanced-topics/performance"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-10.0/generic-attributes.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/attributes#232-attribute-classes"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/binary-literals.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/digit-separators.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/local-functions.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/statements#1364-local-function-declarations"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/out-var.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1217-declaration-expressions"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/pattern-matching.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/patterns"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/task-types.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#15152-task-type-builder-pattern"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.0/throw-expression.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1215-the-throw-expression-operator"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.1/async-main.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/basic-concepts#71-application-startup"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.1/generics-pattern-match.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/patterns"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.1/infer-tuple-names.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/types#8311-tuple-types"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.1/target-typed-default.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12719-default-value-expressions"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/conditional-ref.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1219-conditional-operator"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/non-trailing-named-arguments.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12621-general"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/private-protected.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#1536-access-modifiers"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/readonly-ref.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/readonly-struct.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/structs#1624-struct-interfaces"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.2/span-safety.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/auto-prop-field-attrs.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/attributes#223-attribute-specification"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/blittable.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/classes#1525-type-parameter-constraints"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/expression-variables-in-initializers.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#1217-declaration-expressions"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/improved-overload-candidates.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12642-applicable-function-member"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/indexing-movable-fixed-fields.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/unsafe-code#2383-fixed-size-buffers-in-expressions"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/leading-digit-separator.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/lexical-structure#6453-integer-literals"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/pattern-based-fixed.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/unsafe-code#247-the-fixed-statement"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/ref-local-reassignment.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/variables#97-reference-variables-and-returns"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/stackalloc-array-initializers.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#12821-stack-allocation"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-7.3/tuple-equality.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/expressions#121211-tuple-equality-operators"
+ },
+ {
+ "source_path_from_root": "/redirections/proposals/csharp-9.0/nullable-reference-types-specification.md",
+ "redirect_url": "/dotnet/csharp/language-reference/language-specification/types#893-nullable-reference-types"
}
]
-}
\ No newline at end of file
+}
diff --git a/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj b/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj
index 289919ae1d6a3..e6aa6e6f3f975 100644
--- a/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj
+++ b/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/docs/ai/how-to/snippets/content-filtering/AIContentFiltering.csproj b/docs/ai/how-to/snippets/content-filtering/AIContentFiltering.csproj
index 5bf960341478f..70173243d85c1 100644
--- a/docs/ai/how-to/snippets/content-filtering/AIContentFiltering.csproj
+++ b/docs/ai/how-to/snippets/content-filtering/AIContentFiltering.csproj
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj b/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj
index dc2f053f66ea2..a9d8b36169e01 100644
--- a/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj
+++ b/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj
@@ -11,9 +11,9 @@
-
-
-
+
+
+
diff --git a/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj b/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj
index 596ae20c6a945..a2a04fd9152f0 100644
--- a/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj
+++ b/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/docs/core/compatibility/10.md b/docs/core/compatibility/10.md
index e3705fdec883e..134934b9f8eb3 100644
--- a/docs/core/compatibility/10.md
+++ b/docs/core/compatibility/10.md
@@ -121,6 +121,7 @@ See [Breaking changes in EF Core 10](/ef/core/what-is-new/ef-core-10.0/breaking-
| [Default workload configuration from 'loose manifests' to 'workload sets' mode](sdk/10.0/default-workload-config.md) | Behavioral change |
| [`DefineConstants` for target frameworks not available at evaluation time](sdk/10.0/defineconstants-not-available-at-evaluation.md) | Behavioral change |
| [Code coverage EnableDynamicNativeInstrumentation defaults to false](sdk/10.0/code-coverage-dynamic-native-instrumentation.md) | Behavioral change |
+| [dnx scripts bypass global.json SDK selection](sdk/11/dnx-scripts-bypass-global-json.md) | Behavioral change |
| [dnx.ps1 file is no longer included in .NET SDK](sdk/10.0/dnx-ps1-removed.md) | Source incompatible |
| [Double quotes in file-level directives are disallowed](sdk/10.0/file-level-directive-double-quotes.md) | Source incompatible |
| [`dotnet new sln` defaults to SLNX file format](sdk/10.0/dotnet-new-sln-slnx-default.md) | Behavioral change |
diff --git a/docs/core/compatibility/11.md b/docs/core/compatibility/11.md
index 5a974af91ea77..7450fa0d83314 100644
--- a/docs/core/compatibility/11.md
+++ b/docs/core/compatibility/11.md
@@ -95,6 +95,7 @@ See [Breaking changes in EF Core 11](/ef/core/what-is-new/ef-core-11.0/breaking-
| Title | Type of change |
|-------------------------------------------------------------------|-------------------|
+| [dnx scripts bypass global.json SDK selection](sdk/11/dnx-scripts-bypass-global-json.md) | Behavioral change |
| [mono launch target not set for .NET Framework apps](sdk/11/mono-launch-target-removed.md) | Behavioral change |
| [NU1703 warns for packages that use deprecated MonoAndroid framework assets](sdk/11/nu1703-deprecated-monoandroid-framework.md) | Source incompatible |
| [Template engine packages no longer support netstandard2.0](sdk/11/template-engine-netstandard.md) | Binary/source incompatible |
diff --git a/docs/core/compatibility/sdk/11/dnx-scripts-bypass-global-json.md b/docs/core/compatibility/sdk/11/dnx-scripts-bypass-global-json.md
new file mode 100644
index 0000000000000..6e260c4175300
--- /dev/null
+++ b/docs/core/compatibility/sdk/11/dnx-scripts-bypass-global-json.md
@@ -0,0 +1,40 @@
+---
+title: "Breaking change: dnx scripts bypass global.json SDK selection"
+description: "Learn about the breaking change in .NET 11 where the dnx and dnx.cmd scripts no longer respect global.json for SDK selection."
+ms.date: 07/05/2026
+ai-usage: ai-assisted
+---
+
+# dnx scripts bypass global.json SDK selection
+
+The `dnx` and `dnx.cmd` scripts no longer use the .NET muxer to select the SDK version. Instead, they find the newest installed SDK and invoke it directly, which bypasses any `global.json` file in the working directory.
+
+## Version introduced
+
+.NET 10 SDK 10.0.302, 10.0.400, and .NET 11 Preview 6
+
+## Previous behavior
+
+Previously, the `dnx` scripts invoked `dotnet dnx`, which relied on the .NET muxer to select the SDK version based on any `global.json` file in the working directory. If `global.json` pinned an SDK version that predated .NET 10, the scripts failed with the following error:
+
+```output
+Unrecognized command or argument 'execute'
+```
+
+Starting with .NET 10 SDK 10.0.302 (and later) and .NET 11 Preview 6, the `dnx` and `dnx.cmd` scripts use `dotnet --list-sdks` to identify the newest installed SDK. They then invoke `dotnet exec /dotnet.dll dnx` directly, bypassing the .NET muxer and any `global.json` SDK pinning.
+
+## Type of breaking change
+
+This change is a [behavioral change](../../categories.md#behavioral-change).
+
+## Reason for change
+
+Some .NET CLI commands, including `dnx`, are considered version-independent features that should always run with the newest installed SDK. Relying on `global.json` meant that users who pinned an older SDK version to reduce risk from build-impacting changes also inadvertently broke `dnx`. In folders where a pre-.NET 10 SDK was pinned, the `dnx` command was unavailable, which caused confusing errors and, in some cases, timeouts in tools like Copilot CLI.
+
+## Recommended action
+
+To restore the previous behavior where the .NET muxer and `global.json` control SDK selection, run `dotnet dnx` explicitly instead of the `dnx` script.
+
+## Affected APIs
+
+None.
diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml
index 9d1da27463472..6117c83450f24 100644
--- a/docs/core/compatibility/toc.yml
+++ b/docs/core/compatibility/toc.yml
@@ -72,6 +72,8 @@ items:
href: maui/11/android-minimum-api-level.md
- name: SDK and MSBuild
items:
+ - name: dnx scripts bypass global.json SDK selection
+ href: sdk/11/dnx-scripts-bypass-global-json.md
- name: mono launch target not set for .NET Framework apps
href: sdk/11/mono-launch-target-removed.md
- name: NU1703 warns for packages that use deprecated MonoAndroid framework assets
diff --git a/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj b/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj
index f43a09e41ea84..d8803776079f8 100644
--- a/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj
+++ b/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/docs/core/extensions/dependency-injection/snippets/console-ienumerable/console-di-ienumerable.csproj b/docs/core/extensions/dependency-injection/snippets/console-ienumerable/console-di-ienumerable.csproj
index 5db61a5b48163..262868f35581c 100644
--- a/docs/core/extensions/dependency-injection/snippets/console-ienumerable/console-di-ienumerable.csproj
+++ b/docs/core/extensions/dependency-injection/snippets/console-ienumerable/console-di-ienumerable.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/docs/core/extensions/snippets/http/generated/generated.csproj b/docs/core/extensions/snippets/http/generated/generated.csproj
index 56119750c4149..757bcbb57b017 100644
--- a/docs/core/extensions/snippets/http/generated/generated.csproj
+++ b/docs/core/extensions/snippets/http/generated/generated.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/docs/core/porting/github-copilot-app-modernization/best-practices.md b/docs/core/porting/github-copilot-app-modernization/best-practices.md
index 4607b10e7d8bb..78325af1d934c 100644
--- a/docs/core/porting/github-copilot-app-modernization/best-practices.md
+++ b/docs/core/porting/github-copilot-app-modernization/best-practices.md
@@ -2,7 +2,7 @@
title: Best practices for GitHub Copilot modernization
description: "Learn best practices for using GitHub Copilot modernization to upgrade .NET projects, including preparation, collaboration tips, common pitfalls, and recovery strategies."
ms.topic: best-practice
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to follow best practices when using GitHub Copilot modernization so that I can get the best results from my .NET upgrades and avoid common problems.
diff --git a/docs/core/porting/github-copilot-app-modernization/concepts.md b/docs/core/porting/github-copilot-app-modernization/concepts.md
index db536c222c65f..25e0466d52534 100644
--- a/docs/core/porting/github-copilot-app-modernization/concepts.md
+++ b/docs/core/porting/github-copilot-app-modernization/concepts.md
@@ -2,7 +2,7 @@
title: GitHub Copilot modernization core concepts
description: "Learn the key concepts behind GitHub Copilot modernization, including scenarios, skills, tasks, the three-stage workflow, state management, and flow modes."
ms.topic: concept-article
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to understand the core concepts of GitHub Copilot modernization so that I can use the agent effectively and get the best results from my upgrades.
@@ -158,7 +158,6 @@ The agent maintains persistent state so you can stop and resume at any time. Eve
| `upgrade-options.md` | Confirmed upgrade decisions |
| `plan.md` | The upgrade plan with strategy and task descriptions |
| `tasks.md` | Visual progress dashboard showing task status |
-| `execution-log.md` | Detailed log of all changes and decisions |
| `tasks/{taskId}/task.md` | Per-task scope and context |
| `tasks/{taskId}/progress-details.md` | Per-task execution notes and results |
diff --git a/docs/core/porting/github-copilot-app-modernization/customization.md b/docs/core/porting/github-copilot-app-modernization/customization.md
index 7a679fb353b4e..e126092689312 100644
--- a/docs/core/porting/github-copilot-app-modernization/customization.md
+++ b/docs/core/porting/github-copilot-app-modernization/customization.md
@@ -2,7 +2,7 @@
title: Customize GitHub Copilot modernization
description: "Learn how to customize GitHub Copilot modernization with custom skills, custom scenarios, scenario artifact edits, and chat instructions to encode your team's upgrade patterns."
ms.topic: concept-article
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to customize GitHub Copilot modernization so that I can encode my team's upgrade patterns, enforce coding standards during upgrades, and define custom upgrade workflows.
diff --git a/docs/core/porting/github-copilot-app-modernization/faq.yml b/docs/core/porting/github-copilot-app-modernization/faq.yml
index fd1d58d4c79f7..9e1fe02c9ece5 100644
--- a/docs/core/porting/github-copilot-app-modernization/faq.yml
+++ b/docs/core/porting/github-copilot-app-modernization/faq.yml
@@ -4,7 +4,7 @@ metadata:
description: "This article answers frequently asked questions about GitHub Copilot modernization for .NET."
titleSuffix: ""
ms.topic: faq
- ms.date: 04/06/2026
+ ms.date: 07/07/2026
title: GitHub Copilot modernization FAQ
summary: |
@@ -102,11 +102,7 @@ sections:
answer: |
The agent supports the following upgrade paths:
- | Source | Target |
- |------------------------------|-----------------|
- | .NET Framework (any version) | .NET 8 or later |
- | .NET Core 1.x–3.x | .NET 8 or later |
- | .NET 5 or later | .NET 8 or later |
+ [!INCLUDE[supported-upgrade-paths](./includes/supported-upgrade-paths.md)]
- question: Can I use the agent offline?
answer: |
diff --git a/docs/core/porting/github-copilot-app-modernization/how-to-custom-upgrade-instructions.md b/docs/core/porting/github-copilot-app-modernization/how-to-custom-upgrade-instructions.md
index fb39e2cc6fe5a..2bba426764314 100644
--- a/docs/core/porting/github-copilot-app-modernization/how-to-custom-upgrade-instructions.md
+++ b/docs/core/porting/github-copilot-app-modernization/how-to-custom-upgrade-instructions.md
@@ -41,14 +41,13 @@ Beyond custom upgrade instructions, you can extend GitHub Copilot modernization
Follow these steps to generate and refine a new instruction file. These sections focus on replacing `Newtonsoft.Json` with `System.Text.Json` as an example.
-1. In the **Solution Explorer** window, right-click the **solution** > **Modernize**.
+### Initiate the upgrade
- \-or-
+Use the following steps to start an upgrade:
- Open the Copilot chat panel and type `@Modernize` to start a conversation with the agent.
+[!INCLUDE[github-copilot-how-to-initiate](./includes/how-to-initiate.md)]
- > [!NOTE]
- > These steps apply to Visual Studio. In Visual Studio Code and other environments, invoke the `modernize-dotnet` agent directly from the Copilot chat panel. In Visual Studio, the agent is named `Modernize`.
+### Create the instruction file
1. In the chat, type: `I want to generate a custom upgrade instruction`.
1. When asked, provide a scenario like `I want to replace Newtonsoft with System.Text.Json` to have Copilot create the file.
@@ -76,10 +75,13 @@ Follow these guidelines to write clear, effective custom upgrade instructions th
Before running the instruction during an upgrade, validate it in isolation. Isolated testing helps you refine detection and verify code changes.
-1. In the **Solution Explorer** window, right-click the **solution** > **Modernize**.
+### Initiate the upgrade
- > [!NOTE]
- > These steps apply to Visual Studio. In Visual Studio Code and other environments, invoke the `modernize-dotnet` agent directly from the Copilot chat panel.
+Use the following steps to start an upgrade:
+
+[!INCLUDE[github-copilot-how-to-initiate](./includes/how-to-initiate.md)]
+
+### Test the upgrade instruction
1. In chat, invoke the instruction with wording similar to the file name. For example, `replace Newtonsoft with System.Text.Json`.
1. Confirm in the chat window that Copilot retrieved the instruction file:
@@ -106,12 +108,16 @@ If the test run doesn't produce the expected results, use these troubleshooting
Use these steps to incorporate an existing custom upgrade instruction into the assessment stage of an upgrade.
-1. In the **Solution Explorer** window, right-click the **solution** > **Modernize**.
+### Initiate the upgrade
+
+To start the upgrade, follow these steps:
+
+[!INCLUDE[github-copilot-how-to-initiate](./includes/how-to-initiate.md)]
+
+### Customize the upgrade
- > [!NOTE]
- > These steps apply to Visual Studio. In Visual Studio Code and other environments, invoke the `modernize-dotnet` agent directly from the Copilot chat panel.
+Follow these steps during the assessment stage:
-1. In the chat, choose `Upgrade to a newer version of .NET`. Answer Copilot's questions until it begins the assessment.
1. Monitor the chat to see if Copilot automatically retrieves your custom instruction file during the assessment. Look for a message indicating it opened the Markdown instruction file.
If Copilot doesn't automatically apply the custom instructions, explicitly request them. Use wording similar to the file name. For example, `use the custom instructions to replace Newtonsoft with System.Text.Json during the assessment`.
diff --git a/docs/core/porting/github-copilot-app-modernization/how-to-upgrade-with-github-copilot.md b/docs/core/porting/github-copilot-app-modernization/how-to-upgrade-with-github-copilot.md
index 45ee2ed5011c9..834cb6d0e5e27 100644
--- a/docs/core/porting/github-copilot-app-modernization/how-to-upgrade-with-github-copilot.md
+++ b/docs/core/porting/github-copilot-app-modernization/how-to-upgrade-with-github-copilot.md
@@ -2,7 +2,7 @@
title: How to upgrade a .NET app with GitHub Copilot modernization
description: "Learn how to upgrade your .NET applications to newer versions using GitHub Copilot modernization. This step-by-step guide covers assessment and the three-stage workflow: assessment, planning, and execution."
ms.topic: how-to
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to upgrade my .NET app using GitHub Copilot modernization so that I can modernize my codebase efficiently with AI assistance through a structured three-stage process.
@@ -21,7 +21,7 @@ Set up GitHub Copilot modernization in your development environment before start
## Initiate the upgrade
-To start an upgrade, use the `modernize-dotnet` agent in Copilot:
+To start the upgrade, follow these steps:
[!INCLUDE[github-copilot-how-to-initiate](./includes/how-to-initiate.md)]
diff --git a/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md b/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md
index 9d6352b16e534..cf087861d2ac8 100644
--- a/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md
+++ b/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md
@@ -1,16 +1,15 @@
---
author: adegeo
ms.author: adegeo
-ms.date: 03/04/2026
+ms.date: 07/08/2026
ms.topic: include
---
-1. Open your .NET project or solution in your development environment.
1. Start the agent by using one of these methods:
- - **Visual Studio**: Right-click the solution or project in **Solution Explorer** and select **Modernize**. Or, open the **GitHub Copilot Chat** window and type `@Modernize`.
+ - **Visual Studio**: Right-click the solution or project in **Solution Explorer** and select **Modernize**. Alternatively, open the **GitHub Copilot Chat** window and type `@Modernize`.
- **Visual Studio Code**: Open the **GitHub Copilot Chat** panel and type `@modernize-dotnet`.
- - **GitHub Copilot CLI**: Type `@modernize-dotnet` followed by your upgrade or migration request.
- - **GitHub.com**: Use the `modernize-dotnet` coding agent in your repository.
+ - **GitHub Copilot CLI**: Type `@upgrade` followed by your upgrade or migration request.
+ - **GitHub Copilot app**: In the **Agent** picker, select `Upgrade`.
1. Tell the agent what to upgrade or migrate.
diff --git a/docs/core/porting/github-copilot-app-modernization/includes/supported-upgrade-paths.md b/docs/core/porting/github-copilot-app-modernization/includes/supported-upgrade-paths.md
new file mode 100644
index 0000000000000..d47407d58ab80
--- /dev/null
+++ b/docs/core/porting/github-copilot-app-modernization/includes/supported-upgrade-paths.md
@@ -0,0 +1,13 @@
+---
+author: adegeo
+ms.author: adegeo
+ms.date: 07/07/2026
+ms.topic: include
+---
+
+| Source | Target |
+|------------------------------|---------------------------|
+| .NET Framework (any version) | .NET 8 or later |
+| .NET Framework (any version) | .NET Framework 4.8.1 |
+| .NET Core 1.x–3.x | .NET 8 or later |
+| .NET 5 or later | .NET 8 or later |
diff --git a/docs/core/porting/github-copilot-app-modernization/install.md b/docs/core/porting/github-copilot-app-modernization/install.md
index c950cdc87bd2c..5d11a84e13744 100644
--- a/docs/core/porting/github-copilot-app-modernization/install.md
+++ b/docs/core/porting/github-copilot-app-modernization/install.md
@@ -2,7 +2,7 @@
title: Install GitHub Copilot modernization
description: "Learn how to install and set up GitHub Copilot modernization across Visual Studio, Visual Studio Code, GitHub Copilot CLI, and GitHub.com."
ms.topic: install-set-up-deploy
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
zone_pivot_groups: copilot-modernization-install
@@ -22,14 +22,14 @@ Before you install, make sure you have:
- Windows operating system.
- [Visual Studio 2026](https://visualstudio.microsoft.com/downloads/) (or Visual Studio 2022 version 17.14.17+).
-- [.NET desktop development workload](/visualstudio/install/modify-visual-studio?view=visualstudio&preserve-view=true#change-workloads-or-individual-components) with these optional components enabled: **GitHub Copilot**, **GitHub Copilot modernization**.
+- [.NET desktop development workload](/visualstudio/install/modify-visual-studio?view=visualstudio&preserve-view=true#change-workloads-or-individual-components) with these optional components enabled: **GitHub Copilot**, **GitHub Copilot app modernization**.
- GitHub Copilot subscription (paid or free).
- [Sign in to Visual Studio with a GitHub account](/visualstudio/ide/work-with-github-accounts) that has [Copilot access](https://docs.github.com/copilot/get-started/plans#ready-to-choose-a-plan).
- Code written in C# or Visual Basic.
## Install
-Visual Studio includes GitHub Copilot modernization, so you don't need to install it separately. Enable the **GitHub Copilot** and **GitHub Copilot modernization** optional components in the **.NET desktop development** workload through the Visual Studio Installer.
+Visual Studio includes GitHub Copilot modernization through the **GitHub Copilot app modernization** optional component, so you don't need to install it separately. Enable the **GitHub Copilot** and **GitHub Copilot app modernization** optional components in the **.NET desktop development** workload through the Visual Studio Installer.
## Verify the installation
@@ -50,6 +50,8 @@ Before you install, make sure you have:
## Install
+Install as a Visual Studio Code extension:
+
1. In Visual Studio Code, open the **Extensions** view (Ctrl+Shift+X).
1. Search for **GitHub Copilot modernization**.
1. Select **Install**.
@@ -59,7 +61,12 @@ The extension automatically acquires the .NET SDK if it's missing, registers too
## Verify the installation
1. Open a project in Visual Studio Code.
-1. Open **GitHub Copilot Chat** and type `@modernize-dotnet`.
+1. Open the **GitHub Copilot Chat** view.
+1. Send `@modernize-dotnet` in chat and confirm the agent responds.
+
+ -or-
+
+ Select the **Agent** picker and find the `modernize-dotnet` entry.
::: zone-end
@@ -69,52 +76,58 @@ The extension automatically acquires the .NET SDK if it's missing, registers too
Before you install, make sure you have:
-- GitHub Copilot CLI installed.
+- [GitHub Copilot CLI](https://gh.io/cli) installed.
- GitHub Copilot subscription (paid or free).
## Install
-To install:
+Install through the GitHub Copilot CLI:
1. Open the GitHub Copilot chat window.
1. Add the marketplace plugin:
```console
- /plugin marketplace add dotnet/modernize-dotnet
+ /plugin marketplace add microsoft/upgrade-agent-plugins
```
1. Install the plugin:
```console
- /plugin install modernize-dotnet@modernize-dotnet-plugins
+ /plugin install upgrade-agent@upgrade-agent-plugins
```
## Verify the installation
-Run `/agent` to confirm that `modernize-dotnet` appears in the agent list.
+Run `/agent` to confirm that `upgrade-agent` appears in the agent list.
::: zone-end
-::: zone pivot="github-com"
+::: zone pivot="github-copilot-app"
## Prerequisites
Before you install, make sure you have:
-- GitHub Copilot Enterprise or Business subscription with coding agents enabled.
-- Repository admin access.
+- [GitHub Copilot app](https://gh.io/app) installed.
+- GitHub Copilot subscription (paid or free).
## Install
-Add the custom coding agent to your repository:
+Install through the GitHub Copilot app:
-1. Review [adding custom coding agents to your repository](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents).
-1. Add the `modernize-dotnet` agent. See the [coding agent README](https://github.com/dotnet/modernize-dotnet/blob/main/coding-agent/README.md) for details.
+1. Click [https://github.com/copilot/app/launch](https://github.com/copilot/app/launch?entry_point=upgrade_agent_docs&open=ghapp%3A%2F%2Fplugins%2Fmarketplace%2Fadd%3Fsource%3Dmicrosoft%2Fupgrade-agent-plugins) to automatically open the **Settings** > **Plugins** window in the GitHub Copilot app.
+1. In the **Add plugin marketplace?** dialog, select **Allow**.
+1. In the **Plugins** window, select **Add marketplace**.
+1. Expand the **upgrade-agent-plugins** entry and select **Install** on the **upgrade-agent** plugin.
## Verify the installation
-Confirm that the `modernize-dotnet` agent appears as an available coding agent in your repository.
+Run `/agent` to confirm that `upgrade-agent:upgrade` appears in the agent list.
+
+-or-
+
+Select the **Default agent** picker and find the **Upgrade** entry.
::: zone-end
diff --git a/docs/core/porting/github-copilot-app-modernization/overview.md b/docs/core/porting/github-copilot-app-modernization/overview.md
index 91c758cf5f272..14297194b8c58 100644
--- a/docs/core/porting/github-copilot-app-modernization/overview.md
+++ b/docs/core/porting/github-copilot-app-modernization/overview.md
@@ -3,7 +3,7 @@ title: GitHub Copilot modernization overview
description: "Learn about GitHub Copilot modernization, a Copilot agent available across Visual Studio, Visual Studio Code, GitHub Copilot CLI, and GitHub.com that upgrades .NET projects and migrates apps to Azure."
titleSuffix: ""
ms.topic: overview
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to learn about what GitHub Copilot modernization is, so that I understand its capabilities and how I can take advantage of it.
@@ -36,6 +36,9 @@ The agent provides multiple end-to-end modernization workflows called _scenarios
| **SqlClient upgrade** | Upgrades from System.Data.SqlClient to Microsoft.Data.SqlClient. | _"Update SqlClient"_ |
| **Azure Functions upgrade** | Upgrades Azure Functions from in-process to isolated worker model. | _"Upgrade my Azure Functions"_ |
| **Semantic Kernel to Agents** | Upgrades Semantic Kernel Agents to Microsoft Agent Framework. | _"Upgrade my SK agents"_ |
+| **Aspire integration** | Adds [Aspire](https://aspire.dev) support for inner-loop and Azure deployment. | _"Add Aspire to my app"_ |
+| **Aspire version upgrade** | Upgrades existing Aspire applications to newer versions. | _"Upgrade my Aspire version"_ |
+| **WebForms-to-Blazor upgrade** | Upgrades ASP.NET Web Forms applications to Blazor. | _"Migrate my Web Forms app to Blazor"_ |
For a full reference of all scenarios and 30+ built-in upgrade skills, see [Scenarios and skills reference](scenarios-and-skills.md).
@@ -45,7 +48,7 @@ Microsoft values your feedback and uses it to improve the agent. Leave feedback
- In Visual Studio, use the [Suggest a feature](/visualstudio/ide/suggest-a-feature) and [Report a problem](/visualstudio/ide/report-a-problem) options.
-- File an issue at the [@modernize-dotnet GitHub repository](https://github.com/dotnet/modernize-dotnet).
+- File an issue at the [Upgrade Agent GitHub repository](https://github.com/microsoft/upgrade-agent-plugins).
## Prerequisites
@@ -73,11 +76,7 @@ To start an upgrade, see [Upgrade a .NET app with GitHub Copilot modernization](
The agent supports the following upgrade paths:
-| Source | Target |
-|------------------------------|-----------------|
-| .NET Framework (any version) | .NET 8 or later |
-| .NET Core 1.x–3.x | .NET 8 or later |
-| .NET 5 or later | .NET 8 or later |
+[!INCLUDE[supported-upgrade-paths](./includes/supported-upgrade-paths.md)]
## Migrate .NET projects to Azure
@@ -193,7 +192,6 @@ The agent stores all upgrade state in `.github/upgrades/{scenarioId}/`. The fold
| `plan.md` | Ordered task plan |
| `tasks.md` | Live progress dashboard |
| `scenario-instructions.md` | Agent's persistent memory, including preferences, decisions, and custom instructions |
-| `execution-log.md` | Detailed audit trail of all changes |
| `tasks/{taskId}/task.md` | Per-task scope and context |
| `tasks/{taskId}/progress-details.md` | Per-task execution notes and results |
diff --git a/docs/core/porting/github-copilot-app-modernization/scenarios-and-skills.md b/docs/core/porting/github-copilot-app-modernization/scenarios-and-skills.md
index 2c9ffa8556ec0..131537a9215e6 100644
--- a/docs/core/porting/github-copilot-app-modernization/scenarios-and-skills.md
+++ b/docs/core/porting/github-copilot-app-modernization/scenarios-and-skills.md
@@ -2,7 +2,7 @@
title: GitHub Copilot modernization scenarios and skills
description: "Complete reference of all scenarios and built-in upgrade skills available in GitHub Copilot modernization for .NET, organized by domain."
ms.topic: reference
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to see all the scenarios and skills that GitHub Copilot modernization supports so that I can understand which upgrade tasks the agent can handle for me.
@@ -33,6 +33,9 @@ Scenarios are the agent's top-level upgrade workflows. When you start a conversa
| [**SqlClient upgrade**](#sqlclient-upgrade) | Upgrades System.Data.SqlClient to Microsoft.Data.SqlClient. | _"Update SqlClient to the modern package"_ |
| [**Azure Functions upgrade**](#azure-functions-upgrade) | Upgrades Azure Functions from in-process to isolated worker model. | _"Upgrade my Azure Functions"_ |
| [**Semantic Kernel to Agents**](#semantic-kernel-to-microsoft-agent-framework) | Upgrades from SK Agents to Microsoft Agent Framework. | _"Upgrade my SK agents"_ |
+| [**Aspire integration**](#aspire-integration) | Adds [Aspire](https://aspire.dev) support for inner-loop and Azure deployment. | _"Add Aspire to my app"_ |
+| [**Aspire version upgrade**](#aspire-version-upgrade) | Upgrades existing Aspire applications to newer versions. | _"Upgrade my Aspire version"_ |
+| [**WebForms-to-Blazor upgrade**](#webforms-to-blazor-upgrade) | Upgrades ASP.NET Web Forms applications to Blazor. | _"Migrate my Web Forms app to Blazor"_ |
For an end-to-end walkthrough, see [Core concepts](concepts.md).
@@ -40,11 +43,7 @@ For an end-to-end walkthrough, see [Core concepts](concepts.md).
The most common scenario. Upgrades your projects from any older .NET variant to the latest:
-| Source | Target |
-|------------------------------|-----------------|
-| .NET Framework (any version) | .NET 8 or later |
-| .NET Core 1.x–3.x | .NET 8 or later |
-| .NET 5 or later | .NET 8 or later |
+[!INCLUDE[supported-upgrade-paths](./includes/supported-upgrade-paths.md)]
The agent analyzes your dependency graph, checks NuGet compatibility, identifies breaking changes, and creates a task plan using the best strategy for your solution (bottom-up, top-down, or all-at-once). If your projects need format conversions, the agent handles them automatically as part of the upgrade.
@@ -68,6 +67,18 @@ Upgrades Azure Functions from the in-process hosting model to the isolated worke
Upgrades from Semantic Kernel Agents (`ChatCompletionAgent`, `OpenAIAssistantAgent`) to [Microsoft Agent Framework](/agent-framework/overview/). Updates packages and API patterns.
+### Aspire integration
+
+Adds [Aspire](https://aspire.dev) support to existing applications for inner-loop development and Azure deployment. Configures the Aspire orchestration layer and integrates with the Aspire CLI agent.
+
+### Aspire version upgrade
+
+Upgrades existing Aspire applications to newer versions of Aspire. Handles package updates, configuration changes, and breaking API changes between Aspire versions.
+
+### WebForms-to-Blazor upgrade
+
+Upgrades ASP.NET Web Forms applications to Blazor using native Blazor and HTML5 patterns. Converts Web Forms pages, controls, and code-behind to Blazor components.
+
## Upgrade skills: common
General-purpose upgrade skills that apply across project types.
@@ -94,6 +105,7 @@ Skills for upgrading data access layers, including Entity Framework, LINQ to SQL
| **Upgrading EDMX to Code-First** | Converts EF6 Database-First (`.edmx`) models to EF Core Code-First. Scaffolds entities from the database. |
| **Upgrading EF DbContext** | Registers `DbContext` in ASP.NET Core dependency injection. Handles both EF6 to EF Core and existing EF Core patterns. |
| **Upgrading EF6 Code-First to EF Core** | Upgrades EF6 Code-First to EF Core. Swaps packages, updates namespaces, and replaces `EntityTypeConfiguration` and `DbModelBuilder`. |
+| **Upgrading LINQ to SQL to EF Core** | Migrates LINQ to SQL (`System.Data.Linq`) data access to Entity Framework Core. |
| **Upgrading to Microsoft.Data.SqlClient** | Upgrades from `System.Data.SqlClient`. Handles the `Encrypt=true` default change and connection string differences. |
## Upgrade skills: web and ASP.NET
@@ -147,6 +159,7 @@ Skills for upgrading ASP.NET Framework applications to ASP.NET Core.
| **Upgrading Azure Functions Startup** | Upgrades Azure Functions from the in-process `Startup` class to isolated worker model with `Program.cs`. |
| **Upgrading Azure Functions to v2** | Upgrades Azure Functions to the v2 hosting pattern using `IHostApplicationBuilder`. |
| **Upgrading Azure Key Vault** | Upgrades legacy Azure Key Vault SDK to the modern `Azure.Security.KeyVault` libraries. |
+| **Upgrading Azure SDK** | Upgrades legacy Azure SDK dependencies to the latest `Azure.*` libraries. |
| **Upgrading Azure Service Bus** | Upgrades legacy Azure Service Bus SDK to the modern `Azure.Messaging.ServiceBus` library. |
| **Upgrading Azure Storage** | Upgrades legacy Azure Storage SDK to the modern `Azure.Storage` libraries. |
diff --git a/docs/core/porting/github-copilot-app-modernization/troubleshooting.md b/docs/core/porting/github-copilot-app-modernization/troubleshooting.md
index 109f3c49b7074..b6cc517146375 100644
--- a/docs/core/porting/github-copilot-app-modernization/troubleshooting.md
+++ b/docs/core/porting/github-copilot-app-modernization/troubleshooting.md
@@ -2,7 +2,7 @@
title: Troubleshoot GitHub Copilot modernization
description: "Find solutions to common problems when you use GitHub Copilot modernization for .NET, including workflow, build, Git, performance, and customization issues."
ms.topic: troubleshooting-general
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to troubleshoot issues with GitHub Copilot modernization so that I can resolve problems and continue my .NET upgrade.
@@ -76,7 +76,7 @@ These issues relate to build failures, NuGet restore problems, and code generati
1. Tell the agent about the failure. The agent analyzes errors automatically.
1. If the agent can't resolve the issue, revert the last commit (`git revert HEAD`) and ask the agent to try a different approach.
-1. For complex failures, check `execution-log.md` to understand what the agent changed and in what order.
+1. For complex failures, check `tasks.md` to find the failing task ID, and then review `tasks/{taskId}/progress-details.md` to understand what the agent changed and in what order.
### NuGet restore fails
@@ -185,7 +185,7 @@ These issues relate to custom skills and scenario instruction files.
When something isn't working as expected:
1. **Ask the agent:** Ask _"What went wrong with the last task?"_ The agent can often explain what happened and suggest next steps.
-1. **Review the execution log:** Open `execution-log.md` in `.github/upgrades/{scenarioId}/`. The log shows a chronological record of what the agent did, including any errors it encountered.
+1. **Review the task progress:** Open `tasks.md` in `.github/upgrades/{scenarioId}/` to find the last task ID, and then open `tasks/{taskId}/progress-details.md`. The progress details show what the agent did, including any errors it encountered.
1. **File an issue:** If you've found a bug or the agent consistently fails at something, file an issue at the [@modernize-dotnet GitHub repository](https://github.com/dotnet/modernize-dotnet).
## Related content
diff --git a/docs/core/porting/github-copilot-app-modernization/working-with-agent.md b/docs/core/porting/github-copilot-app-modernization/working-with-agent.md
index a5491edc99c78..3bbb4dd949e2b 100644
--- a/docs/core/porting/github-copilot-app-modernization/working-with-agent.md
+++ b/docs/core/porting/github-copilot-app-modernization/working-with-agent.md
@@ -2,7 +2,7 @@
title: Work with GitHub Copilot modernization
description: "Learn how to collaborate effectively with GitHub Copilot modernization, including communication patterns, teaching preferences, mid-session corrections, and multi-session workflows."
ms.topic: concept-article
-ms.date: 04/06/2026
+ms.date: 07/07/2026
ai-usage: ai-assisted
#customer intent: As a developer, I want to learn how to work effectively with the GitHub Copilot modernization agent so that I can get the best results from my .NET upgrade.
@@ -30,9 +30,7 @@ public API surface."
## Start a conversation
-1. Open **Copilot Chat** in VS Code, Visual Studio, or Copilot CLI.
-1. Select the **GitHub Copilot modernization agent for .NET** from the agent picker, or type the correct agent mention for your environment: `@modernize-dotnet` in VS Code and Copilot CLI, or `@Modernize` in Visual Studio.
-1. Describe what you want to accomplish in natural language.
+[!INCLUDE [how-to-initiate](includes/how-to-initiate.md)]
### What to say
@@ -196,7 +194,6 @@ The agent maintains several files in `.github/upgrades/{scenarioId}/` that give
| File | What it shows |
|---|---|
| `tasks.md` | Visual progress overview with all tasks, status indicators (✅ done, 🔄 in progress, ⬜ pending), and a progress bar |
-| `execution-log.md` | Complete chronological audit trail of every action the agent took, when, and what happened |
| `assessment.md` | The initial analysis of your solution, including dependencies, breaking changes, and upgrade complexity |
| `scenario-instructions.md` | Your preferences and the agent's learned decisions |
| `tasks/{taskId}/progress-details.md` | Per-task details: build errors encountered, how they were resolved, test results, and decisions made |
@@ -230,7 +227,7 @@ Large upgrades, such as a 20-project solution, a complex framework upgrade, or a
### Tips for multi-session work
- **Commit the state folder.** Push `.github/upgrades/` to your branch to back up the folder and make it visible to your team.
-- **Review between sessions.** Read `tasks.md` and `execution-log.md` to refresh your memory on what happened in the last session.
+- **Review between sessions.** Read `tasks.md` to refresh your memory on what happened in the last session.
- **Update preferences as you learn.** If you discover something in testing that should change the agent's approach, tell the agent at the start of the next session.
## Ask for help
diff --git a/docs/core/testing/microsoft-testing-platform-architecture-extensions.md b/docs/core/testing/microsoft-testing-platform-architecture-extensions.md
index 4bcd1417fd33a..aa32c4872d13e 100644
--- a/docs/core/testing/microsoft-testing-platform-architecture-extensions.md
+++ b/docs/core/testing/microsoft-testing-platform-architecture-extensions.md
@@ -3,7 +3,7 @@ title: Build extensions for Microsoft.Testing.Platform (MTP)
description: Learn how to create in-process and out-of-process extensions for Microsoft.Testing.Platform (MTP).
author: MarcoRossignoli
ms.author: mrossignoli
-ms.date: 06/02/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -206,35 +206,38 @@ If your extension requires intensive initialization and you need to use the asyn
### The `ITestApplicationLifecycleCallbacks` extensions
-The `ITestApplicationLifecycleCallbacks` is an *in-process* extension that enables the execution of code before everything, it's like to have access to the first line of the hypothetical *main* of the *test host*.
+> [!IMPORTANT]
+> `ITestApplicationLifecycleCallbacks` was removed in MTP 2.0.0. Use `ITestHostApplicationLifetime` instead. For more information, see [Migrate from Microsoft.Testing.Platform (MTP) v1 to v2](microsoft-testing-platform-migration-from-v1-to-v2.md#removed-obsolete-types).
+
+The `ITestHostApplicationLifetime` interface lets an *in-process* extension run code at the start and end of the *test host*.
-To register a custom `ITestApplicationLifecycleCallbacks`, utilize the following api:
+To register a custom `ITestHostApplicationLifetime`, use the following API:
```csharp
var builder = await TestApplication.CreateBuilderAsync(args);
// ...
-builder.TestHost.AddTestApplicationLifecycleCallbacks(
+builder.TestHost.AddTestHostApplicationLifetime(
static serviceProvider
- => new CustomTestApplicationLifecycleCallbacks());
+ => new CustomTestHostApplicationLifetime());
```
-The factory utilizes the [IServiceProvider](./microsoft-testing-platform-architecture-services.md#the-imessagebus-service) to gain access to the suite of services offered by the testing platform.
+The factory uses the [IServiceProvider](./microsoft-testing-platform-architecture-services.md#the-imessagebus-service) to access the services offered by the testing platform.
> [!IMPORTANT]
> The sequence of registration is significant, as the APIs are called in the order they were registered.
-The `ITestApplicationLifecycleCallbacks` interface includes the following methods:
+The `ITestHostApplicationLifetime` interface includes the following methods:
```csharp
-public interface ITestApplicationLifecycleCallbacks : ITestHostExtension
+public interface ITestHostApplicationLifetime : ITestHostExtension
{
Task BeforeRunAsync(CancellationToken cancellationToken);
Task AfterRunAsync(
int exitCode,
- CancellationToken cancellation);
+ CancellationToken cancellationToken);
}
public interface ITestHostExtension : IExtension
@@ -242,7 +245,7 @@ public interface ITestHostExtension : IExtension
}
```
-The `ITestApplicationLifecycleCallbacks` is a type of `ITestHostExtension`, which serves as a base for all *test host* extensions. Like all other extension points, it also inherits from [IExtension](./microsoft-testing-platform-architecture-test-framework.md#the-iextension-interface). Therefore, like any other extension, you can choose to enable or disable it using the `IExtension.IsEnabledAsync` API.
+The `ITestHostApplicationLifetime` interface extends `ITestHostExtension`, which serves as a base for all *test host* extensions. Like all other extension points, it also inherits from [IExtension](./microsoft-testing-platform-architecture-test-framework.md#the-iextension-interface). Therefore, like any other extension, you can choose to enable or disable it using the `IExtension.IsEnabledAsync` API.
`BeforeRunAsync`: This method serves as the initial point of contact for the *test host* and is the first opportunity for an *in-process* extension to execute a feature. It's typically used to establish a connection with any corresponding *out-of-process* extensions if a feature is designed to operate across both environments.
@@ -492,7 +495,7 @@ Consider the following details for this API:
`OnTestHostProcessStartedAsync`: This method is invoked immediately after the test host starts. This method offers an object that implements the `ITestHostProcessInformation` interface, which provides key details about the test host process result.
> [!IMPORTANT]
-> The invocation of this method does not halt the test host's execution. If you need to pause it, you should register an [*in-process*](./microsoft-testing-platform-architecture.md#in-process-vs-out-of-process-extensions) extension such as [`ITestApplicationLifecycleCallbacks`](#the-itestapplicationlifecyclecallbacks-extensions) and synchronize it with the *out-of-process* extension.
+> The invocation of this method does not halt the test host's execution. If you need to pause it, you should register an [*in-process*](./microsoft-testing-platform-architecture.md#in-process-vs-out-of-process-extensions) extension such as [`ITestHostApplicationLifetime`](#the-itestapplicationlifecyclecallbacks-extensions) and synchronize it with the *out-of-process* extension.
`OnTestHostProcessExitedAsync`: This method is invoked when the test suite execution is complete. This method supplies an object that adheres to the `ITestHostProcessInformation` interface, which conveys crucial details about the outcome of the test host process.
@@ -595,18 +598,18 @@ The testing platform consists of a [testing framework](./microsoft-testing-platf
1. [ITestHostEnvironmentVariableProvider.UpdateAsync](#the-itesthostenvironmentvariableprovider-extensions) : Out-of-process
1. [ITestHostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync](#the-itesthostenvironmentvariableprovider-extensions) : Out-of-process
-1. [ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync](#the-itestsessionlifetimehandler-extensions) : Out-of-process
+1. [ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync](#the-itesthostprocesslifetimehandler-extensions) : Out-of-process
1. Test host process start
-1. [ITestHostProcessLifetimeHandler.OnTestHostProcessStartedAsync](#the-itestsessionlifetimehandler-extensions) : Out-of-process, this event can intertwine the actions of *in-process* extensions, depending on race conditions.
-1. [ITestApplicationLifecycleCallbacks.BeforeRunAsync](#the-itestsessionlifetimehandler-extensions): In-process
+1. [ITestHostProcessLifetimeHandler.OnTestHostProcessStartedAsync](#the-itesthostprocesslifetimehandler-extensions) : Out-of-process, this event can intertwine the actions of *in-process* extensions, depending on race conditions.
+1. [ITestHostApplicationLifetime.BeforeRunAsync](#the-itestapplicationlifecyclecallbacks-extensions): In-process
1. [ITestSessionLifetimeHandler.OnTestSessionStartingAsync](#the-itestsessionlifetimehandler-extensions): In-process
1. [ITestFramework.CreateTestSessionAsync](./microsoft-testing-platform-architecture-test-framework.md#test-framework-extension): In-process
1. [ITestFramework.ExecuteRequestAsync](./microsoft-testing-platform-architecture-test-framework.md#test-framework-extension): In-process, this method can be called one or more times. At this point, the testing framework will transmit information to the [IMessageBus](./microsoft-testing-platform-architecture-services.md#the-imessagebus-service) that can be utilized by the [IDataConsumer](#the-idataconsumer-extensions).
1. [ITestFramework.CloseTestSessionAsync](./microsoft-testing-platform-architecture-test-framework.md#test-framework-extension): In-process
1. [ITestSessionLifetimeHandler.OnTestSessionFinishingAsync](#the-itestsessionlifetimehandler-extensions): In-process
-1. [ITestApplicationLifecycleCallbacks.AfterRunAsync](#the-itestsessionlifetimehandler-extensions): In-process
+1. [ITestHostApplicationLifetime.AfterRunAsync](#the-itestapplicationlifecyclecallbacks-extensions): In-process
1. In-process cleanup, involves calling dispose and [IAsyncCleanableExtension](#asynchronous-initialization-and-cleanup-of-extensions) on all extension points.
-1. [ITestHostProcessLifetimeHandler.OnTestHostProcessExitedAsync](#the-itestsessionlifetimehandler-extensions) : Out-of-process
+1. [ITestHostProcessLifetimeHandler.OnTestHostProcessExitedAsync](#the-itesthostprocesslifetimehandler-extensions) : Out-of-process
1. Out-of-process cleanup, involves calling dispose and [IAsyncCleanableExtension](#asynchronous-initialization-and-cleanup-of-extensions) on all extension points.
## Extensions helpers
diff --git a/docs/core/testing/microsoft-testing-platform-cli-options.md b/docs/core/testing/microsoft-testing-platform-cli-options.md
index d3d557b164038..5d018601b41c4 100644
--- a/docs/core/testing/microsoft-testing-platform-cli-options.md
+++ b/docs/core/testing/microsoft-testing-platform-cli-options.md
@@ -3,7 +3,7 @@ title: Microsoft.Testing.Platform (MTP) CLI options reference
description: Find platform and extension command-line options for MTP in one place.
author: Evangelink
ms.author: amauryleve
-ms.date: 06/01/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -68,6 +68,9 @@ This article gives a central entry point for MTP command-line options.
Forces the built-in file logger to synchronously write logs. Useful for scenarios where you don't want to lose any log entries (if the process crashes). This slows down the test execution.
+ > [!NOTE]
+ > Available in MTP starting with version 2.0.0. It replaces the previous `--diagnostic-filelogger-synchronouswrite` option, which was removed in MTP 2.0.0.
+
- **`--diagnostic-output-directory`**
The output directory of the diagnostic logging, if not specified the file is generated in the default _TestResults_ directory.
@@ -76,6 +79,9 @@ This article gives a central entry point for MTP command-line options.
The prefix for the log file name. Defaults to `"log"`.
+ > [!NOTE]
+ > Available in MTP starting with version 2.0.0. It replaces the previous `--diagnostic-output-fileprefix` option, which was removed in MTP 2.0.0.
+
- **`--diagnostic-verbosity`**
Defines the verbosity level when the `--diagnostic` switch is used. The available values are `Trace`, `Debug`, `Information`, `Warning`, `Error`, or `Critical`.
diff --git a/docs/core/testing/microsoft-testing-platform-config.md b/docs/core/testing/microsoft-testing-platform-config.md
index 82d94a17eba9a..a83e147ffb9cb 100644
--- a/docs/core/testing/microsoft-testing-platform-config.md
+++ b/docs/core/testing/microsoft-testing-platform-config.md
@@ -3,7 +3,7 @@ title: Microsoft.Testing.Platform (MTP) config options
description: Learn how to configure MTP using testconfig.json configuration settings and environment variables.
author: Evangelink
ms.author: amauryleve
-ms.date: 06/01/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -78,9 +78,27 @@ Example:
}
```
-### Extension options are CLI-only
+### Environment variables in testconfig.json
-Extension features such as [crash dump](microsoft-testing-platform-crash-hang-dumps.md), [hang dump](microsoft-testing-platform-crash-hang-dumps.md), [retry](microsoft-testing-platform-retry.md), [TRX reports](microsoft-testing-platform-test-reports.md), and [code coverage](microsoft-testing-platform-code-coverage.md) are **not** configurable via *testconfig.json*. These features are configured exclusively through command-line arguments.
+> [!NOTE]
+> Available in MTP starting with version 2.3.0.
+
+The `environmentVariables` section sets environment variables for the test process before it starts. Use string values for each variable.
+
+```json
+{
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development",
+ "FEATURE_FLAG": "true"
+ }
+}
+```
+
+### CLI options in testconfig.json
+
+Before MTP 2.3.0, extension features such as [crash dump](microsoft-testing-platform-crash-hang-dumps.md), [hang dump](microsoft-testing-platform-crash-hang-dumps.md), [retry](microsoft-testing-platform-retry.md), [TRX reports](microsoft-testing-platform-test-reports.md), and [code coverage](microsoft-testing-platform-code-coverage.md) aren't configurable via *testconfig.json*. These features are configured exclusively through command-line arguments.
+
+Starting with MTP 2.3.0, MTP can read CLI options from *testconfig.json* through `IConfiguration`. This support includes extension options, so you can use JSON entries for options that you don't want to pass on the command line each run. Command-line arguments still take precedence.
For a complete reference of command-line options, see [MTP CLI options reference](microsoft-testing-platform-cli-options.md).
@@ -128,9 +146,9 @@ If you're migrating from a *.runsettings* file, the following table maps common
| `RunConfiguration/MaxCpuCount` | No equivalent | Process-level parallelism is controlled by `dotnet test --max-parallel-test-modules` or MSBuild `/m` option. |
| `MSTest/*` | `mstest.*` | See [Configure MSTest — testconfig.json](unit-testing-mstest-configure.md#testconfigjson). |
| `xUnit/*` | `xUnit.*` | See [xUnit.net testconfig.json](https://xunit.net/docs/config-testconfig-json). |
-| `LoggerRunSettings/Loggers` | CLI only | Use `--report-trx` or similar CLI options. |
-| `DataCollectionRunSettings` (blame) | CLI only | Use `--crashdump` and `--hangdump` CLI options. See [Crash and hang dumps](microsoft-testing-platform-crash-hang-dumps.md). |
-| `DataCollectionRunSettings` (coverage) | CLI only | Use `--coverage` CLI option. See [Code coverage](microsoft-testing-platform-code-coverage.md). |
+| `LoggerRunSettings/Loggers` | CLI options | Use `--report-trx` or similar CLI options. Starting with MTP 2.3.0, MTP can read CLI options from *testconfig.json*. |
+| `DataCollectionRunSettings` (blame) | CLI options | Use `--crashdump` and `--hangdump` CLI options. Starting with MTP 2.3.0, MTP can read CLI options from *testconfig.json*. See [Crash and hang dumps](microsoft-testing-platform-crash-hang-dumps.md). |
+| `DataCollectionRunSettings` (coverage) | CLI options | Use `--coverage` CLI option. Starting with MTP 2.3.0, MTP can read CLI options from *testconfig.json*. See [Code coverage](microsoft-testing-platform-code-coverage.md). |
| `TestRunParameters` | `--test-parameter` CLI | Use `--test-parameter key=value` on the command line. |
## Environment variables
@@ -186,6 +204,13 @@ A semicolon-separated list of exit codes to ignore. When an exit code is ignored
When set to `1` or `true`, suppresses the startup banner, the copyright message, and the telemetry banner. Equivalent to the `--no-banner` command-line option. The `DOTNET_NOLOGO` environment variable has the same effect.
+### `NO_COLOR` environment variable
+
+When set to any non-empty value, suppresses all ANSI color output. MTP honors the [`NO_COLOR`](https://no-color.org/) convention.
+
+> [!NOTE]
+> Available in MTP starting with version 2.3.0.
+
### `DOTNET_NOLOGO` environment variable
When set to `1` or `true`, suppresses the startup banner, the copyright message, and the telemetry banner. This is the standard .NET CLI environment variable and is honored by MTP. See also `TESTINGPLATFORM_NOBANNER`.
diff --git a/docs/core/testing/microsoft-testing-platform-features.md b/docs/core/testing/microsoft-testing-platform-features.md
index 18c9b8019cff9..926a0e45e5fae 100644
--- a/docs/core/testing/microsoft-testing-platform-features.md
+++ b/docs/core/testing/microsoft-testing-platform-features.md
@@ -3,7 +3,7 @@ title: Microsoft.Testing.Platform features
description: Learn about the various Microsoft.Testing.Platform features, both built-in and available as extensions.
author: nohwnd
ms.author: jajares
-ms.date: 02/25/2026
+ms.date: 07/03/2026
ai-usage: ai-assisted
---
@@ -17,6 +17,8 @@ If you opt out of the auto-generated entry point by setting ` [!NOTE]
-> The Microsoft.Extensions.Logging bridge was introduced in MTP 2.3.0.
-
-The [Microsoft.Testing.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Logging) package bridges Microsoft.Testing.Platform diagnostics to , so platform and extension logs flow through the same `Microsoft.Extensions.Logging` pipeline your application already uses.
+**[Video recorder](https://www.nuget.org/packages/Microsoft.Testing.Extensions.VideoRecorder)** (experimental, introduced in MTP 2.3.0)
-Manual registration:
+Record the screen during a test run. It requires `ffmpeg` to be available on the machine and is enabled with the `--capture-video` option. Register it manually with `builder.AddVideoRecorderProvider()`.
-```csharp
-var builder = await TestApplication.CreateBuilderAsync(args);
-builder.AddMicrosoftExtensionsLogging(logging => logging.AddConsole());
-```
+**[Packaged app deployment](https://www.nuget.org/packages/Microsoft.Testing.Extensions.PackagedApp)** (experimental, introduced in MTP 2.3.0)
-## Experimental extensions
+A reference extension that uses the experimental `ITestHostLauncher` extension point to deploy and launch a packaged-app test host. Register it manually with `builder.AddPackagedAppDeployment()`.
-The following extensions are experimental. Their APIs are annotated with the `TPEXP` diagnostic and might change in a future release; using them requires acknowledging the experimental diagnostic. For more information, see [Microsoft.Testing.Platform diagnostics](https://aka.ms/testingplatform/diagnostics).
+## Microsoft.Extensions integration
-**[Video recorder](https://www.nuget.org/packages/Microsoft.Testing.Extensions.VideoRecorder)** (experimental, introduced in MTP 2.3.0)
+These extensions bridge Microsoft.Testing.Platform to the `Microsoft.Extensions.*` libraries your application already uses.
-Records the screen during a test run. It requires `ffmpeg` to be available on the machine and is enabled with the `--capture-video` option. Register it manually with `builder.AddVideoRecorderProvider()`.
+**[Logging bridge](https://www.nuget.org/packages/Microsoft.Testing.Extensions.Logging)** (experimental, introduced in MTP 2.3.0)
-**[Packaged app deployment](https://www.nuget.org/packages/Microsoft.Testing.Extensions.PackagedApp)** (experimental, introduced in MTP 2.3.0)
+The Microsoft.Testing.Extensions.Logging package bridges Microsoft.Testing.Platform diagnostics to , so platform and extension logs flow through the same `Microsoft.Extensions.Logging` pipeline your application already uses. Register it manually with the following call:
-A reference extension that uses the experimental `ITestHostLauncher` extension point to deploy and launch a packaged-app test host. Register it manually with `builder.AddPackagedAppDeployment()`.
+```csharp
+var builder = await TestApplication.CreateBuilderAsync(args);
+builder.AddMicrosoftExtensionsLogging(logging => logging.AddConsole());
+```
diff --git a/docs/core/testing/microsoft-testing-platform-open-telemetry.md b/docs/core/testing/microsoft-testing-platform-open-telemetry.md
index 21a04b336e5e1..97781093d81a9 100644
--- a/docs/core/testing/microsoft-testing-platform-open-telemetry.md
+++ b/docs/core/testing/microsoft-testing-platform-open-telemetry.md
@@ -3,7 +3,7 @@ title: Microsoft.Testing.Platform (MTP) OpenTelemetry
description: Learn how to use the OpenTelemetry extension to emit traces and metrics from MTP.
author: Evangelink
ms.author: amauryleve
-ms.date: 02/25/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -13,6 +13,9 @@ This feature requires the [Microsoft.Testing.Extensions.OpenTelemetry](https://n
This extension integrates [OpenTelemetry](https://opentelemetry.io/) with Microsoft.Testing.Platform (MTP), allowing test runs to emit traces and metrics through the standard OpenTelemetry SDK.
+> [!NOTE]
+> This extension is available in MTP starting with version 2.1.0.
+
> [!IMPORTANT]
> This extension is currently experimental. All public APIs are gated behind the `TPEXP` diagnostic ID.
diff --git a/docs/core/testing/microsoft-testing-platform-run-and-debug.md b/docs/core/testing/microsoft-testing-platform-run-and-debug.md
index c1ce9b5610594..5ad3bfd3f91a0 100644
--- a/docs/core/testing/microsoft-testing-platform-run-and-debug.md
+++ b/docs/core/testing/microsoft-testing-platform-run-and-debug.md
@@ -3,7 +3,7 @@ title: Run and debug tests with Microsoft.Testing.Platform (MTP)
description: Learn how to run and debug MTP test projects from CLI, Visual Studio, Visual Studio Code, and CI pipelines.
author: Evangelink
ms.author: amauryleve
-ms.date: 02/24/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -23,6 +23,11 @@ MTP test projects are built as executables that can be run (or debugged) directl
> [!IMPORTANT]
> By default, MTP collects telemetry. For more information and options on opting out, see [MTP telemetry](microsoft-testing-platform-telemetry.md).
+> [!NOTE]
+> Available in MTP starting with version 2.3.0.
+>
+> For a graceful stop, press Ctrl+C once to request cancellation. Running tests can finish teardown. To terminate immediately, press Ctrl+C again.
+
## [.NET CLI](#tab/dotnetcli)
Publishing the test project using `dotnet publish` and running the app directly is another way to run your tests. For example, executing the `./Contoso.MyTests.exe`. In some scenarios it's also viable to use `dotnet build` to produce the executable, but there can be edge cases to consider, such [Native AOT](../deploying/native-aot/index.md).
diff --git a/docs/core/testing/microsoft-testing-platform-terminal-output.md b/docs/core/testing/microsoft-testing-platform-terminal-output.md
index 83a78d95ab0f0..ae07042ab86c4 100644
--- a/docs/core/testing/microsoft-testing-platform-terminal-output.md
+++ b/docs/core/testing/microsoft-testing-platform-terminal-output.md
@@ -3,7 +3,7 @@ title: Microsoft.Testing.Platform (MTP) terminal output
description: Learn about the built-in terminal test reporter in MTP, including output modes, ANSI support, and progress indicators.
author: evangelink
ms.author: amauryleve
-ms.date: 06/01/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -45,9 +45,13 @@ The progress bar is written based on the selected mode:
| Option | Description |
|---|---|
-| `--no-progress` | Disables reporting progress to screen. |
+| `--no-progress` | Disables reporting progress to screen. Deprecated in MTP 2.3.0 in favor of `--progress off`. |
+| `--progress` | Controls whether progress is shown. Valid values are `auto` (default), `on` (also accepts `true`, `enable`, `1`), and `off` (also accepts `false`, `disable`, `0`). Available in MTP starting with version 2.3.0. |
| `--no-ansi` | Disables outputting ANSI escape characters to screen. |
| `--ansi` | Controls whether ANSI escape characters are emitted. Valid values are `auto` (default), `on` (also accepts `true`, `enable`, `1`), and `off` (also accepts `false`, `disable`, `0`). Available in MTP starting with version 2.3.0. |
| `--output` | Specifies the output verbosity when reporting tests. Valid values are `Normal` and `Detailed`. Default is `Normal`. |
| `--show-stdout` | Determines when to show captured standard output of a test. Valid values are `All`, `Failed`, and `None`. Default is `All`. Available in MTP starting with version 2.2.1. |
| `--show-stderr` | Determines when to show captured error output of a test. Valid values are `All`, `Failed`, and `None`. Default is `All`. Available in MTP starting with version 2.2.1. |
+
+> [!NOTE]
+> Starting with MTP 2.3.0, when MTP detects that it runs inside an LLM or AI tool environment, it suppresses the startup banner and changes the default of `--show-stdout` and `--show-stderr` from `All` to `Failed` to reduce noise.
diff --git a/docs/core/testing/microsoft-testing-platform-test-reports.md b/docs/core/testing/microsoft-testing-platform-test-reports.md
index 210d8263f4a14..a3ae65ed39d27 100644
--- a/docs/core/testing/microsoft-testing-platform-test-reports.md
+++ b/docs/core/testing/microsoft-testing-platform-test-reports.md
@@ -1,9 +1,9 @@
---
title: Microsoft.Testing.Platform (MTP) test reports
-description: Learn about the MTP extensions for generating test report files (TRX, Azure DevOps).
+description: Learn about the MTP extensions that create test report files (TRX, HTML, JUnit, CTRF, Azure DevOps).
author: evangelink
ms.author: amauryleve
-ms.date: 06/01/2026
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -14,6 +14,26 @@ These features require installing additional NuGet packages, as described in eac
> [!TIP]
> When using [Microsoft.Testing.Platform.MSBuild](https://www.nuget.org/packages/Microsoft.Testing.Platform.MSBuild) (included transitively by MSTest, NUnit, and xUnit runners), these extensions are auto-registered when you install their NuGet packages — no code changes needed. The manual registration specified in this article is only required if you disabled the auto-generated entry point by setting `false`.
+## Report file names
+
+Every report extension writes its file to the test results directory, which you can set with the [`--results-directory`](microsoft-testing-platform-cli-options.md) option. To override the name, use the matching `--report-*-filename` option. Each report section lists the default name for that report.
+
+A file name can include a relative path that stays within the test results directory, and it can use the following replacement items (placeholders):
+
+| Placeholder | Description |
+|---|---|
+| `{asm}` | Entry assembly name, or `unknown` when it's unavailable. |
+| `{tfm}` | Target framework moniker detected at runtime, such as `net9.0`. |
+| `{arch}` | Process architecture, such as `x64`, `x86`, or `arm64`. |
+| `{pname}` | Process name. |
+| `{pid}` | Process ID. |
+| `{time}` | High-precision timestamp. |
+
+For example, `--report-trx-filename "{asm}_{tfm}_{arch}.trx"` reproduces the default TRX name.
+
+> [!NOTE]
+> Placeholder names are case-sensitive and use lowercase. Placeholder support for report file names is available in MTP starting with version 2.3.0.
+
## Visual Studio test reports (TRX)
The Visual Studio test result file (or TRX) is the default format for publishing test results. This extension requires the [Microsoft.Testing.Extensions.TrxReport](https://nuget.org/packages/Microsoft.Testing.Extensions.TrxReport) NuGet package.
@@ -28,15 +48,84 @@ builder.AddTrxReportProvider();
> [!NOTE]
> When using manual registration, register the TRX report provider last. The current implementation depends on registration order, so registering it after all other extensions ensures it captures all test data.
+> [!NOTE]
+> Available in MTP starting with version 1.9.0, the TRX report includes the test `Description` field.
+
+> [!NOTE]
+> Available in MTP starting with version 2.3.0, TRX results stream to disk as the run progresses. If the test host crashes, the TRX file keeps the results collected before the crash.
+
### Options
| Option | Description |
|---|---|
| `--report-trx` | Generates the TRX report. |
-| `--report-trx-filename` | The name of the generated TRX report. The default name matches the following format `__.trx`. |
+| `--report-trx-filename` | The name of the generated TRX report. Starting with MTP 2.3.0, the default is the deterministic `{asm}_{tfm}_{arch}.trx` form; before MTP 2.3.0, the default was `__.trx`. To customize the name, see [Report file names](#report-file-names). |
The report is saved inside the default _TestResults_ folder that can be specified through the `--results-directory` command line argument.
+## HTML reports
+
+The HTML report creates an interactive, self-contained HTML file for a test session. This extension requires the [Microsoft.Testing.Extensions.HtmlReport](https://nuget.org/packages/Microsoft.Testing.Extensions.HtmlReport) NuGet package.
+
+> [!NOTE]
+> Available in MTP starting with version 2.3.0. This extension is experimental, and its options and output format might change in a future version.
+
+### Manual registration
+
+```csharp
+var builder = await TestApplication.CreateBuilderAsync(args);
+builder.AddHtmlReportProvider();
+```
+
+### Options
+
+| Option | Description |
+|---|---|
+| `--report-html` | Generates the HTML report. |
+| `--report-html-filename` | The name of the generated HTML report. The value must end with `.html`. The default is `{asm}_{tfm}_{arch}.html`. To customize the name, see [Report file names](#report-file-names). Requires `--report-html`. |
+
+## JUnit reports
+
+The JUnit report creates a JUnit-compatible XML file for a test session. This extension requires the [Microsoft.Testing.Extensions.JUnitReport](https://nuget.org/packages/Microsoft.Testing.Extensions.JUnitReport) NuGet package.
+
+> [!NOTE]
+> Available in MTP starting with version 2.3.0. This extension is experimental, and its options and output format might change in a future version.
+
+### Manual registration
+
+```csharp
+var builder = await TestApplication.CreateBuilderAsync(args);
+builder.AddJUnitReportProvider();
+```
+
+### Options
+
+| Option | Description |
+|---|---|
+| `--report-junit` | Generates the JUnit XML report. |
+| `--report-junit-filename` | The name of the generated JUnit XML report. The value must end with `.xml`. The default is `{asm}_{tfm}_{arch}.xml`. To customize the name, see [Report file names](#report-file-names). Requires `--report-junit`. |
+
+## CTRF reports
+
+The CTRF report creates a JSON file that uses the [Common Test Report Format](https://ctrf.io) for a test session. This extension requires the [Microsoft.Testing.Extensions.CtrfReport](https://nuget.org/packages/Microsoft.Testing.Extensions.CtrfReport) NuGet package.
+
+> [!NOTE]
+> Available in MTP starting with version 2.3.0. This extension is experimental, and its options and output format might change in a future version.
+
+### Manual registration
+
+```csharp
+var builder = await TestApplication.CreateBuilderAsync(args);
+builder.AddCtrfReportProvider();
+```
+
+### Options
+
+| Option | Description |
+|---|---|
+| `--report-ctrf` | Generates the CTRF JSON report. |
+| `--report-ctrf-filename` | The name of the generated CTRF JSON report. The value must end with `.json`. The default is `____.ctrf.json`. To customize the name, see [Report file names](#report-file-names). Requires `--report-ctrf`. |
+
## Azure DevOps reports
Azure DevOps report plugin enhances test running for developers that host their code on GitHub, but build on Azure DevOps build agents. It adds additional information to failures to show failure directly in GitHub PR.
@@ -61,6 +150,8 @@ builder.TestHost.AddAzureDevOpsProvider();
| `--report-azdo-flaky-history` | Queries Azure DevOps test result history for the past N days (1-90) and annotates reported failures with flakiness context. Requires `--report-azdo`. |
| `--report-azdo-demote-known-flaky` | Demotes failures that are flaky enough in the Azure DevOps history window (default threshold is 25%) from errors to warnings. Requires `--report-azdo` and `--report-azdo-flaky-history`. |
| `--report-azdo-quarantine-file` | Path to a text file that lists quarantined test fully qualified names or glob patterns. Matching failures are reported as warnings. Requires `--report-azdo`. |
+| `--report-azdo-summary` | Writes a Markdown job summary at the end of the test run and uploads it through `##vso[task.uploadsummary]`. An optional file path argument overrides the default location (`{testResultsDir}/azdo-summary-{tfm}.md`). Requires `--report-azdo`. |
+| `--report-azdo-stackframe-filter` | Adds regex patterns, matched against the fully qualified type prefix of each stack frame, that are skipped when the extension locates the user's call site to annotate. The option is repeatable, up to 16 patterns, and each pattern is compiled with a 500-ms match timeout. These patterns are additive to the extension's built-in MSTest assertion-implementation prefixes. Requires `--report-azdo`. |
| `--report-azdo-upload-artifacts` | Uploads test result files and/or adds build tags to Azure DevOps. Valid values are `off` (default), `tags-only`, `files`, and `all`. |
| `--report-azdo-upload-artifact-include` | Includes files in the Azure DevOps artifact upload using glob patterns relative to the test results directory. Defaults to `**/*`. Requires `--report-azdo-upload-artifacts` to be a value other than `off`. |
| `--report-azdo-upload-artifact-exclude` | Excludes files from the Azure DevOps artifact upload using glob patterns relative to the test results directory. Requires `--report-azdo-upload-artifacts` to be a value other than `off`. |
@@ -69,6 +160,6 @@ builder.TestHost.AddAzureDevOpsProvider();
| `--publish-azdo-run-name` | Sets a custom Azure DevOps test run name for live test-result publishing. Requires `--publish-azdo-test-results`. |
> [!NOTE]
-> The Azure DevOps extension became stable in MTP 1.9.0 (`--report-azdo` and `--report-azdo-severity`). All other options in the table — `--report-azdo-flaky-history`, `--report-azdo-demote-known-flaky`, `--report-azdo-quarantine-file`, `--report-azdo-upload-artifacts`, `--report-azdo-upload-artifact-include`, `--report-azdo-upload-artifact-exclude`, `--report-azdo-upload-artifact-name`, `--publish-azdo-test-results`, and `--publish-azdo-run-name` — are available in MTP starting with version 2.3.0.
+> The Azure DevOps extension became stable in MTP 1.9.0 (`--report-azdo` and `--report-azdo-severity`). All other options in the table — `--report-azdo-flaky-history`, `--report-azdo-demote-known-flaky`, `--report-azdo-quarantine-file`, `--report-azdo-summary`, `--report-azdo-stackframe-filter`, `--report-azdo-upload-artifacts`, `--report-azdo-upload-artifact-include`, `--report-azdo-upload-artifact-exclude`, `--report-azdo-upload-artifact-name`, `--publish-azdo-test-results`, and `--publish-azdo-run-name` — are available in MTP starting with version 2.3.0.
The extension automatically detects that it is running in continuous integration (CI) environment by checking the `TF_BUILD` environment variable.
diff --git a/docs/core/testing/mstest-analyzers/design-rules.md b/docs/core/testing/mstest-analyzers/design-rules.md
index 85099c9ef667a..14d1df3c74863 100644
--- a/docs/core/testing/mstest-analyzers/design-rules.md
+++ b/docs/core/testing/mstest-analyzers/design-rules.md
@@ -27,6 +27,7 @@ Design rules help you create and maintain test suites that adhere to proper desi
| [MSTEST0036](mstest0036.md) | Do not use shadowing. | Warning | No |
| [MSTEST0044](mstest0044.md) | Prefer TestMethod over DataTestMethod. | Info | Yes |
| [MSTEST0045](mstest0045.md) | Use cooperative cancellation for timeout. | Info | Yes |
+| [MSTEST0066](mstest0066.md) | `[Ignore]` should specify a justification. | Info | No |
## Common scenarios
@@ -63,6 +64,7 @@ Similarly, choose between Dispose and TestCleanup:
- **[MSTEST0036](mstest0036.md)**: Avoid shadowing base class members.
- **[MSTEST0044](mstest0044.md)**: Use TestMethod unless data-driven testing is needed.
- **[MSTEST0045](mstest0045.md)**: Enable cancellation tokens for timeout handling.
+- **[MSTEST0066](mstest0066.md)**: Provide a justification message on `[Ignore]`.
## Related documentation
diff --git a/docs/core/testing/mstest-analyzers/mstest0047.md b/docs/core/testing/mstest-analyzers/mstest0047.md
new file mode 100644
index 0000000000000..c457b017de210
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0047.md
@@ -0,0 +1,32 @@
+---
+title: "MSTEST0047: Unused TestContext parameter suppressor."
+description: "Learn about code suppressor MSTEST0047: Unused TestContext parameter suppressor."
+ms.date: 06/16/2026
+ai-usage: ai-assisted
+f1_keywords:
+- MSTEST0047
+- UnusedParameterSuppressor
+helpviewer_keywords:
+- UnusedParameterSuppressor
+- MSTEST0047
+author: Evangelink
+ms.author: amauryleve
+---
+# MSTEST0047: Unused TestContext parameter suppressor
+
+| Property | Value |
+|-------------------------------------|-----------------------------------------------------------|
+| **Rule ID** | MSTEST0047 |
+| **Title** | Suppress IDE0060 for the TestContext parameter |
+| **Category** | Suppressor |
+| **Introduced in version** | 3.10.0 |
+
+## Suppressor description
+
+Suppress the [IDE0060: Remove unused parameter](../../../fundamentals/code-analysis/style-rules/ide0060.md) diagnostic for the parameter of fixture methods.
+
+MSTest lets you receive the `TestContext` as a parameter of fixture methods that are marked with , , , or . Because the parameter is required by MSTest even when your method body doesn't use it, IDE0060 would otherwise incorrectly flag it as unused.
+
+## When to disable suppressor
+
+.NET suppressors cannot be disabled.
diff --git a/docs/core/testing/mstest-analyzers/mstest0064.md b/docs/core/testing/mstest-analyzers/mstest0064.md
new file mode 100644
index 0000000000000..928cf1d6d0e15
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0064.md
@@ -0,0 +1,105 @@
+---
+title: "MSTEST0064: Prefer async assertion methods"
+description: "Learn about code analysis rule MSTEST0064: Prefer async assertion methods"
+ms.date: 06/04/2026
+f1_keywords:
+- MSTEST0064
+- PreferAsyncAssertionAnalyzer
+helpviewer_keywords:
+- PreferAsyncAssertionAnalyzer
+- MSTEST0064
+author: Evangelink
+ms.author: amauryleve
+ai-usage: ai-assisted
+dev_langs:
+- CSharp
+---
+# MSTEST0064: Prefer async assertion methods
+
+| Property | Value |
+|-------------------------------------|----------------------------------------------------|
+| **Rule ID** | MSTEST0064 |
+| **Title** | Prefer async assertion methods |
+| **Category** | Usage |
+| **Fix is breaking or non-breaking** | Non-breaking |
+| **Enabled by default** | Yes |
+| **Default severity** | Info |
+| **Introduced in version** | 4.3.0 |
+| **Is there a code fix** | No |
+
+> [!NOTE]
+> This rule is available starting with MSTest 4.3.
+
+## Cause
+
+A test method uses or to assert an exception is thrown by code that is asynchronous and blocks the asynchronous operation using `GetAwaiter().GetResult()`.
+
+## Rule description
+
+When asserting an exception is thrown by asynchronous code, prefer the async assertion methods `Assert.ThrowsAsync` and `Assert.ThrowsExactlyAsync` over blocking the asynchronous operation with `GetAwaiter().GetResult()`. Blocking on async code can cause deadlocks in some synchronization contexts and is harder to read than the equivalent `await`-based assertion.
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public async Task Test_ThrowsOnAsyncCall()
+ {
+ // Violation: blocks the async call inside Assert.Throws.
+ Assert.Throws(() => DoAsync().GetAwaiter().GetResult());
+ }
+
+ private static async Task DoAsync()
+ {
+ await Task.Yield();
+ throw new InvalidOperationException();
+ }
+}
+```
+
+## How to fix violations
+
+Use the asynchronous assertion method and `await` it:
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public async Task Test_ThrowsOnAsyncCall()
+ {
+ await Assert.ThrowsAsync(() => DoAsync());
+ }
+
+ private static async Task DoAsync()
+ {
+ await Task.Yield();
+ throw new InvalidOperationException();
+ }
+}
+```
+
+The same applies to , which has an `Assert.ThrowsExactlyAsync` counterpart.
+
+## When to suppress warnings
+
+You can suppress this warning when the containing test method cannot be made `async` (for example, a synchronous test overload required by a base class or interface signature) and you need to keep the blocking call.
+
+## Suppress a warning
+
+If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable MSTEST0064
+// The code that's violating the rule is on this line.
+#pragma warning restore MSTEST0064
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.MSTEST0064.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md).
diff --git a/docs/core/testing/mstest-analyzers/mstest0065.md b/docs/core/testing/mstest-analyzers/mstest0065.md
new file mode 100644
index 0000000000000..b2c41bbe2375b
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0065.md
@@ -0,0 +1,101 @@
+---
+title: "MSTEST0065: Avoid Assert.AreEqual on collection types"
+description: "Learn about code analysis rule MSTEST0065: Avoid Assert.AreEqual on collection types"
+ms.date: 06/04/2026
+f1_keywords:
+- MSTEST0065
+- AvoidAssertAreEqualOnCollectionsAnalyzer
+helpviewer_keywords:
+- AvoidAssertAreEqualOnCollectionsAnalyzer
+- MSTEST0065
+author: Evangelink
+ms.author: amauryleve
+ai-usage: ai-assisted
+dev_langs:
+- CSharp
+---
+# MSTEST0065: Avoid `Assert.AreEqual` on collection types
+
+| Property | Value |
+|-------------------------------------|----------------------------------------------------|
+| **Rule ID** | MSTEST0065 |
+| **Title** | Avoid `Assert.AreEqual` on collection types |
+| **Category** | Usage |
+| **Fix is breaking or non-breaking** | Non-breaking |
+| **Enabled by default** | Yes |
+| **Default severity** | Warning |
+| **Introduced in version** | 4.3.0 |
+| **Is there a code fix** | No |
+
+> [!NOTE]
+> This rule is available starting with MSTest 4.3.
+
+## Cause
+
+A call to or is made on a value whose static type implements (other than ).
+
+## Rule description
+
+ and use . For most collection types — for example arrays, , or any user-defined type implementing — this falls back to reference equality (or to whatever equality the type defines for itself), and not to element-wise comparison. As a result, the assertion almost never asserts what the test author intended.
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public void Test()
+ {
+ var expected = new[] { 1, 2, 3 };
+ var actual = new[] { 1, 2, 3 };
+
+ // Violation: this compares references, not contents, and fails.
+ Assert.AreEqual(expected, actual);
+ }
+}
+```
+
+## How to fix violations
+
+Choose the assertion that matches your intent:
+
+- Use `Assert.AreSequenceEqual` for ordered element-wise comparison.
+- Use `Assert.AreSequenceEqual(expected, actual, SequenceOrder.InAnyOrder)` for unordered element-wise comparison.
+- Use `Assert.AreEquivalent` for deep structural comparison.
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public void Test()
+ {
+ var expected = new[] { 1, 2, 3 };
+ var actual = new[] { 1, 2, 3 };
+
+ Assert.AreSequenceEqual(expected, actual);
+ }
+}
+```
+
+## When to suppress warnings
+
+Suppress this warning only if the type defines its own `Equals`/`GetHashCode` to compare contents and you intentionally rely on that.
+
+## Suppress a warning
+
+If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable MSTEST0065
+// The code that's violating the rule is on this line.
+#pragma warning restore MSTEST0065
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.MSTEST0065.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md).
diff --git a/docs/core/testing/mstest-analyzers/mstest0066.md b/docs/core/testing/mstest-analyzers/mstest0066.md
new file mode 100644
index 0000000000000..3d8a6ee1833d9
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0066.md
@@ -0,0 +1,102 @@
+---
+title: "MSTEST0066: '[Ignore]' should specify a justification"
+description: "Learn about code analysis rule MSTEST0066: '[Ignore]' should specify a justification"
+ms.date: 06/04/2026
+f1_keywords:
+- MSTEST0066
+- IgnoreShouldHaveJustificationAnalyzer
+helpviewer_keywords:
+- IgnoreShouldHaveJustificationAnalyzer
+- MSTEST0066
+author: Evangelink
+ms.author: amauryleve
+ai-usage: ai-assisted
+dev_langs:
+- CSharp
+---
+# MSTEST0066: `[Ignore]` should specify a justification
+
+| Property | Value |
+|-------------------------------------|----------------------------------------------------|
+| **Rule ID** | MSTEST0066 |
+| **Title** | `[Ignore]` should specify a justification |
+| **Category** | Design |
+| **Fix is breaking or non-breaking** | Non-breaking |
+| **Enabled by default** | Yes |
+| **Default severity** | Info |
+| **Introduced in version** | 4.3.0 |
+| **Is there a code fix** | No |
+
+> [!NOTE]
+> This rule is available starting with MSTest 4.3.
+
+## Cause
+
+A test method or test class is marked with but no justification message is provided.
+
+## Rule description
+
+To improve the discoverability and triage of skipped tests, an `[Ignore]` attribute applied to a test method or test class should include a non-empty message explaining why the test or class is ignored. A justification message helps reviewers understand the intent and prevents tests from being silently disabled forever.
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ [Ignore] // Violation - no justification provided.
+ public void Test()
+ {
+ }
+}
+```
+
+## How to fix violations
+
+Pass a non-empty message to the `[Ignore]` attribute, either positionally or via the `IgnoreMessage` named property:
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ [Ignore("Disabled until issue #1234 is fixed.")]
+ public void Test()
+ {
+ }
+}
+```
+
+```csharp
+[TestClass]
+[Ignore(IgnoreMessage = "Disabled until issue #1234 is fixed.")]
+public class TestClass
+{
+ [TestMethod]
+ public void Test()
+ {
+ }
+}
+```
+
+## When to suppress warnings
+
+Don't suppress warnings from this rule. Ignored tests without a justification are easy to forget.
+
+## Suppress a warning
+
+If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable MSTEST0066
+// The code that's violating the rule is on this line.
+#pragma warning restore MSTEST0066
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.MSTEST0066.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md).
diff --git a/docs/core/testing/mstest-analyzers/mstest0067.md b/docs/core/testing/mstest-analyzers/mstest0067.md
new file mode 100644
index 0000000000000..bd941c9ad61da
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0067.md
@@ -0,0 +1,99 @@
+---
+title: "MSTEST0067: Avoid synchronously blocking calls in test code"
+description: "Learn about code analysis rule MSTEST0067: Avoid synchronously blocking calls in test code"
+ms.date: 06/04/2026
+f1_keywords:
+- MSTEST0067
+- AvoidThreadSleepAndTaskWaitInTestsAnalyzer
+helpviewer_keywords:
+- AvoidThreadSleepAndTaskWaitInTestsAnalyzer
+- MSTEST0067
+author: Evangelink
+ms.author: amauryleve
+ai-usage: ai-assisted
+dev_langs:
+- CSharp
+---
+# MSTEST0067: Avoid synchronously blocking calls in test code
+
+| Property | Value |
+|-------------------------------------|-------------------------------------------------|
+| **Rule ID** | MSTEST0067 |
+| **Title** | Avoid synchronously blocking calls in test code |
+| **Category** | Usage |
+| **Fix is breaking or non-breaking** | Non-breaking |
+| **Enabled by default** | No |
+| **Default severity** | Info |
+| **Introduced in version** | 4.3.0 |
+| **Is there a code fix** | No |
+
+> [!NOTE]
+> This rule is available starting with MSTest 4.3. It's disabled by default. It's enabled as a warning when `All` is set.
+
+## Cause
+
+Test code uses a synchronously blocking call such as , , , , or .
+
+The rule fires on methods marked with (including custom attributes that inherit from it) and on fixture methods marked with , , , , , , `GlobalTestInitializeAttribute`, and `GlobalTestCleanupAttribute`.
+
+## Rule description
+
+Synchronously blocking the current thread inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a synchronization context that requires cooperative scheduling. Prefer `await Task.Delay` for time-based waits and `await` the task to observe its result.
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public async Task Test()
+ {
+ Thread.Sleep(1000); // Violation
+ var result = ComputeAsync().Result; // Violation
+ ComputeAsync().Wait(); // Violation
+ }
+
+ private static Task ComputeAsync() => Task.FromResult(42);
+}
+```
+
+## How to fix violations
+
+Use the asynchronous equivalent:
+
+```csharp
+[TestClass]
+public class TestClass
+{
+ [TestMethod]
+ public async Task Test()
+ {
+ await Task.Delay(1000);
+ var result = await ComputeAsync();
+ }
+
+ private static Task ComputeAsync() => Task.FromResult(42);
+}
+```
+
+## When to suppress warnings
+
+This rule is disabled by default. When opted-in, suppress individual occurrences when the synchronous wait is intentional and not avoidable — for example, when interacting with a synchronous API that cannot be made asynchronous.
+
+## Suppress a warning
+
+If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable MSTEST0067
+// The code that's violating the rule is on this line.
+#pragma warning restore MSTEST0067
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.MSTEST0067.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md).
diff --git a/docs/core/testing/mstest-analyzers/mstest0068.md b/docs/core/testing/mstest-analyzers/mstest0068.md
new file mode 100644
index 0000000000000..f9137f140ec57
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/mstest0068.md
@@ -0,0 +1,83 @@
+---
+title: "MSTEST0068: Use Assert instead of CollectionAssert"
+description: "Learn about code analysis rule MSTEST0068: Use Assert instead of CollectionAssert"
+ms.date: 06/04/2026
+f1_keywords:
+- MSTEST0068
+- CollectionAssertToAssertAnalyzer
+helpviewer_keywords:
+- CollectionAssertToAssertAnalyzer
+- MSTEST0068
+author: Evangelink
+ms.author: amauryleve
+ai-usage: ai-assisted
+dev_langs:
+- CSharp
+---
+# MSTEST0068: Use Assert instead of CollectionAssert
+
+| Property | Value |
+|-------------------------------------|----------------------------------------------------|
+| **Rule ID** | MSTEST0068 |
+| **Title** | Use `Assert` instead of `CollectionAssert` |
+| **Category** | Usage |
+| **Fix is breaking or non-breaking** | Non-breaking |
+| **Enabled by default** | Yes |
+| **Default severity** | Info |
+| **Introduced in version** | 4.3.0 |
+| **Is there a code fix** | Yes |
+
+> [!NOTE]
+> This rule is available starting with MSTest 4.3.
+
+## Cause
+
+A test method uses methods instead of equivalent methods.
+
+## Rule description
+
+Most methods have equivalent counterparts in that provide the same functionality. Prefer the methods for consistency, better readability, improved discoverability, and alignment with behavior across all test frameworks.
+
+The following methods have equivalent methods:
+
+- `CollectionAssert.AreEqual(a, b)` → `Assert.AreSequenceEqual(a, b)`
+- `CollectionAssert.AreNotEqual(a, b)` → `Assert.AreNotSequenceEqual(a, b)`
+- `CollectionAssert.AreEquivalent(a, b)` → `Assert.AreSequenceEqual(a, b, SequenceOrder.InAnyOrder)`
+- `CollectionAssert.AreNotEquivalent(a, b)` → `Assert.AreNotSequenceEqual(a, b, SequenceOrder.InAnyOrder)`
+- `CollectionAssert.AllItemsAreNotNull(a)` → `Assert.AreAllNotNull(a)`
+- `CollectionAssert.AllItemsAreUnique(a)` → `Assert.AreAllDistinct(a)`
+- `CollectionAssert.AllItemsAreInstancesOfType(collection, typeof(T))` → `Assert.AreAllOfType(collection)`
+- `CollectionAssert.Contains(collection, value)` → `Assert.Contains(value, collection)`
+- `CollectionAssert.DoesNotContain(collection, value)` → `Assert.DoesNotContain(value, collection)`
+
+> [!WARNING]
+> When migrating from to , be careful about the change in parameter order for `Contains`, `DoesNotContain`, and `AllItemsAreInstancesOfType`. In , the expected value is always the first parameter.
+
+Overloads of `AreEqual`/`AreNotEqual` that take an are skipped because `Assert.AreSequenceEqual` expects an (different semantics). Overloads of `AreEquivalent`/`AreNotEquivalent` that take an are also skipped. `IsSubsetOf`/`IsNotSubsetOf` have no direct equivalent today and are not handled.
+
+## How to fix violations
+
+Use the provided code fixer to automatically replace method calls with their equivalent methods. You can also manually replace the method calls if needed.
+
+## When to suppress warnings
+
+Don't suppress warnings from this rule. The methods provide the same functionality with better consistency.
+
+## Suppress a warning
+
+If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable MSTEST0068
+// The code that's violating the rule is on this line.
+#pragma warning restore MSTEST0068
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.MSTEST0068.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md).
diff --git a/docs/core/testing/mstest-analyzers/overview.md b/docs/core/testing/mstest-analyzers/overview.md
index 6d3ff4c60e02c..21b99490cb64e 100644
--- a/docs/core/testing/mstest-analyzers/overview.md
+++ b/docs/core/testing/mstest-analyzers/overview.md
@@ -130,6 +130,8 @@ Rules for writing asynchronous test code correctly:
- [MSTEST0045](mstest0045.md) - Use cooperative cancellation for timeout
- [MSTEST0049](mstest0049.md) - Flow TestContext CancellationToken
- [MSTEST0054](mstest0054.md) - Use CancellationToken property
+- [MSTEST0064](mstest0064.md) - Prefer async assertion methods
+- [MSTEST0067](mstest0067.md) - Avoid synchronously blocking calls in test code
Related documentation: [TestContext](../unit-testing-mstest-writing-tests-testcontext.md)
@@ -161,7 +163,9 @@ Rules for test initialization, cleanup, and lifecycle management:
- [MSTEST0021](mstest0021.md) - Prefer Dispose over TestCleanup
- [MSTEST0022](mstest0022.md) - Prefer TestCleanup over Dispose
- [MSTEST0034](mstest0034.md) - Use ClassCleanupBehavior.EndOfClass
+- [MSTEST0047](mstest0047.md) - Suppress IDE0060 for unused TestContext parameter on initialize and cleanup methods
- [MSTEST0050](mstest0050.md) - Global test fixture should be valid
+- [MSTEST0066](mstest0066.md) - `[Ignore]` should specify a justification
Related documentation: [Lifecycle](../unit-testing-mstest-writing-tests-lifecycle.md)
@@ -183,6 +187,9 @@ Rules for using assertion methods correctly and effectively:
- [MSTEST0051](mstest0051.md) - Assert.Throws should contain single statement
- [MSTEST0053](mstest0053.md) - Avoid Assert format parameters
- [MSTEST0058](mstest0058.md) - Avoid asserts in catch blocks
+- [MSTEST0064](mstest0064.md) - Prefer async assertion methods
+- [MSTEST0065](mstest0065.md) - Avoid Assert.AreEqual on collection types
+- [MSTEST0068](mstest0068.md) - Use Assert instead of CollectionAssert
Related documentation: [Assertions](../unit-testing-mstest-writing-tests-assertions.md)
@@ -193,6 +200,7 @@ Rules for properly using the TestContext object:
- [MSTEST0005](mstest0005.md) - TestContext should be valid
- [MSTEST0024](mstest0024.md) - Do not store static TestContext
- [MSTEST0033](mstest0033.md) - Suppress non-nullable reference not initialized warning
+- [MSTEST0047](mstest0047.md) - Suppress IDE0060 for the TestContext parameter
- [MSTEST0048](mstest0048.md) - TestContext property usage
- [MSTEST0049](mstest0049.md) - Flow TestContext CancellationToken
- [MSTEST0054](mstest0054.md) - Use CancellationToken property
@@ -266,6 +274,7 @@ Related documentation: [Configure MSTest](../unit-testing-mstest-configure.md),
| [MSTEST0044](mstest0044.md) | Design | Prefer TestMethod over DataTestMethod | Info |
| [MSTEST0045](mstest0045.md) | Design | Use cooperative cancellation for timeout | Info |
| [MSTEST0046](mstest0046.md) | Usage | Use Assert instead of StringAssert | Info |
+| [MSTEST0047](mstest0047.md) | Suppression | Suppress IDE0060 for the TestContext parameter | N/A |
| [MSTEST0048](mstest0048.md) | Usage | TestContext property usage | Warning |
| [MSTEST0049](mstest0049.md) | Usage | Flow TestContext CancellationToken | Info |
| [MSTEST0050](mstest0050.md) | Usage | Global test fixture should be valid | Warning |
@@ -282,6 +291,11 @@ Related documentation: [Configure MSTest](../unit-testing-mstest-configure.md),
| [MSTEST0061](mstest0061.md) | Usage | Use OSCondition attribute instead of runtime check | Info |
| [MSTEST0062](mstest0062.md) | Usage | Avoid out/ref test method parameters | Warning |
| [MSTEST0063](mstest0063.md) | Usage | Test class should have valid constructor | Warning |
+| [MSTEST0064](mstest0064.md) | Usage | Prefer async assertion methods | Info |
+| [MSTEST0065](mstest0065.md) | Usage | Avoid `Assert.AreEqual` on collection types | Warning |
+| [MSTEST0066](mstest0066.md) | Design | `[Ignore]` should specify a justification | Info |
+| [MSTEST0067](mstest0067.md) | Usage | Avoid synchronously blocking calls in test code | Info (disabled by default) |
+| [MSTEST0068](mstest0068.md) | Usage | Use `Assert` instead of `CollectionAssert` | Info |
| [MSTEST0069](mstest0069.md) | Usage | Inherited `[TestClass]` is ignored by the MSTest source generator | Warning |
| [MSTEST0070](mstest0070.md) | Usage | `[MemberCondition]` arguments should be valid | Warning |
| [MSTEST0071](mstest0071.md) | Usage | Test method should not specify a display name equal to its name | Info |
diff --git a/docs/core/testing/mstest-analyzers/suppression-rules.md b/docs/core/testing/mstest-analyzers/suppression-rules.md
index c6c665ed534ab..9e48d59f66224 100644
--- a/docs/core/testing/mstest-analyzers/suppression-rules.md
+++ b/docs/core/testing/mstest-analyzers/suppression-rules.md
@@ -17,6 +17,7 @@ Suppression rules automatically suppress diagnostics from other analyzers (like
| [MSTEST0027](mstest0027.md) | Suppress async suffix for test methods. | VSTHRD200 |
| [MSTEST0028](mstest0028.md) | Suppress async suffix for test fixture methods. | VSTHRD200 |
| [MSTEST0033](mstest0033.md) | Suppress non-nullable reference not initialized. | CS8618 |
+| [MSTEST0047](mstest0047.md) | Suppress the unused TestContext parameter of fixture methods. | IDE0060 |
## How suppression rules work
@@ -62,6 +63,26 @@ public class MyTests
}
```
+### IDE0060: Remove unused parameter
+
+**Suppressed by**: [MSTEST0047](mstest0047.md)
+
+**Why suppress**: MSTest lets you receive the `TestContext` as a parameter of fixture methods marked with `[AssemblyInitialize]`, `[ClassInitialize]`, `[GlobalTestInitialize]`, or `[GlobalTestCleanup]`. MSTest requires this parameter even when the method body doesn't use it, so IDE0060 (which flags unused parameters) doesn't apply.
+
+**Example**:
+
+```csharp
+[TestClass]
+public class MyTests
+{
+ [ClassInitialize]
+ public static void ClassInitialize(TestContext context) // IDE0060 would warn without suppression
+ {
+ // context isn't used, but MSTest requires the parameter
+ }
+}
+```
+
## Disable suppression rules
If you prefer to see these warnings, disable the suppression rules in your `.editorconfig`:
@@ -71,6 +92,7 @@ If you prefer to see these warnings, disable the suppression rules in your `.edi
dotnet_diagnostic.MSTEST0027.severity = none
dotnet_diagnostic.MSTEST0028.severity = none
dotnet_diagnostic.MSTEST0033.severity = none
+dotnet_diagnostic.MSTEST0047.severity = none
```
## Related documentation
diff --git a/docs/core/testing/mstest-analyzers/usage-rules.md b/docs/core/testing/mstest-analyzers/usage-rules.md
index 906a918257e3b..ad28a028a8ad6 100644
--- a/docs/core/testing/mstest-analyzers/usage-rules.md
+++ b/docs/core/testing/mstest-analyzers/usage-rules.md
@@ -60,6 +60,10 @@ Usage rules support proper usage of MSTest attributes, methods, and patterns. Th
| [MSTEST0061](mstest0061.md) | Use OSCondition attribute instead of runtime check. | Info | Yes |
| [MSTEST0062](mstest0062.md) | Avoid out/ref test method parameters. | Warning | Yes |
| [MSTEST0063](mstest0063.md) | Test class should have valid constructor. | Warning | No |
+| [MSTEST0064](mstest0064.md) | Prefer async assertion methods. | Info | No |
+| [MSTEST0065](mstest0065.md) | Avoid `Assert.AreEqual` on collection types. | Warning | No |
+| [MSTEST0067](mstest0067.md) | Avoid synchronously blocking calls in test code. | Info (disabled by default) | No |
+| [MSTEST0068](mstest0068.md) | Use `Assert` instead of `CollectionAssert`. | Info | Yes |
| [MSTEST0069](mstest0069.md) | Inherited `[TestClass]` is ignored by the MSTest source generator. | Warning | No |
| [MSTEST0070](mstest0070.md) | `[MemberCondition]` arguments should be valid. | Warning | No |
| [MSTEST0071](mstest0071.md) | Test method should not specify a display name equal to its name. | Info | Yes |
@@ -117,6 +121,9 @@ Rules for correct and effective assertion usage:
- **[MSTEST0051](mstest0051.md)**: Assert.Throws should test single statement.
- **[MSTEST0053](mstest0053.md)**: Use string interpolation instead of format parameters.
- **[MSTEST0058](mstest0058.md)**: Don't put assertions in catch blocks.
+- **[MSTEST0064](mstest0064.md)**: Prefer async assertion methods over blocking on async code.
+- **[MSTEST0065](mstest0065.md)**: Avoid `Assert.AreEqual` on collection types.
+- **[MSTEST0068](mstest0068.md)**: Prefer `Assert` over `CollectionAssert`.
### TestContext usage
@@ -133,6 +140,7 @@ Proper usage of the TestContext object:
Rules for asynchronous test code:
- **[MSTEST0040](mstest0040.md)**: Avoid asserts in async void methods.
+- **[MSTEST0067](mstest0067.md)**: Avoid `Thread.Sleep`, `Task.Wait`, and other synchronously blocking calls in test code (opt-in).
### Test configuration
diff --git a/docs/core/testing/unit-testing-mstest-configure.md b/docs/core/testing/unit-testing-mstest-configure.md
index 8f8458fce636a..aa8ff713065ba 100644
--- a/docs/core/testing/unit-testing-mstest-configure.md
+++ b/docs/core/testing/unit-testing-mstest-configure.md
@@ -3,7 +3,8 @@ title: Configure MSTest
description: Learn how to configure MSTest.
author: Evangelink
ms.author: amauryleve
-ms.date: 04/16/2024
+ms.date: 06/19/2026
+ai-usage: ai-assisted
---
# Configure MSTest
@@ -22,29 +23,32 @@ The following runsettings entries let you configure how MSTest behaves.
| Configuration | Default | Values |
|---------------|---------|--------|
-|**AssemblyCleanupTimeout**|0|Specify globally the timeout to apply on each instance of assembly cleanup method. `[Timeout]` attribute specified on the assembly cleanup method overrides the global timeout .|
-|**AssemblyInitializeTimeout**|0|Specify globally the timeout to apply on each instance of assembly initialize method. `[Timeout]` attribute specified on the assembly initialize method overrides the global timeout .|
-|**AssemblyResolution**|false|You can specify paths to extra assemblies when finding and running unit tests. For example, use these paths for dependency assemblies that aren't in the same directory as the test assembly. To specify a path, use a **Directory Path** element. Paths can include environment variables.
` `
This feature is only applied when using a .NET Framework target.|
-|**CaptureTraceOutput**|true|Capture text messages coming from the `Console.Write*`, `Trace.Write*`, and `Debug.Write*` APIs that will be associated to the current running test.|
-|**ClassCleanupLifecycle**|EndOfClass|If you want the class cleanup to occur at the end of assembly, set it to **EndOfAssembly**. (No longer supported starting from MSTest v4 as EndOfClass is the default and only [ClassCleanup]() behavior)|
-|**ClassCleanupTimeout**|0|Specify globally the timeout to apply on each instance of class cleanup method. `[Timeout]` attribute specified on the class cleanup method overrides the global timeout.|
-|**ClassInitializeTimeout**|0|Specify globally the timeout to apply on each instance of class initialize method. `[Timeout]` attribute specified on the class initialize method overrides the global timeout.|
-|**ConsiderFixturesAsSpecialTests**|false|To display `AssemblyInitialize`, `AssemblyCleanup`, `ClassInitialize`, `ClassCleanup` as individual entries in Visual Studio and Visual Studio Code `Test Explorer` and _.trx_ log, set this value to **true**|
-|**DeleteDeploymentDirectoryAfterTestRunIsComplete**|true|To retain the deployment directory after a test run, set this value to **false**.|
-|**DeploymentEnabled**|true|If you set the value to **false**, deployment items that you specify in your test method aren't copied to the deployment directory.|
-|**DeployTestSourceDependencies**|true|A value indicating whether the test source references are to be deployed.|
-|**EnableBaseClassTestMethodsFromOtherAssemblies**|true|A value indicating whether to enable discovery of test methods from base classes in a different assembly from the inheriting test class.|
-|**ForcedLegacyMode**|false|In older versions of Visual Studio, the MSTest adapter was optimized to make it faster and more scalable. Some behavior, such as the order in which tests are run, might not be exactly as it was in previous editions of Visual Studio. Set the value to **true** to use the older test adapter.
For example, you might use this setting if you have an *app.config* file specified for a unit test.
We recommend that you consider refactoring your tests to allow you to use the newer adapter.|
-|**MapInconclusiveToFailed**|false|If a test completes with an inconclusive status, it's mapped to the skipped status in **Test Explorer**. If you want inconclusive tests to be shown as failed, set the value to **true**.|
-|**MapNotRunnableToFailed**|true|A value indicating whether a not runnable result is mapped to failed test.|
-|**OrderTestsByNameInClass**|false|If you want to run tests by test names both in Test Explorers and on the command line, set this value to **true**.|
-|**Parallelize**||Used to set the parallelization settings:
**Workers**: The number of threads/workers to be used for parallelization, which is by default **the number of processors on the current machine**.
**SCOPE**: The scope of parallelization. You can set it to **MethodLevel**. By default, it's **ClassLevel**.
`32MethodLevel`|
-|**SettingsFile**||You can specify a test settings file to use with the MSTest adapter here. You can also specify a test settings file [from the settings menu](/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file#specify-a-run-settings-file-in-the-ide).
If you specify this value, you must also set the **ForcedLegacyMode** to **true**.
`true`|
-|**TestCleanupTimeout**|0|Specify globally the timeout to apply on each instance of test cleanup method. `[Timeout]` attribute specified on the test cleanup method overrides the global timeout.|
-|**TestInitializeTimeout**|0|Specify globally the timeout to apply on each instance of test initialize method. `[Timeout]` attribute specified on the test initialize method overrides the global timeout.|
-|**TestTimeout**|0|Gets specified global test case timeout.|
-|**TreatClassAndAssemblyCleanupWarningsAsErrors**|false|To see your failures in class cleanups as errors, set this value to **true**.|
-|**TreatDiscoveryWarningsAsErrors**|false|To report test discovery warnings as errors, set this value to **true**.|
+|`AssemblyCleanupTimeout`|0|Specify globally the timeout to apply on each instance of assembly cleanup method. `[Timeout]` attribute specified on the assembly cleanup method overrides the global timeout .|
+|`AssemblyInitializeTimeout`|0|Specify globally the timeout to apply on each instance of assembly initialize method. `[Timeout]` attribute specified on the assembly initialize method overrides the global timeout .|
+|`AssemblyResolution`|false|You can specify paths to extra assemblies when finding and running unit tests. For example, use these paths for dependency assemblies that aren't in the same directory as the test assembly. To specify a path, use a **Directory Path** element. Paths can include environment variables.
` `
This feature is only applied when using a .NET Framework target.|
+|`CaptureTraceOutput`|true|Capture text messages coming from the `Console.Write*`, `Trace.Write*`, and `Debug.Write*` APIs that will be associated to the current running test.|
+|`ClassCleanupLifecycle`|EndOfClass|If you want the class cleanup to occur at the end of assembly, set it to `EndOfAssembly`. (No longer supported starting from MSTest v4 as `EndOfClass` is the default and only [ClassCleanup]() behavior)|
+|`ClassCleanupTimeout`|0|Specify globally the timeout to apply on each instance of class cleanup method. `[Timeout]` attribute specified on the class cleanup method overrides the global timeout.|
+|`ClassInitializeTimeout`|0|Specify globally the timeout to apply on each instance of class initialize method. `[Timeout]` attribute specified on the class initialize method overrides the global timeout.|
+|`ConsiderFixturesAsSpecialTests`|false|To display `AssemblyInitialize`, `AssemblyCleanup`, `ClassInitialize`, `ClassCleanup` as individual entries in Visual Studio and Visual Studio Code `Test Explorer` and _.trx_ log, set this value to **true**|
+|`DeleteDeploymentDirectoryAfterTestRunIsComplete`|true|To retain the deployment directory after a test run, set this value to **false**.|
+|`DeploymentEnabled`|true|If you set the value to **false**, deployment items that you specify in your test method aren't copied to the deployment directory.|
+|`DeployTestSourceDependencies`|true|A value indicating whether the test source references are to be deployed.|
+|`EnableBaseClassTestMethodsFromOtherAssemblies`|true|A value indicating whether to enable discovery of test methods from base classes in a different assembly from the inheriting test class.|
+|`ForcedLegacyMode`|false|In older versions of Visual Studio, the MSTest adapter was optimized to make it faster and more scalable. Some behavior, such as the order in which tests are run, might not be exactly as it was in previous editions of Visual Studio. Set the value to **true** to use the older test adapter.
For example, you might use this setting if you have an *app.config* file specified for a unit test.
We recommend that you consider refactoring your tests to allow you to use the newer adapter.|
+|`LaunchDebuggerOnTestFailure`|false|Starting with MSTest 4.2, when set to **true**, MSTest launches the debugger when a test fails.|
+|`MapInconclusiveToFailed`|false|If a test completes with an inconclusive status, it's mapped to the skipped status in **Test Explorer**. If you want inconclusive tests to be shown as failed, set the value to **true**.|
+|`MapNotRunnableToFailed`|true|A value indicating whether a not runnable result is mapped to failed test.|
+|`OrderTestsByNameInClass`|false|If you want to run tests by test names both in Test Explorers and on the command line, set this value to **true**.|
+|`Parallelize`||Used to set the parallelization settings:
`Workers`: The number of threads/workers to be used for parallelization, which is by default **the number of processors on the current machine**.
`Scope`: The scope of parallelization. You can set it to `MethodLevel`. By default, it's `ClassLevel`.
`32MethodLevel`|
+|`RandomizeTestOrder`|false|Starting with MSTest 4.3, set this value to **true** to run tests in a random order, which helps surface hidden ordering dependencies between tests. This setting can't be combined with `OrderTestsByNameInClass`.|
+|`RandomTestOrderSeed`||Starting with MSTest 4.3, when `RandomizeTestOrder` is **true**, set an integer seed to make the random order reproducible across runs. When unset, a new seed is used for each run.|
+|`SettingsFile`||You can specify a test settings file to use with the MSTest adapter here. You can also specify a test settings file [from the settings menu](/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file#specify-a-run-settings-file-in-the-ide).
If you specify this value, you must also set the `ForcedLegacyMode` to **true**.
`true`|
+|`TestCleanupTimeout`|0|Specify globally the timeout to apply on each instance of test cleanup method. `[Timeout]` attribute specified on the test cleanup method overrides the global timeout.|
+|`TestInitializeTimeout`|0|Specify globally the timeout to apply on each instance of test initialize method. `[Timeout]` attribute specified on the test initialize method overrides the global timeout.|
+|`TestTimeout`|0|Gets specified global test case timeout.|
+|`TreatClassAndAssemblyCleanupWarningsAsErrors`|false|To see your failures in class cleanups as errors, set this value to **true**.|
+|`TreatDiscoveryWarningsAsErrors`|false|To report test discovery warnings as errors, set this value to **true**.|
### `TestRunParameter` element
@@ -214,7 +218,10 @@ All the settings in this section belong to the `execution` element.
| considerEmptyDataSourceAsInconclusive | false | When set to `true`, an empty data source is considered as inconclusive. |
| considerFixturesAsSpecialTests | false | To display `AssemblyInitialize`, `AssemblyCleanup`, `ClassInitialize`, `ClassCleanup` as individual entries in Visual Studio and Visual Studio Code `Test Explorer` and _.trx_ log, set this value to **true**. |
| mapInconclusiveToFailed | false | If a test completes with an inconclusive status, it's mapped to the skipped status in **Test Explorer**. If you want inconclusive tests to be shown as failed, set the value to **true**. |
+| launchDebuggerOnTestFailure | false | Starting with MSTest 4.2, when set to `true`, MSTest launches the debugger when a test fails. |
| mapNotRunnableToFailed | true | A value indicating whether a not runnable result is mapped to failed test. |
+| randomizeTestOrder | false | Starting with MSTest 4.3, set this value to `true` to run tests in a random order, which helps surface hidden ordering dependencies between tests. This setting can't be combined with `orderTestsByNameInClass`. |
+| randomTestOrderSeed | | Starting with MSTest 4.3, when `randomizeTestOrder` is `true`, set an integer seed to make the random order reproducible across runs. When unset, a new seed is used for each run. |
| treatClassAndAssemblyCleanupWarningsAsErrors | false | To see your failures in class cleanups as errors, set this value to **true**. |
| treatDiscoveryWarningsAsErrors | false | To report test discovery warnings as errors, set this value to **true**. |
@@ -299,3 +306,23 @@ Each element of the file is optional because it has a default value.
}
}
```
+
+## MSBuild properties
+
+Starting with MSTest 4.3, opt in to assembly-level parallelization from your project file or `Directory.Build.props` without authoring an `[assembly: Parallelize]` attribute. These properties emit the corresponding assembly attribute during build, so they require `GenerateAssemblyInfo` to be `true` (the default for SDK-style projects).
+
+| Property | Default | Description |
+|----------|---------|-------------|
+| `MSTestParallelizeScope` | | The parallelization scope. Set it to `MethodLevel` or `ClassLevel` to emit `[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]` (or `ExecutionScope.ClassLevel`), or to `None` to emit `[assembly: DoNotParallelize]`. |
+| `MSTestParallelizeWorkers` | | The maximum number of worker threads, emitted as the `Workers` value of `[assembly: Parallelize]`. A value of `0` maps to the number of processors on the current machine. This property can't be set when `MSTestParallelizeScope` is `None`. |
+
+The following example enables method-level parallelization with four workers for every test project that imports the `Directory.Build.props` file:
+
+```xml
+
+
+ MethodLevel
+ 4
+
+
+```
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-assertions.md b/docs/core/testing/unit-testing-mstest-writing-tests-assertions.md
index 56db40616c9b2..34b190e65b55d 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-assertions.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-assertions.md
@@ -34,6 +34,9 @@ Assert.AreEqual(expected, actual, "Values should match after processing");
Use the class to verify that the code under test behaves as expected.
+> [!NOTE]
+> Starting with MSTest 4.0, all `Assert` APIs capture the argument expression and include it in failure messages. This support provides richer diagnostics without a manual `message` parameter.
+
### Common assertion methods
```csharp
@@ -67,6 +70,14 @@ public async Task AssertExamples()
}
```
+### The `Assert.That` method
+
+Starting with MSTest 4.0, `Assert.That` evaluates any Boolean expression and produces a clear failure message. For richer diagnostics, `Assert.That` uses `[CallerArgumentExpression]` to capture the expression text automatically.
+
+```csharp
+Assert.That(order.Total > 0);
+```
+
### Available APIs
-
@@ -79,10 +90,12 @@ public async Task AssertExamples()
-
-
-
+-
-
-
-
-
+-
-
-
-
@@ -92,6 +105,7 @@ public async Task AssertExamples()
-
-
-
+-
-
-
-
@@ -99,11 +113,21 @@ public async Task AssertExamples()
-
-
-
+- `Assert.That`
-
-
-
-
+> [!NOTE]
+> Starting with MSTest 3.8, collection assertions include `Assert.Contains`, `Assert.DoesNotContain`, `Assert.HasCount`, `Assert.IsEmpty`, `Assert.IsNotEmpty`, and `Assert.ContainsSingle`.
+>
+> Starting with MSTest 3.10, comparison assertions include `Assert.IsInRange`, `Assert.IsGreaterThan`, `Assert.IsGreaterThanOrEqualTo`, `Assert.IsLessThan`, `Assert.IsLessThanOrEqualTo`, `Assert.IsPositive`, and `Assert.IsNegative`.
+>
+> Starting with MSTest 3.10, string-matching assertions include `Assert.StartsWith`, `Assert.EndsWith`, `Assert.MatchesRegex`, `Assert.DoesNotStartWith`, `Assert.DoesNotEndWith`, and `Assert.DoesNotMatchRegex`.
+>
+> Starting with MSTest 4.1, `Assert.IsExactInstanceOfType` and `Assert.IsNotExactInstanceOfType` require an exact type match. Unlike `Assert.IsInstanceOfType`, these methods don't match derived types.
+
### New collection and equivalence assertions in MSTest 4.3
> [!NOTE]
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-controlling-execution.md b/docs/core/testing/unit-testing-mstest-writing-tests-controlling-execution.md
index 9b35cc1f3b88f..0947a5ed5db3b 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-controlling-execution.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-controlling-execution.md
@@ -3,7 +3,7 @@ title: Test execution and control in MSTest
description: Learn how to control test execution in MSTest with parallelization, threading, timeouts, retries, and conditional execution.
author: Evangelink
ms.author: amauryleve
-ms.date: 07/15/2025
+ms.date: 06/19/2026
ai-usage: ai-assisted
---
@@ -143,7 +143,7 @@ The `Workers` property specifies the maximum number of threads for parallel exec
```
> [!TIP]
-> You can also configure parallelization through [runsettings](unit-testing-mstest-configure.md#mstest-element) or [testconfig.json](unit-testing-mstest-configure.md#testconfigjson) without modifying code.
+> You can configure parallelization without modifying code through [runsettings](unit-testing-mstest-configure.md#mstest-element), [testconfig.json](unit-testing-mstest-configure.md#testconfigjson), or the [`MSTestParallelizeScope` and `MSTestParallelizeWorkers` MSBuild properties](unit-testing-mstest-configure.md#msbuild-properties).
> [!TIP]
> Enable parallelization at the assembly level by default, even if many tests currently require sequential execution. This approach encourages writing new tests that support parallel execution from the start. Use the [MSTEST0001](mstest-analyzers/mstest0001.md) analyzer to ensure that the assembly explicitly declares its parallelization intent with `[assembly: Parallelize]` or `[assembly: DoNotParallelize]`. Once parallelization is enabled, review each test class to determine whether it safely supports concurrent execution. Often, excluding just a few classes or methods with `DoNotParallelize` is sufficient, allowing the majority of your tests to run in parallel for significantly faster test execution.
@@ -365,7 +365,7 @@ public class RetryTests
### Custom retry implementations
-Create custom retry logic by inheriting from :
+Starting with MSTest 3.8, create custom retry logic by inheriting from :
```csharp
public class CustomRetryAttribute : RetryBaseAttribute
@@ -390,6 +390,9 @@ Conditional execution attributes control whether tests run based on specific con
The is the abstract base class for conditional execution. MSTest provides several built-in implementations.
+> [!NOTE]
+> The `ConditionBaseAttribute` was introduced in MSTest 3.8.
+
> [!NOTE]
> By default, condition attributes aren't inherited. Applying them to a base class doesn't affect derived classes. Custom condition attributes can override this behavior by redefining `AttributeUsage`, but this isn't recommended to maintain consistency with the built-in condition attributes.
@@ -402,6 +405,9 @@ The i
The runs or skips tests based on the operating system. Use the flags enum to specify which operating systems apply.
+> [!NOTE]
+> The `OSConditionAttribute` was introduced in MSTest 3.8.
+
```csharp
[TestClass]
public class OSSpecificTests
@@ -449,6 +455,9 @@ Combine operating systems with the bitwise OR operator (`|`).
The runs or skips tests based on whether they're executing in a continuous integration environment.
+> [!NOTE]
+> The `CIConditionAttribute` was introduced in MSTest 3.10.
+
```csharp
[TestClass]
public class CIAwareTests
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-data-driven.md b/docs/core/testing/unit-testing-mstest-writing-tests-data-driven.md
index 568d0d83e56a3..6039045c0dcc8 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-data-driven.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-data-driven.md
@@ -4,7 +4,7 @@ description: Learn how to use data-driven testing in MSTest with DataRow, Dynami
author: Evangelink
ms.author: amauryleve
ai-usage: ai-assisted
-ms.date: 03/09/2026
+ms.date: 06/16/2026
---
# Data-driven testing in MSTest
@@ -98,6 +98,9 @@ public class DataRowExamples
}
```
+> [!NOTE]
+> Starting with MSTest v3.10, use `DateOnly` and `TimeOnly` as `DataRow` arguments and in `DynamicData` parameterized tests.
+
### Using params for variable arguments
Use the `params` keyword to accept a variable number of arguments:
@@ -117,6 +120,20 @@ public class ParamsExample
}
```
+### Generic test methods
+
+Starting with MSTest v3.8, a `TestMethod` can have type parameters. The framework infers type arguments from `DataRow` or `DynamicData` values:
+
+```csharp
+[TestMethod]
+[DataRow(42)]
+[DataRow("alpha")]
+public void Value_RoundTrips(T value)
+{
+ Assert.AreEqual(value, value);
+}
+```
+
### Custom display names
Set the property to customize how test cases appear in Test Explorer:
@@ -178,7 +195,10 @@ The data source can return any `IEnumerable` where `T` is one of the types li
### Data sources
-The data source can be a method, property, or field. All three are interchangeable—choose based on your preference:
+The data source can be a method or property and, starting with MSTest v3.11, a field. These sources are interchangeable, so choose based on your preference:
+
+> [!NOTE]
+> Starting with MSTest v3.8, `DynamicData` auto-detects the data source type. You don't need to specify `DynamicDataSourceType` explicitly.
```csharp
[TestClass]
@@ -231,6 +251,9 @@ public class DynamicDataExample
> [!NOTE]
> Data source methods, properties, and fields must be `public static` and return an `IEnumerable` of a supported type.
+> [!NOTE]
+> Starting with MSTest v3.11, the data source can be a field. Earlier versions support methods and properties.
+
> [!TIP]
> Related analyzer: [MSTEST0018](mstest-analyzers/mstest0018.md) validates that the data source exists, is accessible, and has the correct signature.
@@ -260,6 +283,19 @@ public class DynamicDataExternalExample
}
```
+### Parameterized `DynamicData` source methods
+
+Starting with MSTest v3.10, pass values to a `DynamicData` source method with the `Arguments` property:
+
+```csharp
+[TestMethod]
+[DynamicData(nameof(GetValues), Arguments = new object[] { true })]
+public void Value_IsPositive(int value, bool expected) => Assert.AreEqual(expected, value > 0);
+
+public static IEnumerable<(int Value, bool Expected)> GetValues(bool includeZero) =>
+ includeZero ? [(1, true), (0, false)] : [(1, true)];
+```
+
### Custom display names
Customize test case display names using the property:
@@ -326,6 +362,9 @@ public class IgnoreDynamicDataExample
The class provides enhanced control over test data in data-driven tests. Use of as your data source return type to specify:
+> [!NOTE]
+> MSTest introduced `TestDataRow` in version 3.8.
+
- **Custom display names**: Set a unique display name per test case using the property.
- **Test categories**: Attach metadata to individual test cases using the property.
- **Ignore messages**: Skip specific test cases with reasons using the property.
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-lifecycle.md b/docs/core/testing/unit-testing-mstest-writing-tests-lifecycle.md
index cda5a692e7fbc..f45d7087980f9 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-lifecycle.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-lifecycle.md
@@ -3,7 +3,7 @@ title: MSTest test lifecycle
description: Learn about the creation and lifecycle of test classes and test methods in MSTest, including initialization and cleanup at assembly, class, and test levels.
author: marcelwgn
ms.author: marcelwagner
-ms.date: 07/15/2025
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -151,6 +151,9 @@ public class ClassLifecycleExample
- `ClassCleanup` accepts zero parameters, or one `TestContext` parameter (MSTest 3.8+)
- Only one of each attribute allowed per class
+> [!NOTE]
+> Starting with MSTest 4.2, MSTest reports failures in `ClassCleanup` and `AssemblyCleanup` as a separate test result. The separate result makes cleanup failures easier to identify in Test Explorer and TRX reports.
+
### Inheritance behavior
Control whether `ClassInitialize` runs for derived classes using :
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-organizing.md b/docs/core/testing/unit-testing-mstest-writing-tests-organizing.md
index 1de4fb210f206..db58b232371fe 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-organizing.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-organizing.md
@@ -3,7 +3,8 @@ title: Test organization and metadata in MSTest
description: Learn how to organize and categorize tests in MSTest using categories, properties, priorities, owners, and work item references.
author: Evangelink
ms.author: amauryleve
-ms.date: 07/15/2025
+ms.date: 06/16/2026
+ai-usage: ai-assisted
---
# Test organization and metadata in MSTest
@@ -288,6 +289,9 @@ public class BugFixTests
The links tests to GitHub issues.
+> [!NOTE]
+> The `GitHubWorkItemAttribute` was introduced in MSTest 3.8.
+
```csharp
[TestClass]
public class GitHubLinkedTests
diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md b/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md
index fb3a61c551ebf..297c723997a3e 100644
--- a/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md
+++ b/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md
@@ -3,7 +3,7 @@ title: MSTest TestContext
description: Learn about the TestContext class of MSTest.
author: Evangelink
ms.author: amauryleve
-ms.date: 11/12/2024
+ms.date: 06/16/2026
ai-usage: ai-assisted
---
@@ -42,6 +42,7 @@ The provides inf
- - the directory where the test results are stored. Typically a subdirectory of the .
- - the directory where the test results are stored. Typically a subdirectory of the .
- - the directory where the test results are stored. Typically a subdirectory of the .
+- Starting with MSTest 3.9, - the number of times the current test has run, counting from 1. The value is greater than 1 when a test is retried with `[Retry]`.
In MSTest 3.7 and later, the class also provides new properties helpful for `TestInitialize` and `TestCleanup` methods:
@@ -78,8 +79,14 @@ string value = TestContext.Properties["MyKey"]?.ToString();
```
> [!NOTE]
+> Starting with MSTest 4.2, test categories from `[TestCategory]` are included in .
+>
> Starting with MSTest 4.3, custom properties added to `TestContext.Properties` in `[AssemblyInitialize]` flow to every class and test in the assembly, and properties added in `[ClassInitialize]` flow to every test in that class. This lets fixtures publish shared context that test methods can read.
+### Access `TestContext` from the current call stack
+
+Starting with MSTest 4.2, returns the current test's from anywhere in the call stack during test method execution. This API is experimental, uses the `[Experimental]` attribute, and might change in a future MSTest version.
+
### Associate data to a test
The method allows you to add a file to the test results, making it available for review in the test output. This can be useful if you generate files during your test (for example, log files, screenshots, or data files) that you want to attach to the test results.
diff --git a/docs/core/tools/dotnet-environment-variables.md b/docs/core/tools/dotnet-environment-variables.md
index 3db2af9a1a1c3..141dcafcef2c3 100644
--- a/docs/core/tools/dotnet-environment-variables.md
+++ b/docs/core/tools/dotnet-environment-variables.md
@@ -192,6 +192,7 @@ This section describes the following environment variables:
- [`DOTNET_SERVICING`](#dotnet_servicing)
- [`DOTNET_NOLOGO`](#dotnet_nologo)
- [`DOTNET_CLI_PERF_LOG`](#dotnet_cli_perf_log)
+- [`DOTNET_CLI_ENABLEAOT`](#dotnet_cli_enableaot)
- [`DOTNET_GENERATE_ASPNET_CERTIFICATE`](#dotnet_generate_aspnet_certificate)
- [`DOTNET_ADD_GLOBAL_TOOLS_TO_PATH`](#dotnet_add_global_tools_to_path)
- [`DOTNET_CLI_TELEMETRY_OPTOUT`](#dotnet_cli_telemetry_optout)
@@ -324,6 +325,18 @@ Specifies whether .NET welcome and telemetry messages are displayed on the first
Specifies whether performance details about the current CLI session are logged. Enabled when set to `1`, `true`, or `yes`. This is disabled by default.
+### `DOTNET_CLI_ENABLEAOT`
+
+Specifies whether the .NET SDK uses its native (ahead-of-time compiled) CLI command-handling fast path. When enabled, common commands (such as command-line parsing, `dotnet --version`, and `dotnet --info`) are handled by a native entry point for faster startup, transparently falling back to the managed CLI for anything the fast path doesn't handle.
+
+Set this variable to control the fast path explicitly:
+
+- To enable it, set the variable to `true`, `1`, `yes`, or `on`.
+- To disable it and route every invocation to the managed CLI, set the variable to `false`, `0`, `no`, or `off`.
+
+> [!NOTE]
+> Starting in .NET 11 Preview 7, this fast path is enabled by default (`true`) on Windows. On macOS and Linux it's disabled by default because of a command-line parsing issue ([dotnet/command-line-api#2812](https://github.com/dotnet/command-line-api/issues/2812)): when the native CLI is loaded as a NativeAOT shared library, `Environment.GetCommandLineArgs()` returns an empty array on those platforms, which causes command-line parsing to throw. It will be enabled by default on macOS and Linux once that issue is resolved. In the meantime, you can opt in early on those platforms by setting the variable to a value that enables it.
+
### `DOTNET_GENERATE_ASPNET_CERTIFICATE`
Specifies whether to generate an ASP.NET Core certificate. The default value is `true`, but this can be overridden by setting this environment variable to either `0`, `false`, or `no`.
diff --git a/docs/core/tools/dotnet-tool-exec.md b/docs/core/tools/dotnet-tool-exec.md
index 173958aa876d6..2af3fdfe72552 100644
--- a/docs/core/tools/dotnet-tool-exec.md
+++ b/docs/core/tools/dotnet-tool-exec.md
@@ -41,7 +41,7 @@ When you run `dotnet tool exec`, the command:
This command also exists in two other forms for easier use
* `dotnet dnx` - A hidden alias for `dotnet tool exec` that is used as a way to easily implement the `dnx` script itself
-* `dnx` - A shell script that invokes `dotnet dnx` from the SDK. This script is provided by the installer and is available on `PATH`. It allows for very simple use of tools directly via `dnx `.
+* `dnx` - A shell script provided by the installer and available on `PATH`. It allows for simple use of tools directly via `dnx `.
## Arguments
diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml
index 32ef47e296010..92b994442b625 100644
--- a/docs/csharp/toc.yml
+++ b/docs/csharp/toc.yml
@@ -233,6 +233,10 @@ items:
href: whats-new/version-update-considerations.md
- name: Tutorials
items:
+ - name: Explore union types
+ href: whats-new/tutorials/unions.md
+ - name: Explore closed hierarchies
+ href: whats-new/tutorials/closed-hierarchies.md
- name: Explore extension members
href: whats-new/tutorials/extension-members.md
- name: Explore compound assignment
diff --git a/docs/csharp/whats-new/tutorials/closed-hierarchies.md b/docs/csharp/whats-new/tutorials/closed-hierarchies.md
new file mode 100644
index 0000000000000..ae76e678cafa2
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/closed-hierarchies.md
@@ -0,0 +1,148 @@
+---
+title: Explore closed hierarchies in C#
+description: "A closed hierarchy restricts a base type's direct subtypes to one assembly so the compiler can verify exhaustive matches. Learn to declare closed hierarchies, decide what to seal, and use them with generics."
+author: billwagner
+ms.author: wiwagn
+ms.service: dotnet-csharp
+ms.topic: tutorial
+ms.date: 07/03/2026
+ai-usage: ai-assisted
+#customer intent: As a C# developer, I model a fixed set of related types so the compiler enforces that I handle every subtype.
+---
+# Tutorial: Explore C# closed hierarchies
+
+A *closed hierarchy* restricts the direct subtypes of a base type to the assembly that declares it. Because the compiler knows the full set of subtypes, it can verify that a `switch` expression is exhaustive without a default arm. Closed hierarchies suit domains where the set of cases is stable and you want the compiler to flag every place that needs to change when you add a case.
+
+In this tutorial, you build the sensor model of a smart-home telemetry monitor. You declare a closed hierarchy of sensor types, match the sensors exhaustively, and decide which cases to seal and which to leave open for extension.
+
+In this tutorial, you:
+
+> [!div class="checklist"]
+>
+> * Declare a closed hierarchy and match its cases exhaustively.
+> * Decide which subtypes to seal and which to leave open.
+> * Extend an open case from another assembly.
+> * Use a closed hierarchy with generics.
+
+## Prerequisites
+
+This tutorial uses preview language features. You need an SDK that supports closed hierarchies and a language version set to `preview`. To get started, you'll need:
+
+- The .NET 11 SDK preview 5 SDK or a later version. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet).
+- An editor such as Visual Studio or Visual Studio Code with the C# Dev Kit.
+
+> [!IMPORTANT]
+> Closed hierarchies are a preview feature. The syntax and behavior can change before the feature ships. Set `preview` in your project to enable it.
+
+## Create the sample solution
+
+You build a class library, `SmartHome.Core`, that holds the closed hierarchy, a second library, `SmartHome.Extensions`, that extends an open case, and a console app, `SmartHome.App`, that drives them.
+
+1. Open a terminal and run the following `dotnet` commands from a new folder previously created to store the code for tutorial:
+
+ ```dotnetcli
+ dotnet new sln -n TelemetryMonitor
+ dotnet new classlib --langversion preview -n SmartHome.Core
+ dotnet new classlib --langversion preview -n SmartHome.Extensions
+ dotnet new console --langversion preview -n SmartHome.App
+ dotnet sln add SmartHome.Core SmartHome.Extensions SmartHome.App
+ dotnet add SmartHome.Extensions reference SmartHome.Core
+ dotnet add SmartHome.App reference SmartHome.Core SmartHome.Extensions
+ ```
+
+1. The previous commands included the `--langversion preview` to enable C# 15 preview features. In each project file, verify that the language version is set to `preview`:
+
+ ```xml
+
+ preview
+
+ ```
+
+## Declare a closed hierarchy
+
+Start with the sensor model. The monitor supports a fixed set of sensor kinds, so you model them as a closed hierarchy in a single assembly.
+
+1. In `SmartHome.Core`, add a file named `Sensors.cs` and declare the `Sensor` base type with the `closed` modifier and its three derived types:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Sensors.cs" id="ClosedSensor":::
+
+1. In the same file, add a method that matches every sensor with a switch expression:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Sensors.cs" id="SensorExhaustive":::
+
+1. Build the project. .NET 11 preview 5 has the language support for closed hierarchies, but a necessary type won't be added until a later preview. If you get build errors, you need to add a polyfill for the `Closed` attribute. Add the following code to the `SmartHome.Core` project in a file named `ClosedPolyfill.cs`:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/ClosedPolyfill.cs":::
+
+The `closed` modifier restricts the direct subtypes of `Sensor` to the declaring assembly, and a `closed` type is implicitly abstract, so you can't instantiate it directly. Because the compiler knows the complete set of subtypes, the switch needs no default arm. If you add a new sensor type later, the compiler reports that this switch no longer covers every case. That feedback is the central benefit of a closed hierarchy. The compiler points you to every match that needs to change. The `Temperature` and `Humidity` cases are sealed because their shape is final, while `Contact` stays open as an extension point that the next section covers. For more information, see the [`closed` modifier](../../language-reference/keywords/closed.md) and [Closed hierarchy patterns](../../language-reference/operators/patterns.md#closed-hierarchy-patterns).
+
+## Decide what to seal
+
+A subtype of a closed type isn't itself closed unless you declare it so. For each subtype, you have three choices:
+
+- Mark it `closed` to continue the hierarchy: further subtypes are allowed, but only in the same assembly.
+- Mark it `sealed` to end the hierarchy: no further subtypes are allowed anywhere.
+- Leave it unmarked to make it open: other assemblies can derive from it, and those derived types still match the original case.
+
+You left `Contact` unmarked for that reason, so now you extend it from another assembly.
+
+1. In `SmartHome.Extensions`, add a file named `DoorContact.cs` that derives from the open `Contact` case:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Extensions/DoorContact.cs" id="DoorContact":::
+
+1. In `SmartHome.App`, add code that matches a `DoorContact` through the existing `Sensor` switch:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.App/Program.cs" id="DoorContactConsume":::
+
+A `DoorContact` can't derive from `Sensor` directly, because it's closed to other assemblies. `DoorContact` extends the open `Contact` leaf instead. A `DoorContact` still matches the `Contact` case, so the exhaustive switch over `Sensor` stays correct without any change. When you choose what to seal, weigh the trade-off: seal a case to lock its shape and keep the hierarchy fully known, or leave a case open to allow extension at the cost of a less precise match, because the switch sees the open base case rather than the derived type. For more information, see the [`closed` modifier](../../language-reference/keywords/closed.md).
+
+## Use a closed hierarchy with generics
+
+A closed hierarchy can be generic. A report from the monitor is either a single value or a group of nested reports, so model it as a generic closed hierarchy.
+
+1. In `SmartHome.Core`, add a file named `Report.cs` and declare the closed `Report` base with its two cases. A derived type can't introduce a type parameter that the base type doesn't have, but it can supply fixed arguments for one or more of the base type's type parameters:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Report.cs" id="ClosedReport":::
+
+1. Add a recursive method that accumulates the report by switching over its cases:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Report.cs" id="ReportFold":::
+
+The switch over `Single` and `Group` is exhaustive because `Report` is closed, so the recursive accumulator needs no default arm. For more information, see [Closed hierarchy patterns](../../language-reference/operators/patterns.md#closed-hierarchy-patterns).
+
+## Run the sample
+
+The console app builds each sensor and report, then prints them through the exhaustive switches. Open `Program.cs` and add the following code:
+
+:::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.App/Program.cs" id="ClosedMain":::
+
+Then, run the app:
+
+```dotnetcli
+dotnet run --project SmartHome.App
+```
+
+The sensors and report print through their exhaustive switches:
+
+```output
+Sensor: 21.4°C
+Sensor: 55% RH
+Sensor: open
+Sensor: closed
+Report leaves: 3
+```
+
+## Summary
+
+You built the sensor model of a smart-home telemetry monitor and, in the process, worked through closed-hierarchy scenarios. You:
+
+- Declared a `closed Sensor` base type and matched its subtypes with an exhaustive switch that needs no default arm.
+- Weighed the three choices for each subtype: `closed` to continue the hierarchy in the same assembly, `sealed` to end it, or unmarked to leave an extension point.
+- Extended the open `Contact` case from a separate assembly with `DoorContact`, and confirmed it still matches the `Contact` case in the existing switch.
+- Declared a generic closed hierarchy, `Report`, and folded it with a recursive exhaustive switch.
+
+## Related content
+
+- [Union types tutorial](unions.md)
+- [Pattern matching overview](../../fundamentals/functional/pattern-matching.md)
+- [What's new in C# 15](../csharp-15.md)
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/Program.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/Program.cs
new file mode 100644
index 0000000000000..2a513f74b11d0
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/Program.cs
@@ -0,0 +1,63 @@
+using SmartHome.Core;
+using SmartHome.Extensions;
+
+UnionMain();
+ClosedMain();
+
+void UnionMain()
+{
+ //
+ // Union declarations: a Reading holds a double, bool, or string.
+ Reading[] readings = [23.5, true, "offline"];
+ foreach (Reading reading in readings)
+ {
+ Console.WriteLine($"Reading: {ReadingReporter.Render(reading)}");
+ }
+ Console.WriteLine($"Reading: {ReadingReporter.Render(default)}");
+
+ // Migrate from a conventional result type to a union.
+ Result ok = 42.0;
+ Result bad = new TimeoutException("sensor timed out");
+ Console.WriteLine(ResultReporter.Describe(ok));
+ Console.WriteLine(ResultReporter.Describe(bad));
+
+ // Generic union reused across numeric widths.
+ Sample raw = (byte)200;
+ Sample railed = new Saturated(High: true);
+ Console.WriteLine($"Sample: {SampleReporter.Normalize(raw, byte.MaxValue):P0} (in range: {raw.InRange})");
+ Console.WriteLine($"Sample: {SampleReporter.Normalize(railed, short.MaxValue):P0} (in range: {railed.InRange})");
+
+ // Custom non-boxing union.
+ Console.WriteLine(QuantityReporter.Describe(new Quantity(3)));
+ Console.WriteLine(QuantityReporter.Describe(new Quantity(2.5)));
+ //
+}
+
+void ClosedMain()
+{
+ //
+ // Closed hierarchy with an exhaustive switch.
+ Sensor[] sensors =
+ [
+ new Temperature(21.4),
+ new Humidity(55),
+ new Contact(Open: true),
+ ];
+ foreach (Sensor sensor in sensors)
+ {
+ Console.WriteLine($"Sensor: {SensorReporter.Describe(sensor)}");
+ }
+
+ //
+ // A DoorContact from another assembly still matches the Contact case.
+ Sensor frontDoor = new DoorContact(Open: false, Door: "Front");
+ Console.WriteLine($"Sensor: {SensorReporter.Describe(frontDoor)}");
+ //
+
+ // Generic closed hierarchy.
+ Report report = new Group(
+ new Single("Kitchen"),
+ new Group(new Single("Garage"), new Single("Attic")));
+ Console.WriteLine($"Report leaves: {ReportReporter.Count(report)}");
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/SmartHome.App.csproj b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/SmartHome.App.csproj
new file mode 100644
index 0000000000000..6b21776a405c3
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.App/SmartHome.App.csproj
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ preview
+
+
+
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/ClosedPolyfill.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/ClosedPolyfill.cs
new file mode 100644
index 0000000000000..229927f42009d
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/ClosedPolyfill.cs
@@ -0,0 +1,4 @@
+namespace System.Runtime.CompilerServices;
+
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+public sealed class ClosedAttribute : Attribute { }
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Quantity.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Quantity.cs
new file mode 100644
index 0000000000000..02fdee4591b67
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Quantity.cs
@@ -0,0 +1,45 @@
+using System.Runtime.CompilerServices;
+
+namespace SmartHome.Core;
+
+//
+// A custom union type. The 'union' shorthand boxes value-type cases, so a
+// performance-sensitive type can implement the union pattern by hand to store
+// the value without boxing. The [Union] attribute opts the struct into union
+// behaviors; the non-boxing access members (HasValue and TryGetValue) let the
+// compiler match each case without boxing.
+[Union]
+public readonly struct Quantity : IUnion
+{
+ private readonly double _value;
+ private readonly bool _isCount;
+
+ public Quantity(int count) => (_value, _isCount) = (count, true);
+ public Quantity(double measure) => (_value, _isCount) = (measure, false);
+
+ public object? Value => _isCount ? (int)_value : _value;
+
+ public bool HasValue => true;
+ public bool TryGetValue(out int value)
+ {
+ value = (int)_value;
+ return _isCount;
+ }
+ public bool TryGetValue(out double value)
+ {
+ value = _value;
+ return !_isCount;
+ }
+}
+//
+
+public static class QuantityReporter
+{
+ //
+ public static string Describe(Quantity quantity) => quantity switch
+ {
+ int count => $"{count} items",
+ double measure => $"{measure:F2} units",
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Readings.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Readings.cs
new file mode 100644
index 0000000000000..3ac3e62ae6d2d
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Readings.cs
@@ -0,0 +1,22 @@
+namespace SmartHome.Core;
+
+//
+// A union declaration is shorthand for a struct that holds one of the listed
+// case types. The 'string?' case makes the contents nullable.
+public union Reading(double, bool, string?);
+//
+
+public static class ReadingReporter
+{
+ //
+ public static string Render(Reading reading) => reading switch
+ {
+ // Each type pattern applies to the union's contents, not to the Reading value.
+ double measure => $"{measure:F1}",
+ bool isOn => isOn ? "on" : "off",
+ string text => text,
+ // The contents can be null because 'string?' is a nullable case type.
+ null => "no reading",
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Report.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Report.cs
new file mode 100644
index 0000000000000..36366bb61acd8
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Report.cs
@@ -0,0 +1,21 @@
+namespace SmartHome.Core;
+
+//
+// A generic closed hierarchy. Every type parameter of a derived type must appear
+// in the base type, so a single derived construction exhausts each Report.
+public closed record class Report;
+public sealed record class Single(T Value) : Report;
+public sealed record class Group(Report Left, Report Right) : Report;
+//
+
+public static class ReportReporter
+{
+ //
+ public static int Count(Report report) => report switch
+ {
+ Single => 1,
+ Group group => Count(group.Left) + Count(group.Right),
+ // Exhaustive: Report is closed and both subtypes are handled.
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs
new file mode 100644
index 0000000000000..8f2ac6c5fcbaa
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs
@@ -0,0 +1,39 @@
+namespace SmartHome.Core;
+
+//
+// A conventional result type. Callers must remember to check 'IsSuccess' before
+// they read 'Value', and nothing stops them from reading the wrong field.
+public sealed class QueryResult
+{
+ private QueryResult(bool isSuccess, T? value, Exception? error)
+ {
+ IsSuccess = isSuccess;
+ Value = value;
+ Error = error;
+ }
+
+ public bool IsSuccess { get; }
+ public T? Value { get; }
+ public Exception? Error { get; }
+
+ public static QueryResult Success(T value) => new(true, value, null);
+ public static QueryResult Failure(Exception error) => new(false, default, error);
+}
+//
+
+//
+// The same idea as a union declaration. A Result holds either a T or an Exception.
+public union Result(T, Exception);
+//
+
+public static class ResultReporter
+{
+ //
+ public static string Describe(Result result) => result switch
+ {
+ T value => $"Success: {value}",
+ Exception error => $"Failure: {error.Message}",
+ null => "Failure: no value",
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sample.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sample.cs
new file mode 100644
index 0000000000000..a43ceb8795444
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sample.cs
@@ -0,0 +1,34 @@
+using System.Numerics;
+
+namespace SmartHome.Core;
+
+//
+// A generic union, reusable across sensors of different numeric precision. A
+// Sample holds either an in-range reading of type T or a Saturated marker
+// for a sensor that railed. The 'struct, INumber' constraint keeps T a
+// non-nullable numeric value type, so a switch over the cases needs no null arm.
+public union Sample(T, Saturated) where T : struct, INumber
+{
+ // A union can declare members. This property patterns over 'this' to report
+ // whether the sample carries a usable reading.
+ public bool InRange => this is T;
+}
+
+// A marker for a railed sensor, carrying which rail it hit.
+public readonly record struct Saturated(bool High);
+//
+
+public static class SampleReporter
+{
+ //
+ // Scale any numeric width to a fraction of full scale. The INumber
+ // constraint makes the same arithmetic work for byte, short, int, and more.
+ public static double Normalize(Sample sample, T fullScale)
+ where T : struct, INumber => sample switch
+ {
+ T value => double.CreateChecked(value) / double.CreateChecked(fullScale),
+ Saturated { High: true } => 1.0,
+ Saturated => 0.0,
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sensors.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sensors.cs
new file mode 100644
index 0000000000000..a98a2dbf7cb4d
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/Sensors.cs
@@ -0,0 +1,27 @@
+namespace SmartHome.Core;
+
+//
+// A closed class restricts its direct subtypes to this assembly. A 'closed'
+// class is implicitly abstract.
+public closed record class Sensor;
+
+// Seal the cases whose shape is final.
+public sealed record class Temperature(double Celsius) : Sensor;
+public sealed record class Humidity(double Percent) : Sensor;
+
+// Leave a case unsealed as an "escape hatch" so other assemblies can specialize it.
+public record class Contact(bool Open) : Sensor;
+//
+
+public static class SensorReporter
+{
+ //
+ public static string Describe(Sensor sensor) => sensor switch
+ {
+ Temperature temperature => $"{temperature.Celsius:F1}°C",
+ Humidity humidity => $"{humidity.Percent:F0}% RH",
+ Contact contact => contact.Open ? "open" : "closed",
+ // No default arm is needed. Sensor is closed, so these cases are exhaustive.
+ };
+ //
+}
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/SmartHome.Core.csproj b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/SmartHome.Core.csproj
new file mode 100644
index 0000000000000..39b1711893882
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/SmartHome.Core.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net10.0
+ enable
+ enable
+ preview
+
+
+
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/UnionSupport.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/UnionSupport.cs
new file mode 100644
index 0000000000000..f735dbc2c28eb
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Core/UnionSupport.cs
@@ -0,0 +1,21 @@
+// TEMPORARY SHIM.
+//
+// The unions and closed-hierarchy features rely on these support types. A later
+// .NET SDK ships them in the base class library, at which point this file should
+// be deleted. They're defined here so the sample compiles on the preview SDK that
+// recognizes the language syntax but doesn't yet include the types.
+//
+// This file is intentionally NOT referenced by any tutorial snippet.
+
+namespace System.Runtime.CompilerServices;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
+public class UnionAttribute : Attribute;
+
+public interface IUnion
+{
+ object? Value { get; }
+}
+
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+public sealed class IsClosedTypeAttribute : Attribute;
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/DoorContact.cs b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/DoorContact.cs
new file mode 100644
index 0000000000000..05a5eba6b097d
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/DoorContact.cs
@@ -0,0 +1,11 @@
+using SmartHome.Core;
+
+namespace SmartHome.Extensions;
+
+//
+// This type lives in a different assembly than the closed Sensor hierarchy.
+// It can't derive from Sensor directly, but it can extend the unsealed Contact
+// leaf. A DoorContact still matches the 'Contact' case, so switches over Sensor
+// stay exhaustive.
+public sealed record class DoorContact(bool Open, string Door) : Contact(Open);
+//
diff --git a/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/SmartHome.Extensions.csproj b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/SmartHome.Extensions.csproj
new file mode 100644
index 0000000000000..d3227e65cc5e2
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/snippets/shared/telemetry-monitor/SmartHome.Extensions/SmartHome.Extensions.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ net10.0
+ enable
+ enable
+ preview
+
+
+
diff --git a/docs/csharp/whats-new/tutorials/unions.md b/docs/csharp/whats-new/tutorials/unions.md
new file mode 100644
index 0000000000000..82ffeec1f6fec
--- /dev/null
+++ b/docs/csharp/whats-new/tutorials/unions.md
@@ -0,0 +1,163 @@
+---
+title: Explore union types in C#
+description: "Union types let a single value hold one of a fixed set of types. Learn to declare union types, match their cases exhaustively, build custom unions, and use them with generics."
+author: billwagner
+ms.author: wiwagn
+ms.service: dotnet-csharp
+ms.topic: tutorial
+ms.date: 07/02/2026
+ai-usage: ai-assisted
+#customer intent: As a C# developer, I model a value that can be one of several types so the compiler enforces that I handle every case.
+---
+# Tutorial: Explore C# union types
+
+A *union type* holds a single value that's one of a fixed set of types. Those types typically aren't related by inheritance, so a union lets you group unrelated types without forcing them into a common base class or interface. Unions are useful when a value is conceptually "one of these," such as a sensor reading that's a number, a switch state, or a status message. Because the set of cases is fixed, the compiler can verify that you handle every case when you read the value.
+
+In this tutorial, you build the readings layer of a smart-home telemetry monitor. You declare union types for sensor data, replace a hand-rolled result type with a union, and create a custom union for performance-sensitive code.
+
+In this tutorial, you:
+
+> [!div class="checklist"]
+>
+> * Declare union types and match their cases exhaustively.
+> * Handle null contents in a union.
+> * Add members and use generics with union declarations.
+> * Build a custom union type that avoids boxing.
+
+## Prerequisites
+
+This tutorial uses preview language features. You need an SDK that supports closed hierarchies and a language version set to `preview`. To get started, you'll need:
+
+- The .NET 11 SDK preview 5 SDK or a later version. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet).
+- An editor such as Visual Studio or Visual Studio Code with the C# Dev Kit.
+
+> [!IMPORTANT]
+> Union types are a preview feature. The syntax and supporting types can change before the feature ships. Set `preview` in your project to enable it.
+
+## Create the sample solution
+
+You build a class library, `SmartHome.Core`, that holds the union types, and a console app, `SmartHome.App`, that exercises them.
+
+1. Create the solution and projects:
+
+ ```dotnetcli
+ dotnet new sln -n TelemetryMonitor
+ dotnet new classlib --langversion preview -n SmartHome.Core
+ dotnet new console --langversion preview -n SmartHome.App
+ dotnet sln add SmartHome.Core SmartHome.App
+ dotnet add SmartHome.App reference SmartHome.Core
+ ```
+
+1. The previous commands included the `--langversion preview` to enable C# 15 preview features. In each project file, verify that the language version is set to `preview`:
+
+ ```xml
+
+ preview
+
+ ```
+
+## Declare a union type
+
+Start with the raw sensor data. A reading arrives as a number, a switch state, or a status message, so you model it as a union of those three types.
+
+1. In `SmartHome.Core`, add a file named `Readings.cs` and declare the `Reading` union. A *union declaration* lists the case types in parentheses:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Readings.cs" id="ReadingUnion":::
+
+1. In the same file, add a method that reads a `Reading` by switching over its case types:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Readings.cs" id="ReadingConsume":::
+
+Each type pattern applies to the union's *contents*, not to the `Reading` instance, because most patterns unwrap the union. The `string?` case is nullable, so the compiler treats null as a distinct case and requires the `null` arm. The switch is exhaustive: if you remove any arm, the compiler reports that a case isn't covered. That guarantee is one benefit of a union. When you add a case type later, every switch that reads the union flags the missing arm. For more information, see [Union exhaustiveness](../../language-reference/builtin-types/union.md#union-exhaustiveness) and [Union patterns](../../language-reference/operators/patterns.md#union-patterns).
+
+## Migrate a result type to a generic union
+
+When a sensor read can fail, you need a type that carries either a value or an error. Many codebases model that type with a class that exposes a success flag and two fields. Replace that class with a generic union.
+
+1. In `SmartHome.Core`, add a file named `Result.cs` with the hand-rolled result class that the migration replaces:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs" id="ResultBefore":::
+
+1. Replace that class with a generic union. A `Result` holds either a `T` or an `Exception`:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs" id="ResultUnion":::
+
+1. Add a method that reads the result by switching over its case types:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Result.cs" id="ResultConsume":::
+
+The original class lets a caller incorrectly read `Value` on a failure or `Error` on a success. The union removes those invalid states: a `Result` is either a `T` that holds the successful result or an `Exception` that explains why the operation failed. Each case converts to the union implicitly, so you assign an instance of `T` or an instance of `Exception` directly to a `Result`. When you read the result, a switch verifies that you handle the success value, the failure, and null. For more information, see [Union declarations](../../language-reference/builtin-types/union.md#union-declarations) and [Union conversions](../../language-reference/builtin-types/union.md#union-conversions).
+
+## Reuse a generic union across numeric types
+
+Sensors report at different resolutions: a contact sensor uses a `byte`, a position sensor uses a `short`, and a counter uses an `int`. Rather than write a union per type, write one generic union and instantiate it with each numeric type.
+
+1. In `SmartHome.Core`, add a file named `Sample.cs` and declare the `Sample` union. It holds either an in-range reading of type `T` or a `Saturated` marker for a sensor that railed. Give the union a body that adds an `InRange` property:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Sample.cs" id="SampleUnion":::
+
+1. Add a `Normalize` method that scales any reading to a fraction of full scale:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Sample.cs" id="SampleConsume":::
+
+The `where T : struct, INumber` constraint keeps `T` a non-nullable numeric value type and lets a single method process every numeric width through arithmetic. The same `Normalize` method works for a `Sample`, a `Sample`, or a `Sample`. Because `Saturated` is a value type and `T` is constrained to a value type, neither case is nullable, so the switch is exhaustive without a null arm. The `InRange` property shows that a union declaration can carry its own members and pattern over `this`. For more information, see [Union declarations](../../language-reference/builtin-types/union.md#union-declarations).
+
+## Build a custom union that avoids boxing
+
+A union declaration is a struct that stores its value in a single `object?` field, so a value-type case boxes when you store it. For performance-sensitive code, implement the union pattern by hand to store the value without boxing.
+
+1. In `SmartHome.Core`, add a file named `Quantity.cs`. Apply the `[Union]` attribute to a struct, and provide the access members the compiler uses to match each case:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Quantity.cs" id="QuantityUnion":::
+
+1. Add a method that consumes the custom union the same way you consume a union declaration:
+
+ :::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.Core/Quantity.cs" id="QuantityConsume":::
+
+The `HasValue` property and the `TryGetValue` overloads let the compiler match each case without boxing. The struct stores the value in a `double` field and a discriminator, so neither the `int` case nor the `double` case allocates. The switch over `int` and `double` is exhaustive, and no null arm is needed because neither case type is nullable. For more information, see [Custom union types](../../language-reference/builtin-types/union.md#custom-union-types).
+
+> [!NOTE]
+> Another scenario for a custom union is to add language support to an existing type that models a union. If your app has union-like types you created before C# had `union` types, apply the `Union` attribute and implement the `IUnion` interface on those types. The compiler then gives your custom type the same language support as a union declaration. For details, see the [Unions feature specification](~/_csharplang/proposals/unions.md).
+
+## Run the sample
+
+The console app drives each union. Replace the contents of `Program.cs`:
+
+:::code language="csharp" source="snippets/shared/telemetry-monitor/SmartHome.App/Program.cs" id="UnionMain":::
+
+Run the app:
+
+```dotnetcli
+dotnet run --project SmartHome.App
+```
+
+The readings, results, samples, and quantities each print through their exhaustive switches:
+
+```output
+Reading: 23.5
+Reading: on
+Reading: offline
+Reading: no reading
+Success: 42
+Failure: sensor timed out
+Sample: 78% (in range: True)
+Sample: 100% (in range: False)
+3 items
+2.50 units
+```
+
+## Summary
+
+You built the readings layer of a smart-home telemetry monitor and, in the process, worked through the core union scenarios. You:
+
+- Declared a `Reading` union and read it with an exhaustive switch, letting the compiler flag any case you don't handle.
+- Handled a nullable case, where the compiler requires a `null` arm.
+- Replaced a hand-rolled result type with a generic `Result` union that models success or failure without invalid states.
+- Reused a generic `Sample` union across several numeric types with a constraint, and added members to the union declaration.
+- Built a custom `[Union]` struct that avoids boxing for performance-sensitive code.
+
+## Related content
+
+- [Closed hierarchies tutorial](closed-hierarchies.md)
+- [Pattern matching overview](../../fundamentals/functional/pattern-matching.md)
+- [What's new in C# 15](../csharp-15.md)
diff --git a/docs/fundamentals/code-analysis/style-rules/ide0043.md b/docs/fundamentals/code-analysis/style-rules/ide0043.md
new file mode 100644
index 0000000000000..3a0c9586ff9e8
--- /dev/null
+++ b/docs/fundamentals/code-analysis/style-rules/ide0043.md
@@ -0,0 +1,84 @@
+---
+title: "IDE0043: Invalid format string"
+description: "Learn about code analysis rule IDE0043: Invalid format string"
+ms.date: 07/07/2026
+f1_keywords:
+- IDE0043
+helpviewer_keywords:
+- IDE0043
+author: gewarren
+ms.author: gewarren
+dev_langs:
+- CSharp
+- VB
+ai-usage: ai-assisted
+---
+# Invalid format string (IDE0043)
+
+| Property | Value |
+|--------------------------|------------------------------------|
+| **Rule ID** | IDE0043 |
+| **Title** | Invalid format string |
+| **Category** | Style |
+| **Subcategory** | Language rules (string operations) |
+| **Applicable languages** | C# and Visual Basic |
+| **Options** | None |
+
+## Overview
+
+This rule flags calls to composite formatting methods, such as , where a placeholder index in the format string refers to an argument that doesn't exist. For example, if the format string contains `{1}` but only one argument is provided (accessible as `{0}`), the rule flags the `{1}` placeholder.
+
+> [!NOTE]
+> This rule is similar to code quality rule [CA2241](../quality-rules/ca2241.md), which also validates format string arguments.
+
+## Example
+
+```csharp
+// Code with violations.
+// '{1}' is out of range — only one argument is provided.
+string s = string.Format("Hello, {0}! You have {1} messages.", "Alice");
+
+// Fixed code.
+string s = string.Format("Hello, {0}! You have {1} messages.", "Alice", 5);
+```
+
+```vb
+' Code with violations.
+' '{1}' is out of range — only one argument is provided.
+Dim s As String = String.Format("Hello, {0}! You have {1} messages.", "Alice")
+
+' Fixed code.
+Dim s As String = String.Format("Hello, {0}! You have {1} messages.", "Alice", 5)
+```
+
+## Suppress a warning
+
+If you want to suppress only a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable IDE0043
+// The code that's violating the rule is on this line.
+#pragma warning restore IDE0043
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_diagnostic.IDE0043.severity = none
+```
+
+To disable all of the code-style rules, set the severity for the category `Style` to `none` in the [configuration file](../configuration-files.md).
+
+```ini
+[*.{cs,vb}]
+dotnet_analyzer_diagnostic.category-Style.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../suppress-warnings.md).
+
+## See also
+
+- [Provide correct arguments to formatting methods (CA2241)](../quality-rules/ca2241.md)
+- [Code style language rules](language-rules.md)
+- [Code style rules reference](index.md)
diff --git a/docs/fundamentals/code-analysis/style-rules/ide0390-ide0391.md b/docs/fundamentals/code-analysis/style-rules/ide0390-ide0391.md
new file mode 100644
index 0000000000000..85e7bbd8bce8a
--- /dev/null
+++ b/docs/fundamentals/code-analysis/style-rules/ide0390-ide0391.md
@@ -0,0 +1,100 @@
+---
+title: "IDE0390 and IDE0391: Make method synchronous"
+description: "Learn about code analysis rules IDE0390 and IDE0391: Make method synchronous"
+ms.date: 07/07/2026
+f1_keywords:
+- IDE0390
+- IDE0391
+helpviewer_keywords:
+- IDE0390
+- IDE0391
+dev_langs:
+- CSharp
+ai-usage: ai-assisted
+---
+# Make method synchronous (IDE0390 and IDE0391)
+
+| Property | Value |
+|--------------------------|--------------------------------------------------|
+| **Rule ID** | IDE0390, IDE0391 |
+| **Title** | Make method synchronous |
+| **Category** | Style |
+| **Subcategory** | Unnecessary code rules (modifier preferences) |
+| **Applicable languages** | C# |
+| **Options** | None |
+
+## Overview
+
+These rules flag `async` methods that don't contain any `await` expressions. For better performance, remove the `async` modifier and adjust the return type, because an `async` method that never `await`s anything runs synchronously but with the overhead of the async state machine.
+
+The two rules target different scenarios:
+
+- **IDE0390**: Reports `async` methods, local functions, and lambda expressions that aren't interface implementations or overrides.
+- **IDE0391**: Reports `async` methods that implement an interface member or override a base class method.
+
+To avoid breaking the ability of callers to `await` the method through the interface, use caution when applying the fix to interface implementations or overrides. Removing `async` can have different behavioral implications in those cases.
+
+## Example
+
+```csharp
+// Code with violations.
+
+// IDE0390: Regular method with no 'await'.
+public async Task GetValueAsync()
+{
+ return 42;
+}
+
+// IDE0391: Override method with no 'await'.
+public override async Task GetNameAsync()
+{
+ return "example";
+}
+
+// Fixed code.
+
+// Remove 'async' and return the value directly.
+public Task GetValueAsync()
+{
+ return Task.FromResult(42);
+}
+
+// Remove 'async' and return the value directly.
+public override Task GetNameAsync()
+{
+ return Task.FromResult("example");
+}
+```
+
+## Suppress a warning
+
+If you want to suppress only a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
+
+```csharp
+#pragma warning disable IDE0390
+// The code that's violating the rule is on this line.
+#pragma warning restore IDE0390
+```
+
+To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../configuration-files.md).
+
+```ini
+[*.cs]
+dotnet_diagnostic.IDE0390.severity = none
+dotnet_diagnostic.IDE0391.severity = none
+```
+
+To disable all of the code-style rules, set the severity for the category `Style` to `none` in the [configuration file](../configuration-files.md).
+
+```ini
+[*.cs]
+dotnet_analyzer_diagnostic.category-Style.severity = none
+```
+
+For more information, see [How to suppress code analysis warnings](../suppress-warnings.md).
+
+## See also
+
+- [Asynchronous programming with async and await](../../../csharp/asynchronous-programming/index.md)
+- [Code style language rules](language-rules.md)
+- [Code style rules reference](index.md)
diff --git a/docs/fundamentals/code-analysis/style-rules/ide1007.md b/docs/fundamentals/code-analysis/style-rules/ide1007.md
new file mode 100644
index 0000000000000..f5c4c8ca33213
--- /dev/null
+++ b/docs/fundamentals/code-analysis/style-rules/ide1007.md
@@ -0,0 +1,59 @@
+---
+title: "IDE1007: The name does not exist in the current context"
+description: "Learn about code analysis rule IDE1007: The name does not exist in the current context"
+ms.date: 07/07/2026
+f1_keywords:
+- IDE1007
+helpviewer_keywords:
+- IDE1007
+dev_langs:
+- CSharp
+ai-usage: ai-assisted
+---
+# The name does not exist in the current context (IDE1007)
+
+| Property | Value |
+|--------------------------|--------------------------------------------|
+| **Rule ID** | IDE1007 |
+| **Title** | The name does not exist in the current context |
+| **Category** | Style |
+| **Subcategory** | Language rules |
+| **Applicable languages** | C# |
+| **Options** | None |
+
+## Overview
+
+This rule identifies incomplete member declarations where a type name can't be resolved in the current context. It's an internal IDE diagnostic that enables code fixes such as **Add using**, **Fully Qualify**, and **Generate Type**.
+
+> [!NOTE]
+> This rule is not configurable and is primarily an internal diagnostic used to drive IDE code-fix features. You might encounter it as part of IDE functionality, but it isn't intended as a user-facing quality or style rule.
+
+A common scenario is when you start typing a member declaration but the type referenced hasn't been imported. For example, if you type `public DateTime` without a variable name and without a `using System;` directive, this rule fires on `DateTime` to enable the **Add using** code fix.
+
+## Example
+
+```csharp
+// Code that triggers IDE1007.
+// 'DateTime' is unresolved because 'using System;' is missing.
+
+class MyClass
+{
+ public DateTime // incomplete member — 'DateTime' is unresolved
+}
+```
+
+Adding the missing `using` directive or fully qualifying the type resolves the issue:
+
+```csharp
+using System;
+
+class MyClass
+{
+ public DateTime MyDate { get; set; }
+}
+```
+
+## See also
+
+- [Code style language rules](language-rules.md)
+- [Code style rules reference](index.md)
diff --git a/docs/fundamentals/code-analysis/style-rules/index.md b/docs/fundamentals/code-analysis/style-rules/index.md
index 9f041c435ff83..c116dd39b86d6 100644
--- a/docs/fundamentals/code-analysis/style-rules/index.md
+++ b/docs/fundamentals/code-analysis/style-rules/index.md
@@ -72,6 +72,7 @@ The following table list all the code-style rules by ID and [options](../code-st
> | [IDE0040](ide0040.md) | Add accessibility modifiers | [dotnet_style_require_accessibility_modifiers](ide0040.md#dotnet_style_require_accessibility_modifiers) |
> | [IDE0041](ide0041.md) | Use is null check | [dotnet_style_prefer_is_null_check_over_reference_equality_method](ide0041.md#dotnet_style_prefer_is_null_check_over_reference_equality_method) |
> | [IDE0042](ide0042.md) | Deconstruct variable declaration | [csharp_style_deconstructed_variable_declaration](ide0042.md#csharp_style_deconstructed_variable_declaration) |
+> | [IDE0043](ide0043.md) | Invalid format string | |
> | [IDE0044](ide0044.md) | Add readonly modifier | [dotnet_style_readonly_field](ide0044.md#dotnet_style_readonly_field) |
> | [IDE0045](ide0045.md) | Use conditional expression for assignment | [dotnet_style_prefer_conditional_expression_over_assignment](ide0045.md#dotnet_style_prefer_conditional_expression_over_assignment) |
> | [IDE0046](ide0046.md) | Use conditional expression for return | [dotnet_style_prefer_conditional_expression_over_return](ide0046.md#dotnet_style_prefer_conditional_expression_over_return) |
@@ -150,8 +151,11 @@ The following table list all the code-style rules by ID and [options](../code-st
> | [IDE0360](ide0360.md) | Simplify property accessor | [csharp_style_prefer_simple_property_accessors](ide0360.md#csharp_style_prefer_simple_property_accessors) |
> | [IDE0370](ide0370.md) | Remove unnecessary suppression | |
> | [IDE0380](ide0380.md) | Remove unnecessary 'unsafe' modifier | |
+> | [IDE0390](ide0390-ide0391.md) | Make method synchronous | |
+> | [IDE0391](ide0390-ide0391.md) | Make method synchronous | |
> | [IDE1005](ide1005.md) | Use conditional delegate call | [csharp_style_conditional_delegate_call](ide1005.md#csharp_style_conditional_delegate_call) |
> | [IDE1006](naming-rules.md) | Naming styles | |
+> | [IDE1007](ide1007.md) | The name does not exist in the current context | |
> | [IDE2000](ide2000.md) | Avoid multiple blank lines | [dotnet_style_allow_multiple_blank_lines_experimental](ide2000.md#dotnet_style_allow_multiple_blank_lines_experimental)† |
> | [IDE2001](ide2001.md) | Embedded statements must be on their own line | [csharp_style_allow_embedded_statements_on_same_line_experimental](ide2001.md#csharp_style_allow_embedded_statements_on_same_line_experimental)† |
> | [IDE2002](ide2002.md) | Consecutive braces must not have blank line between them | [csharp_style_allow_blank_lines_between_consecutive_braces_experimental](ide2002.md#csharp_style_allow_blank_lines_between_consecutive_braces_experimental)† |
diff --git a/docs/fundamentals/code-analysis/style-rules/language-rules.md b/docs/fundamentals/code-analysis/style-rules/language-rules.md
index c6f2af1738f4a..356f6aeab8e9d 100644
--- a/docs/fundamentals/code-analysis/style-rules/language-rules.md
+++ b/docs/fundamentals/code-analysis/style-rules/language-rules.md
@@ -151,6 +151,7 @@ C# style rules:
- [Simplify 'default' expression (IDE0034)](ide0034.md)
- [Use local function instead of lambda (IDE0039)](ide0039.md)
- [Deconstruct variable declaration (IDE0042)](ide0042.md)
+- [Invalid format string (IDE0043)](ide0043.md)
- [Use index operator (IDE0056)](ide0056.md)
- [Use range operator (IDE0057)](ide0057.md)
- [Add missing cases to switch expression (IDE0072)](ide0072.md)
@@ -174,6 +175,7 @@ C# style rules:
- [Use unbound generic type (IDE0340)](ide0340.md)
- [Use implicitly typed lambda (IDE0350)](ide0350.md)
- [Simplify property accessor (IDE0360)](ide0360.md)
+- [The name does not exist in the current context (IDE1007)](ide1007.md)
Visual Basic style rules:
@@ -208,6 +210,7 @@ C# style rules:
- [Member can be made 'readonly' (IDE0251)](ide0251.md)
- [Make anonymous function static (IDE0320)](ide0320.md)
- [Remove unnecessary `unsafe` modifier (IDE0380)](ide0380.md)
+- [Make method synchronous (IDE0390, IDE0391)](ide0390-ide0391.md)
### New-line preferences
diff --git a/docs/navigate/devops-testing/toc.yml b/docs/navigate/devops-testing/toc.yml
index 082e426a1b0d4..f69f46f375a3f 100644
--- a/docs/navigate/devops-testing/toc.yml
+++ b/docs/navigate/devops-testing/toc.yml
@@ -114,6 +114,8 @@ items:
href: ../../core/testing/mstest-analyzers/mstest0044.md
- name: MSTEST0045
href: ../../core/testing/mstest-analyzers/mstest0045.md
+ - name: MSTEST0066
+ href: ../../core/testing/mstest-analyzers/mstest0066.md
- name: Performance rules
items:
- name: Overview
@@ -130,6 +132,8 @@ items:
href: ../../core/testing/mstest-analyzers/mstest0028.md
- name: MSTEST0033
href: ../../core/testing/mstest-analyzers/mstest0033.md
+ - name: MSTEST0047
+ href: ../../core/testing/mstest-analyzers/mstest0047.md
- name: Usage rules
items:
- name: Overview
@@ -224,6 +228,14 @@ items:
href: ../../core/testing/mstest-analyzers/mstest0062.md
- name: MSTEST0063
href: ../../core/testing/mstest-analyzers/mstest0063.md
+ - name: MSTEST0064
+ href: ../../core/testing/mstest-analyzers/mstest0064.md
+ - name: MSTEST0065
+ href: ../../core/testing/mstest-analyzers/mstest0065.md
+ - name: MSTEST0067
+ href: ../../core/testing/mstest-analyzers/mstest0067.md
+ - name: MSTEST0068
+ href: ../../core/testing/mstest-analyzers/mstest0068.md
- name: MSTEST0069
href: ../../core/testing/mstest-analyzers/mstest0069.md
- name: MSTEST0070
diff --git a/docs/navigate/tools-diagnostics/toc.yml b/docs/navigate/tools-diagnostics/toc.yml
index fe01b6dfeb346..b619595b661ae 100644
--- a/docs/navigate/tools-diagnostics/toc.yml
+++ b/docs/navigate/tools-diagnostics/toc.yml
@@ -3759,6 +3759,8 @@ items:
href: ../../fundamentals/code-analysis/style-rules/ide0041.md
- name: IDE0042
href: ../../fundamentals/code-analysis/style-rules/ide0042.md
+ - name: IDE0043
+ href: ../../fundamentals/code-analysis/style-rules/ide0043.md
- name: IDE0044
href: ../../fundamentals/code-analysis/style-rules/ide0044.md
- name: IDE0045
@@ -3909,8 +3911,14 @@ items:
href: ../../fundamentals/code-analysis/style-rules/ide0370.md
- name: IDE0380
href: ../../fundamentals/code-analysis/style-rules/ide0380.md
+ - name: IDE0390
+ href: ../../fundamentals/code-analysis/style-rules/ide0390-ide0391.md
+ - name: IDE0391
+ href: ../../fundamentals/code-analysis/style-rules/ide0390-ide0391.md
- name: IDE1005
href: ../../fundamentals/code-analysis/style-rules/ide1005.md
+ - name: IDE1007
+ href: ../../fundamentals/code-analysis/style-rules/ide1007.md
- name: IDE2000
href: ../../fundamentals/code-analysis/style-rules/ide2000.md
- name: IDE2001
diff --git a/docs/standard/base-types/best-practices-regex.md b/docs/standard/base-types/best-practices-regex.md
index a3e3ebb38fd62..3a89130f85cf4 100644
--- a/docs/standard/base-types/best-practices-regex.md
+++ b/docs/standard/base-types/best-practices-regex.md
@@ -16,15 +16,20 @@ ms.assetid: 618e5afb-3a97-440d-831a-70e4c526a51c
The regular expression engine in .NET is a powerful, full-featured tool that processes text based on pattern matches rather than on comparing and matching literal text. In most cases, it performs pattern matching rapidly and efficiently. However, in some cases, the regular expression engine can appear to be slow. In extreme cases, it can even appear to stop responding as it processes a relatively small input over the course of hours or even days.
-This article outlines some of the best practices that developers can adopt to ensure that their regular expressions achieve optimal performance.
+This article outlines some of the best practices that developers can adopt to ensure that their regular expressions achieve optimal performance and robustness.
-[!INCLUDE [regex](../../../includes/regex.md)]
+> [!WARNING]
+> Unrestricted use of regular expressions with untrusted input can subject applications to [denial-of-service attacks](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS). The .NET regular expression engine offers options to mitigate these attacks. For more information, see [Consider the input source](#consider-the-input-source), [Take charge of backtracking](#take-charge-of-backtracking), and [Use time-out values](#use-time-out-values).
+>
+> The .NET regular expression engine does not offer protection against untrusted *patterns*, and applications should not create regular expression patterns from untrusted user-provided values. For more information, see [Use trusted patterns](#use-trusted-patterns).
## Use trusted patterns
-The .NET regular expression engine is designed with the assumption that patterns are trusted, that is, they are authored or reviewed by the application developer, not supplied by end users or other untrusted sources. Patterns can cause excessive resource consumption regardless of the input text, and the regular expression engine does not attempt to guard against hostile patterns.
+The .NET regular expression engine distinguishes *patterns* (the regular expression itself, such as `^[0-9A-Za-z]+$`) from the *input text* (the string being evaluated against the regular expression, such as `123AbC456`). These values are typically passed to the `Regex` APIs through arguments named *pattern* and *input*, respectively.
+
+These APIs are designed with the assumption that patterns are trusted, that is, they are authored or reviewed by the application developer, not supplied by end users or other untrusted sources. Patterns can cause excessive resource consumption regardless of the input text, and the regular expression engine does not attempt to guard against hostile patterns.
-If your application needs to accept search expressions from users, avoid passing user input directly as a regex pattern. Instead, consider these alternatives:
+If your application needs to accept search expressions from users, avoid passing user-provided values directly as a regex pattern. Instead, consider these alternatives:
- Support a restricted search syntax (such as simple wildcards or substring matching) that you translate into a regex pattern internally.
- Use to treat any user-supplied text as a literal string within a pattern.
@@ -222,6 +227,9 @@ The regular expression time-out interval defines the period of time that the reg
If you've defined a time-out interval and a match isn't found at the end of that interval, the regular expression method throws a exception. In your exception handler, you can choose to retry the match with a longer time-out interval, abandon the match attempt and assume that there's no match, or abandon the match attempt and log the exception information for future analysis.
+> [!WARNING]
+> Time-out values are not intended as a security boundary against malicious *patterns*. For more information, see [Use trusted patterns](#use-trusted-patterns).
+
The following example defines a `GetWordData` method that instantiates a regular expression with a time-out interval of 350 milliseconds to calculate the number of words and average number of characters in a word in a text document. If the matching operation times out, the time-out interval is increased by 350 milliseconds and the object is reinstantiated. If the new time-out interval exceeds one second, the method rethrows the exception to the caller.
[!code-csharp[Conceptual.RegularExpressions.BestPractices#12](./snippets/regex/csharp/timeout1.cs#12)]
diff --git a/docs/standard/base-types/regular-expression-options.md b/docs/standard/base-types/regular-expression-options.md
index 5d16d1e83da21..f7dfe3a455b9a 100644
--- a/docs/standard/base-types/regular-expression-options.md
+++ b/docs/standard/base-types/regular-expression-options.md
@@ -398,7 +398,10 @@ The following example is identical to the previous example, except that the stat
## NonBacktracking mode
-By default, .NET's regex engine uses *backtracking* to try to find pattern matches. A backtracking engine is one that tries to match one pattern, and if that fails, goes backs and tries to match an alternate pattern, and so on. A backtracking engine is very fast for typical cases, but slows down as the number of pattern alternations increases, which can lead to *catastrophic backtracking*. The option, which was introduced in .NET 7, doesn't use backtracking and avoids that worst-case scenario. Its goal is to provide consistently good behavior, regardless of the input being searched.
+By default, .NET's regex engine uses *backtracking* to try to find pattern matches. A backtracking engine is one that tries to match one pattern, and if that fails, goes back and tries to match an alternate pattern, and so on. A backtracking engine is very fast for typical cases, but slows down as the number of pattern alternations increases, which can lead to *catastrophic backtracking*. The option, which was introduced in .NET 7, doesn't use backtracking and avoids that worst-case scenario. Its goal is to provide consistently good behavior, regardless of the input being searched.
+
+> [!WARNING]
+> The .NET regex engine assumes the *pattern* is trusted. NonBacktracking mode doesn't change this assumption: it guards against expensive *input*, not against actively malicious *patterns*. For more information, see [Use trusted patterns](best-practices-regex.md#use-trusted-patterns).
The option doesn't support everything the other built-in engines support. In particular, the option can't be used in conjunction with , , or . It also doesn't allow for the following constructs in the pattern:
diff --git a/docs/standard/native-interop/apply-interop-attributes.md b/docs/standard/native-interop/apply-interop-attributes.md
index 6c8b3f663e324..6ec63fa324b2e 100644
--- a/docs/standard/native-interop/apply-interop-attributes.md
+++ b/docs/standard/native-interop/apply-interop-attributes.md
@@ -48,7 +48,7 @@ The namespace provides three categories of
||Indicates that the data in a field or parameter must be marshalled from a called object back to its caller.|
||Suppresses the HRESULT or retval signature transformation that normally takes place during interoperation calls. The attribute affects marshalling as well as type library exporting.
COM interop tools can apply this attribute.|
||Specifies the ProgID of a .NET class. Can be used to attribute classes.|
-||Controls the physical layout of the fields of a class.
COM interop tools can apply this attribute.|
+||Controls the physical layout of the fields of a class. For managed fixed-size buffers, see [Fixed-size buffers and inline arrays](customize-struct-marshalling.md#fixed-size-buffers-and-inline-arrays) and .
COM interop tools can apply this attribute.|
## Conversion-Tool Attributes
diff --git a/docs/standard/native-interop/customize-struct-marshalling.md b/docs/standard/native-interop/customize-struct-marshalling.md
index 4438549c39536..cbffa8b64af8b 100644
--- a/docs/standard/native-interop/customize-struct-marshalling.md
+++ b/docs/standard/native-interop/customize-struct-marshalling.md
@@ -26,6 +26,60 @@ Sometimes the default marshalling rules for structures aren't exactly what you n
❌ AVOID using `LayoutKind.Explicit` when marshalling structures on non-Windows platforms if you need to target runtimes before .NET Core 3.0. The .NET Core runtime before 3.0 doesn't support passing explicit structures by value to native functions on Intel or AMD 64-bit non-Windows systems. However, the runtime supports passing explicit structures by reference on all platforms.
+## Fixed-size buffers and inline arrays
+
+If you need to define a fixed-size buffer in a structure, don't use the property to allocate extra space. The `Size` property controls the unmanaged layout of the type (the layout used when calling `Marshal.StructureToPtr`) and only affects the managed layout for blittable types. For non-blittable types, the runtime only allocates space based on the actual fields, which can lead to memory corruption if you attempt to use the extra space.
+
+❌ AVOID using `StructLayoutAttribute.Size` to create fixed-size buffers in managed types.
+
+✔️ DO use to define fixed-size buffers in modern .NET (C# 12 and later).
+
+The following example shows the incorrect approach that can lead to memory corruption:
+
+```csharp
+// ❌ DON'T: This is dangerous and can corrupt memory
+[StructLayout(LayoutKind.Explicit, Size = 100)]
+class Bad100ByteBuffer
+{
+ [FieldOffset(0)]
+ private byte b;
+
+ unsafe void UseBuffer()
+ {
+ fixed (byte* p = &b)
+ {
+ // Writing beyond the first byte corrupts memory
+ }
+ }
+}
+```
+
+Instead, use `InlineArrayAttribute` to create a properly sized buffer:
+
+```csharp
+// ✔️ DO: Use InlineArrayAttribute for fixed-size buffers
+class Good100ByteBuffer
+{
+ [InlineArray(100)]
+ private struct Buffer100
+ {
+ private byte _element0;
+ }
+
+ private Buffer100 buffer;
+
+ unsafe void UseBuffer()
+ {
+ fixed (byte* p = &buffer[0])
+ {
+ // The buffer is guaranteed to be 100 bytes
+ }
+ }
+}
+```
+
+For more information about inline arrays, see the [C# language reference](../../csharp/language-reference/builtin-types/struct.md#inline-arrays).
+
## Customizing Boolean field marshalling
Native code has many different Boolean representations. On Windows alone, there are three ways to represent Boolean values. The runtime doesn't know the native definition of your structure, so the best it can do is make a guess on how to marshal your Boolean values. The .NET runtime provides a way to indicate how to marshal your Boolean field. The following examples show how to marshal .NET `bool` to different native Boolean types.
diff --git a/docs/zone-pivot-groups.yml b/docs/zone-pivot-groups.yml
index 1020b5f41f480..1225143c188f2 100644
--- a/docs/zone-pivot-groups.yml
+++ b/docs/zone-pivot-groups.yml
@@ -56,8 +56,8 @@ groups:
title: Visual Studio Code
- id: copilot-cli
title: GitHub Copilot CLI
- - id: github-com
- title: GitHub.com
+ - id: github-copilot-app
+ title: GitHub Copilot app
- id: copilot-modernization-migrate
title: Development environment
prompt: Choose your development environment
diff --git a/includes/regex.md b/includes/regex.md
index dac95ae302513..fcee819c5e887 100644
--- a/includes/regex.md
+++ b/includes/regex.md
@@ -1,3 +1,3 @@
> [!WARNING]
-> When using to process untrusted input, pass a timeout. A malicious user can provide input to `RegularExpressions`, causing a [Denial-of-Service attack](https://www.cisa.gov/news-events/news/understanding-denial-service-attacks). ASP.NET Core framework APIs that use `RegularExpressions` pass a timeout.
+> Unrestricted use of with untrusted input can subject applications to [denial-of-service attacks](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS). Consult [Best practices for regular expressions in .NET](../docs/standard/base-types/best-practices-regex.md) for guidance on how to safely use .NET regular expressions with untrusted input.