migrate-dotnet9-to-dotnet10
Migrate a .NET 9 project or solution to .NET 10 and resolve all breaking changes. USE FOR: upgrading TargetFramework from net9.0 to net10.0, fixing build errors after updating the .NET 10 SDK, resolving source and behavioral changes in .NET 10 / C# 14 / ASP.NET Core 10 / EF Core
Install
npx skills add https://github.com/dotnet/skills/tree/main/plugins/dotnet-upgrade/skills/migrate-dotnet9-to-dotnet10
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install dotnet-skills@llmmart
git clone https://github.com/dotnet/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole dotnet/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
.NET 9 → .NET 10 Migration
Migrate a .NET 9 project or solution to .NET 10, systematically resolving all breaking changes. The outcome is a project targeting net10.0 that builds cleanly, passes tests, and accounts for every behavioral, source-incompatible, and binary-incompatible change introduced in the .NET 10 release.
When to Use
- Upgrading
TargetFrameworkfromnet9.0tonet10.0 - Resolving build errors or new warnings after updating the .NET 10 SDK
- Adapting to behavioral changes in .NET 10 runtime, ASP.NET Core 10, or EF Core 10
- Updating CI/CD pipelines, Dockerfiles, or deployment scripts for .NET 10
- Migrating from the community
System.Linq.Asyncpackage to the built-inSystem.Linq.AsyncEnumerable
When Not to Use
- The project already targets
net10.0and builds cleanly — migration is done - Upgrading from .NET 8 or earlier — use the
migrate-dotnet8-to-dotnet9skill first to reachnet9.0, then return to this skill for thenet9.0→net10.0migration - Migrating from .NET Framework — that is a separate, larger effort
- Greenfield projects that start on .NET 10 (no migration needed)
Inputs
| Input | Required | Description |
|---|---|---|
| Project or solution path | Yes | The .csproj, .sln, or .slnx entry point to migrate |
| Build command | No | How to build (e.g., dotnet build, a repo build script). Auto-detect if not provided |
| Test command | No | How to run tests (e.g., dotnet test). Auto-detect if not provided |
| Project type hints | No | Whether the project uses ASP.NET Core, EF Core, WinForms, WPF, containers, etc. Auto-detect from PackageReferences and SDK attributes if not provided |
Workflow
Answer directly from the loaded reference documents. Do not search the filesystem or fetch web pages for breaking change information — the references contain the authoritative details. Focus on identifying which breaking changes apply and providing concrete fixes. Exception: If you suspect a security vulnerability (CVE) may apply to the project's dependencies, check for published security advisories — the reference documents may not cover post-publication CVEs.
Commit strategy: Commit at each logical boundary — after updating the TFM (Step 2), after resolving build errors (Step 3), after addressing behavioral changes (Step 4), and after updating infrastructure (Step 5). This keeps each commit focused and reviewable.
Step 1: Assess the project
- Identify how the project is built and tested. Look for build scripts,
.sln/.slnxfiles, or individual.csprojfiles. - Run
dotnet --versionto confirm the .NET 10 SDK is installed. If it is not, stop and inform the user. - Determine which technology areas the project uses by examining:
- SDK attribute:
Microsoft.NET.Sdk.Web→ ASP.NET Core;Microsoft.NET.Sdk.WindowsDesktopwith<UseWPF>or<UseWindowsForms>→ WPF/WinForms - PackageReferences:
Microsoft.EntityFrameworkCore.*→ EF Core;Microsoft.Data.Sqlite→ Sqlite;Microsoft.Extensions.Hosting→ Generic Host / BackgroundService - Dockerfile presence → Container changes relevant
- P/Invoke or native interop usage → Interop changes relevant
System.Linq.Asyncpackage reference → AsyncEnumerable migration neededSystem.Text.Jsonusage with polymorphism → Serialization changes relevant
- SDK attribute:
- Record which reference documents are relevant (see the reference loading table in Step 3).
- Do a clean build (
dotnet build --no-incrementalor deletebin/obj) on the currentnet9.0target to establish a clean baseline. Record any pre-existing warnings.
Step 2: Update the Target Framework
In each
.csproj(orDirectory.Build.propsif centralized), change:<TargetFramework>net9.0</TargetFramework>to:
<TargetFramework>net10.0</TargetFramework>For multi-targeted projects, add
net10.0to<TargetFrameworks>or replacenet9.0.Update all
Microsoft.Extensions.*,Microsoft.AspNetCore.*,Microsoft.EntityFrameworkCore.*, and other Microsoft package references to their 10.0.x versions. If using Central Package Management (Directory.Packages.props), update versions there.Run
dotnet restore. Watch for:- NU1510: Direct references pruned by NuGet — the package may be included in the shared framework now. Remove the explicit
<PackageReference>if so. - PackageReference without a version now raises an error — every
<PackageReference>must have aVersion(or use CPM). - NuGet auditing of transitive packages (
dotnet restorenow audits transitive deps) — review any new vulnerability warnings.
- NU1510: Direct references pruned by NuGet — the package may be included in the shared framework now. Remove the explicit
Run a clean build. Collect all errors and new warnings. These will be addressed in Step 3.
Step 3: Resolve build errors and source-incompatible changes
Work through compilation errors and new warnings systematically. Load the appropriate reference documents based on the project type:
| If the project uses… | Load reference |
|---|---|
| Any .NET 10 project | references/csharp-compiler-dotnet9to10.md |
| Any .NET 10 project | references/core-libraries-dotnet9to10.md |
| Any .NET 10 project | references/sdk-msbuild-dotnet9to10.md |
| ASP.NET Core | references/aspnet-core-dotnet9to10.md |
| Entity Framework Core | references/efcore-dotnet9to10.md |
| Cryptography APIs | references/cryptography-dotnet9to10.md |
| Microsoft.Extensions.Hosting, BackgroundService, configuration | references/extensions-hosting-dotnet9to10.md |
| System.Text.Json, XmlSerializer, HttpClient, MailAddress, Uri | references/serialization-networking-dotnet9to10.md |
| Windows Forms or WPF | references/winforms-wpf-dotnet9to10.md |
| Docker containers, single-file apps, native interop | references/containers-interop-dotnet9to10.md |
Common source-incompatible changes to check for:
System.Linq.Asyncconflicts — Remove theSystem.Linq.Asyncpackage reference or upgrade to v7.0.0. If consumed transitively, add<ExcludeAssets>compile</ExcludeAssets>. RenameSelectAwaitcalls toSelectwhere needed.New obsoletion warnings (SYSLIB0058–SYSLIB0062):
SYSLIB0058: ReplaceSslStream.KeyExchangeAlgorithm/CipherAlgorithm/HashAlgorithmwithNegotiatedCipherSuite— if the old properties were used to reject weak TLS ciphers, preserve equivalent validation logic using the new APISYSLIB0059: ReplaceSystemEvents.EventsThreadShutdownwithAppDomain.ProcessExitSYSLIB0060: ReplaceRfc2898DeriveBytesconstructors withRfc2898DeriveBytes.Pbkdf2SYSLIB0061: ReplaceQueryable.MaxBy/MinByoverloads takingIComparer<TSource>with ones takingIComparer<TKey>SYSLIB0062: ReplaceXsltSettings.EnableScriptusage
C# 14
fieldkeyword in property accessors — The identifierfieldis now a contextual keyword inside propertyget/set/initaccessors. Local variables namedfieldcause CS9272 (error). Class members namedfieldreferenced withoutthis.cause CS9258 (warning). Fix by renaming (e.g.,fieldValue) or escaping with@field. Seereferences/csharp-compiler-dotnet9to10.md.C# 14
extensioncontextual keyword — Types, aliases, or type parameters namedextensionare disallowed. Rename or escape with@extension.C# 14 overload resolution with span parameters — Expression trees containing
.Contains()on arrays may now bind toMemoryExtensions.Containsinstead ofEnumerable.Contains.Enumerable.Reverseon arrays may resolve to the in-placeSpanextension. Fix by casting toIEnumerable<T>, using.AsEnumerable(), or explicit static invocations. Seereferences/csharp-compiler-dotnet9to10.mdfor full details.ASP.NET Core obsoletions (if applicable):
WebHostBuilder,IWebHost,WebHostare obsolete — migrate toHost.CreateDefaultBuilderorWebApplication.CreateBuilderIActionContextAccessor/ActionContextAccessorobsoleteWithOpenApiextension method deprecatedIncludeOpenAPIAnalyzersproperty deprecatedIPNetworkandForwardedHeadersOptions.KnownNetworksobsolete- Razor runtime compilation is obsolete
Microsoft.Extensions.ApiDescription.Clientpackage deprecatedMicrosoft.OpenApiv2.x breaking changes —Microsoft.AspNetCore.OpenApi 10.0pulls inMicrosoft.OpenApiv2.x which restructures namespaces and models.OpenApiString/OpenApiAnytypes are removed (useJsonNode),OpenApiSecurityScheme.Referencereplaced byOpenApiSecuritySchemeReference, collections on OpenAPI model objects may be null, andOpenApiSchema.Nullableis removed. Seereferences/aspnet-core-dotnet9to10.mdfor migration patterns.
SDK changes:
dotnet new slnnow defaults to SLNX format — use--format slnif the old format is needed- Double quotes in file-level directives are disallowed
dnx.ps1removed from .NET SDKproject.jsonno longer supported indotnet restore
EF Core source changes (if applicable) — See
references/efcore-dotnet9to10.mdfor:ExecuteUpdateAsyncnow accepts a regular lambda (expression tree construction code must be rewritten)IDiscriminatorPropertySetConventionsignature changedIRelationalCommandDiagnosticsLoggermethods addlogCommandTextparameter
WinForms/WPF source changes (if applicable):
- Applications referencing both WPF and WinForms must disambiguate
MenuItemandContextMenutypes - Renamed parameter in
HtmlElement.InsertAdjacentElement - Empty
ColumnDefinitionsandRowDefinitionsare disallowed in WPF
- Applications referencing both WPF and WinForms must disambiguate
Cryptography source changes (if applicable):
MLDsaandSlhDsamembers renamed fromSecretKeytoPrivateKey(e.g.,ExportMLDsaSecretKey→ExportMLDsaPrivateKey,SecretKeySizeInBytes→PrivateKeySizeInBytes)Rfc2898DeriveBytesconstructors are obsolete (SYSLIB0060) — replace with staticRfc2898DeriveBytes.Pbkdf2(password, salt, iterations, hashAlgorithm, outputLength)CoseSigner.Keycan now be null — check for null before useX509Certificate.GetKeyAlgorithmParameters()andPublicKey.EncodedParameterscan return null- Environment variable renamed from
CLR_OPENSSL_VERSION_OVERRIDEtoDOTNET_OPENSSL_VERSION_OVERRIDE
Build again after each batch of fixes. Repeat until the build is clean.
Step 4: Address behavioral changes
Behavioral changes do not cause build errors but may change runtime behavior. Review each applicable item and determine whether the previous behavior was relied upon.
High-impact behavioral changes (check first):
SIGTERM signal handling removed — The .NET runtime no longer registers default SIGTERM handlers. If you rely on
AppDomain.ProcessExitorAssemblyLoadContext.Unloadingbeing raised on SIGTERM:- ASP.NET Core and Generic Host apps are unaffected (they register their own handlers)
- Console apps and containerized apps without Generic Host must register
PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => Environment.Exit(0))explicitly
BackgroundService.ExecuteAsync runs entirely on a background thread — The synchronous portion before the first
awaitno longer blocks startup. If startup ordering matters, move that code toStartAsyncor the constructor, or implementIHostedLifecycleService.Configuration null values are now preserved — JSON
nullvalues are no longer converted to empty strings. Properties initialized with non-default values will be overwritten withnull. Review configuration binding code.Microsoft.Data.Sqlite DateTimeOffset changes (all High impact):
GetDateTimeOffsetwithout an offset now assumes UTC (previously assumed local)- Writing
DateTimeOffsetinto REAL columns now converts to UTC first GetDateTimewith an offset now returns UTC withDateTimeKind.Utc- Mitigation:
AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true)as a temporary workaround
EF Core parameterized collections —
.Contains()on collections now uses multiple scalar parameters instead of JSON/OPENJSON. May affect query performance for large collections. Mitigation:UseParameterizedCollectionMode(ParameterTranslationMode.Parameter)to revert.EF Core JSON data type on Azure SQL — Azure SQL and compatibility level ≥170 now use the
jsondata type instead ofnvarchar(max). A migration will be generated to alter existing columns. Mitigation: set compatibility level to 160 or useHasColumnType("nvarchar(max)")explicitly.System.Text.Json property name conflict validation — Polymorphic types with properties conflicting with metadata names (
$type,$id,$ref) now throwInvalidOperationException. Add[JsonIgnore]to conflicting properties.
Other behavioral changes to review:
BufferedStream.WriteByteno longer implicitly flushes — add explicitFlush()calls if needed- Default trace context propagator updated to W3C standard
DriveInfo.DriveFormatreturns actual Linux filesystem type names- LDAP
DirectoryControlparsing is more stringent - Default .NET container images switched from Debian to Ubuntu (Debian images no longer shipped)
- Single-file apps no longer look for native libraries in executable directory by default
DllImportSearchPath.AssemblyDirectoryonly searches the assembly directoryMailAddressenforces validation for consecutive dots- Streaming HTTP responses enabled by default in browser HTTP clients
Urilength limits removed — add explicit length validation ifUriwas used to reject oversized input from untrusted sources- Cookie login redirects disabled for known API endpoints (ASP.NET Core)
XmlSerializerno longer ignores[Obsolete]properties — audit obsolete properties for sensitive data and add[XmlIgnore]to prevent unintended data exposuredotnet restoreaudits transitive packagesdotnet watchlogs to stderr instead of stdoutdotnetCLI commands log non-command-relevant data to stderr- Various NuGet behavioral changes (see
references/sdk-msbuild-dotnet9to10.md) StatusStripuses System RenderMode by default (WinForms)TreeViewcheckbox image truncation fix (WinForms)DynamicResourceincorrect usage causes crash (WPF)
Step 5: Update infrastructure
Dockerfiles: Update base images. Default tags now use Ubuntu instead of Debian. Debian images are no longer shipped for .NET 10.
# Before FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:9.0 # After FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:10.0CI/CD pipelines: Update SDK version references. If using
global.json, update:{ "sdk": { "version": "10.0.100" } }Environment variables renamed:
DOTNET_OPENSSL_VERSION_OVERRIDEreplaces the old nameDOTNET_ICU_VERSION_OVERRIDEreplaces the old nameNUGET_ENABLE_ENHANCED_HTTP_RETRYhas been removed
OpenSSL requirements: OpenSSL 1.1.1 or later is now required on Unix. OpenSSL cryptographic primitives are no longer supported on macOS.
Solution file format: If
dotnet new slnis used in scripts, note it now generates SLNX format. Pass--format slnif the old format is needed.
Step 6: Verify
- Run a full clean build:
dotnet build --no-incremental - Run all tests:
dotnet test - If the application is containerized, build and test the container image
- Smoke-test the application, paying special attention to:
- Signal handling / graceful shutdown behavior
- Background services startup ordering
- Configuration binding with null values
- Date/time handling with Sqlite
- JSON serialization with polymorphic types
- EF Core queries using
.Contains()on collections
- Security review — verify that the migration has not weakened security controls:
- TLS cipher validation logic is preserved after
SslStreamAPI migration (SYSLIB0058) - Obsolete properties containing sensitive data are excluded from serialization (
[XmlIgnore],[JsonIgnore]) - Input validation still rejects oversized URIs if
Uriwas used as a length gate - Exception handlers emit security-relevant telemetry (auth failures, access violations) before returning
true - Connection strings set an explicit
Application Namethat does not leak version info dotnet restorevulnerability audit findings are addressed, not suppressed
- TLS cipher validation logic is preserved after
- Review the diff and ensure no unintended behavioral changes were introduced
Reference Documents
The references/ folder contains detailed breaking change information organized by technology area. Load only the references relevant to the project being migrated:
| Reference file | When to load |
|---|---|
references/csharp-compiler-dotnet9to10.md |
Always (C# 14 compiler breaking changes — field keyword, extension keyword, span overloads) |
references/core-libraries-dotnet9to10.md |
Always (applies to all .NET 10 projects) |
references/sdk-msbuild-dotnet9to10.md |
Always (SDK and build tooling changes) |
references/aspnet-core-dotnet9to10.md |
Project uses ASP.NET Core |
references/efcore-dotnet9to10.md |
Project uses Entity Framework Core or Microsoft.Data.Sqlite |
references/cryptography-dotnet9to10.md |
Project uses System.Security.Cryptography or X.509 certificates |
references/extensions-hosting-dotnet9to10.md |
Project uses Generic Host, BackgroundService, or Microsoft.Extensions.Configuration |
references/serialization-networking-dotnet9to10.md |
Project uses System.Text.Json, XmlSerializer, HttpClient, or networking APIs |
references/winforms-wpf-dotnet9to10.md |
Project uses Windows Forms or WPF |
references/containers-interop-dotnet9to10.md |
Project uses Docker containers, single-file publishing, or native interop (P/Invoke) |
Files (skills)
-
references
-
aspnet-core-dotnet9to10.md 6.7 KB
# ASP.NET Core 10 Breaking Changes These changes affect projects using ASP.NET Core (Microsoft.NET.Sdk.Web). ## Source-Incompatible Changes ### WebHostBuilder, IWebHost, and WebHost are obsolete The legacy `WebHostBuilder` and related APIs are now marked obsolete. Migrate to the modern hosting model: ```csharp // Before (.NET 9) var host = new WebHostBuilder() .UseKestrel() .UseStartup<Startup>() .Build(); // After (.NET 10) var builder = WebApplication.CreateBuilder(args); // Configure services in builder.Services var app = builder.Build(); // Configure middleware pipeline app.Run(); ``` If still using `Startup` classes, the `WebApplication` model supports them via `builder.Host.ConfigureWebHostDefaults(...)` or inline configuration. ### IActionContextAccessor and ActionContextAccessor are obsolete These types are obsolete. Access `ActionContext` through dependency injection or the `HttpContext` instead: ```csharp // Before services.AddSingleton<IActionContextAccessor, ActionContextAccessor>(); // After — use IHttpContextAccessor or inject ActionContext directly in filters/middleware ``` ### Deprecation of WithOpenApi extension method The `WithOpenApi()` extension method is deprecated. Use the built-in OpenAPI document generation in ASP.NET Core 10 instead. ### IncludeOpenAPIAnalyzers property and MVC API analyzers deprecated The `<IncludeOpenAPIAnalyzers>` MSBuild property is deprecated. Remove it from `.csproj` files. The analyzers are no longer needed with the new OpenAPI infrastructure. ### IPNetwork and ForwardedHeadersOptions.KnownNetworks are obsolete `IPNetwork` is obsolete. Use `System.Net.IPNetwork` (the new runtime type) and the new `KnownIpNetworks` property instead: ```csharp // Before app.UseForwardedHeaders(new ForwardedHeadersOptions { KnownNetworks = { new IPNetwork(IPAddress.Parse("10.0.0.0"), 8) } }); // After — use KnownIpNetworks with the new System.Net.IPNetwork type app.UseForwardedHeaders(new ForwardedHeadersOptions { KnownIpNetworks = { new System.Net.IPNetwork(IPAddress.Parse("10.0.0.0"), 8) } }); ``` ### Razor runtime compilation is obsolete `AddRazorRuntimeCompilation()` is obsolete. Razor views and pages should be precompiled. For development, use hot reload (`dotnet watch`) instead. ### Microsoft.Extensions.ApiDescription.Client package deprecated The `Microsoft.Extensions.ApiDescription.Client` package is deprecated. Use the built-in OpenAPI client generation tooling instead. ### Microsoft.OpenApi 2.x breaking API changes `Microsoft.AspNetCore.OpenApi 10.0` depends on `Microsoft.OpenApi` v2.x (from [`microsoft/OpenAPI.NET`](https://github.com/microsoft/OpenAPI.NET) repo), which has significant breaking API changes from v1.x. Projects that customize OpenAPI document generation using transformers or directly manipulate OpenAPI models will need code changes. Note: no official v1→v2 migration guide exists; the repo has a [v3 upgrade guide](https://github.com/microsoft/OpenAPI.NET/blob/main/docs/upgrade-guide-3.md) only. These changes are also not listed on the ASP.NET Core 10 breaking changes page. **Namespace changes — `Microsoft.OpenApi.Models` and `Microsoft.OpenApi.Any` are completely removed:** All types previously in these namespaces (`OpenApiSchema`, `OpenApiParameter`, `OpenApiResponse`, `OpenApiSecurityScheme`, etc.) have moved to the root `Microsoft.OpenApi` namespace. Replace all `using Microsoft.OpenApi.Models;` and `using Microsoft.OpenApi.Any;` with `using Microsoft.OpenApi;`. ```csharp // Before (.NET 9 — Microsoft.OpenApi v1.x) using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; // After (.NET 10 — Microsoft.OpenApi v2.x) using Microsoft.OpenApi; // ALL model types are here now using System.Text.Json.Nodes; // replaces OpenApiAny types ``` **Key API changes:** 1. **`OpenApiString` / `OpenApiAny` types removed** — Use `System.Text.Json.Nodes.JsonNode` instead: ```csharp // Before parameter.Schema.Example = new OpenApiString("1.0"); // After parameter.Schema.Example = JsonNode.Parse("\"1.0\""); ``` 2. **`OpenApiSecurityScheme.Reference` replaced** — Use `OpenApiSecuritySchemeReference` directly: ```csharp // Before var scheme = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; // After var scheme = new OpenApiSecuritySchemeReference("oauth2", null); ``` 3. **Collections now nullable** — `operation.Parameters`, `operation.Responses`, `document.Components.SecuritySchemes`, and other collection properties may be null and must be checked or initialized: ```csharp operation.Responses ??= new OpenApiResponses(); operation.Parameters?.FirstOrDefault(p => p.Name == "api-version"); document.Components ??= new(); document.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>(); ``` 4. **`OpenApiSchema.Nullable` removed** — OpenAPI 3.1 uses JSON Schema `type: ["string", "null"]` instead of `nullable: true`. Schema transformers that set `.Nullable = false` can be removed. 5. **Security requirement values require `List<string>`** — Implicit conversion from `string[]` may not work: ```csharp // Before [oAuthScheme] = scopes // After [oAuthScheme] = scopes.ToList() ``` 6. **Interface types in some positions** — Some properties now use interfaces (e.g., `IOpenApiSecurityScheme` instead of `OpenApiSecurityScheme`). Check for compilation errors in transformer code. ## Behavioral Changes ### Cookie login redirects disabled for known API endpoints ASP.NET Core no longer redirects to login pages for requests to known API endpoints (e.g., those returning `ProblemDetails`). Instead, a `401` status code is returned directly. This is controlled by `IApiEndpointMetadata`, which is automatically applied to endpoints with `[ApiController]`, minimal API endpoints that read/write JSON, SignalR hubs, and endpoints returning `TypedResults`. This is generally the desired behavior for APIs, but may affect apps that relied on the redirect for API calls. To influence this behavior, you can manually add or check for `IApiEndpointMetadata` on specific endpoints. ### Exception diagnostics suppressed when TryHandleAsync returns true **Security consideration:** When `IExceptionHandler.TryHandleAsync` returns `true`, the exception diagnostics middleware no longer emits diagnostic events for that exception. If handled exceptions include security-relevant events (authentication failures, authorization violations, injection attempts), suppressing diagnostics could create blind spots in security monitoring and audit logging. Ensure your exception handler explicitly emits security-relevant telemetry before returning `true`. -
containers-interop-dotnet9to10.md 3 KB
# Containers, Interop, and Deployment Breaking Changes (.NET 10) These changes affect Docker containers, single-file apps, native interop (P/Invoke), and deployment scenarios. ## Containers ### Default .NET images use Ubuntu (Debian images discontinued) **Impact: Medium.** Default .NET container image tags now reference Ubuntu 24.04 (Noble Numbat) instead of Debian. Debian-based images are no longer provided for .NET 10. ```dockerfile # .NET 10 images — all Ubuntu-based FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:10.0 FROM mcr.microsoft.com/dotnet/runtime:10.0 # Explicit Ubuntu tag (same as default) FROM mcr.microsoft.com/dotnet/sdk:10.0-noble ``` **What to check:** - Dockerfile `RUN apt-get` commands — Ubuntu and Debian share `apt` but may differ in available packages and versions - Native library dependencies that were Debian-specific - Custom base image layers that assumed Debian - CI/CD scripts that referenced Debian-specific image tags **If you need Debian:** Create custom images following [Microsoft's guide for installing .NET in a Dockerfile](https://github.com/dotnet/dotnet-docker/blob/main/documentation/scenarios/installing-dotnet.md). ## Interop ### Single-file apps no longer look for native libraries in executable directory In single-file apps, the application directory is no longer automatically added to `NATIVE_DLL_SEARCH_DIRECTORIES`. The directory is only searched when `DllImportSearchPath.AssemblyDirectory` is included in the search paths (which is the default for P/Invokes without explicit search paths). **Breaking scenario:** P/Invokes with `[DefaultDllImportSearchPaths]` that explicitly exclude `AssemblyDirectory`: ```csharp // This no longer finds "lib" in the app directory: [DllImport("lib")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] static extern void Method(); // Fix: Add AssemblyDirectory to the search paths: [DllImport("lib")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] static extern void Method(); ``` For NativeAOT on non-Windows, the `rpath` is no longer set to the application directory. Add explicit linker arguments if needed. ### DllImportSearchPath.AssemblyDirectory only searches the assembly directory `DllImportSearchPath.AssemblyDirectory` now strictly searches only the assembly directory, not additional directories that were previously included. ### Casting IDispatchEx COM object to IReflect fails Casting a COM object that implements `IDispatchEx` to `IReflect` now fails. Use `dynamic` or explicit COM interop interfaces instead. ## Other Changes - **Globalization**: Environment variable renamed to `DOTNET_ICU_VERSION_OVERRIDE` - **Reflection**: `[DynamicallyAccessedMembers]` annotations on `IReflect.InvokeMember`, `Type.FindMembers` are more restrictive (new trim warnings possible) - **Reflection**: `Type.MakeGenericSignatureType` arguments validated more strictly - **VS Code**: `dotnet.acquire` API no longer always downloads latest — pin specific versions -
core-libraries-dotnet9to10.md 4.8 KB
# Core .NET Libraries Breaking Changes (.NET 10) These breaking changes affect all .NET 10 projects regardless of application type. ## Source-Incompatible Changes ### System.Linq.AsyncEnumerable included in core libraries .NET 10 adds `System.Linq.AsyncEnumerable` with full LINQ support for `IAsyncEnumerable<T>`, replacing the community `System.Linq.Async` NuGet package. Projects referencing `System.Linq.Async` will get ambiguity errors. **Fix:** - Remove the `System.Linq.Async` package reference, or upgrade to v7.0.0 - If consumed transitively, suppress with `<ExcludeAssets>`: ```xml <PackageReference Include="System.Linq.Async" Version="6.0.1"> <ExcludeAssets>compile</ExcludeAssets> </PackageReference> ``` - Rename `SelectAwait` calls to `Select` where the new API uses a different name ### API obsoletions (SYSLIB0058–SYSLIB0062) | Diagnostic | What's obsolete | Replacement | |------------|----------------|-------------| | SYSLIB0058 | `SslStream.KeyExchangeAlgorithm`, `CipherAlgorithm`, `HashAlgorithm` and their strength properties | `SslStream.NegotiatedCipherSuite` — **Security note:** if existing code used these properties to reject weak ciphers (e.g., RC4, 3DES, NULL), ensure equivalent validation is preserved using `NegotiatedCipherSuite` | | SYSLIB0059 | `SystemEvents.EventsThreadShutdown` | `AppDomain.ProcessExit` | | SYSLIB0060 | `Rfc2898DeriveBytes` constructors | `Rfc2898DeriveBytes.Pbkdf2` static method | | SYSLIB0061 | `Queryable.MaxBy`/`MinBy` overloads with `IComparer<TSource>` | New overloads with `IComparer<TKey>` | | SYSLIB0062 | `XsltSettings.EnableScript` | N/A (XSLT scripting deprecated) | These use custom diagnostic IDs — suppressing `CS0618` does not suppress them. ### FilePatternMatch.Stem changed to non-nullable `FilePatternMatch.Stem` is now `string` instead of `string?`. Code checking for null may get warnings. ### Other source-incompatible changes (low impact) - `[DynamicallyAccessedMembers]` annotation removed from `DefaultValueAttribute` constructor (affects trimming annotations) - ARM64 SVE nonfaulting load intrinsics now require a mask parameter ## Behavioral Changes ### .NET runtime no longer provides default termination signal handlers **Impact: High for console/containerized apps without Generic Host.** On Unix, the runtime no longer registers SIGTERM/SIGHUP handlers. On Windows, `CTRL_SHUTDOWN_EVENT` and `CTRL_CLOSE_EVENT` are no longer handled. `AppDomain.ProcessExit` and `AssemblyLoadContext.Unloading` will NOT be raised on termination signals. - **ASP.NET Core and Generic Host apps are unaffected** (they register their own handlers) - **Console apps** must register handlers explicitly: ```csharp using var sigterm = PosixSignalRegistration.Create( PosixSignal.SIGTERM, _ => Environment.Exit(0)); using var sighup = PosixSignalRegistration.Create( PosixSignal.SIGHUP, _ => Environment.Exit(0)); ``` ### C# 14 overload resolution with span parameters Methods with `ReadOnlySpan<T>` or `Span<T>` parameters now participate in type inference and extension method resolution. This can cause `MemoryExtensions.Contains` to bind instead of `Enumerable.Contains` inside Expression lambdas, causing runtime exceptions. **Fix:** Cast to `IEnumerable<T>`, use `.AsEnumerable()`, or call the static method explicitly: ```csharp // Fails — binds to MemoryExtensions.Contains M((array, num) => array.Contains(num)); // Fix options: M((array, num) => ((IEnumerable<int>)array).Contains(num)); M((array, num) => array.AsEnumerable().Contains(num)); M((array, num) => Enumerable.Contains(array, num)); ``` ### BufferedStream.WriteByte no longer performs implicit flush `BufferedStream.WriteByte` no longer flushes when the buffer is full. Add explicit `Flush()` calls if your code relied on the implicit behavior. ### Consistent shift behavior in generic math Shift operations in generic math now behave consistently. If custom types relied on the previous inconsistent behavior, update them. ### Default trace context propagator updated to W3C standard The default `DistributedContextPropagator` now uses W3C Trace Context format. If your system relies on legacy propagation formats, configure the propagator explicitly. ### Other behavioral changes (lower impact) - `DriveInfo.DriveFormat` returns actual Linux filesystem type names (e.g., `ext4`) instead of generic values - `GnuTarEntry`/`PaxTarEntry` no longer include atime/ctime by default — set explicitly if needed - LDAP `DirectoryControl` parsing is more stringent — invalid data now throws - MacCatalyst versions normalized differently (affects .NET MAUI) - `ActivitySource.CreateActivity`/`StartActivity` sampling behavior changed - `[InlineArray]` structs can no longer have explicit `[StructLayout(Size = ...)]` — assembly fails to load - `Type.MakeGenericSignatureType` arguments validated more strictly -
cryptography-dotnet9to10.md 2.8 KB
# Cryptography Breaking Changes (.NET 10) These changes affect projects using `System.Security.Cryptography`, X.509 certificates, or OpenSSL. ## Source-Incompatible Changes ### MLDsa and SlhDsa 'SecretKey' members renamed to 'PrivateKey' All members containing `SecretKey` on `MLDsa` and `SlhDsa` types have been renamed to use `PrivateKey`. This affects methods and properties: ```csharp // Before int size = key.Algorithm.SecretKeySizeInBytes; byte[] output = new byte[size]; key.ExportMLDsaSecretKey(output); key.ImportMLDsaSecretKey(data); // After int size = key.Algorithm.PrivateKeySizeInBytes; byte[] output = new byte[size]; key.ExportMLDsaPrivateKey(output); key.ImportMLDsaPrivateKey(data); // Same pattern for SlhDsa: ExportSlhDsaSecretKey → ExportSlhDsaPrivateKey, etc. ``` ### Rfc2898DeriveBytes constructors are obsolete (SYSLIB0060) All `Rfc2898DeriveBytes` constructors are now obsolete. Use the static `Rfc2898DeriveBytes.Pbkdf2` method instead: ```csharp // Before using var deriveBytes = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256); byte[] key = deriveBytes.GetBytes(32); // After byte[] key = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA256, 32); ``` ### CoseSigner.Key can be null `CoseSigner.Key` is now nullable (`AsymmetricAlgorithm?`). Code that assumes it's non-null needs null checks: ```csharp // Before var algorithm = signer.Key.SignatureAlgorithm; // After var algorithm = signer.Key?.SignatureAlgorithm ?? throw new InvalidOperationException("Key is null"); ``` ### X509Certificate and PublicKey key parameters can be null `X509Certificate.GetKeyAlgorithmParameters()` and `PublicKey.EncodedParameters` can now return null. Add null checks where these values are consumed. ## Behavioral Changes ### OpenSSL 1.1.1 or later required on Unix .NET 10 requires OpenSSL 1.1.1+ on Unix systems. Older OpenSSL versions are no longer supported. Check with: ```bash openssl version ``` ### OpenSSL cryptographic primitives aren't supported on macOS Using OpenSSL-specific cryptographic primitives on macOS is no longer supported. Use the platform's native cryptography (Apple Security framework) instead. ### X500DistinguishedName validation is stricter `X500DistinguishedName` now validates input more strictly. Malformed distinguished names that were previously accepted may now throw exceptions. ### CompositeMLDsa updated to draft-08 The Composite ML-DSA implementation has been updated to align with draft-08. Key and signature formats from earlier drafts are incompatible. ### Environment variable renamed from CLR_OPENSSL_VERSION_OVERRIDE to DOTNET_OPENSSL_VERSION_OVERRIDE If you use `CLR_OPENSSL_VERSION_OVERRIDE` to specify the preferred OpenSSL library version on Linux, rename it to `DOTNET_OPENSSL_VERSION_OVERRIDE`. -
csharp-compiler-dotnet9to10.md 4.9 KB
# C# 14 Compiler Breaking Changes (.NET 10) These breaking changes are introduced by the Roslyn compiler shipping with the .NET 10 SDK. They affect all projects targeting `net10.0` (which uses C# 14 by default). These are maintained separately from the runtime breaking changes at: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%2010 ## Source-Incompatible Changes ### `field` keyword in property accessors **Impact: High.** `field` is now a contextual keyword inside property `get`, `set`, and `init` accessors (for the semi-auto properties feature). Two diagnostics apply: - **CS9258** (warning, VS 17.12+): `field` binds to the synthesized backing field instead of an existing member (e.g., a class field named `field`). Use `this.field` or `@field` to refer to the member. - **CS9272** (error, VS 17.14+): A local variable or nested-function parameter named `field` is **disallowed** inside a property accessor. Rename the variable or use `@field`. ```csharp // BREAKS — CS9272 error public object Property { get { int field = 0; // error: 'field' is a keyword in a property accessor return @field; } } // Also BREAKS — CS9272 error public string Name { get { payload.TryGetProperty("field", out var field); // error: local named 'field' return field.GetString(); } } ``` **Fix options:** 1. Rename the variable: `var fieldValue = ...`, `var fieldElem = ...` 2. Escape the identifier: `var @field = ...` (compiles but less readable) 3. For class members named `field`, qualify with `this.field` or `@field` ### `extension` contextual keyword **Impact: Medium.** Starting in C# 14, `extension` is a contextual keyword for extension containers. Code that uses `extension` as a type name, constructor, or return type will break. ```csharp // BREAKS in C# 14 class extension { } // type cannot be named "extension" using extension = SomeNamespace.Foo; // alias cannot be named "extension" class C<extension> { } // type parameter cannot be named "extension" ``` **Fix:** Rename the type, or escape as `@extension`. ### `Span<T>` and `ReadOnlySpan<T>` overloads applicable in more scenarios **Impact: Medium.** C# 14 introduces new built-in span conversions and type inference rules. Different overloads may be chosen, and new ambiguity errors can arise. Common patterns affected: ```csharp // Ambiguity — Assert.Equal<T>(T[], T[]) vs Assert.Equal<T>(ReadOnlySpan<T>, Span<T>) var x = new long[] { 1 }; Assert.Equal([2], x); // ambiguous Assert.Equal([2], x.AsSpan()); // fix // Enumerable.Reverse now resolves to MemoryExtensions.Reverse (in-place, returns void) int[] arr = [1, 2, 3]; var reversed = arr.Reverse(); // BREAKS: resolves to Span extension, not Enumerable var reversed = Enumerable.Reverse(arr); // fix // ReadOnlySpan preferred over Span — MemoryMarshal.Cast may fail Span<ulong> y = MemoryMarshal.Cast<double, ulong>(x); // BREAKS Span<ulong> y = MemoryMarshal.Cast<double, ulong>(x.AsSpan()); // fix // ArrayTypeMismatchException with covariant arrays string[] s = ["a"]; object[] o = s; C.R(o); // BREAKS at runtime: Span<T> ctor throws ArrayTypeMismatchException C.R(o.AsEnumerable()); // fix ``` **Fix options:** - Add `.AsSpan()`, `.AsEnumerable()`, or explicit casts to disambiguate - Call static methods explicitly (e.g., `Enumerable.Reverse(arr)`) - API authors: use `[OverloadResolutionPriority]` attribute > **Note:** The span overload resolution change is also listed in the runtime breaking changes (`core-libraries.md`). This entry provides the full Roslyn-side detail. ### Other low-impact source changes - **`scoped` in lambda parameters**: Always treated as a modifier. If you have a ref struct type named `scoped`, escape as `@scoped`. - **`partial` as return type**: Cannot use a type named `partial` as a return type. Escape as `@partial`. ## Behavioral Changes ### Enumerator state set to "after" during disposal `MoveNext()` on a disposed enumerator now properly returns `false` without executing further user code. Previously, the state machine allowed resuming execution after disposal. ```csharp var enumerator = GetItems().GetEnumerator(); enumerator.MoveNext(); // True, yields 1 enumerator.Dispose(); enumerator.MoveNext(); // now returns False (previously could continue) ``` ### Diagnostics reported for pattern-based disposal in `foreach` Obsolete `DisposeAsync` methods on enumerator types are now reported in `await foreach`. Previously these diagnostics were silently ignored. ### Redundant pattern warning in `or` patterns The compiler now warns when the second pattern in a disjunctive `or` is redundant due to precedence: ```csharp _ = o is not null or 42; // warning: pattern "42" is redundant _ = o is not int or string; // warning: pattern "string" is redundant // Likely intended: is not (null or 42) / is not (int or string) ``` -
efcore-dotnet9to10.md 6.5 KB
# Entity Framework Core 10 Breaking Changes These changes affect projects using EF Core or Microsoft.Data.Sqlite. ## Medium-Impact Changes ### EF tools require framework to be specified for multi-targeted projects When running EF tools on a project with `<TargetFrameworks>` (plural), you must now specify `--framework`: ```bash dotnet ef migrations add MyMigration --framework net10.0 dotnet ef database update --framework net10.0 ``` Without this, you'll get: "The project targets multiple frameworks. Use the --framework option to specify which target framework to use." ## Low-Impact Changes ### Application Name injected into connection string EF now inserts an `Application Name` containing EF and SqlClient version info into connection strings that don't already have one. This changes the effective connection string, which can cause: - Separate connection pools when mixing EF and non-EF data access (e.g., Dapper) - Potential distributed transaction escalation within `TransactionScope` - **Information disclosure**: version strings are visible in `sys.dm_exec_sessions`, database server logs, and monitoring tools, potentially aiding attackers in fingerprinting your stack **Mitigation:** Explicitly set `Application Name` in your connection string to a value that does not reveal version information. ### SQL Server json data type used by default on Azure SQL and compatibility level 170 For Azure SQL (`UseAzureSql`) or compatibility level ≥170, EF now maps JSON columns to the `json` data type instead of `nvarchar(max)`. A migration will be generated to alter existing columns. **Considerations:** - SQL Server does not support `DISTINCT` over JSON arrays — queries using it will fail - The column alteration is a non-trivial schema change **Mitigation:** ```csharp // Option 1: Set compatibility level below 170 optionsBuilder.UseAzureSql(connStr, o => o.UseCompatibilityLevel(160)); // Option 2: Explicitly set column type per property modelBuilder.Entity<Blog>() .PrimitiveCollection(b => b.Tags) .HasColumnType("nvarchar(max)"); ``` ### Parameterized collections now use multiple parameters by default `.Contains()` on collections now translates to `WHERE x IN (@p1, @p2, @p3)` instead of using `OPENJSON`. This gives the query planner cardinality information but may regress performance for large collections. **Mitigation:** ```csharp // Global: revert to JSON parameter mode optionsBuilder.UseSqlServer(connStr, o => o.UseParameterizedCollectionMode(ParameterTranslationMode.Parameter)); // Per-query: use EF.Parameter() for JSON array translation var blogs = await context.Blogs .Where(b => EF.Parameter(ids).Contains(b.Id)) .ToListAsync(); ``` ### ExecuteUpdateAsync now accepts a regular lambda `ExecuteUpdateAsync` now takes `Action<...>` instead of `Expression<Func<...>>` for column setters. Code that manually builds expression trees for dynamic setters will no longer compile but can be dramatically simplified: ```csharp // Before (.NET 9) — complex expression tree construction for dynamic setters Expression<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>> setters = s => s.SetProperty(b => b.Views, 8); if (nameChanged) { var blogParameter = Expression.Parameter(typeof(Blog), "b"); setters = Expression.Lambda<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>>( Expression.Call( instance: setters.Body, methodName: nameof(SetPropertyCalls<Blog>.SetProperty), typeArguments: [typeof(string)], arguments: [ Expression.Lambda<Func<Blog, string>>( Expression.Property(blogParameter, nameof(Blog.Name)), blogParameter), Expression.Constant("foo") ]), setters.Parameters); } await context.Blogs.ExecuteUpdateAsync(setters); // After (.NET 10) — simple lambda with conditionals await context.Blogs.ExecuteUpdateAsync(s => { s.SetProperty(b => b.Views, 8); if (nameChanged) { s.SetProperty(b => b.Name, "foo"); } }); ``` ### Complex type column names are now uniquified If multiple complex types have properties with the same name, column names are now uniquified by appending a number. This may generate a migration that renames columns. **Mitigation:** Explicitly configure column names with `HasColumnName()`. ### Nested complex type properties use full path in column names `EntityType.Complex.NestedComplex.Property` is now mapped to `Complex_NestedComplex_Property` (was `NestedComplex_Property`). This generates a migration renaming columns. **Mitigation:** Use `HasColumnName()` to preserve old names. ### IDiscriminatorPropertySetConvention signature changed The method parameter changed from `IConventionEntityTypeBuilder` to `IConventionTypeBaseBuilder`. Update custom convention implementations. ### IRelationalCommandDiagnosticsLogger methods add logCommandText parameter Methods like `CommandReaderExecuting`, `CommandReaderExecuted`, `CommandScalarExecuting`, etc. now have an additional `string logCommandText` parameter containing redacted SQL for logging. Update custom implementations: ```csharp public InterceptionResult<DbDataReader> CommandReaderExecuting( IRelationalConnection connection, DbCommand command, DbContext context, Guid commandId, Guid connectionId, DateTimeOffset startTime, string logCommandText) // New parameter — redacted SQL for logging { // Use logCommandText for logging (may have constants redacted) // Use command.CommandText for actual SQL execution } ``` ## Microsoft.Data.Sqlite Breaking Changes (All High Impact) ### GetDateTimeOffset without an offset now assumes UTC Previously, a textual timestamp without an offset (e.g., `2014-04-15 10:47:16`) was parsed using the local timezone. Now it's treated as UTC. ### Writing DateTimeOffset into REAL column now writes in UTC `DateTimeOffset` values written to REAL columns are now converted to UTC before writing. Previously the offset was ignored. ### GetDateTime with an offset now returns value in UTC `GetDateTime` on timestamps with offsets (e.g., `2014-04-15 10:47:16+02:00`) now returns the value converted to UTC with `DateTimeKind.Utc`. Previously it returned `DateTimeKind.Local`. **Mitigation for all three:** ```csharp // Temporary workaround to revert to .NET 9 behavior AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true); ``` Review all date/time handling code that reads from or writes to SQLite databases. The new behavior aligns with SQLite's convention that timestamps are UTC. -
extensions-hosting-dotnet9to10.md 3.2 KB
# Extensions and Hosting Breaking Changes (.NET 10) These changes affect projects using `Microsoft.Extensions.Hosting`, `BackgroundService`, `Microsoft.Extensions.Configuration`, and related libraries. ## Behavioral Changes ### BackgroundService.ExecuteAsync runs entirely on a background thread **Impact: Medium.** Previously, the synchronous code in `ExecuteAsync` before the first `await` ran on the main thread during startup, blocking other hosted services from starting. Now ALL of `ExecuteAsync` runs on a background thread. **If startup ordering matters:** ```csharp // Option 1: Move synchronous startup code to StartAsync public override async Task StartAsync(CancellationToken cancellationToken) { // This still runs synchronously during startup InitializeResources(); await base.StartAsync(cancellationToken); } // Option 2: Use IHostedLifecycleService for fine-grained lifecycle control public class MyService : BackgroundService, IHostedLifecycleService { public Task StartingAsync(CancellationToken ct) { // runs before StartAsync return Task.CompletedTask; } public Task StartedAsync(CancellationToken ct) { // runs after StartAsync return Task.CompletedTask; } // ... other lifecycle methods } // Option 3: Move code to the constructor public MyService(ILogger<MyService> logger) { // Constructor code runs during DI resolution } ``` ### Null values preserved in configuration **Impact: Medium.** JSON `null` values are now properly bound instead of being converted to empty strings or ignored. **Empty arrays (`[]`) are also now correctly bound as empty arrays instead of being ignored.** | Scenario | .NET 9 behavior | .NET 10 behavior | |----------|----------------|-----------------| | `"StringProperty": null` | Bound as `""` (empty string) | Bound as `null` (overwrites constructor default) | | `"IntProperty": null` | Ignored (kept constructor default) | Bound as `null` (if `int?`) | | `"Array": [null, null]` | Bound as `["", ""]` | Bound as `[null, null]` | | **`"Array": []`** | **Ignored (`null`)** | **Bound as empty array `[]`** | **If you need the old behavior:** - Replace `null` with `""` in JSON config files - Or remove `null` entries to skip binding ### Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey `GetKeyedService()` and `GetKeyedServices()` with `AnyKey` now work correctly. If your code relied on the previous buggy behavior, update it. ### Message no longer duplicated in Console log output When using the JSON console logger, messages are no longer duplicated. If your log parsing relied on the duplicated format, update it. ### ProviderAliasAttribute moved to Microsoft.Extensions.Logging.Abstractions assembly `ProviderAliasAttribute` has moved assemblies. If you reference it directly by assembly-qualified name, update the reference. Source-incompatible for code using assembly-qualified type references. ### Removed DynamicallyAccessedMembers annotation from trim-unsafe configuration code The `[DynamicallyAccessedMembers]` annotation was removed from certain configuration APIs that are not trim-safe. Binary incompatible for code that relied on the annotation for trimming analysis. -
sdk-msbuild-dotnet9to10.md 2.4 KB
# SDK and MSBuild Breaking Changes (.NET 10) These changes affect the .NET SDK, CLI tooling, NuGet, and MSBuild behavior. ## Source-Incompatible Changes ### NU1510 raised for direct references pruned by NuGet If NuGet prunes a direct `PackageReference` because the package is already part of the shared framework, a `NU1510` warning is raised. Remove the explicit reference if it's provided by the framework. ### PackageReference without a version raises an error Every `<PackageReference>` must now have a `Version` attribute or use Central Package Management. Missing versions raise an error instead of resolving to the latest. ### Other source-incompatible changes - `dnx.ps1` file removed from .NET SDK — remove any references - File-level directives (`#r`, `#load`) no longer accept double-quoted paths — remove the quotes (e.g., `#r MyLib.dll` instead of `#r "MyLib.dll"`) - `project.json` no longer recognized by `dotnet restore` — use `PackageReference` format - NuGet packages with no runtime assets excluded from `deps.json` - `ToolCommandName` not set for non-tool packages - HTTP sources in `dotnet package list`/`dotnet package search` now error (use HTTPS) ## Behavioral Changes ### `dotnet new sln` defaults to SLNX file format `dotnet new sln` now generates an XML-based `.slnx` file instead of the classic `.sln` format: ```xml <Solution> </Solution> ``` **Mitigation:** Use `dotnet new sln --format sln` for the classic format. Ensure your tooling (Visual Studio, Rider, etc.) supports SLNX. ### Other behavioral changes - `--interactive` defaults to `true` in user scenarios — use `--interactive false` in scripts - CLI diagnostic output now goes to stderr - Tool packages now include RID-specific content - Default workload management mode is 'workload sets' (not 'loose manifests') - `EnableDynamicNativeInstrumentation` defaults to false for code coverage - `dotnet package list` performs restore before listing - `dotnet tool install --local` creates manifest by default - `dotnet watch` logs to stderr instead of stdout - `PrunePackageReference` privatizes direct prunable references (`PrivateAssets="All"`) - SHA-1 fingerprints deprecated in `dotnet nuget sign` — use SHA-256 - `MSBUILDCUSTOMBUILDEVENTWARNING` escape hatch removed - MSBuild custom culture resource handling changed - `NUGET_ENABLE_ENHANCED_HTTP_RETRY` env var removed (enhanced retry always on) - NuGet logs errors for invalid package IDs -
serialization-networking-dotnet9to10.md 2.9 KB
# Serialization and Networking Breaking Changes (.NET 10) These changes affect projects using System.Text.Json, XmlSerializer, HttpClient, and networking APIs. ## Serialization ### System.Text.Json checks for property name conflicts **Impact: Medium.** Polymorphic types with properties that conflict with metadata names (`$type`, `$id`, `$ref`, or custom `TypeDiscriminatorPropertyName`) now throw `InvalidOperationException` during serialization instead of producing invalid JSON. ```csharp // This now throws InvalidOperationException at serialization time: [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] [JsonDerivedType(typeof(Dog), "dog")] public abstract class Animal { public abstract string Type { get; } // Conflicts with "Type" discriminator } ``` **Fix:** rename the conflicting property, or suppress it with `[JsonIgnore]`: ```csharp [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] [JsonDerivedType(typeof(Dog), "dog")] public abstract class Animal { [JsonIgnore] public abstract string Type { get; } } ``` ### XmlSerializer no longer ignores properties marked with ObsoleteAttribute **Security consideration:** Properties marked `[Obsolete]` are now included in XML serialization. Previously they were silently skipped. If obsolete properties contain sensitive data (e.g., deprecated password fields, legacy PII, or internal-only values), they will now appear in serialized output. Audit obsolete properties for sensitive data and mark them with `[XmlIgnore]` if they should not be serialized. ## Networking ### HTTP/3 support disabled by default with PublishTrimmed **When `<PublishTrimmed>true</PublishTrimmed>` or `<PublishAot>true</PublishAot>` is set, HTTP/3 support is completely disabled by default.** The HTTP/3 code is stripped by the trimmer. This is NOT a native library search issue — the HTTP/3 implementation code itself is removed. **Fix:** Add `<Http3Support>true</Http3Support>` to your `.csproj` to preserve HTTP/3 support when trimming: ```xml <PropertyGroup> <PublishTrimmed>true</PublishTrimmed> <Http3Support>true</Http3Support> </PropertyGroup> ``` ### MailAddress enforces validation for consecutive dots `MailAddress` now rejects email addresses with consecutive dots (e.g., `user..name@example.com`). Previously these were accepted. ### Streaming HTTP responses enabled by default in browser HTTP clients In Blazor WebAssembly and other browser-based HTTP clients, streaming responses are now enabled by default. This may change how response content is buffered and consumed. ### Uri length limits removed **Security consideration:** The `Uri` class no longer enforces length limits. Previously, very long URIs could throw exceptions. If your application relied on `Uri` to reject excessively long input (as an input validation or sanitization gate), this removal may expose denial-of-service or resource exhaustion attack surface. Add explicit length validation before constructing `Uri` instances from untrusted input. -
winforms-wpf-dotnet9to10.md 3.4 KB
# Windows Forms and WPF Breaking Changes (.NET 10) These changes affect projects using Windows Forms (`<UseWindowsForms>true</UseWindowsForms>`) or WPF (`<UseWPF>true</UseWPF>`). ## Windows Forms ### Source-Incompatible Changes #### API obsoletions Several Windows Forms APIs have been marked obsolete with custom diagnostic IDs. Follow the guidance in the warning message for each. #### Applications referencing both WPF and WinForms must disambiguate MenuItem and ContextMenu types If a project references both WPF and WinForms, the `MenuItem` and `ContextMenu` types are ambiguous. Use fully qualified names: ```csharp // Before (ambiguous in .NET 10) var item = new MenuItem("File"); // After var item = new System.Windows.Forms.MenuItem("File"); // or var item = new System.Windows.Controls.MenuItem(); ``` #### Renamed parameter in HtmlElement.InsertAdjacentElement The parameter name in `HtmlElement.InsertAdjacentElement` has changed from `orientation`. Calls that use named arguments with `orientation` will no longer compile; update them to use positional arguments: ```csharp // Before — named arguments with old parameter name element.InsertAdjacentElement(orientation: HtmlElementInsertionOrientation.BeforeBegin, newElement: newElement); // After — use positional arguments element.InsertAdjacentElement(HtmlElementInsertionOrientation.BeforeBegin, newElement); ``` ### Behavioral Changes #### TreeView checkbox image truncation The checkbox rendering in `TreeView` controls has been adjusted, which changes text positioning. Visual appearance may differ slightly. #### StatusStrip uses System RenderMode by default `StatusStrip` now uses the system render mode by default instead of a custom renderer. The visual appearance may change. Set `RenderMode` explicitly to restore the previous look. #### System.Drawing OutOfMemoryException changed to ExternalException **Important:** Some `System.Drawing` operations that previously threw `OutOfMemoryException` now throw `ExternalException` (from `System.Runtime.InteropServices` — NOT `ArgumentException`). This reflects the actual GDI+ error code. Update catch blocks: ```csharp // Before — only catching OutOfMemoryException try { /* drawing operation */ } catch (OutOfMemoryException) { /* handle */ } // After — catch ExternalException (the new exception type in .NET 10) try { /* drawing operation */ } catch (ExternalException) { /* handle */ } catch (OutOfMemoryException) { /* handle — for older runtimes */ } ``` ## WPF ### Source-Incompatible / Behavioral Changes #### Empty ColumnDefinitions and RowDefinitions are disallowed Empty `<Grid.ColumnDefinitions/>` and `<Grid.RowDefinitions/>` elements in XAML now cause errors. Remove them if they don't contain any definitions: ```xml <!-- Before (now causes error) --> <Grid> <Grid.ColumnDefinitions/> <Grid.RowDefinitions/> </Grid> <!-- After --> <Grid> <!-- Only include definitions if you have columns/rows to define --> </Grid> ``` #### Incorrect usage of DynamicResource causes application crash Incorrect `DynamicResource` usage that was silently ignored now causes crashes at runtime. Common issues: - Using `DynamicResource` where `StaticResource` is required (e.g., in non-dependency-property contexts) - Referencing resources that don't exist Audit all `DynamicResource` usage in XAML and ensure each reference points to a valid resource and is used in a context that supports dynamic resources.
-
-
SKILL.md 18.9 KB
--- name: migrate-dotnet9-to-dotnet10 description: > Migrate a .NET 9 project or solution to .NET 10 and resolve all breaking changes. USE FOR: upgrading TargetFramework from net9.0 to net10.0, fixing build errors after updating the .NET 10 SDK, resolving source and behavioral changes in .NET 10 / C# 14 / ASP.NET Core 10 / EF Core 10, updating Dockerfiles for Debian-to-Ubuntu base images, resolving obsoletion warnings (SYSLIB0058-SYSLIB0062), adapting to SDK/NuGet changes (NU1510, PrunePackageReference), migrating System.Linq.Async to built-in AsyncEnumerable, fixing OpenApi v2 API changes, cryptography renames, and C# 14 compiler changes (field keyword, extension keyword, span overloads). DO NOT USE FOR: .NET Framework migrations, upgrading from .NET 8 or earlier (use migrate-dotnet8-to-dotnet9 first), greenfield .NET 10 projects, or cosmetic modernization. LOADS REFERENCES: csharp-compiler, core-libraries, sdk-msbuild (always); aspnet-core, efcore, cryptography, extensions-hosting, serialization-networking, winforms-wpf, containers-interop (selective). license: MIT --- # .NET 9 → .NET 10 Migration Migrate a .NET 9 project or solution to .NET 10, systematically resolving all breaking changes. The outcome is a project targeting `net10.0` that builds cleanly, passes tests, and accounts for every behavioral, source-incompatible, and binary-incompatible change introduced in the .NET 10 release. ## When to Use - Upgrading `TargetFramework` from `net9.0` to `net10.0` - Resolving build errors or new warnings after updating the .NET 10 SDK - Adapting to behavioral changes in .NET 10 runtime, ASP.NET Core 10, or EF Core 10 - Updating CI/CD pipelines, Dockerfiles, or deployment scripts for .NET 10 - Migrating from the community `System.Linq.Async` package to the built-in `System.Linq.AsyncEnumerable` ## When Not to Use - The project already targets `net10.0` and builds cleanly — migration is done - Upgrading from .NET 8 or earlier — use the `migrate-dotnet8-to-dotnet9` skill first to reach `net9.0`, then return to this skill for the `net9.0` → `net10.0` migration - Migrating from .NET Framework — that is a separate, larger effort - Greenfield projects that start on .NET 10 (no migration needed) ## Inputs | Input | Required | Description | |-------|----------|-------------| | Project or solution path | Yes | The `.csproj`, `.sln`, or `.slnx` entry point to migrate | | Build command | No | How to build (e.g., `dotnet build`, a repo build script). Auto-detect if not provided | | Test command | No | How to run tests (e.g., `dotnet test`). Auto-detect if not provided | | Project type hints | No | Whether the project uses ASP.NET Core, EF Core, WinForms, WPF, containers, etc. Auto-detect from PackageReferences and SDK attributes if not provided | ## Workflow > **Answer directly from the loaded reference documents.** Do not search the filesystem or fetch web pages for breaking change information — the references contain the authoritative details. Focus on identifying which breaking changes apply and providing concrete fixes. **Exception:** If you suspect a security vulnerability (CVE) may apply to the project's dependencies, check for published security advisories — the reference documents may not cover post-publication CVEs. > > **Commit strategy:** Commit at each logical boundary — after updating the TFM (Step 2), after resolving build errors (Step 3), after addressing behavioral changes (Step 4), and after updating infrastructure (Step 5). This keeps each commit focused and reviewable. ### Step 1: Assess the project 1. Identify how the project is built and tested. Look for build scripts, `.sln`/`.slnx` files, or individual `.csproj` files. 2. Run `dotnet --version` to confirm the .NET 10 SDK is installed. If it is not, stop and inform the user. 3. Determine which technology areas the project uses by examining: - **SDK attribute**: `Microsoft.NET.Sdk.Web` → ASP.NET Core; `Microsoft.NET.Sdk.WindowsDesktop` with `<UseWPF>` or `<UseWindowsForms>` → WPF/WinForms - **PackageReferences**: `Microsoft.EntityFrameworkCore.*` → EF Core; `Microsoft.Data.Sqlite` → Sqlite; `Microsoft.Extensions.Hosting` → Generic Host / BackgroundService - **Dockerfile presence** → Container changes relevant - **P/Invoke or native interop usage** → Interop changes relevant - **`System.Linq.Async` package reference** → AsyncEnumerable migration needed - **`System.Text.Json` usage with polymorphism** → Serialization changes relevant 4. Record which reference documents are relevant (see the reference loading table in Step 3). 5. Do a **clean build** (`dotnet build --no-incremental` or delete `bin`/`obj`) on the current `net9.0` target to establish a clean baseline. Record any pre-existing warnings. ### Step 2: Update the Target Framework 1. In each `.csproj` (or `Directory.Build.props` if centralized), change: ```xml <TargetFramework>net9.0</TargetFramework> ``` to: ```xml <TargetFramework>net10.0</TargetFramework> ``` For multi-targeted projects, add `net10.0` to `<TargetFrameworks>` or replace `net9.0`. 2. Update all `Microsoft.Extensions.*`, `Microsoft.AspNetCore.*`, `Microsoft.EntityFrameworkCore.*`, and other Microsoft package references to their 10.0.x versions. If using Central Package Management (`Directory.Packages.props`), update versions there. 3. Run `dotnet restore`. Watch for: - **NU1510**: Direct references pruned by NuGet — the package may be included in the shared framework now. Remove the explicit `<PackageReference>` if so. - **PackageReference without a version now raises an error** — every `<PackageReference>` must have a `Version` (or use CPM). - **NuGet auditing of transitive packages** (`dotnet restore` now audits transitive deps) — review any new vulnerability warnings. 4. Run a clean build. Collect all errors and new warnings. These will be addressed in Step 3. ### Step 3: Resolve build errors and source-incompatible changes Work through compilation errors and new warnings systematically. Load the appropriate reference documents based on the project type: | If the project uses… | Load reference | |-----------------------|----------------| | Any .NET 10 project | `references/csharp-compiler-dotnet9to10.md` | | Any .NET 10 project | `references/core-libraries-dotnet9to10.md` | | Any .NET 10 project | `references/sdk-msbuild-dotnet9to10.md` | | ASP.NET Core | `references/aspnet-core-dotnet9to10.md` | | Entity Framework Core | `references/efcore-dotnet9to10.md` | | Cryptography APIs | `references/cryptography-dotnet9to10.md` | | Microsoft.Extensions.Hosting, BackgroundService, configuration | `references/extensions-hosting-dotnet9to10.md` | | System.Text.Json, XmlSerializer, HttpClient, MailAddress, Uri | `references/serialization-networking-dotnet9to10.md` | | Windows Forms or WPF | `references/winforms-wpf-dotnet9to10.md` | | Docker containers, single-file apps, native interop | `references/containers-interop-dotnet9to10.md` | **Common source-incompatible changes to check for:** 1. **`System.Linq.Async` conflicts** — Remove the `System.Linq.Async` package reference or upgrade to v7.0.0. If consumed transitively, add `<ExcludeAssets>compile</ExcludeAssets>`. Rename `SelectAwait` calls to `Select` where needed. 2. **New obsoletion warnings (SYSLIB0058–SYSLIB0062)**: - `SYSLIB0058`: Replace `SslStream.KeyExchangeAlgorithm`/`CipherAlgorithm`/`HashAlgorithm` with `NegotiatedCipherSuite` — if the old properties were used to reject weak TLS ciphers, preserve equivalent validation logic using the new API - `SYSLIB0059`: Replace `SystemEvents.EventsThreadShutdown` with `AppDomain.ProcessExit` - `SYSLIB0060`: Replace `Rfc2898DeriveBytes` constructors with `Rfc2898DeriveBytes.Pbkdf2` - `SYSLIB0061`: Replace `Queryable.MaxBy`/`MinBy` overloads taking `IComparer<TSource>` with ones taking `IComparer<TKey>` - `SYSLIB0062`: Replace `XsltSettings.EnableScript` usage 3. **C# 14 `field` keyword in property accessors** — The identifier `field` is now a contextual keyword inside property `get`/`set`/`init` accessors. Local variables named `field` cause CS9272 (error). Class members named `field` referenced without `this.` cause CS9258 (warning). Fix by renaming (e.g., `fieldValue`) or escaping with `@field`. See `references/csharp-compiler-dotnet9to10.md`. 4. **C# 14 `extension` contextual keyword** — Types, aliases, or type parameters named `extension` are disallowed. Rename or escape with `@extension`. 5. **C# 14 overload resolution with span parameters** — Expression trees containing `.Contains()` on arrays may now bind to `MemoryExtensions.Contains` instead of `Enumerable.Contains`. `Enumerable.Reverse` on arrays may resolve to the in-place `Span` extension. Fix by casting to `IEnumerable<T>`, using `.AsEnumerable()`, or explicit static invocations. See `references/csharp-compiler-dotnet9to10.md` for full details. 6. **ASP.NET Core obsoletions** (if applicable): - `WebHostBuilder`, `IWebHost`, `WebHost` are obsolete — migrate to `Host.CreateDefaultBuilder` or `WebApplication.CreateBuilder` - `IActionContextAccessor` / `ActionContextAccessor` obsolete - `WithOpenApi` extension method deprecated - `IncludeOpenAPIAnalyzers` property deprecated - `IPNetwork` and `ForwardedHeadersOptions.KnownNetworks` obsolete - Razor runtime compilation is obsolete - `Microsoft.Extensions.ApiDescription.Client` package deprecated - **`Microsoft.OpenApi` v2.x breaking changes** — `Microsoft.AspNetCore.OpenApi 10.0` pulls in `Microsoft.OpenApi` v2.x which restructures namespaces and models. `OpenApiString`/`OpenApiAny` types are removed (use `JsonNode`), `OpenApiSecurityScheme.Reference` replaced by `OpenApiSecuritySchemeReference`, collections on OpenAPI model objects may be null, and `OpenApiSchema.Nullable` is removed. See `references/aspnet-core-dotnet9to10.md` for migration patterns. 7. **SDK changes**: - `dotnet new sln` now defaults to SLNX format — use `--format sln` if the old format is needed - Double quotes in file-level directives are disallowed - `dnx.ps1` removed from .NET SDK - `project.json` no longer supported in `dotnet restore` 8. **EF Core source changes** (if applicable) — See `references/efcore-dotnet9to10.md` for: - `ExecuteUpdateAsync` now accepts a regular lambda (expression tree construction code must be rewritten) - `IDiscriminatorPropertySetConvention` signature changed - `IRelationalCommandDiagnosticsLogger` methods add `logCommandText` parameter 9. **WinForms/WPF source changes** (if applicable): - Applications referencing both WPF and WinForms must disambiguate `MenuItem` and `ContextMenu` types - Renamed parameter in `HtmlElement.InsertAdjacentElement` - Empty `ColumnDefinitions` and `RowDefinitions` are disallowed in WPF 10. **Cryptography source changes** (if applicable): - `MLDsa` and `SlhDsa` members renamed from `SecretKey` to `PrivateKey` (e.g., `ExportMLDsaSecretKey` → `ExportMLDsaPrivateKey`, `SecretKeySizeInBytes` → `PrivateKeySizeInBytes`) - `Rfc2898DeriveBytes` constructors are obsolete (SYSLIB0060) — replace with static `Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, hashAlgorithm, outputLength)` - `CoseSigner.Key` can now be null — check for null before use - `X509Certificate.GetKeyAlgorithmParameters()` and `PublicKey.EncodedParameters` can return null - Environment variable renamed from `CLR_OPENSSL_VERSION_OVERRIDE` to `DOTNET_OPENSSL_VERSION_OVERRIDE` Build again after each batch of fixes. Repeat until the build is clean. ### Step 4: Address behavioral changes Behavioral changes do not cause build errors but may change runtime behavior. Review each applicable item and determine whether the previous behavior was relied upon. **High-impact behavioral changes (check first):** 1. **SIGTERM signal handling removed** — The .NET runtime no longer registers default SIGTERM handlers. If you rely on `AppDomain.ProcessExit` or `AssemblyLoadContext.Unloading` being raised on SIGTERM: - ASP.NET Core and Generic Host apps are unaffected (they register their own handlers) - Console apps and containerized apps without Generic Host must register `PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => Environment.Exit(0))` explicitly 2. **BackgroundService.ExecuteAsync runs entirely on a background thread** — The synchronous portion before the first `await` no longer blocks startup. If startup ordering matters, move that code to `StartAsync` or the constructor, or implement `IHostedLifecycleService`. 3. **Configuration null values are now preserved** — JSON `null` values are no longer converted to empty strings. Properties initialized with non-default values will be overwritten with `null`. Review configuration binding code. 4. **Microsoft.Data.Sqlite DateTimeOffset changes** (all High impact): - `GetDateTimeOffset` without an offset now assumes UTC (previously assumed local) - Writing `DateTimeOffset` into REAL columns now converts to UTC first - `GetDateTime` with an offset now returns UTC with `DateTimeKind.Utc` - Mitigation: `AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true)` as a temporary workaround 5. **EF Core parameterized collections** — `.Contains()` on collections now uses multiple scalar parameters instead of JSON/OPENJSON. May affect query performance for large collections. Mitigation: `UseParameterizedCollectionMode(ParameterTranslationMode.Parameter)` to revert. 6. **EF Core JSON data type on Azure SQL** — Azure SQL and compatibility level ≥170 now use the `json` data type instead of `nvarchar(max)`. A migration will be generated to alter existing columns. Mitigation: set compatibility level to 160 or use `HasColumnType("nvarchar(max)")` explicitly. 7. **System.Text.Json property name conflict validation** — Polymorphic types with properties conflicting with metadata names (`$type`, `$id`, `$ref`) now throw `InvalidOperationException`. Add `[JsonIgnore]` to conflicting properties. **Other behavioral changes to review:** - `BufferedStream.WriteByte` no longer implicitly flushes — add explicit `Flush()` calls if needed - Default trace context propagator updated to W3C standard - `DriveInfo.DriveFormat` returns actual Linux filesystem type names - LDAP `DirectoryControl` parsing is more stringent - Default .NET container images switched from Debian to Ubuntu (Debian images no longer shipped) - Single-file apps no longer look for native libraries in executable directory by default - `DllImportSearchPath.AssemblyDirectory` only searches the assembly directory - `MailAddress` enforces validation for consecutive dots - Streaming HTTP responses enabled by default in browser HTTP clients - `Uri` length limits removed — add explicit length validation if `Uri` was used to reject oversized input from untrusted sources - Cookie login redirects disabled for known API endpoints (ASP.NET Core) - `XmlSerializer` no longer ignores `[Obsolete]` properties — audit obsolete properties for sensitive data and add `[XmlIgnore]` to prevent unintended data exposure - `dotnet restore` audits transitive packages - `dotnet watch` logs to stderr instead of stdout - `dotnet` CLI commands log non-command-relevant data to stderr - Various NuGet behavioral changes (see `references/sdk-msbuild-dotnet9to10.md`) - `StatusStrip` uses System RenderMode by default (WinForms) - `TreeView` checkbox image truncation fix (WinForms) - `DynamicResource` incorrect usage causes crash (WPF) ### Step 5: Update infrastructure 1. **Dockerfiles**: Update base images. Default tags now use Ubuntu instead of Debian. Debian images are no longer shipped for .NET 10. ```dockerfile # Before FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:9.0 # After FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build FROM mcr.microsoft.com/dotnet/aspnet:10.0 ``` 2. **CI/CD pipelines**: Update SDK version references. If using `global.json`, update: ```json { "sdk": { "version": "10.0.100" } } ``` 3. **Environment variables renamed**: - `DOTNET_OPENSSL_VERSION_OVERRIDE` replaces the old name - `DOTNET_ICU_VERSION_OVERRIDE` replaces the old name - `NUGET_ENABLE_ENHANCED_HTTP_RETRY` has been removed 4. **OpenSSL requirements**: OpenSSL 1.1.1 or later is now required on Unix. OpenSSL cryptographic primitives are no longer supported on macOS. 5. **Solution file format**: If `dotnet new sln` is used in scripts, note it now generates SLNX format. Pass `--format sln` if the old format is needed. ### Step 6: Verify 1. Run a full clean build: `dotnet build --no-incremental` 2. Run all tests: `dotnet test` 3. If the application is containerized, build and test the container image 4. Smoke-test the application, paying special attention to: - Signal handling / graceful shutdown behavior - Background services startup ordering - Configuration binding with null values - Date/time handling with Sqlite - JSON serialization with polymorphic types - EF Core queries using `.Contains()` on collections 5. **Security review** — verify that the migration has not weakened security controls: - TLS cipher validation logic is preserved after `SslStream` API migration (SYSLIB0058) - Obsolete properties containing sensitive data are excluded from serialization (`[XmlIgnore]`, `[JsonIgnore]`) - Input validation still rejects oversized URIs if `Uri` was used as a length gate - Exception handlers emit security-relevant telemetry (auth failures, access violations) before returning `true` - Connection strings set an explicit `Application Name` that does not leak version info - `dotnet restore` vulnerability audit findings are addressed, not suppressed 6. Review the diff and ensure no unintended behavioral changes were introduced ## Reference Documents The `references/` folder contains detailed breaking change information organized by technology area. Load only the references relevant to the project being migrated: | Reference file | When to load | |----------------|-------------| | `references/csharp-compiler-dotnet9to10.md` | Always (C# 14 compiler breaking changes — field keyword, extension keyword, span overloads) | | `references/core-libraries-dotnet9to10.md` | Always (applies to all .NET 10 projects) | | `references/sdk-msbuild-dotnet9to10.md` | Always (SDK and build tooling changes) | | `references/aspnet-core-dotnet9to10.md` | Project uses ASP.NET Core | | `references/efcore-dotnet9to10.md` | Project uses Entity Framework Core or Microsoft.Data.Sqlite | | `references/cryptography-dotnet9to10.md` | Project uses System.Security.Cryptography or X.509 certificates | | `references/extensions-hosting-dotnet9to10.md` | Project uses Generic Host, BackgroundService, or Microsoft.Extensions.Configuration | | `references/serialization-networking-dotnet9to10.md` | Project uses System.Text.Json, XmlSerializer, HttpClient, or networking APIs | | `references/winforms-wpf-dotnet9to10.md` | Project uses Windows Forms or WPF | | `references/containers-interop-dotnet9to10.md` | Project uses Docker containers, single-file publishing, or native interop (P/Invoke) |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.