Tell us about your PDF experience. Breaking changes in .NET Article • 05/24/2023 Use this reference section to find breaking changes that might apply to you if you're upgrading your app to a newer version of .NET. You can navigate the table of contents either by .NET version or by technology area. If you're looking for breaking changes from .NET Framework to .NET, see Breaking changes for migration from .NET Framework to .NET (Core). GitHub issues and announcements You can also view individual issues that detail the breaking changes introduced in .NET in the following GitHub repositories: For .NET Core and .NET 5+, the dotnet/docs For ASP.NET Core, the aspnet/Announcements For Entity Framework Core, the dotnet/efcore repository. repository. repository. See also API removal in .NET .NET runtime compatibility Migrate from .NET Framework to .NET Core Breaking changes for migration from .NET Framework to .NET Core Breaking changes in .NET 8 Article • 08/29/2023 If you're migrating an app to .NET 8, the breaking changes listed here might affect you. Changes are grouped by technology area, such as ASP.NET Core or Windows Forms. This article categorizes each breaking change as binary incompatible or source incompatible, or as a behavioral change: Binary incompatible - When run against the new runtime or component, existing binaries may encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation. Source incompatible - When recompiled using the new SDK or component or to target the new runtime, existing source code may require source changes to compile successfully. Behavioral change - Existing code and binaries may behave differently at run time. If the new behavior is undesirable, existing code would need to be updated and recompiled. 7 Note This article is a work in progress. It's not a complete list of breaking changes in .NET 8. To query breaking changes that are still pending publication, see Issues of .NET . ASP.NET Core Title Type of change Introduced ConcurrencyLimiterMiddleware is obsolete Source incompatible Preview 4 Custom converters for serialization removed Behavioral change Preview 2 ISystemClock is obsolete Source incompatible Preview 5 Rate-limiting middleware requires AddRateLimiter Behavioral change Preview 5 Security token events return a JSonWebToken Preview 7 TrimMode defaults to full for Web SDK projects Preview 7 Containers Title Type of change Introduced 'ca-certificates' and 'krb5-libs' packages removed from Alpine images Binary incompatible Preview 7 Debian container images upgraded to Debian 12 Binary incompatible/behavioral change Preview 1 Default ASP.NET Core port changed to 8080 Behavioral change Preview 1 'libintl' package removed from Alpine images Behavioral change Preview 5 Multi-platform container tags are Linux-only Behavioral change Preview 3 New 'app' user in Linux images Behavioral change Preview 1 Core .NET libraries Title Type of change Introduced Activity operation name when null Behavioral change Preview 1 AnonymousPipeServerStream.Dispose behavior Behavioral change Preview 1 API obsoletions with custom diagnostic IDs Source incompatible Preview 1, 4 Backslash mapping in Unix file paths Behavioral change Preview 1 Base64.DecodeFromUtf8 methods ignore whitespace Behavioral change Preview 5 Boolean-backed enum type support removed Behavioral change Preview 1 FileStream writes when pipe is closed Behavioral change Preview 1 GC.GetGeneration might return Int32.MaxValue Behavioral change Preview 4 GetFolderPath behavior on Unix Behavioral change Preview 1 IndexOfAnyValues renamed to SearchValues Source/binary Preview 5 incompatible ITypeDescriptorContext nullable annotations Source incompatible Preview 1 Legacy Console.ReadKey removed Behavioral change Preview 1 Method builders generate parameters with HasDefaultValue set to false Behavioral change Preview 5 Title Type of change Introduced Removed overloads of ToFrozenDictionary/ToFrozenSet Source/binary incompatible Preview 7 Title Type of change Introduced AesGcm authentication tag size on macOS Behavioral change Preview 1 RSA.EncryptValue and RSA.DecryptValue obsolete Source incompatible Preview 1 Cryptography Deployment Title Type of change Introduced Host determines RID-specific assets Binary incompatible/behavioral change Preview 5 StripSymbols defaults to true Behavioral change Preview 4 Entity Framework Core Breaking changes in EF Core 8 Extensions Title Type of change Introduced ActivatorUtilities.CreateInstance behaves consistently Behavioral change Preview 1 ActivatorUtilities.CreateInstance requires non-null provider Behavioral change Preview 1 ConfigurationBinder throws for mismatched value Behavioral change Preview 1 ConfigurationManager package no longer references System.Security.Permissions Source incompatible Preview 3 DirectoryServices package no longer references System.Security.Permissions Source incompatible Preview 3 Title Type of change Introduced Empty keys added to dictionary by configuration binder Behavioral change Preview 5 HostApplicationBuilderSettings.Args respected by Behavioral Preview 2 HostApplicationBuilder ctor change Globalization Title Type of change Introduced Date and time converters honor culture argument Behavioral change Preview 4 TwoDigitYearMax default is 2049 Behavioral change Preview 1 Interop Title Type of change Introduced CreateObjectFlags.Unwrap only unwraps on target instance Behavioral change Preview 5 IDispatchImplAttribute API is removed Binary incompatible Preview 6 SafeHandle types must have public constructor Source incompatible Preview 5 Reflection Title Type of change Introduced IntPtr no longer used for function pointer types Behavioral change Preview 2 SDK Title Type of change Introduced .NET tool roll-forward behavior Behavioral change Preview 5 CLI console output uses UTF-8 Behavioral change/Source and Preview 1 binary incompatible Console encoding not UTF-8 after completion Behavioral change/Binary incompatible Preview 3 Title Type of change Introduced Containers default to use the 'latest' tag Behavioral change Preview 6 'dotnet pack' uses Release configuration Behavioral change/Source incompatible Preview 1 'dotnet publish' uses Release configuration Behavioral change/Source Preview 1 incompatible MSBuild respects DOTNET_CLI_UI_LANGUAGE Behavioral change Preview 5 Runtime-specific apps not self-contained Source/binary incompatible Preview 5 'dotnet restore' produces security vulnerability warnings Behavioral change Preview 4 Trimming may not be used with .NET Standard or .NET Framework Behavioral change RC 1 Serialization Title Type of change Introduced BinaryFormatter disabled for most projects Behavioral change Preview 4 Windows Forms Title Type of change Introduced Anchor layout changes Behavioral change Preview 1 DefaultValueAttribute removed from some properties Behavioral change Preview 2 ExceptionCollection ctor throws ArgumentException Behavioral change Preview 1 Forms scale according to AutoScaleMode Behavioral change Preview 1 ImageList.ColorDepth default is Depth32Bit Behavioral change Preview 1 TableLayoutStyleCollection throws ArgumentException Behavioral change Preview 1 Top-level forms scale minimum and maximum size to DPI Behavioral change Preview 1 WFDEV002 obsoletion is now an error Source incompatible Preview 1 See also What's new in .NET 8 ConcurrencyLimiterMiddleware is obsolete Article • 05/04/2023 ConcurrencyLimiterMiddleware and its associated methods and types have been marked as obsolete. If you require rate-limiting capabilities, switch to the newer and more capable ratelimiting middleware that was introduced in .NET 7 (for example, RateLimiterApplicationBuilderExtensions.UseRateLimiter). The .NET 7 rate-limiting API includes a concurrency limiter and several other rate-limiting algorithms that you can apply to your application. Version introduced ASP.NET Core 8.0 Preview 4 Previous behavior Developers could use ConcurrencyLimiterMiddleware to control concurrency by adding a policy to dependency injection (DI) and enabling the middleware: C# var builder = WebApplication.CreateBuilder(args); builder.Services.AddStackPolicy<options => { options.MaxConcurrentRequests = 2; options.RequestQueueLimit = 25; }); var app = builder.Build(); app.UseConcurrencyLimiter(); // Map endpoints. app.Run(); New behavior If you use the Affected APIs in your code, you'll get warning CS0618 at compile time. Type of breaking change This change affects source compatibility. Reason for change ConcurrencyLimiterMiddleware is infrequently used and undocumented. The newer rate-limiting API has more extensive functionality. Recommended action If you're using the older ConcurrencyLimiterMiddleware, we recommend moving to the newer rate-limiting middleware. Here's an example usage of the newer API, RateLimiterApplicationBuilderExtensions.UseRateLimiter: C# using Microsoft.AspNetCore.RateLimiting; using System.Threading.RateLimiting; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseRateLimiter(new RateLimiterOptions() .AddConcurrencyLimiter("only-one-at-a-time-stacked", (options) => { options.PermitLimit = 2; options.QueueLimit = 25; options.QueueProcessingOrder = QueueProcessingOrder.NewestFirst; })); app.MapGet("/", async () => { await Task.Delay(10000); return "Hello World"; }).RequireRateLimiting("only-one-at-a-time-stacked"); app.Run(); Affected APIs Microsoft.AspNetCore.Builder.ConcurrencyLimiterExtensions.UseConcurrencyLimite r(IApplicationBuilder) Microsoft.AspNetCore.ConcurrencyLimiter.ConcurrencyLimiterMiddleware System.Threading.RateLimiting.ConcurrencyLimiterOptions See also Rate limiting middleware in ASP.NET Core Custom converters for serialization removed Article • 05/27/2023 ProblemDetails and ValidationProblemDetails previously used custom converters to support JSON serialization due to a lack of built-in support for the IgnoreNullValues option. Now that this option is supported by the System.Text.Json APIs, we've removed the custom converters from the framework in favor of the serialization provided by the framework. As a result of this change, the properties in the ProblemDetails and ValidationProblemDetails types no longer assume lowercase type names. Developers must specify a JsonNamingPolicy to get the correct behavior. Version introduced ASP.NET Core 8.0 Preview 2 Previous behavior Previously, you could add JsonStringEnumConverter to the serialization options as a custom converter, and deserialization resulted in a 400 status for ValidationProblemDetails. C# string content = "{\"status\":400,\"detail\":\"HTTP egress is not enabled.\"}"; using MemoryStream stream = new(); using StreamWriter writer = new(stream); writer.Write(content); writer.Flush(); stream.Position = 0; JsonSerializerOptions options = new(); options.Converters.Add(new JsonStringEnumConverter()); ValidationProblemDetails? details = await JsonSerializer.DeserializeAsync<ValidationProblemDetails>(stream, options); Console.WriteLine(details.Status); // 400 New behavior Starting in .NET 8, the same code results in a null status for ValidationProblemDetails. C# string content = "{\"status\":400,\"detail\":\"HTTP egress is not enabled.\"}"; using MemoryStream stream = new(); using StreamWriter writer = new(stream); writer.Write(content); writer.Flush(); stream.Position = 0; JsonSerializerOptions options = new(); options.Converters.Add(new JsonStringEnumConverter()); ValidationProblemDetails? details = await JsonSerializer.DeserializeAsync<ValidationProblemDetails>(stream, options); Console.WriteLine(details.Status); // null Type of breaking change This change is a behavioral change. Reason for change Now that JsonSerializerOptions.IgnoreNullValues is supported by the System.Text.Json APIs, we've removed the custom converters in favor of the serialization provided by the framework. Recommended action Provide a JsonSerializerOptions with the correct details. C# JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true }; ValidationProblemDetails? details = await JsonSerializer.DeserializeAsync<ValidationProblemDetails>(stream, options); Affected APIs Microsoft.AspNetCore.Mvc.ProblemDetails Microsoft.AspNetCore.Mvc.ValidationProblemDetails ISystemClock is obsolete Article • 06/01/2023 Microsoft.AspNetCore.Authentication.ISystemClock has been used by ASP.NET Core's authentication and identity components since version 1.0 to enable unit testing of timerelated functionality, like expiration checking. .NET 8 includes a suitable abstraction, System.TimeProvider, that provides the same functionality and much more. We're taking this opportunity to obsolete ISystemClock and replace it with TimeProvider throughout the ASP.NET Core libraries. Version introduced ASP.NET Core 8.0 Preview 5 Previous behavior ISystemClock was injected into the constructors of the authentication and identity components by dependency injection (DI) and could be overridden for testing. The default SystemClock implementation truncated to the nearest second for easier formatting. New behavior ISystemClock, SystemClock, and the authentication handler constructors that have an ISystemClock parameter have been marked obsolete. Using these APIs in code will generate a warning at compile time. ISystemClock remains in the dependency injection container but is no longer used. It may be removed from the container in a future version. TimeProvider is now a settable property on the Options classes for the authentication and identity components. It can be set directly or by registering a provider in the dependency injection container. TimeProvider does not truncate to the nearest second. Consumers are expected to correctly format the time as needed. Type of breaking change This change affects source compatibility. Reason for change This change was made to unify time abstraction across the stack for easier testing. Recommended action If you have components that derive from Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions> or Microsoft.AspNetCore.Identity.SecurityStampValidator<TUser>, remove the ISystemClock constructor parameter and call the new base constructor accordingly. diff - public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder) + : base(options, logger, encoder) Similarly, derived implementations that reference the Clock property on these types should reference the new TimeProvider property instead. diff - var currentUtc = Clock.UtcNow; + var currentUtc = TimeProvider.GetUtcNow(); You can set TimeProvider for testing on the options or via DI. Affected APIs Microsoft.AspNetCore.Authentication.ISystemClock Microsoft.AspNetCore.Authentication.SystemClock Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions> Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.Clock CookieAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions>, ILoggerFactory, UrlEncoder, ISystemClock) FacebookHandler(IOptionsMonitor<FacebookOptions>, ILoggerFactory, UrlEncoder, ISystemClock) GoogleHandler(IOptionsMonitor<GoogleOptions>, ILoggerFactory, UrlEncoder, ISystemClock) JwtBearerHandler(IOptionsMonitor<JwtBearerOptions>, ILoggerFactory, UrlEncoder, ISystemClock) MicrosoftAccountHandler(IOptionsMonitor<MicrosoftAccountOptions>, ILoggerFactory, UrlEncoder, ISystemClock) NegotiateHandler(IOptionsMonitor<NegotiateOptions>, ILoggerFactory, UrlEncoder, ISystemClock) OAuthHandler<TOptions>(IOptionsMonitor<TOptions>, ILoggerFactory, UrlEncoder, ISystemClock) OpenIdConnectHandler(IOptionsMonitor<OpenIdConnectOptions>, ILoggerFactory, HtmlEncoder, UrlEncoder, ISystemClock) Microsoft.AspNetCore.Authentication.PolicySchemeHandler.PolicySchemeHandler(I OptionsMonitor<PolicySchemeOptions>, ILoggerFactory, UrlEncoder, ISystemClock) Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions> SignInAuthenticationHandler<TOptions>(IOptionsMonitor<TOptions>, ILoggerFactory, UrlEncoder, ISystemClock) SignOutAuthenticationHandler<TOptions>(IOptionsMonitor<TOptions>, ILoggerFactory, UrlEncoder, ISystemClock) TwitterHandler(IOptionsMonitor<TwitterOptions>, ILoggerFactory, UrlEncoder, ISystemClock) WsFederationHandler(IOptionsMonitor<WsFederationOptions>, ILoggerFactory, UrlEncoder, ISystemClock) SecurityStampValidator<TUser>(IOptions<SecurityStampValidatorOptions>, SignInManager<TUser>, ISystemClock, ILoggerFactory) Microsoft.AspNetCore.Identity.SecurityStampValidator<TUser>.Clock TwoFactorSecurityStampValidator<TUser> (IOptions<SecurityStampValidatorOptions>, SignInManager<TUser>, ISystemClock, ILoggerFactory) Rate-limiting middleware requires AddRateLimiter Article • 06/01/2023 ASP.NET Core rate-limiting middleware has been updated with extra functionality. The middleware now requires services registered with AddRateLimiter. Version introduced ASP.NET Core 8.0 Preview 5 Previous behavior Previously, rate limiting could be used without AddRateLimiter. For example, the middleware could be configured by calling Configure<RateLimiterOptions>(o => { }) : C# var builder = WebApplication.CreateBuilder(args); builder.Services.Configure<RateLimiterOptions>(o => o .AddFixedWindowLimiter(policyName: "fixed", options => { // configuration })); var app = builder.Build(); app.UseRateLimiter(); app.MapGet("/", () => Results.Ok($"Hello world")).RequireRateLimiting("fixed"); app.Run(); New behavior If AddRateLimiter is not called on app startup, ASP.NET Core throws an informative error: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddRateLimiter' in the application startup code. Type of breaking change This change is a behavioral change. Reason for change Rate-limiting middleware requires services that are only registered by calling AddRateLimiter. Recommended action Ensure that UseRateLimiter is called at application startup. For example, update Configure<RateLimiterOptions>(o => { }) to use UseRateLimiter: C# var builder = WebApplication.CreateBuilder(args); builder.Services.AddRateLimiter(o => o .AddFixedWindowLimiter(policyName: "fixed", options => { // configuration })); var app = builder.Build(); app.UseRateLimiter(); app.MapGet("/", () => Results.Ok($"Hello world")).RequireRateLimiting("fixed"); app.Run(); Affected APIs Microsoft.AspNetCore.Builder.RateLimiterApplicationBuilderExtensions.UseRateLim iter Security token events return a JSonWebToken Article • 08/03/2023 The JwtBearerEvents, WsFederationEvents, and OpenIdConnectEvents events are authentication events fired respectively by the JwtBearer, WsFederation, and OpenIdConnect authentication handlers. For example, the OnTokenValidated event is fired when a security token is validated. These events are fired with a context (for example, TokenValidatedContext) that exposes a TokenValidatedContext.SecurityToken property of abstract type SecurityToken. The default real implementation of TokenValidatedContext.SecurityToken changed from JwtSecurityToken to JsonWebToken. Version introduced ASP.NET Core 8.0 Preview 7 Previous behavior Previously, the affected SecurityToken properties were implemented by JwtSecurityToken, which derives from SecurityToken, JwtSecurityToken is the previous generation of JSON Web Token (JWT) implementation. The JwtSecurityToken tokens were produced by SecurityTokenValidators. New behavior Starting in ASP.NET Core 8.0, the Microsoft.IdentityModel.JsonWebTokens class, which also derives from SecurityToken, implements the SecurityToken properties, by default. Microsoft.IdentityModel.JsonWebTokens tokens are produced by more optimized TokenHandler handlers. Type of breaking change This change is a behavioral change. Reason for change This change was made because JsonWebToken (and its associated JsonWebTokenHandler) bring the following benefits: 30% performance improvement. Improved reliability by using a "last known good" metadata (such as OpenIdConnectMetadata ). Async processing. Recommended action For most users, this change shouldn't be a problem as the type of the properties (SecurityToken) hasn't changed, and you weren't supposed to look at the real type. However, if you were down-casting one of the affected SecurityToken properties to JwtSecurityToken (for example, to get the claims), you have two options: Down-cast the property to JSonWebToken : C# service.Configure<JwtBearerOptions> (JwtBearerDefaults.AuthenticationScheme, options => { options.Events.TokenValidated = (context) => { // Replace your cast to JwtSecurityToken. JSonWebToken token = context.SecurityToken as JSonWebToken; // Do something ... }; }); Set one of the UseSecurityTokenValidators Boolean properties on the corresponding options (JwtBearerOptions, WsFederationOptions, or OpenIdConnectOptions) to true . By setting the property to true , the authentication handlers will keep using JwtTokenValidators and will keep producing JwtSecurityToken tokens. C# service.Configure<JwtBearerOptions> (JwtBearerDefaults.AuthenticationScheme, options => { options.UseSecurityTokenValidators = true; options.Events.TokenValidated = (context) => { // As you were doing before JwtSecurityToken token = context.SecurityToken as JwtSecurityToken; // Do something ... }; }); Affected APIs Microsoft.AspNetCore.Authentication.WsFederation.SecurityTokenValidatedContext .SecurityToken Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext.SecurityTok en Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext.Secur ityToken AuthorizationCodeReceivedContext.SecurityToken TrimMode defaults to full for Web SDK projects Article • 08/03/2023 Trimming now trims all assemblies in applications that target the Web SDK, by default. This change only affects apps that are published with PublishTrimmed=true , and it only breaks apps that had existing trim warnings. Version introduced ASP.NET Core 8.0 Preview 7 Previous behavior Previously, TrimMode=partial was set by default for all projects that targeted the Web SDK. New behavior Starting in .NET 8, all the assemblies in the app are trimmed, by default. Apps that previously worked with PublishTrimmed=true and TrimMode=partial might not work in .NET 8 Preview 7 and later versions. However, only apps with trim warnings are affected. If your app has no trim warnings, the change in behavior should not cause any adverse effects. Type of breaking change This change can affect source compatibility. Reason for change This change helps to decrease app size without users having to explicitly opt in. It also aligns with user expectations that the entire app is trimmed unless noted otherwise. Recommended action The best resolution is to resolve all the trim warnings in your application. For information about resolving the warnings in your own libraries, see Introduction to trim warnings. To revert to the previous behavior, set the TrimMode property to partial . XML <TrimMode>partial</TrimMode> Affected APIs None. 'ca-certificates' and 'krb5-libs' packages removed from Alpine images Article • 08/03/2023 The krb5-libs package is no longer installed in .NET Alpine container images. This package enables Kerberos secure networking. Kerberos is installed by default in Debian and Ubuntu, so .NET Debian and Ubuntu images aren't affected by this change. In addition, the ca-certificates package is no longer installed in .NET Alpine container images. The Alpine base image includes the ca-certificates-bundle package, which provides the same baseline content that's needed for most .NET apps. It's expected that very few (if any) .NET apps will be affected by this change. Previous behavior Prior to .NET 8, the ca-certificates and krb5-libs packages were included in .NET's Alpine container images. New behavior .NET no longer includes the ca-certificates and krb5-libs packages in its Alpine container images. Version introduced .NET 8 Preview 7 Type of change This change can affect binary compatibility. Reason for change The packages were removed to reduce the image size. For krb5-libs , the Kerberos secure networking scenario was considered not popular enough to warrant installing this package by default. The removal of this package reduces .NET 8 Alpine images by ~2.7 MB. For ca-certificates , the removal of this package reduces .NET 8 Alpine images by 0.6MB. Recommended action If you require the affected packages for your scenario, install them yourself using the following Dockerfile instruction. Dockerfile RUN apk add --upgrade krb5-libs RUN apk add --upgrade ca-certificates Affected APIs System.DirectoryServices.Protocols System.Net.Http.HttpClient Debian container images upgraded to Debian 12 Article • 07/14/2023 The default Linux distro for .NET container images is Debian. In .NET 8, the Debian version has been upgraded to Debian 12 (Bookworm). As a result of upgraded package versions, this new version of Debian may have changes in it that break your application. The most notable change is the upgrade of Open SSL from 1.1 to 3.0. Previous behavior In .NET 6 and 7, the default Debian version was Debian 11 (Bullseye). Notable package versions: libicu : 67 libssl : 1.1 New behavior In .NET 8, the default Debian version is Debian 12 (Bookworm). Notable package versions: libicu : 72 libssl : 3 Version introduced .NET 8 Preview 1 Type of change This change can affect binary compatibility and is also a behavioral change. Reason for change According to the container support policy , with each version of .NET, the default version of Debian that's targeted is the latest stable version. Recommended action If necessary, update your application to work with the newer package versions. Affected APIs None. See also Debian release notes Default ASP.NET Core port changed to 8080 Article • 08/10/2023 The default ASP.NET Core port configured in .NET container images has been updated from port 80 to 8080. We also added the new ASPNETCORE_HTTP_PORTS environment variable instead of ASPNETCORE_URLS . Previous behavior Prior to .NET 8, you could run a container expecting port 80 to be the default port and be able to access the running app. For example, running the following command allowed you to access the app locally at port 9999, which is mapped to port 80 in the container: docker run --rm -it -p 9999:80 <my-app> New behavior Starting with .NET 8, if you map to port 80 in the container without explicitly setting the ASP.NET Core port used in the container, any attempt to connect to that mapped port will fail. For example, if you run the following command, you'd be unable to connect to the application locally using port 9999. docker run --rm -it -p 9999:80 <my-app> Instead, change the command to use port 8080 within the container: docker run --rm -it -p 9999:8080 <my-app> Version introduced .NET 8 Preview 1 Type of change This change is a behavioral change. Reason for change The change to the port number was made because of the need to provide a good usability experience when switching to a non-root user. Running as a non-root user requires the use of a non-privileged port in some environments. Since port 80, the previous default port, is a privileged port, the default was updated to port 8080, which is a non-privileged port. Recommended action There are two ways to respond to this breaking change: Recommended: Explicitly set the ASPNETCORE_HTTP_PORTS , ASPNETCORE_HTTPS_PORTS , and ASPNETCORE_URLS environment variables to the desired port. Example: docker run --rm -it -p 9999:80 -e ASPNETCORE_HTTP_PORTS=80 <my-app> Update existing commands and configuration that rely on the expected default port of port 80 to reference port 8080 instead. Example: docker run --rm -it -p 9999:8080 <my-app> Affected APIs None. See also New non-root 'app' user in Linux images Containerize a .NET app Blog: Secure your .NET cloud apps with rootless Linux containers Bog: Running non-root .NET containers with Kubernetes 'libintl' package removed from Alpine images Article • 07/14/2023 The libintl package is no longer included in .NET's Alpine container images. Previous behavior Prior to .NET 8, the libintl package was included in .NET's Alpine container images. New behavior .NET no longer includes the libintl package in its Alpine container images. If your application has its own dependency on libintl , you might see the following error when running with .NET 8 in an Alpine container: Error loading shared library libintl.so.8: No such file or directory Version introduced .NET 8 Preview 5 Type of change This change is a behavioral change. Reason for change It was determined that .NET has no dependency on the libintl package. Only packages that .NET requires are included on top of the base Alpine container image. Recommended action Verify the functionality of your application when upgrading to .NET 8. If your application has a dependency on the libintl package, you can include it in the image by adding the following instruction to your Dockerfile: RUN apk add --no-cache libintl Affected APIs None. See also dotnet/docker issue 4627 Multi-platform container tags are Linuxonly Article • 07/14/2023 The .NET 8 multi-platform container tags have been updated to be Linux-only. This means that the latest , <major>.<minor> , and <major>.<minor>.<patch> tags are Linuxonly going forward. Multi-platform tags, also known as multi-arch or manifest list tags, are dynamic tags that cause the appropriate image to be retrieved based on the context of the host system. For example, if you pull an image with a multi-platform tag from a Linux Arm64 machine, you'll get an Arm64 image (if the tag supports that). Previous behavior Previously, you could reference a tag like 7.0 and be able to retrieve a Windows-based container image. New behavior Starting in .NET 8, the 8.0 tag will only retrieve a Linux-based image. Version introduced .NET 8 Preview 3 Type of change This change is a behavioral change. Reason for change This change was made because of usability issues related to the platform-matching algorithm for containerd when used in conjunction with Windows desktop OS versions. This change aligns .NET's Windows container images with the method of tagging that's used for the actual base Windows Server container images. Recommended action Update your tag usage to indicate which Windows version you're targeting. Instead of using an image name like mcr.microsoft.com/dotnet/aspnet:8.0 , you'll now need to use something like one of the following: mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809 mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-ltsc2022 mcr.microsoft.com/dotnet/aspnet:8.0-windowsservercore-ltsc2019 mcr.microsoft.com/dotnet/aspnet:8.0-windowsservercore-ltsc2022 Select an image name based on whether you're using Nano Server or Windows Server Core and which version of that OS. You can find a full list of all supported tags on .NET's Docker Hub page . 7 Note In the example image names, the 8.0 tag prefix is used, which is the value that will exist once .NET 8 ships. While .NET 8 is still in preview, you can replace 8.0 with 8.0-preview . Affected APIs None. See also dotnet/dotnet-docker issue 4492 New 'app' user in Linux images Article • 07/14/2023 The .NET Linux container images include a new non-root user named app . You can opt into this new user to provide security benefits. The name of this user may conflict with an existing user defined by an application's Dockerfile. Previous behavior Prior to .NET 8, the Linux container images did not include any additional users beyond what was included by default in the base Linux container image (for example, Debian, Alpine, and Ubuntu). New behavior Starting in .NET 8, Linux container images define a user named `app`` that can be optedinto for additional security benefits. However, the name of this user may conflict with an existing user that was defined by the application's Dockerfile. If the application's Dockerfile attempts to create a user with the same name, an error might occur saying that the user already exists. Version introduced .NET 8 Preview 1 Type of change This change is a behavioral change. Reason for change The new user was introduced to improve usability for securing containers. Recommended action If your application's Dockerfile attempts to create a new user with the same name as the existing app user, there are two options: Update the Dockerfile to change the name of the user so that it no longer conflicts. Remove the user creation logic and migrate to use the built-in app user instead. Affected APIs None. See also Blog post: Rootless Linux containers Activity operation name when null Article • 01/27/2023 Starting in .NET 8, if you create an Activity object using null for the operation name, the operation name will be stored as an empty string ( "" ) instead of null . Previous behavior Previously, if you created an Activity object using a null operation name, the operation name inside the activity was stored as null . C# new Activity(operationName: null).OperationName // Value is null. New behavior Starting in .NET 8, if you create an Activity object using a null operation name, the operation name is stored as an empty string. C# new Activity(operationName: null).OperationName // Value is "". Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change A null operation name in an Activity object can have an undesirable effect on backend trace collectors, which usually assume non-null operation names. To avoid crashes, trace collectors have to special case null operation names inside an Activity object. This change removes the special case requirement. Recommended action This change is unlikely to cause breaks as using null when creating Activity objects is rare. If for any reason your code depended on the null value for the operation name, adjust the code to either not use null or expect that the operation name will be stored as an empty string when you specify null . Affected APIs Activity constructor System.Diagnostics.Activity.OperationName System.Diagnostics.ActivitySource.CreateActivity System.Diagnostics.ActivitySource.StartActivity AnonymousPipeServerStream.Dispose behavior for HandleInheritability.Inheritable Article • 02/08/2023 To avoid resource leaks, your code should call the AnonymousPipeServerStream.DisposeLocalCopyOfClientHandle() method after passing the client handle to the child process. The behavior of AnonymousPipeServerStream.Dispose has been improved to lower the chance of similar leaks for users who don't call DisposeLocalCopyOfClientHandle(). Previous behavior Previously, the client handle owned by the AnonymousPipeServerStream instance wasn't disposed by AnonymousPipeServerStream.Dispose unless the handle wasn't exposed at all. New behavior Starting in .NET 8, the client handle owned by a server that was created for out-of-proc communication is disposed by AnonymousPipeServerStream.Dispose if it's not exposed by using the AnonymousPipeServerStream.ClientSafePipeHandle property. (You create a server for out-of-proc communication by passing HandleInheritability.Inheritable to the AnonymousPipeServerStream(PipeDirection, HandleInheritability) constructor.) Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change This change was introduced to avoid a common resource leak. Recommended action If a server was created for out-of-proc communication, don't reuse the client handle that's exposed as a string via the GetClientHandleAsString() method after the server instance has been disposed. Affected APIs System.IO.Pipes.AnonymousPipeServerStream (specifically, AnonymousPipeServerStream.Dispose() ) API obsoletions with non-default diagnostic IDs (.NET 8) Article • 06/08/2023 Some APIs have been marked as obsolete, starting in .NET 8. This breaking change is specific to APIs that have been marked as obsolete with a custom diagnostic ID. Suppressing the default obsoletion diagnostic ID, which is CS0618 for the C# compiler, does not suppress the warnings that the compiler generates when these APIs are used. Change description In previous .NET versions, these APIs can be used without any build warning. In .NET 8 and later versions, use of these APIs produces a compile-time warning or error with a custom diagnostic ID. The use of custom diagnostic IDs allows you to suppress the obsoletion warnings individually instead of blanket-suppressing all obsoletion warnings. The following table lists the custom diagnostic IDs and their corresponding warning messages for obsoleted APIs. Diagnostic ID Description Severity SYSLIB0048 RSA.EncryptValue(Byte[]) and RSA.DecryptValue(Byte[]) are obsolete. Use RSA.Encrypt and RSA.Decrypt instead. Warning SYSLIB0050 Formatter-based serialization is obsolete and should not be used. Warning SYSLIB0051 APIs that support obsolete formatter-based serialization are obsolete. Warning They should not be called or extended by application code. SYSLIB0053 AesGcm should indicate the required tag size for encryption and decryption. Use a constructor that accepts the tag size. Version introduced .NET 8 Type of breaking change These obsoletions can affect source compatibility. Warning Recommended action Follow the specific guidance provided for the each diagnostic ID using the URL link provided on the warning. Warnings or errors for these obsoletions can't be suppressed using the standard diagnostic ID for obsolete types or members; use the custom SYSLIBxxxx diagnostic ID value instead. Affected APIs SYSLIB0048 System.Security.Cryptography.RSA.EncryptValue(Byte[]) System.Security.Cryptography.RSA.DecryptValue(Byte[]) System.Security.Cryptography.RSACryptoServiceProvider.EncryptValue(Byte[]) System.Security.Cryptography.RSACryptoServiceProvider.DecryptValue(Byte[]) SYSLIB0050 System.Runtime.Serialization.FormatterConverter System.Runtime.Serialization.FormatterServices System.Runtime.Serialization.IFormatterConverter System.Runtime.Serialization.IObjectReference System.Runtime.Serialization.ISafeSerializationData System.Runtime.Serialization.ISerializationSurrogate System.Runtime.Serialization.ISurrogateSelector System.Runtime.Serialization.ObjectIDGenerator System.Runtime.Serialization.ObjectManager System.Runtime.Serialization.SafeSerializationEventArgs System.Runtime.Serialization.SerializationObjectManager System.Runtime.Serialization.StreamingContextStates System.Runtime.Serialization.SurrogateSelector System.Runtime.Serialization.Formatters.FormatterAssemblyStyle System.Runtime.Serialization.Formatters.FormatterTypeStyle System.Runtime.Serialization.Formatters.IFieldInfo System.Runtime.Serialization.Formatters.TypeFilterLevel System.Type.IsSerializable System.Reflection.FieldAttributes.NotSerialized System.Reflection.FieldInfo.IsNotSerialized System.Reflection.TypeAttributes.Serializable System.Runtime.Serialization.ISerializable.GetObjectData(SerializationInfo, StreamingContext) SerializationInfo(Type, IFormatterConverter, Boolean) SerializationInfo(Type, IFormatterConverter) StreamingContext(StreamingContextStates, Object) StreamingContext(StreamingContextStates) SYSLIB0051 The SYSLIB0051 API obsoletions are organized here by namespace. Microsoft.CSharp.RuntimeBinder namespace Microsoft.CSharp.RuntimeBinder.RuntimeBinderException.RuntimeBinderException (SerializationInfo, StreamingContext) Microsoft.CSharp.RuntimeBinder.RuntimeBinderInternalCompilerException.Runtim eBinderInternalCompilerException(SerializationInfo, StreamingContext) Microsoft.VisualBasic.FileIO namespace Microsoft.VisualBasic.FileIO.MalformedLineException.MalformedLineException(Seri alizationInfo, StreamingContext) Microsoft.VisualBasic.FileIO.MalformedLineException.GetObjectData(SerializationIn fo, StreamingContext) System namespace System.AccessViolationException.AccessViolationException(SerializationInfo, StreamingContext) System.AggregateException.AggregateException(SerializationInfo, StreamingContext) System.AggregateException.GetObjectData(SerializationInfo, StreamingContext) System.AppDomainUnloadedException.AppDomainUnloadedException(Serializatio nInfo, StreamingContext) System.ApplicationException.ApplicationException(SerializationInfo, StreamingContext) System.ArgumentException.ArgumentException(SerializationInfo, StreamingContext) System.ArgumentException.GetObjectData(SerializationInfo, StreamingContext) System.ArgumentNullException.ArgumentNullException(SerializationInfo, StreamingContext) System.ArgumentOutOfRangeException.ArgumentOutOfRangeException(Serializati onInfo, StreamingContext) System.ArgumentOutOfRangeException.GetObjectData(SerializationInfo, StreamingContext) System.ArithmeticException.ArithmeticException(SerializationInfo, StreamingContext) System.ArrayTypeMismatchException.ArrayTypeMismatchException(SerializationInf o, StreamingContext) System.BadImageFormatException.BadImageFormatException(SerializationInfo, StreamingContext) System.BadImageFormatException.GetObjectData(SerializationInfo, StreamingContext) System.CannotUnloadAppDomainException.CannotUnloadAppDomainException(S erializationInfo, StreamingContext) System.ContextMarshalException.ContextMarshalException(SerializationInfo, StreamingContext) System.DBNull.GetObjectData(SerializationInfo, StreamingContext) System.Delegate.GetObjectData(SerializationInfo, StreamingContext) System.DivideByZeroException.DivideByZeroException(SerializationInfo, StreamingContext) System.DuplicateWaitObjectException.DuplicateWaitObjectException(SerializationI nfo, StreamingContext) System.EntryPointNotFoundException.EntryPointNotFoundException(SerializationIn fo, StreamingContext) System.Exception.Exception(SerializationInfo, StreamingContext) System.Exception.GetObjectData(SerializationInfo, StreamingContext) System.FieldAccessException.FieldAccessException(SerializationInfo, StreamingContext) System.FormatException.FormatException(SerializationInfo, StreamingContext) System.InvalidCastException.InvalidCastException(SerializationInfo, StreamingContext) System.InvalidOperationException.InvalidOperationException(SerializationInfo, StreamingContext) System.InvalidTimeZoneException.InvalidTimeZoneException(SerializationInfo, StreamingContext) System.MemberAccessException.MemberAccessException(SerializationInfo, StreamingContext) System.MethodAccessException.MethodAccessException(SerializationInfo, StreamingContext) System.MissingFieldException.MissingFieldException(SerializationInfo, StreamingContext) System.MissingMemberException.MissingMemberException(SerializationInfo, StreamingContext) System.MissingMemberException.GetObjectData(SerializationInfo, StreamingContext) System.MissingMethodException.MissingMethodException(SerializationInfo, StreamingContext) System.MulticastDelegate.GetObjectData(SerializationInfo, StreamingContext) System.NotImplementedException.NotImplementedException(SerializationInfo, StreamingContext) System.NotSupportedException.NotSupportedException(SerializationInfo, StreamingContext) System.NullReferenceException.NullReferenceException(SerializationInfo, StreamingContext) System.ObjectDisposedException.ObjectDisposedException(SerializationInfo, StreamingContext) System.ObjectDisposedException.GetObjectData(SerializationInfo, StreamingContext) System.OperatingSystem.GetObjectData(SerializationInfo, StreamingContext) System.OperationCanceledException.OperationCanceledException(SerializationInfo , StreamingContext) System.OutOfMemoryException.OutOfMemoryException(SerializationInfo, StreamingContext) System.OverflowException.OverflowException(SerializationInfo, StreamingContext) System.PlatformNotSupportedException.PlatformNotSupportedException(Serializat ionInfo, StreamingContext) System.RankException.RankException(SerializationInfo, StreamingContext) System.RuntimeFieldHandle.GetObjectData(SerializationInfo, StreamingContext) System.RuntimeMethodHandle.GetObjectData(SerializationInfo, StreamingContext) System.RuntimeTypeHandle.GetObjectData(SerializationInfo, StreamingContext) System.SystemException.SystemException(SerializationInfo, StreamingContext) System.TimeoutException.TimeoutException(SerializationInfo, StreamingContext) System.TimeZoneNotFoundException.TimeZoneNotFoundException(SerializationInf o, StreamingContext) System.TypeAccessException.TypeAccessException(SerializationInfo, StreamingContext) System.TypeInitializationException.GetObjectData(SerializationInfo, StreamingContext) System.TypeLoadException.TypeLoadException(SerializationInfo, StreamingContext) System.TypeLoadException.GetObjectData(SerializationInfo, StreamingContext) System.TypeUnloadedException.TypeUnloadedException(SerializationInfo, StreamingContext) System.UnauthorizedAccessException.UnauthorizedAccessException(SerializationIn fo, StreamingContext) System.WeakReference.WeakReference(SerializationInfo, StreamingContext) System.WeakReference.GetObjectData(SerializationInfo, StreamingContext) System.UriFormatException.UriFormatException(SerializationInfo, StreamingContext) System.Collections namespace System.Collections.Comparer.GetObjectData(SerializationInfo, StreamingContext) System.Collections.Generic namespace System.Collections.Generic.LinkedList<T>.LinkedList<T>(SerializationInfo, StreamingContext) System.Collections.Generic.LinkedList<T>.GetObjectData(SerializationInfo, StreamingContext) System.Collections.Generic.SortedSet<T>.SortedSet<T>(SerializationInfo, StreamingContext) System.Collections.Generic.Dictionary<TKey,TValue>.Dictionary<TKey,TValue> (SerializationInfo, StreamingContext) System.Collections.Generic.Dictionary<TKey,TValue>.GetObjectData(SerializationInf o, StreamingContext) System.Collections.Generic.HashSet<T>.HashSet<T>(SerializationInfo, StreamingContext) System.Collections.Generic.HashSet<T>.GetObjectData(SerializationInfo, StreamingContext) System.Collections.Generic.KeyNotFoundException.KeyNotFoundException(Serializ ationInfo, StreamingContext) System.Collections.Specialized namespace System.Collections.Specialized.NameObjectCollectionBase.NameObjectCollectionB ase(SerializationInfo, StreamingContext) System.Collections.Specialized.NameObjectCollectionBase.GetObjectData(Serializat ionInfo, StreamingContext) System.Collections.Specialized.NameValueCollection.NameValueCollection(Serializa tionInfo, StreamingContext) System.Collections.Specialized.OrderedDictionary.OrderedDictionary(SerializationIn fo, StreamingContext) System.Collections.Specialized.OrderedDictionary.GetObjectData(SerializationInfo, StreamingContext) System.ComponentModel namespace System.ComponentModel.InvalidAsynchronousStateException.InvalidAsynchronous StateException(SerializationInfo, StreamingContext) System.ComponentModel.InvalidEnumArgumentException.InvalidEnumArgumentE xception(SerializationInfo, StreamingContext) System.ComponentModel.LicenseException.LicenseException(SerializationInfo, StreamingContext) System.ComponentModel.LicenseException.GetObjectData(SerializationInfo, StreamingContext) System.ComponentModel.WarningException.WarningException(SerializationInfo, StreamingContext) System.ComponentModel.WarningException.GetObjectData(SerializationInfo, StreamingContext) System.ComponentModel.Win32Exception.Win32Exception(SerializationInfo, StreamingContext) System.ComponentModel.Win32Exception.GetObjectData(SerializationInfo, StreamingContext) System.ComponentModel.Composition namespace System.ComponentModel.Composition.CompositionContractMismatchException.C ompositionContractMismatchException(SerializationInfo, StreamingContext) System.ComponentModel.Composition.ImportCardinalityMismatchException.Impor tCardinalityMismatchException(SerializationInfo, StreamingContext) System.ComponentModel.Composition.Primitives namespace System.ComponentModel.Composition.Primitives.ComposablePartException.Comp osablePartException(SerializationInfo, StreamingContext) System.ComponentModel.Composition.Primitives.ComposablePartException.GetOb jectData(SerializationInfo, StreamingContext) System.ComponentModel.DataAnnotations namespace System.ComponentModel.DataAnnotations.ValidationException.ValidationExceptio n(SerializationInfo, StreamingContext) System.ComponentModel.Design namespace System.ComponentModel.Design.CheckoutException.CheckoutException(Serializati onInfo, StreamingContext) System.Configuration namespace System.Configuration.ConfigurationErrorsException.ConfigurationErrorsException(S erializationInfo, StreamingContext) System.Configuration.ConfigurationErrorsException.GetObjectData(SerializationInf o, StreamingContext) System.Configuration.ConfigurationException.ConfigurationException(SerializationI nfo, StreamingContext) System.Configuration.ConfigurationException.GetObjectData(SerializationInfo, StreamingContext) System.Configuration.ConfigurationSectionCollection.GetObjectData(SerializationIn fo, StreamingContext) System.Configuration.ConfigurationSectionGroupCollection.GetObjectData(Serializ ationInfo, StreamingContext) System.Configuration.PropertyInformationCollection.GetObjectData(SerializationInf o, StreamingContext) System.Configuration.SettingsPropertyIsReadOnlyException.SettingsPropertyIsRead OnlyException(SerializationInfo, StreamingContext) System.Configuration.SettingsPropertyNotFoundException.SettingsPropertyNotFou ndException(SerializationInfo, StreamingContext) System.Configuration.SettingsPropertyWrongTypeException.SettingsPropertyWron gTypeException(SerializationInfo, StreamingContext) System.Configuration.Provider.ProviderException.ProviderException(SerializationInf o, StreamingContext) System.Configuration.SettingsPropertyIsReadOnlyException.SettingsPropertyIsRead OnlyException(SerializationInfo, StreamingContext) System.Configuration.SettingsPropertyNotFoundException.SettingsPropertyNotFou ndException(SerializationInfo, StreamingContext) System.Configuration.SettingsPropertyWrongTypeException.SettingsPropertyWron gTypeException(SerializationInfo, StreamingContext) System.Data namespace System.Data.ConstraintException.ConstraintException(SerializationInfo, StreamingContext) System.Data.DataException.DataException(SerializationInfo, StreamingContext) System.Data.DataSet.GetObjectData(SerializationInfo, StreamingContext) System.Data.DataTable.GetObjectData(SerializationInfo, StreamingContext) System.Data.DBConcurrencyException.GetObjectData(SerializationInfo, StreamingContext) System.Data.DeletedRowInaccessibleException.DeletedRowInaccessibleException(S erializationInfo, StreamingContext) System.Data.DuplicateNameException.DuplicateNameException(SerializationInfo, StreamingContext) System.Data.EvaluateException.EvaluateException(SerializationInfo, StreamingContext) System.Data.InRowChangingEventException.InRowChangingEventException(Serializ ationInfo, StreamingContext) System.Data.InvalidConstraintException.InvalidConstraintException(SerializationInfo , StreamingContext) System.Data.InvalidExpressionException.InvalidExpressionException(SerializationInf o, StreamingContext) System.Data.MissingPrimaryKeyException.MissingPrimaryKeyException(Serializatio nInfo, StreamingContext) System.Data.NoNullAllowedException.NoNullAllowedException(SerializationInfo, StreamingContext) System.Data.PropertyCollection.PropertyCollection(SerializationInfo, StreamingContext) System.Data.ReadOnlyException.ReadOnlyException(SerializationInfo, StreamingContext) System.Data.RowNotInTableException.RowNotInTableException(SerializationInfo, StreamingContext) System.Data.StrongTypingException.StrongTypingException(SerializationInfo, StreamingContext) System.Data.SyntaxErrorException.SyntaxErrorException(SerializationInfo, StreamingContext) System.Data.TypedTableBase<T>.TypedTableBase<T>(SerializationInfo, StreamingContext) System.Data.VersionNotFoundException.VersionNotFoundException(SerializationInf o, StreamingContext) System.Data.Common namespace System.Data.Common.DbException.DbException(SerializationInfo, StreamingContext) System.Data.Odbc namespace System.Data.Odbc.OdbcException.GetObjectData(SerializationInfo, StreamingContext) System.Data.OleDb namespace System.Data.OleDb.OleDbException.GetObjectData(SerializationInfo, StreamingContext) System.Data.SqlTypes namespace System.Data.SqlTypes.SqlTypeException.SqlTypeException(SerializationInfo, StreamingContext) System.Diagnostics.Eventing.Reader namespace System.Diagnostics.Eventing.Reader.EventLogException.EventLogException(Serializ ationInfo, StreamingContext) System.Diagnostics.Eventing.Reader.EventLogException.GetObjectData(Serializatio nInfo, StreamingContext) System.Diagnostics.Eventing.Reader.EventLogInvalidDataException.EventLogInvalid DataException(SerializationInfo, StreamingContext) System.Diagnostics.Eventing.Reader.EventLogNotFoundException.EventLogNotFou ndException(SerializationInfo, StreamingContext) System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException.EventLogP roviderDisabledException(SerializationInfo, StreamingContext) System.Diagnostics.Eventing.Reader.EventLogReadingException.EventLogReadingE xception(SerializationInfo, StreamingContext) System.Diagnostics.Tracing namespace System.Diagnostics.Tracing.EventSourceException.EventSourceException(Serializati onInfo, StreamingContext) System.DirectoryServices namespace System.DirectoryServices.DirectoryServicesCOMException.DirectoryServicesCOMEx ception(SerializationInfo, StreamingContext) System.DirectoryServices.DirectoryServicesCOMException.GetObjectData(Serializati onInfo, StreamingContext) System.DirectoryServices.AccountManagement namespace System.DirectoryServices.AccountManagement.MultipleMatchesException.Multiple MatchesException(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.NoMatchingPrincipalException.No MatchingPrincipalException(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PasswordException.PasswordExcept ion(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalException.PrincipalExceptio n(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalExistsException.PrincipalExi stsException(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalOperationException.Princip alOperationException(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalOperationException.GetOb jectData(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalServerDownException.Princ ipalServerDownException(SerializationInfo, StreamingContext) System.DirectoryServices.AccountManagement.PrincipalServerDownException.Get ObjectData(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory namespace System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectExistsException.Acti veDirectoryObjectExistsException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException .ActiveDirectoryObjectNotFoundException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException .GetObjectData(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryOperationException.Active DirectoryOperationException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryOperationException.GetOb jectData(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryServerDownException.Acti veDirectoryServerDownException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ActiveDirectoryServerDownException.Get ObjectData(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ForestTrustCollisionException.ForestTrustC ollisionException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.ForestTrustCollisionException.GetObjectD ata(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.SyncFromAllServersOperationException.Sy ncFromAllServersOperationException(SerializationInfo, StreamingContext) System.DirectoryServices.ActiveDirectory.SyncFromAllServersOperationException.G etObjectData(SerializationInfo, StreamingContext) System.DirectoryServices.Protocols namespace System.DirectoryServices.Protocols.BerConversionException.BerConversionExceptio n(SerializationInfo, StreamingContext) System.DirectoryServices.Protocols.DirectoryException.DirectoryException(Serializat ionInfo, StreamingContext) System.DirectoryServices.Protocols.DirectoryOperationException.DirectoryOperatio nException(SerializationInfo, StreamingContext) System.DirectoryServices.Protocols.DirectoryOperationException.GetObjectData(Se rializationInfo, StreamingContext) System.DirectoryServices.Protocols.LdapException.LdapException(SerializationInfo, StreamingContext) System.DirectoryServices.Protocols.LdapException.GetObjectData(SerializationInfo, StreamingContext) System.DirectoryServices.Protocols.TlsOperationException.TlsOperationException(S erializationInfo, StreamingContext) System.Formats.Asn1 namespace System.Formats.Asn1.AsnContentException.AsnContentException(SerializationInfo, StreamingContext) System.Formats.Cbor namespace System.Formats.Cbor.CborContentException.CborContentException(SerializationInf o, StreamingContext) System.Globalization namespace System.Globalization.CultureNotFoundException.CultureNotFoundException(Seriali zationInfo, StreamingContext) System.Globalization.CultureNotFoundException.GetObjectData(SerializationInfo, StreamingContext) System.IO namespace System.IO.DirectoryNotFoundException.DirectoryNotFoundException(SerializationI nfo, StreamingContext) System.IO.DriveNotFoundException.DriveNotFoundException(SerializationInfo, StreamingContext) System.IO.EndOfStreamException.EndOfStreamException(SerializationInfo, StreamingContext) System.IO.FileFormatException.FileFormatException(SerializationInfo, StreamingContext) System.IO.FileFormatException.GetObjectData(SerializationInfo, StreamingContext) System.IO.FileLoadException.FileLoadException(SerializationInfo, StreamingContext) System.IO.FileLoadException.GetObjectData(SerializationInfo, StreamingContext) System.IO.FileNotFoundException.FileNotFoundException(SerializationInfo, StreamingContext) System.IO.FileNotFoundException.GetObjectData(SerializationInfo, StreamingContext) System.IO.FileSystemInfo.FileSystemInfo(SerializationInfo, StreamingContext) System.IO.FileSystemInfo.GetObjectData(SerializationInfo, StreamingContext) System.IO.InternalBufferOverflowException.InternalBufferOverflowException(Seriali zationInfo, StreamingContext) System.IO.IOException.IOException(SerializationInfo, StreamingContext) System.IO.IsolatedStorage.IsolatedStorageException.IsolatedStorageException(Seri alizationInfo, StreamingContext) System.IO.PathTooLongException.PathTooLongException(SerializationInfo, StreamingContext) System.Management namespace System.Management.ManagementBaseObject.ManagementBaseObject(Serializatio nInfo, StreamingContext) System.Management.ManagementClass.ManagementClass(SerializationInfo, StreamingContext) System.Management.ManagementException.ManagementException(SerializationIn fo, StreamingContext) System.Management.ManagementException.GetObjectData(SerializationInfo, StreamingContext) System.Management.ManagementNamedValueCollection.ManagementNamedValu eCollection(SerializationInfo, StreamingContext) System.Media namespace System.Media.SoundPlayer.SoundPlayer(SerializationInfo, StreamingContext) System.Net namespace System.Net.CookieException.CookieException(SerializationInfo, StreamingContext) System.Net.CookieException.GetObjectData(SerializationInfo, StreamingContext) System.Net.FileWebRequest.FileWebRequest(SerializationInfo, StreamingContext) System.Net.FileWebResponse.FileWebResponse(SerializationInfo, StreamingContext) System.Net.HttpListenerException.HttpListenerException(SerializationInfo, StreamingContext) System.Net.HttpWebRequest.HttpWebRequest(SerializationInfo, StreamingContext) System.Net.HttpWebResponse.HttpWebResponse(SerializationInfo, StreamingContext) System.Net.ProtocolViolationException.ProtocolViolationException(SerializationInfo , StreamingContext) System.Net.ProtocolViolationException.GetObjectData(SerializationInfo, StreamingContext) System.Net.WebException.WebException(SerializationInfo, StreamingContext) System.Net.WebException.GetObjectData(SerializationInfo, StreamingContext) System.Net.WebHeaderCollection.WebHeaderCollection(SerializationInfo, StreamingContext) System.Net.WebHeaderCollection.GetObjectData(SerializationInfo, StreamingContext) System.Net.WebRequest.WebRequest(SerializationInfo, StreamingContext) System.Net.WebResponse.WebResponse(SerializationInfo, StreamingContext) System.Net.Mail namespace System.Net.Mail.SmtpException.SmtpException(SerializationInfo, StreamingContext) System.Net.Mail.SmtpException.GetObjectData(SerializationInfo, StreamingContext) System.Net.Mail.SmtpFailedRecipientException.SmtpFailedRecipientException(Serial izationInfo, StreamingContext) System.Net.Mail.SmtpFailedRecipientException.GetObjectData(SerializationInfo, StreamingContext) System.Net.Mail.SmtpFailedRecipientsException.SmtpFailedRecipientsException(Ser ializationInfo, StreamingContext) System.Net.Mail.SmtpFailedRecipientsException.GetObjectData(SerializationInfo, StreamingContext) System.Net.NetworkInformation namespace System.Net.NetworkInformation.NetworkInformationException.NetworkInformatio nException(SerializationInfo, StreamingContext) System.Net.NetworkInformation.PingException.PingException(SerializationInfo, StreamingContext) System.Net.Sockets namespace System.Net.Sockets.SocketException.SocketException(SerializationInfo, StreamingContext) System.Reflection namespace System.Reflection.Assembly.GetObjectData(SerializationInfo, StreamingContext) System.Reflection.AssemblyName.GetObjectData(SerializationInfo, StreamingContext) System.Reflection.CustomAttributeFormatException.CustomAttributeFormatExcepti on(SerializationInfo, StreamingContext) System.Reflection.InvalidFilterCriteriaException.InvalidFilterCriteriaException(Serializ ationInfo, StreamingContext) System.Reflection.Module.GetObjectData(SerializationInfo, StreamingContext) System.Reflection.ParameterInfo.GetRealObject(StreamingContext) System.Reflection.ReflectionTypeLoadException.GetObjectData(SerializationInfo, StreamingContext) System.Reflection.StrongNameKeyPair.StrongNameKeyPair(SerializationInfo, StreamingContext) System.Reflection.TargetException.TargetException(SerializationInfo, StreamingContext) System.Reflection.Metadata namespace System.Reflection.Metadata.ImageFormatLimitationException.ImageFormatLimitati onException(SerializationInfo, StreamingContext) System.Resources namespace System.Resources.MissingManifestResourceException.MissingManifestResourceExc eption(SerializationInfo, StreamingContext) System.Resources.MissingSatelliteAssemblyException.MissingSatelliteAssemblyExce ption(SerializationInfo, StreamingContext) System.Runtime.CompilerServices namespace System.Runtime.CompilerServices.RuntimeWrappedException.GetObjectData(Serial izationInfo, StreamingContext) System.Runtime.CompilerServices.SwitchExpressionException.GetObjectData(Seriali zationInfo, StreamingContext) System.Runtime.InteropServices namespace System.Runtime.InteropServices.ExternalException.ExternalException(SerializationIn fo, StreamingContext) System.Runtime.Serialization.SerializationException.SerializationException(Serializat ionInfo, StreamingContext) System.Runtime.Serialization namespace System.Runtime.Serialization.InvalidDataContractException.InvalidDataContractExc eption(SerializationInfo, StreamingContext) System.Security namespace System.Security.HostProtectionException.HostProtectionException(SerializationInfo, StreamingContext) System.Security.SecurityException.SecurityException(SerializationInfo, StreamingContext) System.Security.SecurityException.GetObjectData(SerializationInfo, StreamingContext) System.Security.VerificationException.VerificationException(SerializationInfo, StreamingContext) System.Security.AccessControl namespace System.Security.AccessControl.PrivilegeNotHeldException.GetObjectData(Serializati onInfo, StreamingContext) System.Security.Authentication namespace System.Security.Authentication.InvalidCredentialException.InvalidCredentialExcepti on(SerializationInfo, StreamingContext) System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.Exten dedProtectionPolicy(SerializationInfo, StreamingContext) System.Security.Claims namespace System.Security.Claims.ClaimsIdentity.ClaimsIdentity(SerializationInfo) System.Security.Claims.ClaimsIdentity.ClaimsIdentity(SerializationInfo, StreamingContext) System.Security.Claims.ClaimsPrincipal.ClaimsPrincipal(SerializationInfo, StreamingContext) System.Security.Cryptography namespace System.Security.Cryptography.CryptographicException.CryptographicException(Seri alizationInfo, StreamingContext) System.Security.Cryptography.CryptographicUnexpectedOperationException.Crypt ographicUnexpectedOperationException(SerializationInfo, StreamingContext) System.Security.Cryptography.X509Certificates.X509Certificate.X509Certificate(Seri alizationInfo, StreamingContext) System.Security.Cryptography.X509Certificates.X509Certificate2.X509Certificate2(Se rializationInfo, StreamingContext) System.Security.Policy namespace System.Security.Policy.Hash.GetObjectData(SerializationInfo, StreamingContext) System.Security.Policy.PolicyException.PolicyException(SerializationInfo, StreamingContext) System.Security.Principal namespace System.Security.Principal.IdentityNotMappedException.GetObjectData(Serialization Info, StreamingContext) System.Security.Principal.WindowsIdentity.WindowsIdentity(SerializationInfo, StreamingContext) System.Text.Json namespace System.Text.Json.JsonException.JsonException(SerializationInfo, StreamingContext) System.Text.Json.JsonException.GetObjectData(SerializationInfo, StreamingContext) System.Text.RegularExpressions namespace System.Text.RegularExpressions.RegexMatchTimeoutException.RegexMatchTimeout Exception(SerializationInfo, StreamingContext) System.Text.RegularExpressions.RegexParseException.GetObjectData(SerializationIn fo, StreamingContext) System.Threading namespace System.Threading.CompressedStack.GetObjectData(SerializationInfo, StreamingContext) System.Threading.ThreadInterruptedException.ThreadInterruptedException(Serializ ationInfo, StreamingContext) System.Threading.ThreadStateException.ThreadStateException(SerializationInfo, StreamingContext) System.Threading.BarrierPostPhaseException.BarrierPostPhaseException(Serializatio nInfo, StreamingContext) System.Threading.AbandonedMutexException.AbandonedMutexException(Serializa tionInfo, StreamingContext) System.Threading.ExecutionContext.GetObjectData(SerializationInfo, StreamingContext) System.Threading.LockRecursionException.LockRecursionException(SerializationInf o, StreamingContext) System.Threading.SemaphoreFullException.SemaphoreFullException(SerializationIn fo, StreamingContext) System.Threading.SynchronizationLockException.SynchronizationLockException(Ser ializationInfo, StreamingContext) System.Threading.WaitHandleCannotBeOpenedException.WaitHandleCannotBeOp enedException(SerializationInfo, StreamingContext) System.Threading.Channels namespace System.Threading.Channels.ChannelClosedException.ChannelClosedException(Seria lizationInfo, StreamingContext) System.Threading.Tasks namespace System.Threading.Tasks.TaskCanceledException.TaskCanceledException(Serializatio nInfo, StreamingContext) System.Threading.Tasks.TaskSchedulerException.TaskSchedulerException(Serializati onInfo, StreamingContext) System.Transactions namespace System.Transactions.TransactionAbortedException.TransactionAbortedException(Se rializationInfo, StreamingContext) System.Transactions.TransactionException.TransactionException(SerializationInfo, StreamingContext) System.Transactions.TransactionInDoubtException.TransactionInDoubtException(Se rializationInfo, StreamingContext) System.Transactions.TransactionManagerCommunicationException.TransactionMan agerCommunicationException(SerializationInfo, StreamingContext) System.Transactions.TransactionPromotionException.TransactionPromotionExceptio n(SerializationInfo, StreamingContext) System.Xml namespace System.Xml.XmlException.XmlException(SerializationInfo, StreamingContext) System.Xml.XmlException.GetObjectData(SerializationInfo, StreamingContext) System.Xml.Schema namespace System.Xml.Schema.XmlSchemaException.XmlSchemaException(SerializationInfo, StreamingContext) System.Xml.Schema.XmlSchemaException.GetObjectData(SerializationInfo, StreamingContext) System.Xml.Schema.XmlSchemaInferenceException.XmlSchemaInferenceException( SerializationInfo, StreamingContext) System.Xml.Schema.XmlSchemaInferenceException.GetObjectData(SerializationInfo , StreamingContext) System.Xml.Schema.XmlSchemaValidationException.XmlSchemaValidationExceptio n(SerializationInfo, StreamingContext) System.Xml.Schema.XmlSchemaValidationException.GetObjectData(SerializationInf o, StreamingContext) System.Xml.XPath namespace System.Xml.XPath.XPathException.XPathException(SerializationInfo, StreamingContext) System.Xml.XPath.XPathException.GetObjectData(SerializationInfo, StreamingContext) System.Xml.Xsl namespace System.Xml.Xsl.XsltCompileException.XsltCompileException(SerializationInfo, StreamingContext) System.Xml.Xsl.XsltCompileException.GetObjectData(SerializationInfo, StreamingContext) System.Xml.Xsl.XsltException.XsltException(SerializationInfo, StreamingContext) System.Xml.Xsl.XsltException.GetObjectData(SerializationInfo, StreamingContext) SYSLIB0053 AesGcm(Byte[]) AesGcm(ReadOnlySpan<Byte>) See also API obsoletions with non-default diagnostic IDs (.NET 7) API obsoletions with non-default diagnostic IDs (.NET 6) API obsoletions with non-default diagnostic IDs (.NET 5) Obsolete features in .NET 5+ Backslash mapping in Unix file paths Article • 02/01/2023 Backslash ( \ ) characters are valid in directory and file names on Unix. Starting in .NET 8, the native CoreCLR runtime no longer converts \ characters to directory separators— forward slashes ( / )—on Unix. This change enables .NET applications to be located on paths with names that contain backslash characters. It also allows the native runtime, dotnet host, and the ilasm and ildasm tools to access files on paths that contain backslash characters. Previous behavior The native CoreCLR runtime automatically converted backslash ( \ ) characters in file paths to forward slashes ( / ) on Unix. New behavior The native CoreCLR runtime doesn't convert any file path characters on Unix. Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change Without this change, .NET apps located in directories that contain backslash characters fail to start. Recommended action Use Path.DirectorySeparatorChar as a directory separator in your app instead of hardcoding it to \ or / . Use / as a directory separator on Unix in file paths that you pass to the dotnet host, hosting APIs, and ilasm and ildasm tools. Use / as a directory separator on Unix in file paths in various DOTNET_xxx environment variables. Affected APIs Hosting APIs System.Runtime.InteropServices.DllImportAttribute.Value System.Runtime.InteropServices.NativeLibrary.Load System.Runtime.InteropServices.NativeLibrary.TryLoad System.Reflection.Assembly.LoadFrom System.Reflection.Assembly.LoadFile System.Reflection.Assembly.UnsafeLoadFrom(String) System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String) System.Runtime.Loader.AssemblyLoadContext.LoadFromNativeImagePath(String, String) System.Runtime.Loader.AssemblyLoadContext.LoadUnmanagedDllFromPath(String ) Base64.DecodeFromUtf8 methods ignore whitespace Article • 06/13/2023 The Convert.FromBase64String(String), Convert.FromBase64CharArray(Char[], Int32, Int32), and corresponding Try methods on System.Convert ignore the ASCII whitespace characters ' ', '\t', '\r', and '\n' and allow any amount of such whitespace to be in the input. However, when the Base64.DecodeFromUtf8(ReadOnlySpan<Byte>, Span<Byte>, Int32, Int32, Boolean) and Base64.DecodeFromUtf8InPlace(Span<Byte>, Int32) methods were added, they didn't ignore these whitespace characters and instead failed to decode any input that included whitespace. That made the behavior of the UTF16-based APIs different from that of the UTF8-based APIs. It also meant that: The Base64.DecodeFromUtf8 and Base64.DecodeFromUtf8InPlace methods couldn't roundtrip the UTF-encoded base-64 encoded data produced by Convert.FromBase64String(String) with the Base64FormattingOptions.InsertLineBreaks option. The new IsValid(ReadOnlySpan<Char>) and IsValid(ReadOnlySpan<Byte>) methods would either need to have behavior inconsistent with each other or with their corresponding methods for UTF-16 and UTF-8 data on Convert and Base64. With this change, the DecodeFromUtf8(ReadOnlySpan<Byte>, Span<Byte>, Int32, Int32, Boolean) and DecodeFromUtf8InPlace(Span<Byte>, Int32) methods now ignore whitespace in the input. Previous behavior Base64.DecodeFromUtf8(ReadOnlySpan<Byte>, Span<Byte>, Int32, Int32, Boolean) and Base64.DecodeFromUtf8InPlace(Span<Byte>, Int32) failed to process input that contained whitespace and returned OperationStatus.InvalidData if any whitespace was encountered. New behavior Base64.DecodeFromUtf8(ReadOnlySpan<Byte>, Span<Byte>, Int32, Int32, Boolean) and Base64.DecodeFromUtf8InPlace(Span<Byte>, Int32) now ignore whitespace (specifically ' ', '\t', '\r', and '\n') in the input, which matches the behavior of Convert.FromBase64String(String). Version introduced .NET 8 Preview 5 Type of breaking change This change is a behavioral change. Reason for change The change was made so that: The Base64 methods can decode a wider range of input data, including: Data produced by Convert.ToBase64String with the Base64FormattingOptions.InsertLineBreaks option. Common formatting of data in configuration files and other real data sources. The Base64 methods are consistent with the corresponding decoding APIs on Convert. The new Base64.IsValid(ReadOnlySpan<Char>) and Base64.IsValid(ReadOnlySpan<Byte>) APIs could be added in a manner where their behavior is consistent with each other and with the existing Convert and Base64 APIs. Recommended action If the new behavior is problematic for your code, you can call IndexOfAny(" \t\r\n"u8) to search the input for the whitespace that previously would have triggered an InvalidData result. Affected APIs System.Buffers.Text.Base64.DecodeFromUtf8(ReadOnlySpan<Byte>, Span<Byte>, Int32, Int32, Boolean) System.Buffers.Text.Base64.DecodeFromUtf8InPlace(Span<Byte>, Int32) Boolean-backed enum type support removed Article • 08/03/2023 Support for formatting, parsing, and conversions of Boolean-backed enumeration types has been removed. Previous behavior Previously, formatting, parsing, or converting a Boolean-backed enumeration type was somewhat functional. New behavior Starting in .NET 8, an InvalidOperationException is thrown if you try to format, parse, or convert a Boolean-backed enumeration type. Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change This change was made to make the .NET runtime simpler, faster, and smaller. Formatting and parsing Boolean-backed enumeration types is never used in practice and complicates the implementation. Also, Boolean-backed enum types aren't expressible in C#. Recommended action If you're using a Boolean-backed enumeration type, use a regular Boolean type or a byte-backed enumeration type instead. Affected APIs System.Enum.Parse System.Enum.TryParse System.Enum.Format(Type, Object, String) System.Enum.GetName System.Enum.GetNames System.Enum.GetValues System.Enum.ToObject FileStream writes when pipe is closed Article • 01/31/2023 FileStream error handling on Windows has been updated to be consistent with NamedPipeServerStream, NamedPipeClientStream, AnonymousPipeServerStream, and AnonymousPipeClientStream. Previous behavior Previously, when writing to a FileStream that represented a closed or disconnected pipe, the underlying operating system error was ignored and the write was reported as successful. However, nothing was written to the pipe. New behavior Starting in .NET 8, when writing to a FileStream whose underlying pipe is closed or disconnected, the write fails and an IOException is thrown. Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change This change was made to unify the handling of edge cases and avoid silent errors that are difficult to diagnose. Recommended action Close or disconnect the pipe after everything has been written. Affected APIs System.IO.FileStream.WriteByte(Byte) System.IO.FileStream.Write System.IO.FileStream.WriteAsync GC.GetGeneration might return Int32.MaxValue Article • 05/05/2023 Starting in .NET 8, GC.GetGeneration might return Int32.MaxValue for objects allocated on non-GC heaps (also referred as "frozen" heaps), where previously it returned 2. When and how the runtime allocates objects on non-GC heaps is an internal implementation detail. String literals, for example, are allocated on a non-GC heap, and the following method call might return Int32.MaxValue. C# int gen = int GetGeneration("string"); Previous behavior Previously, GC.GetGeneration returned integer values in the range of 0-2. New behavior Starting in .NET 8, GC.GetGeneration can return a value of 0, 1, 2, or Int32.MaxValue. Version introduced .NET 8 Preview 4 Type of breaking change This change is a behavioral change. Reason for change .NET introduced a new, non-GC kind of heap that's slightly different from the existing heaps, which are large object heap (LOH), small object heap (SOH), and pinned object heap (POH). Recommended action Make sure you're not using the return value from GC.GetGeneration() as an array indexer or for anything else where Int32.MaxValue is unexpected. Affected APIs System.GC.GetGeneration(Object) System.GC.GetGeneration(WeakReference) GetFolderPath behavior on Unix Article • 01/26/2023 Starting in .NET 8, the behavior of Environment.GetFolderPath on Unix operating systems has changed. Change description The following tables show how the returned path value changes for each Unix operating system for various special folders. Linux SpecialFolder value Path (.NET 7 and earlier) Path (.NET 8 and later) MyDocuments $HOME Uses XDG_DOCUMENTS_DIR if available; otherwise $HOME/Documents Personal Uses XDG_DOCUMENTS_DIR if available; otherwise $HOME $HOME/Documents macOS SpecialFolder value Path (.NET 7 and earlier) Path (.NET 8 and later) MyDocuments $HOME NSDocumentDirectory ( $HOME/Documents ) Personal $HOME NSDocumentDirectory ( $HOME/Documents ) ApplicationData $HOME/.config NSApplicationSupportDirectory (Library/Application Support) LocalApplicationData $HOME/.local/share NSApplicationSupportDirectory (Library/Application Support) MyVideos $HOME/Videos NSMoviesDirectory ( $HOME/Movies ) Android SpecialFolder value Path (.NET 7 and earlier) Path (.NET 8 and later) SpecialFolder value Path (.NET 7 and earlier) Path (.NET 8 and later) MyDocuments $HOME $HOME/Documents Personal $HOME $HOME/Documents Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change The previous behavior was incorrect and didn't meet user expectations for Linux, macOS, and Android. Recommended action The most common break is if you're passing System.Environment.SpecialFolder.Personal to Environment.GetFolderPath(Environment+SpecialFolder) on Unix to get the $HOME directory ( Environment.GetFolderPath(Environment.SpecialFolder.Personal) ). Environment.SpecialFolder.Personal and Environment.SpecialFolder.MyDocuments are aliases for the same underlying enumeration value. If you're using Environment.SpecialFolder.Personal in this way, change your code to pass Environment.SpecialFolder.UserProfile instead ( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ). For other breaks, the recommended action is to do one of the following: Migrate your application's files to the appropriate directory. Add a fallback check for the previous location to your code. Affected APIs System.Environment.GetFolderPath(Environment+SpecialFolder) System.Environment.GetFolderPath(Environment+SpecialFolder, Environment+SpecialFolderOption) GetSystemVersion no longer returns ImageRuntimeVersion Article • 09/09/2023 RuntimeEnvironment.GetSystemVersion() no longer returns Assembly.ImageRuntimeVersion, which is a .NET Framework-oriented value. It's been updated to return a more relevant value, however, the historical leading v has been maintained. Previous behavior RuntimeEnvironment.GetSystemVersion() returned Assembly.ImageRuntimeVersion, which is an indicator of .NET Framework in-place replacement, not a product release. Example: v4.0.30319 New behavior Starting in .NET 8, RuntimeEnvironment.GetSystemVersion() returns "v" concatenated with Environment.Version, which is the version of the CLR. Example: v8.0.0 Version introduced .NET 8 RC 1 Type of breaking change This change is a behavioral change. Reason for change The existing version wasn't useful or meaningful for .NET. Recommended action Update your code to expect the new version, or use typeof(object).Assembly.ImageRuntimeVersion instead. Affected APIs System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion() See also The following changes are related: Improved .NET Core version APIs FrameworkDescription's value is .NET instead of .NET Core IndexOfAnyValues renamed to SearchValues Article • 06/13/2023 .NET 8 Preview 1 introduced a new System.Buffers.IndexOfAnyValues<T> type to speed up IndexOfAny -like operations. In .NET 8 Preview 5, the type has been renamed to SearchValues<T>. Previous behavior In previous preview versions of .NET 8, the affected types were named IndexOfAnyValues and System.Buffers.IndexOfAnyValues<T> . New behavior IndexOfAnyValues and System.Buffers.IndexOfAnyValues<T> are now named SearchValues and SearchValues<T>. Version introduced .NET 8 Preview 5 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change The type was renamed to SearchValues to allow us to extend its functionality in the future without making the name of the type misleading. IndexOfAnyValues was introduced in a previous preview version of .NET 8 as a way to cache computation associated with preparing any number of values for use in a search. We expected to only use it with IndexOfAny and possibly Contains . However, there are other places that could benefit from exposing overloads of other operations that would take an IndexOfAnyValues , like Count , Replace , or Remove , and in those contexts, the IndexOfAnyValues name doesn't make sense. Recommended action If you've written code using IndexOfAnyValues in a previous preview version of .NET 8, replace all usages with SearchValues . This should be as simple as a text-based find-andreplace of "IndexOfAnyValues" with "SearchValues". Affected APIs System.Buffers.IndexOfAnyValues<T> System.Buffers.IndexOfAnyValues.Create() System.MemoryExtensions.IndexOfAny<T>(ReadOnlySpan<T>, IndexOfAnyValues<T>) System.MemoryExtensions.IndexOfAny<T>(Span<T>, IndexOfAnyValues<T>) System.MemoryExtensions.IndexOfAnyExcept<T>(ReadOnlySpan<T>, IndexOfAnyValues<T>) System.MemoryExtensions.IndexOfAnyExcept<T>(Span<T>, IndexOfAnyValues<T>) ITypeDescriptorContext nullable annotations Article • 02/16/2023 System.ComponentModel.ITypeDescriptorContext has three properties that were previously annotated as being non-nullable, but they were actually nullable in practice. The nullable annotations for these properties have been updated to indicate that they're nullable. This change can result in new build warnings related to use of nullable members. Previous behavior Previously, the affected properties were annotated as not being nullable. You could consume their values and assume they weren't null without any compile-time warnings. New behavior Starting in .NET 8, the affected properties are annotated as being nullable. If you consume their values without null checks, you'll get warnings at compile time. Version introduced .NET 8 Preview 1 Type of breaking change This change can affect source compatibility. Reason for change The previous annotations of these properties were incorrect. This change applies the appropriate annotations for the properties and ensures callers understand that the values can be null . Recommended action Update calling code to guard against null for these properties. Affected APIs System.ComponentModel.ITypeDescriptorContext.Container System.ComponentModel.ITypeDescriptorContext.Instance System.ComponentModel.ITypeDescriptorContext.PropertyDescriptor Legacy Console.ReadKey removed Article • 01/31/2023 The ability to use the legacy Console.ReadKey implementation exposed via the System.Console.UseNet6CompatReadKey JSON setting and the DOTNET_SYSTEM_CONSOLE_USENET6COMPATREADKEY environment variable has been removed. Previous behavior Previously, you could request the .NET 6 console key parsing logic via a runtime configuration switch. New behavior Starting in .NET 8, you can't request the .NET 6 compatibility mode for Console.ReadKey. Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change The compatibility mode was introduced as a safety switch in case the Console.ReadKey implementation rewrite introduced any bugs. Only one bug was reported, and it was fixed in .NET 7, so there's no need to keep the previous implementation anymore. Recommended action If the new implementation doesn't work as expected, open a bug at https://github.com/dotnet/runtime/issues Affected APIs so it can be fixed. System.Console.ReadKey Method builders generate parameters with HasDefaultValue set to false Article • 08/29/2023 System.Reflection.Emit.ConstructorBuilder and System.Reflection.Emit.MethodBuilder now generate method parameters that, when reflected on, have ParameterInfo.HasDefaultValue set to false . Previous behavior Previously, ConstructorBuilder and MethodBuilder generated IL for method parameters where the HasDefaultValue of the parameters was set to true . New behavior Starting in .NET 8, ConstructorBuilder and MethodBuilder generate IL for method parameters where the HasDefaultValue of the parameters is set to false , which is the expected value. Version introduced .NET 8 Preview 5 Type of breaking change This change is a behavioral change. Reason for change The previous behavior was incorrect, as no default parameter values were specified when the method or constructor was defined. Recommended action If you use TypeBuilder.DefineConstructor or TypeBuilder.DefineMethod, make sure consumers of the generated types' methods don't rely on the ParameterInfo.HasDefaultValue property being true . Affected APIs System.Reflection.ParameterInfo.HasDefaultValue Removed Boolean-based overloads of ToFrozenDictionary/ToFrozenSet Article • 08/10/2023 Overloads of ToFrozenDictionary and ToFrozenSet previously allowed for a Boolean optimizeForReading argument to be supplied. These overloads have been removed in .NET 8 Preview 7. Previous behavior In .NET 8 Preview 1 through Preview 6, you could call overloads of ToFrozenDictionary and ToFrozenSet that had an optimizeForReading parameter. If you passed true , the implementations constructed instances of FrozenDictionary<TKey,TValue> and FrozenSet<T> that were optimized for performing lookups and reading data from the collections, at the expense of potentially much more time spent in the ToFrozenDictionary() and ToFrozenSet() calls. New behavior Starting in .NET 8 Preview 7, the affected overloads have been removed. Now all of the ToFrozenDictionary and ToFrozenSet overloads spend extra time to construct a collection that's optimized for reading. Version introduced .NET 8 Preview 7 Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change Construction performance has been optimized such that it now no longer makes sense to differentiate modes. ToFrozenDictionary() and ToFrozenSet() now always produce implementations optimized for reading, regardless of which overload is used. Recommended action If you called the overloads that had a Boolean parameter, remove the Boolean argument from the call site. Affected APIs System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary<TKey,TValue> (System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePai r<TKey,TValue>>,System.Boolean) System.Collections.Frozen.FrozenDictionary.ToFrozenDictionary<TKey,TValue> (System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePai r<TKey,TValue>>,System.Collections.Generic.IEqualityComparer<TKey,TValue>,Syst em.Boolean) System.Collections.Frozen.FrozenSet.ToFrozenSet<TKey,TValue> (System.Collections.Generic.IEnumerable<TKey,TValue>,System.Boolean) System.Collections.Frozen.FrozenSet.ToFrozenSet<TKey,TValue> (System.Collections.Generic.IEnumerable<TKey,TValue>,System.Collections.Generi c.IEqualityComparer<TKey,TValue>,System.Boolean) RuntimeIdentifier returns platform for which the runtime was built Article • 09/09/2023 RuntimeInformation.RuntimeIdentifier returns the platform for which the runtime was built, rather than a value computed at run time. Previous behavior The value was a runtime identifier (RID) computed via OS files or APIs. This generally meant it was a version-specific and distro-specific RID. For example, when running an application on Windows 11, the value was win10-x64 or, on Ubuntu 20.04, it could be ubuntu.20.04-x64 . New behavior Starting in .NET 8, the value is the RID for which the runtime was built. This means that for portable builds of the runtime (all Microsoft-provided builds), the value is nonversion-specific and non-distro-specific. For example, the value on Windows 11 is winx64 , and on Ubuntu 20.04, it's linux-x64 . For non-portable builds (source-build), the build sets a build RID that can have a version and distro, and that value is the RID that's returned. Version introduced .NET 8 RC 1 Type of breaking change This change is a behavioral change. Reason for change This change is in line with a .NET 8 change to RID-specific asset resolution and the move away from a distro-aware runtime. RuntimeInformation.RuntimeIdentifier is an opaque value that should represent the platform on which the host or runtime considers itself to be running. In .NET 8, that corresponds to the platform for which the host or runtime is built, rather than an RID computed at run time. Recommended action RuntimeInformation.RuntimeIdentifier is an opaque value and not intended to be parsed into its component parts. For the OS version of the actual machine an application is running on, use Environment.OSVersion. For a description, use RuntimeInformation.OSDescription. For a specific ID (distro) and corresponding version on Linux, you can read the os-release file. Affected APIs System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier See also .NET SDK uses a smaller RID graph Host determines RID-specific assets AesGcm authentication tag size on macOS Article • 01/25/2023 AesGcm on macOS only supports 16-byte (128-bit) authentication tags when using Encrypt or Decrypt in .NET 8 and later versions. Previous behavior On macOS, Encrypt and Decrypt supported authentication tag sizes ranging from 12 to 16 bytes, provided OpenSSL was available. In addition, the AesGcm.TagByteSizes property reported that it supported sizes ranging from 12 to 16 bytes, inclusive. New behavior On macOS, Encrypt and Decrypt support 16-byte authentication tags only. If you use a smaller tag size on macOS, an ArgumentException is thrown at run time. The AesGcm.TagByteSizes property returns a value of 16 as the supported tag size. Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change The AesGcm class on macOS previously relied on OpenSSL for underlying support. OpenSSL is an external dependency that needed to be installed and configured separately from .NET. AesGcm now uses Apple's CryptoKit to provide an implementation of Advanced Encryption Standard with Galois/Counter Mode (AES-GCM) so that OpenSSL is no longer a dependency for using AesGcm. The CryptoKit implementation of AES-GCM does not support authentication tag sizes other than 128-bits (16-bytes). Recommended action Use 128-bit authentication tags with AesGcm for macOS support. Affected APIs System.Security.Cryptography.AesGcm.TagByteSizes System.Security.Cryptography.AesGcm.Encrypt System.Security.Cryptography.AesGcm.Decrypt RSA.EncryptValue and RSA.DecryptValue are obsolete Article • 01/25/2023 The following methods are obsolete in .NET 8 (and later versions): RSA.EncryptValue(Byte[]) RSA.DecryptValue(Byte[]) RSACryptoServiceProvider.EncryptValue(Byte[]) RSACryptoServiceProvider.DecryptValue(Byte[]) All references to these methods will result in a SYSLIB0048 warning at compile time. Previous behavior Previously, code could call the affected methods without any compilation warnings. However, they threw a NotSupportedException at run time. New behavior Starting in .NET 8, calling the affected methods produces a SYSLIB0048 compilation warning. Version introduced .NET 8 Preview 1 Type of breaking change This change can affect source compatibility. Reason for change The affected methods were never implemented and always threw a NotSupportedException. Since the purpose of these methods is unclear and they shouldn't be called, they were marked as obsolete. Recommended action To encrypt or decrypt with RSA, use RSA.Encrypt or RSA.Decrypt instead. Affected APIs System.Security.Cryptography.RSA.EncryptValue(Byte[]) System.Security.Cryptography.RSA.DecryptValue(Byte[]) System.Security.Cryptography.RSACryptoServiceProvider.EncryptValue(Byte[]) System.Security.Cryptography.RSACryptoServiceProvider.DecryptValue(Byte[]) Host determines RID-specific assets Article • 08/22/2023 When running an application with RID-specific assets, the host determines which assets are relevant for the platform on which it's running. This applies to both the application itself and the resolution logic used by AssemblyDependencyResolver. Previously, the host tried to compute the RID at run time and then read the RID graph to determine which RID-specific assets matched or were compatible with the computed RID. Now, the default behavior doesn't compute the RID or use the RID graph. Instead, the host relies on a known list of RIDs based on how the runtime itself was built. Previous behavior Previously, the process for selecting RID-specific assets was: 1. Read the RID graph from the .deps.json file of the root framework (Microsoft.NetCore.App). 2. Compute the current RID at run time and try to find an entry for it in the RID graph. If it doesn't exist, check for a fallback RID (built into the host at compile time). 3. Starting from the entry found in the RID graph, look for assets matching that RID. 4. Continue down the list of RIDs in the RID graph entry until an asset match is found or the list ends. If the RID graph didn't have the computed RID or the fallback RID, RID assets weren't properly resolved. New behavior By default, the process no longer relies on the RID graph. Instead, it checks for a known set of portable RIDs based on how the host was built. For example: Linux linux-x64 linux unix-x64 unix any Windows win-x64 win any macOS osx-x64 osx unix-x64 unix For non-portable builds of the host or runtime, the build might also set a non-portable RID that's checked first. Version introduced .NET 8 Preview 5 Type of breaking change This change can affect binary compatibility and is also a behavioral change. Reason for change The RID graph was costly to maintain and understand, requiring .NET itself to be distroaware in a fragile manner. The .NET team and the community spend a non-trivial amount of time updating the graph and backporting such updates to previous releases. The long-term goal is to stop updating the RID graph, stop reading it, and eventually remove it. This breaking change is a step towards that goal. Recommended action Use portable RIDs, for example, linux , linux-musl , osx , and win . For specialized use cases, you can use APIs like NativeLibrary.SetDllImportResolver(Assembly, DllImportResolver) or AssemblyLoadContext.ResolvingUnmanagedDll for custom loading logic. If you need to revert to the previous behavior, set the backwards compatibility switch System.Runtime.Loader.UseRidGraph to true in your runtimeconfig.json file. Setting the switch to true instructs the host to use the previous behavior of reading the RID graph. Alternatively, you can add a RuntimeHostConfigurationOption MSBuild item in your project file. For example: XML <ItemGroup> <RuntimeHostConfigurationOption Include="System.Runtime.Loader.UseRidGraph" Value="true" /> </ItemGroup> Affected APIs System.Runtime.Loader.AssemblyDependencyResolver StripSymbols defaults to true Article • 05/09/2023 When .NET 7 introduced Native AOT deployment, it also introduced the StripSymbols property that optionally allows debugging symbols to be stripped from the produced executable on Linux into a separate file. The default value of the property was false . In .NET 8, the default value has changed to true . Previous behavior With PublishAOT , debugging symbols on Linux were placed into the produced executable by default, with an opt-in option to place them into a separate .dbg file. New behavior With PublishAOT , debugging symbols on Linux are placed into a .dbg file by default, with an opt-out option to place them into the executable. Version introduced .NET 8 Preview 4 Reason for change Based on feedback, we determined that .NET users prefer the .NET-symbols convention instead of the platform-native convention. However, the option to strip the symbols was not discoverable enough. Recommended action If you rely on debugging symbols to be present in the main executable, add <StripSymbols>false</StripSymbols> to your project file to restore the previous behavior. If you choose to use the new default, verify that the debugging symbols in .dbg files are properly archived if you expect you'll need to debug the generated executables. Affected APIs None. Breaking changes in EF Core 8.0 (EF8) Article • 08/24/2023 This page documents API and behavior changes that have the potential to break existing applications updating to EF Core 8.0. Summary Breaking change Impact SQL Server date and time now scaffold to .NET DateOnly and TimeOnly Medium SQLite Math methods now translate to SQL Low Medium-impact changes SQL Server date and time now scaffold to .NET DateOnly and TimeOnly Tracking Issue #24507 Old behavior Previously, when scaffolding a SQL Server database with date or time columns, EF would generate entity properties with types DateTime and TimeSpan. New behavior Starting with EF Core 8.0, date and time are scaffolded as DateOnly and TimeOnly. Why DateOnly and TimeOnly were introduced in .NET 6.0, and are a perfect match for mapping the database date and time types. DateTime notably contains a time component that goes unused and can cause confusion when mapping it to date , and TimeSpan represents a time interval - possibly including days - rather than a time of day at which an event occurs. Using the new types prevents bugs and confusion, and provides clarity of intent. Mitigations This change only affects users which regularly re-scaffold their database into an EF code model ("database-first" flow). It is recommended to react to this change by modifying your code to use the newly scaffolded DateOnly and TimeOnly types. However, if that isn't possible, you can edit the scaffolding templates to revert to the previous mapping. To do this, set up the templates as described on this page. Then, edit the EntityType.t4 file, find where the entity properties get generated (search for property.ClrType ), and change the code to the following: c# var clrType = property.GetColumnType() switch { "date" when property.ClrType == typeof(DateOnly) => typeof(DateTime), "date" when property.ClrType == typeof(DateOnly?) => typeof(DateTime?), "time" when property.ClrType == typeof(TimeOnly) => typeof(TimeSpan), "time" when property.ClrType == typeof(TimeOnly?) => typeof(TimeSpan?), _ => property.ClrType }; usings.AddRange(code.GetRequiredUsings(clrType)); var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !clrType.IsValueType; var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !clrType.IsValueType; #> public <#= code.Reference(clrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> <# Low-impact changes SQLite Math methods now translate to SQL Tracking Issue #18843 Old Behavior Previously only the Abs, Max, Min, and Round methods on Math were translated to SQL. All other members would be evaluated on the client if they appeared in the final Select expression of a query. New behavior In EF Core 8.0, all Math methods with corresponding SQLite math functions are translated to SQL. These math functions have been enabled in the native SQLite library that we provide by default (through our dependency on the SQLitePCLRaw.bundle_e_sqlite3 NuGet package). They have also been enabled in the library provided by SQLitePCLRaw.bundle_e_sqlcipher. If you're using one of these libraries, your application should not be affected by this change. There is a chance, however, that applications including the native SQLite library by other means may not enable the math functions. In these cases, the Math methods will be translated to SQL and encounter no such function errors when executed. Why SQLite added built-in math functions in version 3.35.0. Even though they're disabled by default, they've become pervasive enough that we decided to provide default translations for them in our EF Core SQLite provider. We also collaborated with Eric Sink on the SQLitePCLRaw project to enable math functions in all of the native SQLite libraries provided as part of that project. Mitigations The simplest way to fix breaks is, when possible, to enable the math function is the native SQLite library by specifying the SQLITE_ENABLE_MATH_FUNCTIONS compile- time option. If you don't control compilation of the native library, you can also fix breaks by create the functions yourself at runtime using the Microsoft.Data.Sqlite APIs. C# sqliteConnection .CreateFunction<double, double, double>( "pow", Math.Pow, isDeterministic: true); Alternatively, you can force client-evaluation by splitting the Select expression into two parts separated by AsEnumerable . C# // Before var query = dbContext.Cylinders .Select( c => new { Id = c.Id // May throw "no such function: pow" Volume = Math.PI * Math.Pow(c.Radius, 2) * c.Height }); // After var query = dbContext.Cylinders // Select the properties you'll need from the database .Select( c => new { c.Id, c.Radius, c.Height }) // Switch to client-eval .AsEnumerable() // Select the final results .Select( c => new { Id = c.Id, Volume = Math.PI * Math.Pow(c.Radius, 2) * c.Height }); ActivatorUtilities.CreateInstance behaves consistently Article • 03/08/2023 The behavior of ActivatorUtilities.CreateInstance is now more consistent with CreateFactory(Type, Type[]). When IServiceProviderIsService isn't present in the dependency injection (DI) container, CreateInstance falls back to the CreateFactory(Type, Type[]) logic. In that logic, only one constructor is allowed to match with all the provided input parameters. In the more general case when IServiceProviderIsService is present, the CreateInstance API prefers the longest constructor overload that has all its arguments available. The arguments can be input to the API, registered in the container, or available from default values in the constructor itself. Consider the following class definition showing two constructors: C# public class A { A(B b, C c, string st = "default string") { } A() { } } For this class definition, and when IServiceProviderIsService is present, ActivatorUtilities.CreateInstance<A>(serviceProvider, new C()) instantiates A by picking the first constructor that takes B , C , and string . Version introduced .NET 8 Preview 1 Previous behavior ActivatorUtilities.CreateInstance behaved unexpectedly in some cases. It made sure all required instances passed to it existed in the chosen constructor. However, the constructor selection was buggy and unreliable. New behavior CreateInstance tries to find the longest constructor that matches all parameters based on the behavior of IServiceProviderIsService. If no constructors are found or if IServiceProviderIsService isn't present, it falls back to CreateFactory(Type, Type[]) logic. If it finds more than one constructor, it throws an InvalidOperationException. 7 Note If IServiceProviderIsService is configured incorrectly or doesn't exist, CreateInstance may function incorrectly or ambiguously. Type of breaking change This change is a behavioral change. Reason for change This change was introduced to fix a bug where the behavior changed depending on the order of constructor overload definitions. Recommended action If your app starts behaving differently or throwing an exception after upgrading to .NET 8, carefully examine the constructor definitions for the affected instance type. Refer to the New behavior section. Affected APIs Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance<T> (IServiceProvider, Object[]) Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IService Provider, Type, Object[]) See also ActivatorUtilities.CreateInstance requires non-null provider ActivatorUtilities.CreateInstance requires non-null provider Article • 03/08/2023 The two ActivatorUtilities.CreateInstance methods now throw an ArgumentNullException exception if the provider parameter is null . Version introduced .NET 8 Preview 1 Previous behavior A null value was allowed for the provider parameter. In some cases, the specified type was still created correctly. New behavior When provider is null , an ArgumentNullException exception is thrown. Type of breaking change This change is a behavioral change. Reason for change We fixed various the parameter validation along with constructor-matching issues to align with the intended purpose of CreateInstance. The CreateInstance() methods have a non-nullable provider parameter, so it was generally expected that a null provider wasn't allowed. Recommended action Pass a non-null IServiceProvider for the provider argument. If the provider also implements IServiceProviderIsService, constructor arguments can be obtained through that. Alternatively, if your scenario doesn't require dependency injection, since IServiceProvider is null , use Activator.CreateInstance instead. Affected APIs Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance<T> (IServiceProvider, Object[]) Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IService Provider, Type, Object[]) See also ActivatorUtilities.CreateInstance behaves consistently ConfigurationBinder throws for mismatched value Article • 03/08/2023 Previously, BinderOptions.ErrorOnUnknownConfiguration was used solely to raise an exception if a value existed in the configuration but not in the model being bound to. Now, if this property is set to true , an exception is also thrown if the value in the configuration can't be converted to the type of value in the model. Version introduced .NET 8 Preview 1 Previous behavior Previously, the following code silently swallowed the exceptions for the fields that contained invalid enums: C# public enum TestSettingsEnum { Option1, Option2, } public class MyModelContainingArray { public TestSettingsEnum[] Enums { get; set; } } public void SilentlySwallowsInvalidItems() { var dictionary = new Dictionary<string, string> { ["Section:Enums:0"] = "Option1", ["Section:Enums:1"] = "Option3", // invalid - ignored ["Section:Enums:2"] = "Option4", // invalid - ignored ["Section:Enums:3"] = "Option2", }; var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(dictionary); var config = configurationBuilder.Build(); var configSection = config.GetSection("Section"); var model = configSection.Get<MyModelContainingArray>(o => o.ErrorOnUnknownConfiguration = true); // Only Option1 and Option2 are in the bound collection at this point. } New behavior Starting in .NET 8, if a configuration value can't be converted to the type of the value in the model, an InvalidOperationException is thrown. Type of breaking change This change is a behavioral change. Reason for change The previous behavior was confusing for some developers. They set BinderOptions.ErrorOnUnknownConfiguration to true and expected an exception to be thrown if any issue was encountered when the configuration was bound. Recommended action If your app has configuration values that can't be converted to the properties in the bound model, change or remove the values. Alternatively, set BinderOptions.ErrorOnUnknownConfiguration to false . Affected APIs Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration, Object, Action<BinderOptions>) Microsoft.Extensions.Configuration.ConfigurationBinder.Get<T>(IConfiguration, Action<BinderOptions>) Microsoft.Extensions.Configuration.ConfigurationBinder.Get(IConfiguration, Type, Action<BinderOptions>) ConfigurationManager package no longer references System.Security.Permissions Article • 08/29/2023 The System.Configuration.ConfigurationManager package no longer references the System.Security.Permissions package. Version introduced .NET 8 Preview 3 Previous behavior The System.Configuration.ConfigurationManager package referenced the System.Security.Permissions package. New behavior Starting in .NET 8, the System.Configuration.ConfigurationManager package does not reference the System.Security.Permissions package. Type of breaking change This change can affect source compatibility. Reason for change This change avoids a dependency on System.Drawing.Common when System.Configuration.ConfigurationManager is referenced, which is primarily an issue for non-Windows operating systems. The dependency on System.Drawing.Common was caused by the following package dependencies: txt System.Configuration.ConfigurationManager └──System.Security.Permissions └──System.Windows.Extensions └──System.Drawing.Common Recommended action If your app references the System.Configuration.ConfigurationManager package and you also have a dependency on System.Security.Permissions or any of its dependencies, which might include System.Windows.Extensions , System.Security.AccessControl , or System.Drawing.Common , you'll need to reference those packages either directly or indirectly. Affected APIs N/A DirectoryServices package no longer references System.Security.Permissions Article • 08/29/2023 The System.DirectoryServices package no longer references the System.Security.Permissions package. Version introduced .NET 8 Preview 3 Previous behavior The System.DirectoryServices package referenced the System.Security.Permissions package. New behavior Starting in .NET 8, the System.DirectoryServices package does not reference the System.Security.Permissions package. Type of breaking change This change can affect source compatibility. Reason for change This change avoids a dependency on System.Drawing.Common when System.DirectoryServices is referenced, which is primarily an issue for non-Windows operating systems. The dependency on System.Drawing.Common was caused by the following package dependencies: txt System.DirectoryServices └──System.Security.Permissions └──System.Windows.Extensions └──System.Drawing.Common Recommended action If your app references the System.DirectoryServices package and you also have a dependency on System.Security.Permissions or any of its dependencies, which might include System.Windows.Extensions or System.Drawing.Common , you'll need to reference those packages either directly or indirectly. Affected APIs N/A Empty keys added to dictionary by configuration binder Article • 07/31/2023 In previous versions, when configuration was bound to a dictionary type, any keys without corresponding values in the configuration were skipped and weren't added to the dictionary. The behavior has changed such that those keys are longer skipped but instead automatically created with their default values. This change ensures that all keys listed in the configuration will be present within the dictionary. Version introduced .NET 8 Preview 5 Previous behavior Previously, empty keys in the configuration were skipped when bound to a dictionary type. Consider the following configuration string and binding code. C# var json = @"{ ""Queues"": { ""q1"": { ""V"": 1 }, ""q2"": { ""V"": 2 }, ""q3"": { } } }"; C# public class Q { public Dictionary<string, QueueValue> Queues { get; set; } = new(); } public class QueueValue { public int V { get; set; } } var configuration = new ConfigurationBuilder() .AddJsonStream(StringToStream(json)) .Build(); Q options = new Q(); configuration.Bind(options); foreach (var kvp in options.Queues) { Console.WriteLine($"{kvp.Key}: {kvp.Value.V}"); } Previously, you'd see the following output (notice that key q3 is missing): Output q1: 1 q2: 2 New behavior Starting in .NET 8, empty configuration keys are added to the dictionary with their default value during configuration binding. Consider the code from the previous behavior section, which now outputs the following text showing that q3 was added to the dictionary with its default value: Output q1: 1 q2: 2 q3: 0 Type of breaking change This change is a behavioral change. Reason for change This user-requested change ensures that all keys listed in the configuration are present within the dictionary. Having all keys present streamlines the process and avoids potential issues with missing keys. Recommended action Verify and adapt your application logic to accommodate the presence of the newly created dictionary entries with empty values. If the new behavior is undesirable, remove empty-value entries from the configuration. By eliminating these entries, no dictionary entries with empty values will be added during the binding process. Affected APIs Microsoft.Extensions.Configuration.ConfigurationBinder IConfigurationRoot extension methods Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionE xtensions HostApplicationBuilderSettings.Args respected by HostApplicationBuilder ctor Article • 03/14/2023 The HostApplicationBuilder constructor that accepts a HostApplicationBuilderSettings object now applies the HostApplicationBuilderSettings.Args property, regardless of whether DisableDefaults is set to true or false . Version introduced .NET 8 Preview 2 Previous behavior Previously, the HostApplicationBuilderSettings.Args property was ignored when HostApplicationBuilderSettings.DisableDefaults was set to true . New behavior Starting in .NET 8, the HostApplicationBuilderSettings.Args value is added to HostApplicationBuilder.Configuration regardless of whether DisableDefaults is set to true or false . Type of breaking change This change is a behavioral change. Reason for change The behavior of ignoring HostApplicationBuilderSettings.Args was unexpected, even when HostApplicationBuilderSettings.DisableDefaults was set to true . That's because if the caller didn't want the command-line arguments applied to the HostApplicationBuilder, they wouldn't have set them on the HostApplicationBuilderSettings object. Since the caller did pass the command-line arguments on the settings, those arguments should be respected. Recommended action If you don't want the command-line arguments to be added to the HostApplicationBuilder configuration, leave the HostApplicationBuilderSettings.Args property set to null . Affected APIs HostApplicationBuilder(HostApplicationBuilderSettings) Date and time converters honor culture argument Article • 05/08/2023 The ConvertTo methods on the following classes now use the culture from the culture parameter as the format provider for the date and time instead of CultureInfo.CurrentCulture: DateOnlyConverter DateTimeConverter DateTimeOffsetConverter TimeOnlyConverter Previous behavior Previously, the affected APIs used CultureInfo.CurrentCulture as the format provider for the date and time even though the caller specified a culture in the culture parameter. Consider the following code snippet that sets the current culture to Spanish (Spain) but passes a customized French culture to DateTimeConverter.ConvertTo(ITypeDescriptorContext, CultureInfo, Object, Type). C# CultureInfo.CurrentCulture = new CultureInfo("es-ES"); Console.WriteLine($"Current culture: {CultureInfo.CurrentCulture}"); var dt1 = new DateTime(2022, 8, 1); var frCulture = new CultureInfo("fr-FR"); frCulture.DateTimeFormat.ShortDatePattern = "dd MMMM yyyy"; Console.WriteLine(TypeDescriptor.GetConverter(dt1).ConvertTo(null, frCulture, dt1, typeof(string))); In .NET 7 and earlier versions, this code prints the date in the correct format but with the name of the month in Spanish instead of French: Output Current culture: es-ES 01 agosto 2022 New behavior Starting in .NET 8, the affected APIs use the culture specified by the culture parameter as the format provider. The code snippet shown in the Previous behavior correctly prints the name of the month in French: Output Current culture: es-ES 01 août 2022 Version introduced .NET 8 Preview 4 Type of breaking change This change is a behavioral change. Reason for change This change fixes a bug where ConvertTo was not consistent with ConvertFrom . It used the date and time format strings from the input culture but formatted the date and time with CurrentCulture. Recommended action If you relied on the previous behavior, pass in CultureInfo.CurrentCulture, null , or a custom culture for the culture parameter. Affected APIs System.ComponentModel.DateOnlyConverter.ConvertTo(ITypeDescriptorContext, CultureInfo, Object, Type) System.ComponentModel.DateTimeConverter.ConvertTo(ITypeDescriptorContext, CultureInfo, Object, Type) System.ComponentModel.DateTimeOffsetConverter.ConvertTo(ITypeDescriptorCon text, CultureInfo, Object, Type) System.ComponentModel.TimeOnlyConverter.ConvertTo(ITypeDescriptorContext, CultureInfo, Object, Type) TwoDigitYearMax default is 2049 Article • 01/27/2023 Calendar classes, such as GregorianCalendar, have a TwoDigitYearMax property that defines the last year of a 100-year range that can be represented by a two-digit year. This property is often used to translate a two-digit year to a four-digit year. Previously, Calendar.TwoDigitYearMax defaulted to 2029 for GregorianCalendar and other Gregorian-like calendars, such as JulianCalendar and EastAsianLunisolarCalendar. That value meant that two-digit years from 00 to 29 translated to 2000-2029. Two-digit years from 30 to 99 translated to 1930-1999. The default TwoDigitYearMax property value for GregorianCalendar and other Gregorian-like calendars has now changed from 2029 to 2049. The new value means that two-digit years from 00 to 49 are translated to 20002049. Any year from 50 to 99 will be translated to 1950-1999. In addition, on Windows, the default value of the TwoDigitYearMax property is now obtained from the corresponding Windows setting (the default value for which is now also 2049). This matches the behavior prior to .NET 5. Date parsing is the functionality that's most affected by this change. Previous behavior In .NET 6 and .NET 7, if you didn't specify a value for TwoDigitYearMax, parsing a string like "12/10/35" with the Gregorian calendar produced the date "December 10th, 1935". New behavior Starting in .NET 8, parsing a string like "12/10/35" with the Gregorian calendar produces the date "December 10th, 2035". Version introduced .NET 8 Preview 1 Type of breaking change This change is a behavioral change. Reason for change It's more logical to parse a two-digit year that's relatively close to the two digits of the current year to produce a four-digit year in the current century instead of the previous one. The Windows operating system also changed its default settings to the same number (2049). Recommended action If you don't want your app to depend on the default value when parsing a string to a date, you can control how a two-digit year is translated to a four-digit year by setting the TwoDigitYearMax property. The following code shows how to set it for the invariant culture. C# CultureInfo clonedInvariantCulture = (CultureInfo) (CultureInfo.InvariantCulture.Clone()); clonedInvariantCulture.DateTimeFormat.Calendar.TwoDigitYearMax = 2039; // Use any desired cutoff value. DateTime dt = DateTime.Parse("12/25/45", clonedInvariantCulture); Affected APIs System.DateOnly.Parse System.DateOnly.ParseExact System.DateOnly.TryParse System.DateOnly.TryParseExact System.DateTime.Parse System.DateTime.ParseExact System.DateTime.TryParse System.DateTime.TryParseExact System.DateTimeOffset.Parse System.DateTimeOffset.ParseExact System.DateTimeOffset.TryParse System.DateTimeOffset.TryParseExact System.Globalization.GregorianCalendar.TwoDigitYearMax (and other Gregorianlike calendar types) System.Globalization.GregorianCalendar.ToDateTime (and other Gregorian-like calendar types) System.Globalization.GregorianCalendar.ToFourDigitYear(Int32) (and other Gregorian-like calendar types) See also Parse date and time strings in .NET CreateObjectFlags.Unwrap only unwraps on target instance Article • 06/13/2023 Previously, if you called GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags) on a ComWrappers instance with the CreateObjectFlags.Unwrap flag, a managed object wrapper was unwrapped from any ComWrappers instance. Now when the flag is specified, only wrappers from the ComWrappers instance that GetOrCreateObjectFromComInstance was called on are unwrapped. The Unwrap flag was the only API that reached "across" ComWrappers instances, so its behavior was unintuitive. Additionally, the new ComWrappers.TryGetObject(IntPtr, Object) API is available to unwrap a COM object from any ComWrappers instance. Previous behavior Calling GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags) on a ComWrappers instance with the CreateObjectFlags.Unwrap flag unwrapped a managed object wrapper from any ComWrappers instance. New behavior Calling GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags) on a ComWrappers instance with the CreateObjectFlags.Unwrap flag only unwraps a managed object wrapper from the ComWrappers instance that GetOrCreateObjectForComInstance was called on. If given a wrapper from a different ComWrappers instance, the ComWrappers instance creates a new wrapper. Version introduced .NET 8 Preview 5 Type of breaking change This change is a behavioral change. Reason for change The previous behavior was unintuitive. It also broke the encapsulation experience where developers can define how COM interop works for their code by using their own custom ComWrappers instances. Recommended action If you want to keep the previous behavior, call ComWrappers.TryGetObject(IntPtr, Object) before calling GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags). Affected APIs System.Runtime.InteropServices.ComWrappers.GetOrCreateObjectForComInstance (IntPtr, CreateObjectFlags) Custom marshallers require additional members Article • 09/08/2023 The custom marshaller analyzer has changed to require all element-focused marshal modes to satisfy both the managed-to-unmanaged and unmanaged-to-managed shapes. Previous behavior Custom marshallers with MarshalMode.ElementIn only needed a ConvertToUnmanaged method. Custom marshallers with MarshalMode.ElementOut only needed a ConvertToManaged method. New behavior Starting in .NET 8, SYSLIB1057 is reported for custom marshallers with MarshalMode.ElementIn or MarshalMode.ElementOut that don't have both a ConvertToUnmanaged and ConvertToManaged method. Version introduced .NET 8 RC 1 Type of breaking change This change can affect source compatibility. Reason for change With the introduction of source-generated COM, the marshallers can be used in element scenarios in both managed-to-unmanaged and unmanaged-to-managed scenarios. This change updates the analyzer to ensure that user-defined marshallers have the required members for all scenarios where the marshaller might be used. Recommended action Add both a ConvertToManaged and ConvertToUnmanaged method to the marshaller type. Affected APIs System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute IDispatchImplAttribute API is removed Article • 08/23/2023 The IDispatchImplAttribute implementation has officially been removed from .NET. This type was only discoverable at run time and its removal has no impact on visible API surface area. However, if an assembly targeting .NET Framework uses this type and is loaded in .NET 8 or a later version, the runtime will throw a TypeLoadException. Previous behavior The IDispatchImplAttribute type could be found at run time, but none of the documented semantics of the deprecated attribute applied. New behavior Starting in .NET 8, attempting to load an assembly that contains this attribute throws a TypeLoadException. Version introduced .NET 8 Preview 6 Type of breaking change This change can affect binary compatibility. Reason for change This attribute was removed as it was not longer respected and served no functional purpose. Recommended action Remove use of this API in assemblies that are loaded in .NET 8 and later versions. Affected APIs System.Runtime.InteropServices.IDispatchImplAttribute SafeHandle types must have public constructor Article • 06/07/2023 Historically, passing SafeHandle-derived types to P/Invokes and COM methods has implicitly required a parameterless constructor of any visibility when a SafeHandle derived type is passed as a ref or out parameter or a return type. Source-generated interop in .NET 7 and earlier .NET 8 preview versions allowed this behavior to enable easier migration from DllImportAttribute-based P/Invokes. At the same time, we updated the SafeHandle documentation to tell implementers to provide a public parameterless constructor in their derived type. This breaking change makes that recommendation a requirement for source-generated marshalling. Previous behavior A SafeHandle-derived type was required to have a parameterless constructor of any visibility when it was used: As a ref or out parameter or a return type in a LibraryImportAttribute-attributed method. In a method on a GeneratedComInterfaceAttribute-attributed interface. New behavior A SafeHandle-derived type is required to have a public parameterless constructor when it's used: As a ref or out parameter or a return type in a LibraryImportAttribute-attributed method. In a method on a GeneratedComInterfaceAttribute-attributed interface. If the type doesn't have a public parameterless constructor, the interop source generator emits a compile error. Version introduced .NET 8 Preview 5 Type of breaking change This change can affect source compatibility. Reason for change The interop source generators are changing to push more code out of the source generators themselves and into the core .NET libraries. As part of this change, the interop team is starting to enforce the recommended guidelines for more maintainable and understandable interop code. Recommended action Change the existing non- public parameterless constructor on the SafeHandle -derived type to be public . Affected APIs System.Runtime.InteropServices.LibraryImportAttribute System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute IntPtr no longer used for function pointer types Article • 03/22/2023 As a new reflection feature, a function pointer type is now a System.Type instance with new capabilities such as Type.IsFunctionPointer. Previously, the System.Type instance returned was the IntPtr type. Using System.Type in this manner is similar to how other types are exposed, such as pointers (Type.IsPointer) and arrays (Type.IsArray). This new functionality is currently implemented in the CoreCLR runtime and in MetadataLoadContext. Support for the Mono and NativeAOT runtimes is expected later. A function pointer instance, which is a physical address to a function, continues to be represented as an IntPtr; only the reflection type has changed. Previous behavior Previously, typeof(delegate*<void>()) returned the System.IntPtr type for a function pointer type. Similarly, reflection also returned this type for a function pointer type, such as with FieldInfo.FieldType. The IntPtr type didn't allow any access to the parameter types, return type, or calling conventions. New behavior typeof and reflection now use System.Type for a function pointer type, which provides access to the parameter types, return type, and calling conventions. Version introduced .NET 8 Preview 2 Type of breaking change This change is a behavioral change. Reason for change This change adds the capability to obtain function pointer metadata including parameter types, the return type, and the calling conventions. Function pointer support was added with C# 9 and .NET 5, but reflection support wasn't added at that time. Recommended action If you want your code to support function pointers and to treat them specially, use the new Type.IsFunctionPointer API. Affected APIs typeof keyword System.Reflection.FieldInfo.FieldType System.Reflection.PropertyInfo.PropertyType System.Reflection.ParameterInfo.ParameterType CLI console output uses UTF-8 Article • 04/06/2023 If the DOTNET_CLI_UI_LANGUAGE or VSLANG environment variable is set, the .NET CLI console output and input encoding changes to UTF-8, so that the code page can change to UTF-8 as well. This new behavior allows characters from languages set by those environment variables to be rendered correctly. This change only affects Windows operating systems (the encoding was okay on other platforms). Moreover, it only applies to Windows 10 and later versions where the UI culture set by the user is non-English. Previous behavior Characters in certain languages, including Chinese, German, Japanese, and Russian, would sometimes display as garbled characters or as ? in the console. For example: Console C:\>dotnet build MSBuild version 17.3.0-preview[...] for .NET ???????????????... New behavior Starting in .NET 7 (version 7.0.3xx) and .NET 8, characters render correctly. Both the encoding and the code page change. For example: Console C:\>dotnet build MSBuild version 17.3.0-preview[...] for .NET 正在确定要还原的项目… Versions of Windows older than Windows 10 1909 don't fully support UTF-8 and may experience issues after this change. (Starting in .NET 8 Preview 3 and .NET 7.0.300 SDK, the .NET SDK no longer changes the encoding to UTF-8 on these versions, by default. To opt back into using UTF-8 even on Windows 10 versions that don't support it, use the DOTNET_CLI_FORCE_UTF8_ENCODING environment variable.) In addition, there was an existing bug where the SDK can affect the encoding of other commands and programs called in the same command prompt after the SDK has finished execution. Now that the SDK more frequently changes the encoding, the impact of this bug may increase. However, the bug was fixed in .NET 8 Preview 3 and .NET 7.0.300 SDK. For more information, see SDK no longer changes console encoding after completion. Version introduced 7.0.3xx .NET 8 Preview 1 Type of breaking change This change can affect source compatibility and binary compatibility. It's also a behavioral change. Reason for change Using the .NET CLI in non-English languages provided a poor experience. Developers that weren't already using the VSLANG and DOTNET_CLI_UI_LANGUAGE variables aren't impacted. The impact should be minimal, as this language setting wouldn't have worked well in the first place due to garbled characters. Also, only developers using Windows 10 or later might be impacted, most of which are likely using version 1909 or later. The legacy scenarios are already less likely to support the broken languages, so it's unlikely you'd want to use another language that might expose this break anyway. Recommended action If you're using an older version of windows 10, upgrade to version 1909 or later. If you want to use a legacy console or are facing build issues or others due to the encoding change, unset VSLANG and DOTNET_CLI_UI_LANGUAGE to disable this change. See also SDK no longer changes console encoding when finished Console encoding doesn't remain UTF-8 after completion Article • 04/06/2023 The bug mentioned in the CLI console output uses UTF-8 breaking change, where the .NET SDK changed the encoding of the entire console, has been fixed. The console encoding no longer remains UTF-8 after the .NET SDK executes a command. It's possible that users came to rely on that behavior, hence this is a breaking change. In addition, the .NET SDK no longer changes the encoding to UTF-8 on older Windows 10 versions that don't fully support it. Previous behavior The SDK changed the encoding of a terminal after running a command such as dotnet build . The SDK used the UTF-8 encoding to correctly render non-English characters, even on versions of windows 10 that did not officially support UTF-8. The behavior was undefined on those versions. New behavior The SDK doesn't change the terminal encoding after exit for other programs. By default, the SDK no longer uses UTF-8 for Windows versions that don't support it. Version introduced 7.0.3xx .NET 8 Preview 3 Type of breaking change This change can affect binary compatibility. It's also a behavioral change. Reason for change There was an existing bug where the .NET SDK affected the encoding on the console for other programs. That was a bug that was fixed, resulting in this breaking change. Older versions of Windows 10 (that is, versions before the November 2019 update) didn't support UTF-8, so the default behavior shouldn't be to use UTF-8 encoding. Instead, an opt-in is now available. Recommended action If your app needs to change the code page on Windows, it can run a process to invoke the chcp command. Your app shouldn't rely on the .NET SDK to change the encoding. For older Windows 10 versions that don't officially support UTF-8 where you want the .NET SDK to continue to change the encoding to UTF-8 for non-English languages, can you set the environment variable DOTNET_CLI_FORCE_UTF8_ENCODING to true or 1. See also SDK no longer changes console encoding after completion Containers default to use the 'latest' tag Article • 08/01/2023 The default image tag used for .NET SDK-built containers changed from the value of the Version of the project to the value latest . Previous behavior Previously, the image was built with a tag value of $(Version) , which enabled changing the tag based on the same value that the rest of the .NET ecosystem uses. New behavior Starting in .NET 8, the generated image has the latest tag in all cases. Version introduced .NET 8 Preview 6 Type of change This change is a behavioral change. Reason for change This change aligns the default containerization experience with the developer experiences for other container tooling like the Docker CLI. It also makes the development inner-loop of repeated container publishes easier to use with tools like Docker Compose, because the version remains stable. Recommended action Explicitly set the version if you need it. The easiest way is to set the ContainerImageTag property on the command line to an explicit version, for example, /p:ContainerImageTag=1.2.3 . But you can also programmatically set the value as you would any other MSBuild property. In a project file, you can continue to use the $(Version) property by adding the ContainerImageTag property: XML <PropertyGroup> <ContainerImageTag>$(Version)</ContainerImageTag> </PropertyGroup> Affected APIs None. 'dotnet pack' uses Release configuration Article • 02/08/2023 The dotnet pack command, which packs code into a NuGet package, now uses the Release configuration instead of the Debug configuration by default. Previous behavior Previously, dotnet pack used the Debug configuration unless the configuration was specified explicitly or PackRelease was set to true . The PackRelease property was added in .NET 7 as a path forward to this breaking change. Previously, you could set the DOTNET_CLI_ENABLE_PACK_RELEASE_FOR_SOLUTIONS environment variable to use PackRelease in a project that was part of a Visual Studio solution. New behavior If you're developing with the .NET 8 SDK or a later version, dotnet pack uses the Release configuration by default for all projects. If you have a CI/CD script, tests, or code where you've hardcoded Debug into an output path, this change may break your workflow. Also, you won't be able to debug a packed app unless the Debug configuration was explicitly specified (for example, using dotnet pack --configuration Debug . dotnet pack can pack for multiple target framework monikers (TFM) at the same time. If your project targets multiple versions and you have different PackRelease values for different targets, you can have a conflict where some TFMs pack the Release configuration and others pack the Debug configuration. For projects in a solution: dotnet pack can pack all the projects in a Visual Studio solution if given a solution file. For each project in the solution, the value of PackRelease is implicitly set to true if it's undefined. In order for dotnet pack to determine the correct configuration to use, all projects in the solution must agree on their value of PackRelease . This change might cause the performance of dotnet pack to regress, especially for solutions that contain many projects. To address this, a new environment variable DOTNET_CLI_LAZY_PUBLISH_AND_PACK_RELEASE_FOR_SOLUTIONS has been introduced. The DOTNET_CLI_ENABLE_PACK_RELEASE_FOR_SOLUTIONS environment variable is no longer recognized. Version introduced .NET 8 Preview 1 Type of breaking change This change can affect source compatibility and is also a behavioral change. Reason for change In most cases when you create a package, you want your code to be optimized and can keep the package smaller by excluding debugging information. The DOTNET_CLI_ENABLE_PACK_RELEASE_FOR_SOLUTIONS environment variable was removed since the behavior it enabled is now the default behavior and the granular control is no longer necessary. Recommended action To disable the new behavior entirely, you can set the DOTNET_CLI_DISABLE_PUBLISH_AND_PACK_RELEASE environment variable to true (or any other value). This variable affects both dotnet publish and dotnet pack . To explicitly specify the Debug configuration for packing, use the -c or -configuration option with dotnet pack . If your CI/CD pipeline is broken due to hardcoded output paths, update the paths to Release instead of Debug , disable the new behavior using the DOTNET_CLI_DISABLE_PUBLISH_AND_PACK_RELEASE environment variable, or specify that the Debug configuration should be used. If you're packing a solution and it's broken because one or more projects explicitly sets a value for PackRelease , you should explicitly set PackRelease to false in each project: XML <PropertyGroup> <PackRelease>false</PackRelease> </PropertyGroup> If you're packing a solution and the performance has regressed, you can set the DOTNET_CLI_LAZY_PUBLISH_AND_PACK_RELEASE_FOR_SOLUTIONS environment variable to true (or any other value) to remove the regression. If you use this variable and any project defines PackRelease , all projects must define it, or you can use a Directory.Build.Props file. This variable affects both dotnet publish and dotnet pack . See also 'dotnet publish' uses Release configuration 'dotnet publish' uses Release configuration Article • 02/08/2023 The dotnet publish command now uses the Release configuration instead of the Debug configuration by default if the target framework is .NET 8 or a later version. Previous behavior Previously, dotnet publish used the Debug configuration unless the configuration was specified explicitly or PublishRelease was set to true . The PublishRelease property was added in .NET 7 as a path forward to this breaking change. Previously, you could set the DOTNET_CLI_ENABLE_PUBLISH_RELEASE_FOR_SOLUTIONS environment variable to use PublishRelease in a project that was part of a Visual Studio solution. New behavior If you're developing with the .NET 8 SDK or a later version, dotnet publish uses the Release configuration by default for projects whose TargetFramework is set to net8.0 or a later version. If you have a CI/CD script, tests, or code where you've hardcoded Debug into an output path, this change may break your workflow. If your project targets multiple versions, the new behavior only applies if you specify a target framework of .NET 8 or later when you publish (for example, using dotnet publish -f net8.0 ). For projects in a solution: dotnet publish can publish all the projects in a Visual Studio solution if given a solution file. For the solution projects that target .NET 8 or later, the value of PublishRelease is implicitly set to true if it's undefined. However, in order for dotnet publish to determine the correct configuration to use for the solution, all projects in the solution must agree on their value of PublishRelease . If an older project in the solution has PublishRelease set to false , you should explicitly set the property to false for any new .NET 8+ projects as well. This change might cause the performance of dotnet publish to regress, especially for solutions that contain many projects. To address this, a new environment variable DOTNET_CLI_LAZY_PUBLISH_AND_PACK_RELEASE_FOR_SOLUTIONS has been introduced. The DOTNET_CLI_ENABLE_PUBLISH_RELEASE_FOR_SOLUTIONS environment variable is no longer recognized. Version introduced .NET 8 Preview 1 Type of breaking change This change can affect source compatibility and is also a behavioral change. Reason for change In most cases when you publish, you want your code to be optimized and can keep the app smaller by excluding debugging information. Customers have asked for Release to be the default configuration for publish for a long time. Also, Visual Studio has had this behavior for many years. The DOTNET_CLI_ENABLE_PUBLISH_RELEASE_FOR_SOLUTIONS environment variable was removed since the behavior it enabled is now the default behavior and the granular control is no longer necessary. Recommended action To disable the new behavior entirely, you can set the DOTNET_CLI_DISABLE_PUBLISH_AND_PACK_RELEASE environment variable to true (or any other value). This variable affects both dotnet publish and dotnet pack . To explicitly specify the Debug configuration for publishing, use the -c or -configuration option with dotnet publish . If your CI/CD pipeline is broken due to hardcoded output paths, update the paths to Release instead of Debug , disable the new behavior using the DOTNET_CLI_DISABLE_PUBLISH_AND_PACK_RELEASE environment variable, or specify that the Debug configuration should be used. If you're publishing a solution and it's broken, you can explicitly set PublishRelease to true (or false to revert to the previous behavior). XML <PropertyGroup> <PublishRelease>true</PublishRelease> </PropertyGroup> Alternatively, you can specify the property in a Directory.Build.Props file. However, if you set it false in this file, you'll still need to explicitly set the property to false in the .NET 8+ projects in the solution. Similarly, if some projects explicitly set a value that's different from the value in the Directory.Build.Props file, publish will fail. If you're publishing a solution and the performance has regressed, you can set the DOTNET_CLI_LAZY_PUBLISH_AND_PACK_RELEASE_FOR_SOLUTIONS environment variable to true (or any other value) to remove the regression. However, if you set this variable and your solution contains a .NET 8+ project and a project that targets .NET 7 or earlier, publishing will fail until all projects define PublishRelease . This variable affects both dotnet publish and dotnet pack . See also 'dotnet pack' uses Release configuration 'dotnet restore' produces security vulnerability warnings Article • 08/22/2023 The dotnet restore command, which restores the dependencies and tools of a project, now produces security vulnerability warnings by default. Previous behavior Previously, dotnet restore did not emit any security vulnerability warnings by default. New behavior If you're developing with the .NET 8 SDK or a later version, dotnet restore produces security vulnerability warnings by default for all restored projects. When you load a solution or project, or run a CI/CD script, this change may break your workflow if you have <TreatWarningsAsErrors> enabled. Version introduced .NET 8 Preview 4 Type of breaking change This change is a behavioral change. Reason for change In most cases when you restore a package, you want to know whether the restored package version contains any known security vulnerabilities. This functionality was added as it is a highly requested feature and security concerns continue to increase each year where known security issues can not be visible enough to taking immediate action. Recommended action To explicitly reduce the probability of this breaking your build due to warnings, you can consider your usage of <TreatWarningsAsErrors> and use <WarningsNotAsErrors>NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors> to ensure known security vulnerabilities are still allowed in your environment. If you want to set a different security audit level, add the <NuGetAuditLevel> property to your project file with possible values of low , moderate , high , and critical . If you want to ignore these warnings, you can use <NoWarn> to suppress NU1091NU104 warnings. To disable the new behavior entirely, you can set the <NuGetAudit> project property to false . See also Auditing package dependencies for security vulnerabilities MSBuild custom derived build events deprecated Article • 09/07/2023 Custom derived build events of any subclass of BuildEventArgs by any build extensibility (mainly custom tasks) have been deprecated. Previous behavior Previously, you could derive from any subclass of BuildEventArgs and use those types freely in custom tasks and other build extensibility points. New behavior Starting in .NET 8, a build error is issued if your code uses any type derived from BuildEventArgs and you build using the .NET 8 version of MSBuild, that is, from the command line: Usage of unsecure BinaryFormatter during serialization of custom event type 'MyCustomBuildEventArgs'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs If you build from Visual Studio, there is no change in behavior unless you opt in by setting the MSBUILDCUSTOMBUILDEVENTWARNING environment variable to 1 (available in Visual Studio version 17.8 and later). Version introduced .NET 8 RC 1 Type of change This change is a behavioral change. Reason for change BinaryFormatter serialization is obsolete in .NET 8 and later versions. Any use of BinaryFormatter throws an exception at run time. Since MSBuild custom derived build events use BinaryFormatter, your build would crash if you use these events in your build. The new build error provides a more graceful failure. Recommended action Use one of the following newly introduced, built-in events for extensibility instead of your custom derived build event: Microsoft.Build.Framework.ExtendedCustomBuildEventArgs Microsoft.Build.Framework.ExtendedBuildErrorEventArgs Microsoft.Build.Framework.ExtendedBuildMessageEventArgs Microsoft.Build.Framework.ExtendedBuildWarningEventArgs Alternatively, you can temporarily disable the check by explicitly setting the environment variable MSBUILDCUSTOMBUILDEVENTWARNING to something other than 1. Affected APIs Microsoft.Build.Framework.CustomBuildEventArgs MSBuild respects DOTNET_CLI_UI_LANGUAGE Article • 06/13/2023 MSBuild now respects the DOTNET_CLI_UI_LANGUAGE environment variable and uses the language specified by DOTNET_CLI_UI_LANGUAGE for its command-line output. This change affects the output of the msbuild.exe , dotnet build , and dotnet msbuild commands. Previous behavior Previously, MSBuild command-line output was always in the operating system (OS) language and used its own encoding, regardless of DOTNET_CLI_UI_LANGUAGE . New behavior MSBuild uses the language specified by DOTNET_CLI_UI_LANGUAGE instead of the OS language for its command-line output. On Windows, MSBuild output uses UTF-8 encoding now if DOTNET_CLI_UI_LANGUAGE is set and UTF-8 is supported. Version introduced .NET 8 Preview 5 Type of breaking change This change is a behavioral change. Reason for change Previously, output from commands like dotnet build was a mixture of the DOTNET_CLI_UI_LANGUAGE language (for .NET SDK output) and the OS language (for MSBuild output). For example, the "Build succeeded/failed" output used the OS language. With this change, the language of .NET SDK and MSBuild output is consistent. Recommended action If you want to keep the old behavior, unset DOTNET_CLI_UI_LANGUAGE by using the command set DOTNET_CLI_UI_LANGUAGE= (or a similar command for your shell to change environment variables). Runtime-specific apps no longer selfcontained Article • 06/08/2023 Runtime-specific apps, or .NET apps with a RuntimeIdentifier , are no longer selfcontained by default. Instead, they are framework-dependent by default. This is a breaking change in the following situations: If you deployed, distributed, or published your app and didn't explicitly add the SelfContained property, but also didn't require that the .NET runtime be installed on the machine for it to work. In this case, you may have relied on the previous behavior to produce a self-contained app by default. If you rely on the IL Link tool. In this case, you'll have to take the steps described under Recommended action to use IL Link again. Previous behavior Previously, if a runtime identifier (RID) was specified (via RuntimeIdentifier), the app was published as self-contained, even if SelfContained wasn't explicitly specified. In addition: If PublishSelfContained wasn't explicitly set to false , the publish properties PublishSingleFile and PublishAot implied a RuntimeIdentifier and therefore SelfContained (if it wasn't specified) during operations including dotnet build , dotnet restore , and dotnet publish . The PublishTrimmed property did not imply SelfContained . The PublishReadyToRun property implied SelfContained if SelfContained wasn't specified. New behavior Starting in .NET 8, for apps that target .NET 8 or a later version, RuntimeIdentifier no longer implies SelfContained by default. Instead, apps that specify a runtime identifier will be dependent on the .NET runtime by default (framework-dependent). Apps that target .NET 7 or earlier versions aren't affected. In addition: If PublishSelfContained isn't explicitly set to false , the publish properties PublishSingleFile and PublishAot now imply SelfContained (if it's not specified) during dotnet publish only (that is, not for dotnet build or dotnet restore ). The PublishTrimmed property also now implies SelfContained during dotnet publish . The PublishReadyToRun property no longer implies SelfContained if the project targets .NET 8 or later. 7 Note If you publish using msbuild /t:Publish , you must explicitly specify SelfContained if you want your app to be self-contained, even if your project has one of the listed publish properties. Version introduced .NET 8 Preview 5 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change The new .NET SDK behavior aligns with Visual Studio behavior. Framework-dependent apps are smaller by default, since there aren't copies of .NET stored in each app. When .NET is managed outside of the app (that is, for framework-dependent deployments), .NET stays more secure and up-to-date. Apps that have their own copy of the runtime don't get security updates. This change makes more apps framework-dependent by default. Ideally, command-line options are orthogonal. In this case, the tooling supports both RID-specific self-contained deployment (SCD) and RID-specific frameworkdependent deployment (FDD). So it didn't make sense that no RID defaulted to FDD and RID defaulted to SCD. This behavior was often confusing for users. .NET 6 alerted users to this breaking change with the following warning: warning NETSDK1179: One of '--self-contained' or '--no-self-contained' options are required when '--runtime' is used. Now that customers have had time to add SelfContained explicitly, it's okay to introduce the break. Recommended action If you're using .NET 7 or an earlier version and relied on the previous behavior where SelfContained was inferred, you'll see this warning: For projects with TargetFrameworks >= 8.0, RuntimeIdentifier no longer automatically gives a SelfContained app. To continue creating a .NET framework independent app after upgrading to 8.0, consider setting SelfContained explicitly. Follow the guidance of the warning and set SelfContained to true in the project file ( <SelfContained>true</SelfContained> ) or as a command-line argument, for example, dotnet publish --self-contained . If you're using .NET 8 and want to keep the previous behavior, set SelfContained to true . See also .NET application publishing overview .NET SDK uses a smaller RID graph Article • 09/07/2023 Projects that target .NET 8 or later versions now use a smaller, "portable" runtime identifier (RID) graph. Previous behavior The .NET SDK used a complex RID graph to determine assets when building or publishing a project. New behavior Starting in .NET 8, the .NET SDK uses a smaller graph consisting of only portable RIDs, for projects that target .NET 8 or a later version. This means that the SDK won't recognize version-specific or distro-specific RIDs by default. Version introduced .NET 8 RC 1 Type of breaking change This change is a behavioral change and can also affect source compatibility. Reason for change The RID graph was costly to maintain and understand, requiring .NET itself to be distroaware in a fragile manner. The .NET team and the community spend a non-trivial amount of time updating the graph and backporting such updates to previous releases. The long-term goal is to stop updating the RID graph, stop reading it, and eventually remove it. This breaking change is a step towards that goal. Recommended action Use portable RIDs, for example, linux-<arch> , linux-musl-<arch> , osx-<arch> , and win<arch> . If you need to revert to the previous behavior of using the old, full RID graph, you can set the UseRidGraph MSBuild property to true in your project file. However, the old RID graph won't be updated in the future to attempt to handle any other distros or architectures. See also Host determines RID-specific assets Trimming may not be used with .NET standard or .NET framework Article • 08/25/2023 Projects that set <PublishTrimmed>true</PublishTrimmed> , <IsTrimmable>true</IsTrimmable> or <EnableTrimAnalyzer>true</EnableTrimAnalyzer> with a TargetFramework that is any version of .NET Standard or .NET Framework produce a warning or error because trimming is unsupported for these target frameworks. Previous behavior Previously, when used in a .NET Standard or .NET Framework project, these settings behaved as follows: <PublishTrimmed>true</PublishTrimmed> would have no effect. <IsTrimmable>true</IsTrimmable> would embed an assembly-level attribute [assembly: AssemblyMetadata("IsTrimmable", "true")] into the output assembly. That attribute opted the assembly into trimming when consumed in a trimmed app (even an app that uses <TrimMode>partial</TrimMode> ). <EnableTrimAnalyzer>true</EnableTrimAnalyzer> would enable trim analysis for the library, using the .NET Standard or .NET Framework reference assemblies corresponding to the library's TargetFramework even though these reference assemblies aren't annotated for trimming. New behavior Starting in the .NET 8 SDK, in a project targeting .NET Standard or .NET Framework: <PublishTrimmed> produces an error indicating that this setting is unsupported for the target framework. <IsTrimmable> or <EnableTrimAnalyzer> produce a warning indicating that <IsTrimmable> is unsupported for the target framework. These settings otherwise have no effect on the build output. Version introduced .NET 8 RC 1 Type of breaking change This change is a behavioral change. Reason for change Allowing the use of <PublishTrimmed> in a .NET Standard or .NET Framework project might have given the false impression that this setting was trimming the output, when in fact it had no effect. Allowing the use of <IsTrimmable> or <EnableTrimAnalyzer> in a .NET Standard or .NET Framework project meant that it was easy for library authors to opt into trimming, without being alerted about trim incompatibilities. Because the .NET Standard and .NET Framework reference assemblies aren't annotated for trimming, there were no warnings about uses of framework APIs that are incompatible with trimming. Recommended action Avoid setting <PublishTrimmed> in projects that target .NET Standard or .NET Framework. Also avoid setting <PublishAot> which implies the former setting. Avoid setting <IsTrimmable> or <EnableTrimAnalyzer> in libraries that target .NET Standard or .NET Framework. Also avoid setting <IsAotCompatible> , which implies the former settings. Instead, multi-target the library to include the latest TargetFramework , and enable <IsTrimmable> only for the supported target frameworks. Setting <IsTrimmable> will run the latest version of the trim analyzer using trim-compatibility annotations from the latest version of the framework. For example, these settings multi-target to include net8.0 , and set <IsTrimmable> only for this target framework. This logic uses IsTargetFrameworkCompatible so that it will apply to any frameworks compatible with net6.0 , when trimming was first officially supported. This way, the condition doesn't need to be updated when adding new target frameworks. XML <PropertyGroup> <TargetFrameworks>netstandard2.1;net8.0</TargetFrameworks> <IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</IsTrimmable> </PropertyGroup> See also Prepare .NET libraries for trimming Version requirements for .NET 8 SDK Article • 09/07/2023 Per the published support rules, we update the minimum Visual Studio and MSBuild version for each new major release with a one quarter delay. For the .NET 8 release, 8.0.100 requires version 17.7 to be loaded but only supports targeting .NET 7 in that version. To target net8.0 , you must use version 17.8 or later. Version introduced .NET SDK 8 RC 1 Previous behavior .NET 8.0.1xx-preview1 required version 17.4 of Visual Studio and MSBuild. .NET 8.0.1xxpreview4 required version 17.6 of Visual Studio and MSBuild. New behavior Versions 8.0.1xx of the .NET SDK require Visual Studio version 17.7 and MSBuild version 17.7. Reason for change This is our standard support policy for the SDK as we can't support all prior versions of Visual Studio and MSBuild. Recommended action Upgrade your Visual Studio version to the required version. Affected APIs N/A See also Targeting and support rules BinaryFormatter disabled across most project types Article • 05/17/2023 The BinaryFormatter.Serialize(Stream, Object) and BinaryFormatter.Deserialize(Stream) methods now throw a NotSupportedException at run time across nearly all project types, including console applications. Previous behavior In .NET 7, the BinaryFormatter.Serialize(Stream, Object) and BinaryFormatter.Deserialize(Stream) methods were marked obsolete and raised an error at compile time. However, if your application suppressed the obsoletion, it could still call the methods and they functioned properly in most project types (excluding ASP.NET, WASM, and MAUI). For example, the APIs functioned correctly in a console app. New behavior Starting in .NET 8, the affected methods throw a NotSupportedException at run time across all project types except Windows Forms and WPF. The APIs continue to remain obsolete (as error) across all project types, including Windows Forms and WPF. Version introduced .NET 8 Preview 4 Type of breaking change This change is a behavioral change. Reason for change This run-time change is the next stage of the BinaryFormatter obsoletion plan , in which BinaryFormatter will eventually be removed from .NET. Recommended action The best course of action is to migrate away from BinaryFormatter due to its security and reliability flaws. However, should you need to continue using BinaryFormatter , you can set a compatibility switch in your project file to re-enable BinaryFormatter functionality. For more information, see the Recommended action section of the .NET 7 breaking change notification. That compatibility switch continues to be honored in .NET 8. Affected APIs System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream, Object) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream) See also BinaryFormatter serialization methods are obsolete (.NET 5) SerializationFormat.Binary is obsolete (.NET 7) BinaryFormatter serialization APIs produce compiler errors (.NET 7) Reflection-based deserializer resolves metadata eagerly Article • 09/15/2023 The System.Text.Json reflection-based serializer previously used a lazy loading approach to resolve property metadata. That approach made it possible for POCOs that contained unsupported property types to deserialize successfully, provided that the underlying JSON didn't bind to any of the unsupported properties. (This was despite the fact that instances of the same type would fail to serialize.) Starting with .NET 8, the serializer has been changed so that all properties are resolved eagerly in both serialization and deserialization. This change was made to add better support for combining multiple resolvers, which necessitates early analysis of the serialized type graph. A side-effect of this change is that if you depended on the previous behavior, you could start seeing new runtime deserialization errors. Previous behavior The following deserialization code succeeded in .NET 7. C# var result = JsonSerializer.Deserialize<MyPoco>("""{ "Value": 1 }"""); //, MyContext.Default.MyPoco); Console.WriteLine(result.Value); public class MyPoco { public int Value { get; set; } public NestedValue Unsupported { get; set; } } public class NestedValue { public ReadOnlySpan<byte> Span => Array.Empty<byte>(); } New behavior Starting in .NET 8, the same code from the Previous behavior section throws an InvalidOperationException at run time. System.InvalidOperationException: The type 'System.ReadOnlySpan`1[System.Byte]' of property 'Span' on type 'NestedValue' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types. This error is consistent with the error that was thrown even in previous versions if you attempted to serialize an instance of the same type. It's also consistent with the source generator, which produces a compile-time error. Version introduced .NET 8 Preview 4 Type of breaking change This change is a behavioral change. Reason for change This change was necessitated by new requirements related to fast-path serialization support in combined source generated contexts (see dotnet/runtime#71933 Recommended action If this change is problematic for you, you can: Remove the unsupported property from your type. Author a custom converter for the unsupported type. Add the JsonIgnoreAttribute attribute: C# public class MyPoco { public int Value { get; set; } [JsonIgnore] public NestedValue Unsupported { get; set; } } ). Affected APIs System.Text.Json.JsonSerializer.Deserialize Anchor layout changes Article • 01/25/2023 Control anchor computations have been changed to support high DPI devices. For more information about the changes, see Anchor layout changes in .NET 8 . Version introduced .NET 8 Preview 1 Previous behavior Certain applications using HighDpiMode.SystemAware or HighDpiMode.PerMonitorV2 mode and anchored controls encountered layout issues on high DPI devices. New behavior Applications using HighDpiMode.SystemAware or HighDpiMode.PerMonitorV2 mode and anchored controls should have improved layout when rendered on high DPI devices. Change category This change is a behavioral change. Reason for change This change is part of a broader effort to improve the Windows Forms user experience on high DPI monitors. It enables developers to use an anchored layout for applications on high DPI devices. Recommended action If the new behavior is problematic for you, you can opt out by setting System.Windows.Forms.AnchorLayoutV2 to false in your runtimeconfig.json file. runtimeconfig.template.json template file: JSON { "configProperties": { "System.Windows.Forms.AnchorLayoutV2": false } } [appname].runtimeconfig.json output file: JSON { "runtimeOptions": { "configProperties": { "System.Windows.Forms.AnchorLayoutV2": false } } } Affected APIs N/A See also Anchor layout changes in .NET 8 DefaultValueAttribute removed from some properties Article • 03/17/2023 DefaultValueAttribute has been removed from control properties that are dependent on the default font height. Version introduced .NET 8 Previous behavior The affected properties were decorated with DefaultValueAttribute, and default values were hardcoded according to an assumed application-wide font. New behavior Starting in .NET 8, the attribute is removed from certain properties. Design-time default values are calculated at startup based on the current font metrics. Change category This change is a behavioral change. Reason for change The DefaultValueAttribute attribute is designed to define constant default values used by the Windows Forms designer. In the past, this attribute was used to specify defaults on certain properties that depend on the current font height. A new default font was introduced in .NET Core 3.1, but the attribute values weren't updated accordingly. Moreover, there's now an API to modify application font. Thus, it makes sense to use dynamic default values instead of constant ones. The designer provides methods to specify dynamic default values, however, for properties decorated with DefaultValueAttribute, it always uses the constant default value instead. The methods for specifying dynamic defaults preserve the design-time functionality provided by the attribute. Recommended action DefaultValueAttribute is intended for internal use in design-time scenarios. You shouldn't use it in other scenarios. Affected APIs The following table lists the affected properties. Property Change version System.Windows.Forms.DataGridViewRow.Height Preview 2 System.Windows.Forms.ListBox.ItemHeight Preview 2 ExceptionCollection ctor throws ArgumentException Article • 02/15/2023 The ExceptionCollection constructor now throws an ArgumentException if the elements in the input array are not of type Exception. Version introduced .NET 8 Preview 1 Previous behavior Previously, the ExceptionCollection constructor did not check the type passed in, which could delay failure until later in the process. No exceptions were thrown during object creation. New behavior Starting in .NET 8, if the elements in the input array are not of type Exception, an ArgumentException is thrown. Change category This change is a behavioral change. Reason for change This change helps to make exception types consistent across the code base. Recommended action For most scenarios, this change should not have a significant impact. However, consider updating your code to handle ArgumentException at constructor call sites. Affected APIs ExceptionCollection(ArrayList) constructor Forms scale according to AutoScaleMode Article • 02/15/2023 In PerMonitorV2-mode apps, Windows Forms has been using linear sizes (also known as DPI-scaled sizes) provided by Windows for top-level windows, regardless of the AutoScaleMode. This implementation was problematic when using the AutoScaleMode.Font scaling mode, where Form scaling should be non-linear. The child controls are scaled non-linearly and depend on the font that was assigned to the Form or child controls. This change enables WM_GETDPISCALEDSIZE message handling for top-level Form objects. It utilizes WM_GETDPISCALEDSIZE to let Windows know that the Form may need nonlinear sizes depending on AutoScaleMode. Version introduced .NET 8 Preview 1 Previous behavior Previously, in PerMonitorV2-mode apps, top-level windows were scaled by Windows and disregarded AutoScaleMode as specified in the WinForms application. This implementation led to inconsistent scaling between Form objects and their child controls. New behavior In PerMonitorV2-mode apps, top-level windows (such as Forms) are scaled according to AutoScaleMode. This implementation ensures that top-level windows scale consistently with their child controls. Change category This change is a behavioral change. Reason for change This change was made to improve the high-DPI experience for Windows Forms apps in PerMonitorV2 mode. Recommended action No action is required. Affected APIs N/A See also Top-level forms scale minimum and maximum size to DPI ImageList.ColorDepth default is Depth32Bit Article • 02/15/2023 The default value for ImageList.ColorDepth has changed over time. Starting in .NET 8, the default value has changed from Depth8Bit to Depth32Bit. This change affects both new and existing applications if they're upgraded to target .NET 8. Version introduced .NET 8 Preview 1 Previous behavior The default value for ImageList.ColorDepth was ColorDepth.Depth8Bit. New behavior If you haven't explicitly set ImageList.ColorDepth for an image list, the color depth will automatically be reset to ColorDepth.Depth32Bit. This could increase your app's memory usage. Change category This change is a behavioral change. Reason for change The default value was changed to improve image quality. Recommended action If you want to continue using the previous color depth, explicitly set ImageList.ColorDepth to ColorDepth.Depth8Bit. Affected APIs System.Windows.Forms.ImageList.ColorDepth TableLayoutStyleCollection throws ArgumentException Article • 02/15/2023 TableLayoutStyleCollection enforces the type passed to its collection operations. The affected APIs now throw an ArgumentException instead of an InvalidCastException if the input is not of type TableLayoutStyle. Version introduced .NET 8 Preview 1 Previous behavior Previously, if the input couldn't be converted to type TableLayoutStyle, an InvalidCastException was thrown. New behavior Starting in .NET 8, if the input can't be converted to type TableLayoutStyle, an ArgumentException is thrown. Change category This change is a behavioral change. Reason for change This change helps to make exception types consistent across the code base. Recommended action For most scenarios, this change should not have a significant impact. However, if you previously handled InvalidCastException, update your code to handle ArgumentException instead. Affected APIs System.Windows.Forms.TableLayoutStyleCollection.System.Collections.IList.Add(Obj ect) System.Windows.Forms.TableLayoutStyleCollection.System.Collections.IList.Insert(In t32, Object) System.Windows.Forms.TableLayoutStyleCollection.System.Collections.IList.Remove (Object) Top-level forms scale minimum and maximum size to DPI Article • 02/15/2023 Top-level forms in Windows Forms now scale their MinimumSize and MaximumSize values according to the dots per inch (DPI) of the monitor when running in HighDpiMode.PerMonitorV2 mode. Version introduced .NET 8 Preview 1 Previous behavior In .NET 8, the MinimumSize and MaximumSize values for top-level forms remained constant regardless of the application DPI mode and the DPI of the monitor where the form is rendered. This sometimes resulted in scaling limitations of the top-level form. You can also opt into this behavior in .NET 7. To opt in, set the System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi runtime configuration option described in the Recommended action section. New behavior Starting in .NET 8, top-level forms scale their MinimumSize and MaximumSize values according to the DPI of the monitor when running in HighDpiMode.PerMonitorV2 mode. The behavior of your app might change in the following ways: Run-time dependencies might be impacted when the minimum and maximum size of the form change. New MinimumSizeChanged and MaximumSizeChanged events might be raised. The scaled form size now has new constraint values for the minimum and maximum sizes. Change category This change is a behavioral change. Reason for change This change is part of a broader effort to improve the Windows Forms user experience on high DPI monitors. It enables developers to set minimum and maximum sizes for top-Level forms without having to take the DPI of the monitor into account. Recommended action If the new behavior is problematic for you, you can opt out by setting System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi to false in your runtimeconfig.json file. runtimeconfig.template.json template file: JSON { "configProperties": { "System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi": false } } [appname].runtimeconfig.json output file: JSON { "runtimeOptions": { "configProperties": { "System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi": false } } } Affected APIs N/A See also Forms scale according to AutoScaleMode WFDEV002 obsoletion is now an error Article • 02/01/2023 The WFDEV002 obsoletion has been promoted from a warning to an error in .NET 8. Any reference to DomainUpDown.DomainUpDownAccessibleObject will result in a compilation error that can't be suppressed. In addition, DomainUpDown.CreateAccessibilityInstance() now returns an object of the internal type UpDownBase.UpDownBaseAccessibleObject . Version introduced .NET 8 Preview 1 Previous behavior Previously, if you referenced the DomainUpDown.DomainUpDownAccessibleObject type, you got compile-time warning WFDEV002. Also, DomainUpDown.CreateAccessibilityInstance() returned an object of type DomainUpDown.DomainUpDownAccessibleObject. New behavior If you reference the DomainUpDown.DomainUpDownAccessibleObject type, you'll get a compile-time error with the same diagnostic ID (WFDEV002). In addition, since the type has been removed, DomainUpDown.CreateAccessibilityInstance() now returns an object of type UpDownBase.UpDownBaseAccessibleObject (which is an internal type). Change category This change can affect source compatibility. Reason for change The DomainUpDown.DomainUpDownAccessibleObject class has always been documented as "internal use only". All functionality of the class was moved to the base class. Recommended action Update your code to use System.Windows.Forms.Control.ControlAccessibleObject or AccessibleObject instead of DomainUpDown.DomainUpDownAccessibleObject. Affected APIs System.Windows.Forms.DomainUpDown.DomainUpDownAccessibleObject System.Windows.Forms.DomainUpDown.CreateAccessibilityInstance() Breaking changes in .NET 7 Article • 07/28/2023 If you're migrating an app to .NET 7, the breaking changes listed here might affect you. Changes are grouped by technology area, such as ASP.NET Core or Windows Forms. This article indicates whether each breaking change is binary compatible or source compatible: Binary compatible - Existing binaries will load and execute successfully without recompilation, and the run-time behavior won't change. Source compatible - Source code will compile successfully without changes when targeting the new runtime or using the new SDK or component. ASP.NET Core Title Binary compatible Source compatible API controller actions try to infer parameters from DI ✔️ ❌ ASPNET-prefixed environment variable precedence ✔️ ✔️ AuthenticateAsync for remote auth providers ✔️ ❌ Authentication in WebAssembly apps ❌ ✔️ Default authentication scheme ❌ ✔️ Event IDs for some Microsoft.AspNetCore.Mvc.Core log ❌ ✔️ Fallback file endpoints ❌ ✔️ IHubClients and IHubCallerClients hide members ✔️ ❌ Kestrel: Default HTTPS binding removed ❌ ✔️ Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv and libuv.dll removed ❌ ❌ Microsoft.Data.SqlClient updated to 4.0.1 ✔️ ❌ Middleware no longer defers to endpoint with null request delegate ❌ ✔️ MVC's detection of an empty body in model binding changed ❌ ✔️ messages changed Title Binary compatible Source compatible Output caching API changes ❌ ❌ SignalR Hub methods try to resolve parameters from DI ✔️ ❌ Core .NET libraries Title Binary Source compatible compatible API obsoletions with default diagnostic ID ✔️ ❌ API obsoletions with non-default diagnostic IDs ✔️ ❌ BinaryFormatter serialization APIs produce compiler errors ✔️ ❌ BrotliStream no longer allows undefined ❌ ✔️ C++/CLI projects in Visual Studio ✔️ ❌ Changes to reflection invoke API exceptions ❌ ✔️ Collectible Assembly in non-collectible AssemblyLoadContext ❌ ✔️ DateTime addition methods precision change ✔️ ✔️ Equals method behavior change for NaN ❌ ✔️ EventSource callback behavior ✔️ ✔️ Generic type constraint on PatternContext<T> ❌ ❌ Legacy FileStream strategy removed ❌ ✔️ Library support for older frameworks ❌ ❌ Maximum precision for numeric format strings ❌ ✔️ SerializationFormat.Binary is obsolete ❌ ❌ System.Drawing.Common config switch removed ✔️ ✔️ System.Runtime.CompilerServices.Unsafe NuGet package ✔️ ✔️ Time fields on symbolic links ❌ ✔️ Tracking linked cache entries ❌ ✔️ CompressionLevel values Title Binary Source compatible compatible ❌ ✔️ Validate CompressionLevel for BrotliStream Configuration Title Binary compatible Source compatible ❌ ✔️ System.diagnostics entry in app.config Cryptography Title Binary compatible Source compatible Decrypting EnvelopedCms doesn't double unwrap ❌ ✔️ Dynamic X509ChainPolicy verification time ❌ ✔️ X500DistinguishedName parsing of friendly names ❌ ✔️ Deployment Title Binary compatible Source compatible All assemblies trimmed by default ✔️ ❌ Multi-level lookup is disabled ❌ ✔️ x86 host path on 64-bit Windows ✔️ ✔️ TrimmerDefaultAction is deprecated ✔️ ❌ Entity Framework Core Breaking changes in EF Core 7 Extensions Title Binary compatible Source compatible Binding config to dictionary extends values ✔️ ✔️ ContentRootPath for apps launched by Windows ❌ ✔️ ❌ ✔️ Binary Source compatible compatible ❌ ✔️ Binary compatible Source compatible ❌ ✔️ Shell Environment variable prefixes Globalization Title Globalization APIs use ICU libraries on Windows Server Interop Title RuntimeInformation.OSArchitecture under emulation .NET MAUI Title Binary compatible Source compatible Constructors accept base interface instead of concrete type ❌ ✔️ Flow direction helper methods removed ❌ ❌ New UpdateBackground parameter ❌ ✔️ ScrollToRequest property renamed ❌ ❌ Some Windows APIs are removed ❌ ❌ Networking Title Binary Source compatible compatible AllowRenegotiation default is false ❌ ❌ Custom ping payloads on Linux ❌ ✔️ Socket.End methods don't throw ❌ ✔️ ObjectDisposedException SDK and MSBuild Title Binary compatible Source compatible Automatic RuntimeIdentifier for certain projects ✔️ ❌ Automatic RuntimeIdentifier for publish only ❌ ❌ CLI console output uses UTF-8 ❌ ❌ Console encoding not UTF-8 after completion ❌ ✔️ MSBuild serialization of custom types in .NET 7 ❌ ❌ Side-by-side SDK installations ❌ ❌ Tool manifests in root folder ✔️ ✔️ Version requirements for .NET 7 SDK ✔️ ✔️ dotnet test: switch -a to alias --arch instead of --testadapter-path ❌ ❌ dotnet test: switch -r to alias --runtime instead of -- ❌ ❌ --output option no longer is valid for solution-level commands ❌ ❌ SDK no longer calls ResolvePackageDependencies ✔️ ❌ Binary compatible Source compatible ❌ ✔️ results-dir Serialization Title DataContractSerializer retains sign when deserializing -0 Title Binary compatible Source compatible Deserialize Version type with leading or trailing whitespace ❌ ✔️ JsonSerializerOptions copy constructor includes JsonSerializerContext ❌ ✔️ Polymorphic serialization for object types ❌ ✔️ System.Text.Json source generator fallback ❌ ✔️ Windows Forms Title Binary compatible Source compatible Obsoletions and warnings ✔️ ❌ Some APIs throw ArgumentNullException ❌ ✔️ XML and XSLT Title XmlSecureResolver is obsolete See also What's new in .NET 7 Binary compatible Source compatible ❌ ❌ API controller actions try to infer parameters from DI Article • 05/04/2023 The mechanism to infer binding sources of API controller action parameters now marks parameters to be bound from the Dependency Injection (DI) container when the type is registered in the container. In rare cases, this can break apps that have a type in DI that is also accepted in API controller action methods. Version introduced ASP.NET Core 7.0 Previous behavior If you wanted to bind a type registered in the DI container, it must be explicitly decorated using an attribute that implements IFromServiceMetadata, such as FromServicesAttribute: C# Services.AddScoped<SomeCustomType>(); [Route("[controller]")] [ApiController] public class MyController : ControllerBase { public ActionResult Get([FromServices]SomeCustomType service) => Ok(); } If the attribute wasn't specified, the parameter was resolved from the request body sent by the client: C# Services.AddScoped<SomeCustomType>(); [Route("[controller]")] [ApiController] public class MyController : ControllerBase { // Bind from the request body [HttpPost] public ActionResult Post(SomeCustomType service) => Ok(); } New behavior Types in DI are checked at app startup using IServiceProviderIsService to determine if an argument in an API controller action comes from DI or from other sources. In the following example, which assumes you're using the default DI container, SomeCustomType comes from the DI container: C# Services.AddScoped<SomeCustomType>(); [Route("[controller]")] [ApiController] public class MyController : ControllerBase { // Bind from DI [HttpPost] public ActionResult Post(SomeCustomType service) => Ok(); } The mechanism to infer binding sources of API controller action parameters follows the following rules: 1. A previously specified BindingInfo.BindingSource is never overwritten. 2. A complex type parameter registered in the DI container is assigned BindingSource.Services. 3. A complex type parameter not registered in the DI container is assigned BindingSource.Body. 4. A parameter with a name that appears as a route value in any route template is assigned BindingSource.Path. 5. All other parameters are assigned BindingSource.Query. Type of breaking change This change affects source compatibility. Reason for change This same behavior is already implemented in minimal APIs. The likelihood of breaking apps is low as it isn't common to have a type in DI and as an argument in your API controller action at the same time. Recommended action If you're broken by this change, you can disable the feature by setting DisableImplicitFromServicesParameters to true: C# Services.Configure<ApiBehaviorOptions>(options => { options.DisableImplicitFromServicesParameters = true; }); If you're broken by the change, but you want to bind from DI for specific API controller action parameters, you can disable the feature as shown above and use an attribute that implements IFromServiceMetadata, such as FromServicesAttribute: C# Services.AddScoped<SomeCustomType>(); [Route("[controller]")] [ApiController] public class MyController : ControllerBase { // Bind from DI [HttpPost] public ActionResult Post([FromServices]SomeCustomType service) => Ok(); } Affected APIs API controller actions ASPNET-prefixed environment variable precedence Article • 12/07/2022 Starting in .NET 7, and only when using the WebApplicationBuilder host, command-line arguments and DOTNET_ -prefixed environment variables override ASPNET_ -prefixed environment variables when reading from default host configuration sources. These sources are used to read host variables, such as the content root path and environment name, when the WebApplicationBuilder is constructed and serve as a base for app configuration. ASPNET_ -prefixed environment variables now have the lowest precedence of all of the default host configuration sources for WebApplicationBuilder . For other hosts, such as ConfigureWebHostDefaults and WebHost.CreateDefaultBuilder , ASPNET_ -prefixed environment variables still have the highest precedence. Version introduced ASP.NET Core 7.0 Previous behavior ASPNET_ -prefixed environment variables overrode command-line arguments and DOTNET_ -prefixed environment variables when reading WebApplicationBuilder 's default host configuration. New behavior Command-line arguments and DOTNET_ -prefixed environment variables override ASPNET_ -prefixed environment variables when reading WebApplicationBuilder 's default host configuration. Type of breaking change This is a behavioral change. Reason for change This change was made to prevent environment variables from overriding explicit command-line arguments when reading host variables. The new behavior is more consistent with application configuration, which has always given command-line arguments the highest precedence. Recommended action If you were using ASPNETCORE_ -prefixed environment variables to override commandline arguments or DOTNET_ -prefixed environment variables, use something with a higher priority. This could mean using custom WebApplicationOptions, which overrides all default hosting configuration sources. Affected APIs Microsoft.AspNetCore.Builder.WebApplicationBuilder See also Default host configuration sources AuthenticateAsync for remote auth providers Article • 11/08/2022 Remote authentication providers like OpenIdConnect, WsFederation, and OAuth have been updated to avoid unnecessary errors when there's no user information available on the request. Version introduced .NET 7 Previous behavior Previously, when AuthenticateAsync was called on a remote authentication provider and there was no current user, the call failed with a message similar to OpenIdConnect was not authenticated. Failure message: Not authenticated . New behavior Starting in .NET 7, AuthenticateAsync returns AuthenticateResult.NoResult(), an anonymous identity. Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior: Was inconsistent with Cookie and Negotiate authentication, which return AuthenticateResult.NoResult(). Caused excess failure logs, especially if the remote authentication handler was set as the default handler and invoked per request. Recommended action If you have code that directly invokes AuthenticateAsync, check it to ensure it properly handles AuthenticateResult.NoResult() and anonymous or empty ClaimsIdentity instances. Affected APIs Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.Authe nticateAsync Authentication in WebAssembly apps Article • 12/02/2022 We updated the support for authentication in Blazor WebAssembly apps to rely on the history state instead of query strings in the URL. As a result, existing applications that pass the return URL through the query string will fail to redirect back to the original page after a successful login. Existing applications should use the new NavigateToLogin extension method as it's able to flow the data to the login page correctly. Version introduced .NET 7 Previous behavior The return URL was specified in the query string as ?returnUrl=<<return-url>> . New behavior Starting in .NET 7, the return URL and other parameters passed to the authentication/login page are passed via the history.state entry of the page. Type of breaking change This change can affect binary compatibility. Reason for change We decided to switch to using history.state instead of the query string as it simplifies the implementation and removes the surface attack area associated with passing data through the query string. Recommended action Most apps have a RedirectToLogin.razor file that you can update as follows: razor @inject NavigationManager Navigation @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using Microsoft.Extensions.Options @inject IOptionsSnapshot<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions >> Options @code { protected override void OnInitialized() { Navigation.NavigateToLogin(Options.Get(Microsoft.Extensions.Options.Options. DefaultName).AuthenticationPaths.LogInPath); } } Affected APIs Microsoft.AspNetCore.Components.WebAssembly.Authentication.SignOutSessionS tateManager (obsoleted in favor of new NavigationManagerExtensions.NavigateToLogout method) See also RedirectToLogin component - Blazor WebAssembly Default authentication scheme Article • 05/04/2023 Starting in .NET 7, we introduced new behavior in the authentication area in ASP.NET Core. Previously, users were required to set the default authentication scheme, which is used by authentication and authorization handlers, in the AddAuthentication call: C# builder.Services.AddAuthentication("MyDefaultScheme"); Moving forward, when a single authentication scheme is registered, that scheme is treated as the default scheme. For example, "MyDefaultScheme" is treated as the default scheme in the following code. C# builder.Services.AddAuthentication().AddOAuth("MyDefaultScheme"); This change might expose unintended behavior changes in applications, such as authentication options being validated earlier than expected. Version introduced ASP.NET Core 7.0 Previous behavior Previously, when users did not provide a default scheme in the AddAuthentication call, no default scheme was set. C# builder.Services.AddAuthentication().AddCookie(); This impacted the behavior of authentication handlers in the application layer. New behavior Starting in ASP.NET Core 7.0, if (and only if) a single scheme is registered in an application, that scheme is treated as the default. In the following code, the CookieDefaults.AuthenticationScheme is treated as the default scheme. C# builder.Services.AddAuthentication().AddCookie(); However, in the next code snippet, no default is set because multiple schemes are registered. C# builder.Services.AddAuthentication().AddCookie().AddJwtBearer(); Type of breaking change This change affects binary compatibility. Reason for change This change was made to reduce boilerplate when configuring authentication and to set up sensible defaults. Recommended action The change only impacts applications that have a single scheme registered. For those scenarios, it's recommended to ensure that your application is prepared to handle the assumption that a single scheme is the default. For example, ensure that the options associated with that scheme are configured correctly. Alternatively, you can disable the new behavior by setting the Microsoft.AspNetCore.Authentication.SuppressAutoDefaultScheme app context flag. Affected APIs Authentication APIs. Event IDs for some Microsoft.AspNetCore.Mvc.Core log messages changed Article • 05/04/2023 As part of updating the Microsoft.AspNetcore.Mvc.Core assembly to use LoggerMessageAttribute, the ASP.NET Core team discovered logger event IDs that were reused within a single log category. Event IDs and names should be unique so that different message types can be identified. These IDs have been updated to ensure that they're unique within a single log category. Version introduced ASP.NET Core 7.0 Previous behavior Some logger event IDs within the Microsoft.AspNetCore.Mvc.Core assembly were reused within a single log category. New behavior Duplicate logger event IDs within a single log category within the Microsoft.AspNetCore.Mvc.Core assembly have been updated. Type of breaking change This change affects binary compatibility. Reason for change Logger event IDs and names should be unique so that different message types can be identified. Recommended action If you have code or configuration that references the old logger event IDs, update those references to use the new IDs. Affected APIs Not detectable via API analysis. Fallback file endpoints Article • 10/13/2022 The ConsumesAttribute attribute allows controller actions to specify their supported content types. Starting in .NET 6, if a fallback file endpoint was configured, it could match routes that were discarded because the request had a different content type than what was specified in an action's ConsumesAttribute. The .NET 6 behavior was an undesirable change from the .NET 5 behavior. This breaking change partially addresses the issue by making fallback file endpoints only match GET and HEAD requests. Version introduced ASP.NET Core 7.0 RC 2 Previous behavior Endpoints configured with StaticFilesEndpointRouteBuilderExtensions.MapFallbackToFile matched requests made with any request method. New behavior Endpoints configured with StaticFilesEndpointRouteBuilderExtensions.MapFallbackToFile only match HEAD and GET requests. Type of breaking change This change can affect binary compatibility. Reason for change This change partially reverts a larger breaking change accidentally introduced in .NET 6. Since it's highly unusual to expect a fallback file response when making a request with a method other than HEAD or GET , the impact of this breaking change should be minimal. Recommended action If you want fallback file endpoints to match requests with methods other than HEAD or GET, you can specify additional HTTP request methods using WithMetadata() . For example: C# endpoints.MapFallbackToFile("index.html") .WithMetadata(new HttpMethodMetadata(new[] { /* List supported methods here */ })); Affected APIs Microsoft.AspNetCore.Builder.StaticFilesEndpointRouteBuilderExtensions.MapFallba ckToFile IHubClients and IHubCallerClients hide members Article • 06/24/2022 To add support for client results, IHubClients and IHubCallerClients now hide interface members IClientProxy Client(string connectionId); and IClientProxy Caller { get; } with ISingleClientProxy Client(string connectionId); and ISingleClientProxy Caller { get; } . This is not a breaking change to production code unless you use reflection to call the affected Client or Caller methods. You may need to update unit testing SignalR Hubs. Version introduced ASP.NET Core 7.0 Previous behavior When using a testing library like Moq to unit test a SignalR Hub, you could write code similar to the following: C# var hub = new MyHub(); var mockCaller = new Mock<IHubCallerClients>(); var mockClientProxy = new Mock<IClientProxy>(); mockCaller.Setup(x => x.Caller).Returns(mockClientProxy.Object); hub.Clients = mockCaller.Object; class MyHub : Hub { } New behavior C# var hub = new MyHub(); var mockCaller = new Mock<IHubCallerClients>(); var mockClientProxy = new Mock<ISingleClientProxy>(); // <-- updated code mockCaller.Setup(x => x.Caller).Returns(mockClientProxy.Object); hub.Clients = mockCaller.Object; class MyHub : Hub { } Type of breaking change This change affects source compatibility. Reason for change The change was made to add new functionality to SignalR. It is non-breaking in normal use cases, however, it may break test code, which is easily updated. Recommended action Update test code to use the ISingleClientProxy interface when using reflection or reflection-based code. Affected APIs Microsoft.AspNetCore.SignalR.IHubClients Microsoft.AspNetCore.SignalR.IHubCallerClients Kestrel: Default HTTPS binding removed Article • 05/04/2023 The default HTTPS address and port have been removed from Kestrel in .NET 7. This change is part of dotnet/aspnetcore#42016 , which will improve the overall developer experience when dealing with HTTPS. Version introduced ASP.NET Core 7.0 Previous behavior Previously, if no values for the address and port were specified explicitly but a local development certificate was available, Kestrel defaulted to binding to both http://localhost:5000 and https://localhost:5001 . New behavior Users must now manually bind to HTTPS and specify the address and port explicitly, through one of the following means: The launchSettings.json file The ASPNETCORE_URLS environment variable The --urls command-line argument The urls host configuration key The UseUrls(IWebHostBuilder, String[]) extension method HTTP binding is unchanged. Type of breaking change This change affects binary compatibility. Reason for change The previous eager-binding behavior occurs without regard to the configured environment and can lead to a poor developer experience when the certificate has not yet been trusted (that is, trusted as root certificate authority because it's self-signed). Clients often produce a poor user experience when hitting an HTTPS endpoint with an untrusted certificate. For example, they might fail silently or show an error or warning screen that alarms the user. Recommended action If you weren't using the default https://localhost:5001 binding, no changes are required. However, if you were using this binding, see Configure endpoints for the ASP.NET Core Kestrel web server to learn how you can update your server to enable HTTPS. Affected APIs N/A Microsoft.AspNetCore.Server.Kestrel.Tra nsport.Libuv and libuv.dll removed Article • 05/04/2023 Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv and libuv.dll have been removed. Version introduced ASP.NET Core 7.0 Previous behavior Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv was obsoleted in ASP.NET Core 5.0. Its functionality was replaced by the Sockets transport. New behavior Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv and its libuv.dll dependency have been removed. Type of breaking change This change affects binary compatibility and source compatibility. Reason for change To eliminate ongoing maintenance costs associated with this obsolete component. Recommended action Remove project references to Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv. Remove code from Program.cs that calls UseLibuv . The Sockets transport will be used by default. Affected APIs Microsoft.AspNetCore.Hosting.WebHostBuilderLibuvExtensions.UseLibuv Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions Microsoft.Data.SqlClient updated to 4.0.1 Article • 05/04/2023 The Microsoft.Data.SqlClient package has been updated to 4.0.1. Version introduced ASP.NET Core 7.0 Previous behavior The previous version of the package was 1.0.19249.1 . New behavior The new version of the Microsoft.Data.SqlClient package is 4.0.1 . You can see breaking changes in the 4.0 band in the Microsoft.Data.SqlClient 4.0.0 Release Notes . By default, Encrypt now equals true . For more information, see Encrypt default value set to true . Type of breaking change This change affects source compatibility. Reason for change For improvements in the underlying libraries. Recommended action The ASP.NET Core team didn't have to react to any public API changes from this change. However, it's possible that there are breaking changes in the packages themselves that you'll need to react to. Affected APIs Microsoft.Extensions.Caching.SqlServer Middleware no longer defers to endpoint with null request delegate Article • 05/04/2023 As detailed in https://github.com/dotnet/aspnetcore/issues/42413 , the file-serving middleware ( DefaultFilesMiddleware , DirectoryBrowserMiddleware , and StaticFileMiddleware ) have been updated to no longer no-op (that is, defer to the next middleware in the pipeline) when there's an active endpoint with a null request delegate. Version introduced ASP.NET Core 7.0 Previous behavior Previously, if the current request had an active endpoint, that is, HttpContext.GetEndpoint() != null , the file-serving middleware would perform no action and simply delegate to the next middleware in the request pipeline. New behavior The file-serving middleware will now only perform no action if there's an active endpoint and its RequestDelegate property value is not null , that is, HttpContext.GetEndpoint()?.RequestDelegate is not null . Type of breaking change This change affects binary compatibility. Reason for change This change enables endpoints to share metadata with endpoint-aware middleware while allowing other middleware that would otherwise defer to also function. Endpoints can be active in the request for the purposes of setting and sharing metadata with middleware that are endpoint-aware so that they can perform their intended function. Other middleware that would previously defer their behavior when an endpoint was active, for example, the file-serving middleware, can also function. For example, an endpoint with a null request delegate containing authorization metadata can be set as the active endpoint for a request. This causes the AuthorizationMiddleware to enforce authorization requirements, which, if satisfied, would allow the StaticFileMiddleware to serve the requested files. Recommended action If you rely on setting an active endpoint on the request to suppress the behavior of the file-serving middleware, ensure that the endpoint has a non-null value set for its RequestDelegate property. Affected APIs IApplicationBuilder.UseStaticFiles() IApplicationBuilder.UseDefaultFiles() IApplicationBuilder.UseDirectoryBrowser() MVC's detection of an empty body in model binding changed Article • 05/04/2023 The mechanism to detect an empty request body during MVC model binding now uses IHttpRequestBodyDetectionFeature.CanHaveBody. This property is set to: true : For HTTP/1.x requests with a non-zero Content-Length request header or a Transfer-Encoding: chunked request header. For HTTP/2 requests that don't set the END_STREAM flag on the initial header's frame. false : For HTTP/1.x requests with no Content-Length or Transfer-Encoding: chunked request headers, or if the Content-Length request header is 0 . For HTTP/1.x requests with a Connection: Upgrade request header, such as for WebSockets requests. There's no HTTP request body for such requests, so no data should be received until after the upgrade. For HTTP/2 requests that set the END_STREAM flag on the initial header's frame. The previous behavior performed a minimal validation of Content-Length = 0 . In some scenarios, when requests don't include all required HTTP headers and flags, request bodies can now be detected as having an empty body and report a failure to the client. Version introduced ASP.NET Core 7.0 Previous behavior If a controller action binds a parameter from the request body and the client request doesn't include a Content-Length request header, the framework throws an internal exception during deserialization of the request body. For example, the System.Text.Json -based input formatter throws an exception similar to the following: System.Text.Json.JsonException: 'The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.' The following example JSON shows the previous exception formatted as a ProblemDetails response: JSON { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-34e98b5841b88bfb5476965efd9d9c8c-5bb16bc50dfbabb7-00", "errors": { "$": [ "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0." ], "value": [ "The value field is required." ] } } New behavior Deserialization is no longer attempted if IHttpRequestBodyDetectionFeature.CanHaveBody is false . The following example ProblemDetails response shows how the error message returned to clients indicates that the request body is empty: JSON { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-0f87920dc675fdfdf8d7638d3be66577-bd6bdbf32d21b714-00", "errors": { "": [ "A non-empty request body is required." ], "value": [ "The value field is required." ] } } Type of breaking change This change affects binary compatibility. Reason for change To align with other parts of the framework that use IHttpRequestBodyDetectionFeature.CanHaveBody and to fix Optional [FromBody] Model Binding is not working (dotnet/aspnetcore #29570) . Recommended action No changes are required. However, if you're seeing unexpected behavior, ensure that client requests send the appropriate HTTP headers. Affected APIs MVC controller actions Output caching API changes Article • 10/27/2022 Some APIs in the Microsoft.AspNetCore.OutputCaching namespace have changed to better represent their intent. The following APIs were removed: OutputCachePolicyBuilder.#ctor OutputCachePolicyBuilder.Clear The following APIs were renamed: Previous name New name AllowLocking(System.Boolean) SetLocking(Boolean) VaryByRouteValue(System.String[]) SetVaryByRouteValue(String[]) VaryByQuery(System.String[]) SetVaryByQuery(String[]) VaryByHeader(System.String[]) SetVaryByHeader(String[]) The following APIs were added: CacheVaryByRules.VaryByHost OutputCacheOptions.AddPolicy(String, Action<OutputCachePolicyBuilder>, Boolean) OutputCacheOptions.AddBasePolicy(Action<OutputCachePolicyBuilder>, Boolean) Microsoft.Extensions.DependencyInjection.OutputCacheConventionBuilderExtensio ns.CacheOutput<TBuilder>(TBuilder, Action<OutputCachePolicyBuilder>, Boolean) Version introduced ASP.NET Core 7.0 RC 2 Previous behavior OutputCachePolicyBuilder.VaryByQuery(System.String[]) was additive: every call added more query string keys. New behavior The OutputCachePolicyBuilder.VaryByQuery(System.String[]) method is now named OutputCachePolicyBuilder.SetVaryByQuery(String[]), and each call replaces existing query string keys. For other changes, see the first section of this article. Type of breaking change This change affects source compatibility and binary compatibility. Reason for change This change was made to improve the consistency of method names and to remove ambiguity in their behavior. Recommended action Recompile any projects built with an earlier SDK. If you referenced any of these method names directly, update the source to reflect the new names. Affected APIs Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.#ctor Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.Clear Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.AllowLocking(Syste m.Boolean) Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.VaryByRouteValue(S ystem.String[]) Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.VaryByQuery(System .String[]) Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.VaryByHeader(Syste m.String[]) SignalR Hub methods try to resolve parameters from DI Article • 05/04/2023 SignalR Hub methods now support injecting services from your Dependency Injection (DI) container. In rare cases, this can break apps that have a type in DI that is also accepted in Hub methods from SignalR client messages. Version introduced ASP.NET Core 7.0 Previous behavior If you accepted a type in your Hub method that was also in your Dependency Injection container, the type would always be resolved from a message sent by the client. C# Services.AddScoped<SomeCustomType>(); class MyHub : Hub { // type always comes from the client, never comes from DI public Task Method(string text, SomeCustomType type) => Task.CompletedTask; } New behavior Types in DI are checked at app startup using IServiceProviderIsService to determine if an argument in a Hub method comes from DI or from the client. In the following example, which assumes you're using the default DI container, SomeCustomType comes from the DI container instead of from the client. If the client tries to send SomeCustomType , it gets an error: C# Services.AddScoped<SomeCustomType>(); class MyHub : Hub { // comes from DI by default public Task Method(string text, SomeCustomType type) => Task.CompletedTask; } Type of breaking change This change affects source compatibility. Reason for change This change improves the user experience when using different services in different Hub methods. It also improves performance by not requiring the user to inject all dependencies in the Hub's constructor. The likelihood of breaking apps is low as it isn't common to have a type in DI and as an argument in your Hub method at the same time. Recommended action If you're broken by this change, you can disable the feature by setting DisableImplicitFromServicesParameters to true: C# Services.AddSignalR(options => { options.DisableImplicitFromServicesParameters = true; }); If you're broken by the change, but you want to use the feature without breaking clients, you can disable the feature as shown above and use an attribute that implements IFromServiceMetadata on new arguments/Hub methods: C# Services.AddScoped<SomeCustomType>(); Services.AddScoped<SomeCustomType2>(); class MyHub : Hub { // old method with new feature (non-breaking), only SomeCustomType2 is resolved from DI public Task MethodA(string arguments, SomeCustomType type, [FromServices] SomeCustomType2 type2); // new method public Task MethodB(string arguments, [FromServices] SomeCustomType type); } Affected APIs Hub methods API obsoletions with default diagnostic ID (.NET 7) Article • 11/08/2022 Several APIs have been marked as obsolete in .NET 7. Referencing these APIs in your code will result in build warnings. In C#, the compiler diagnostic for these obsoletions is CS0618. Previous behavior Previously, the affected APIs could be referenced without any build warnings. New behavior Starting in .NET 7, referencing the affected APIs will result in build warnings. Version introduced .NET 7 Preview 3 Type of breaking change These obsoletions can affect source compatibility. Reason for change These APIs were previously marked obsolete in the implementation assemblies but not in the reference assemblies. The reference assemblies have now been updated to match the implementation assemblies. Recommended action Follow the recommended action that's emitted when you use the obsolete API. Affected APIs System.ComponentModel.IComNativeDescriptorHandler System.ComponentModel.MemberDescriptor.GetInvokee(Type, Object) System.ComponentModel.RecommendedAsConfigurableAttribute System.Data.OleDb.OleDbParameterCollection.Add(String, Object) System.Net.FileWebRequest.GetObjectData(SerializationInfo, StreamingContext) System.Net.FileWebRequest.System.Runtime.Serialization.ISerializable.GetObjectDa ta(SerializationInfo, StreamingContext) System.Net.FileWebResponse.GetObjectData(SerializationInfo, StreamingContext) System.Net.FileWebResponse.System.Runtime.Serialization.ISerializable.GetObjectD ata(SerializationInfo, StreamingContext) System.Net.Http.HttpRequestMessage.Properties System.Net.WebRequest.GetObjectData(SerializationInfo, StreamingContext) System.Net.WebRequest.System.Runtime.Serialization.ISerializable.GetObjectData(S erializationInfo, StreamingContext) WebResponse(SerializationInfo, StreamingContext) constructor System.Net.WebResponse.GetObjectData(SerializationInfo, StreamingContext) System.Net.WebResponse.System.Runtime.Serialization.ISerializable.GetObjectData (SerializationInfo, StreamingContext) System.Security.Cryptography.PasswordDeriveBytes.GetBytes(Int32) System.Web.HttpUtility.UrlEncodeUnicode(String) System.Web.HttpUtility.UrlEncodeUnicodeToBytes(String) API obsoletions with non-default diagnostic IDs (.NET 7) Article • 11/08/2022 Some APIs have been marked as obsolete, starting in .NET 7. This breaking change is specific to APIs that have been marked as obsolete with a custom diagnostic ID. Suppressing the default obsoletion diagnostic ID, which is CS0618 for the C# compiler, does not suppress the warnings that the compiler generates when these APIs are used. Change description In previous .NET versions, these APIs can be used without any build warning. In .NET 7 and later versions, use of these APIs produces a compile-time warning or error with a custom diagnostic ID. The use of custom diagnostic IDs allows you to suppress the obsoletion warnings individually instead of blanket-suppressing all obsoletion warnings. The following table lists the custom diagnostic IDs and their corresponding warning messages for obsoleted APIs. Diagnostic ID Description Severity SYSLIB0036 Regex.CompileToAssembly is obsolete and not supported. Use RegexGeneratorAttribute with the regular expression source generator Warning instead. SYSLIB0037 AssemblyName members HashAlgorithm, ProcessorArchitecture, and VersionCompatibility are obsolete and not supported. Warning SYSLIB0038 SerializationFormat.Binary is obsolete and should not be used. Warning SYSLIB0039 TLS versions 1.0 and 1.1 have known vulnerabilities and are not Warning recommended. Use a newer TLS version instead, or use SslProtocols.None to defer to OS defaults. SYSLIB0040 EncryptionPolicy.NoEncryption and EncryptionPolicy.AllowNoEncryption significantly reduce security and should not be used in production code. Warning SYSLIB0041 The default hash algorithm and iteration counts in Rfc2898DeriveBytes constructors are outdated and insecure. Use a constructor that accepts the hash algorithm and the number of iterations. Warning Diagnostic ID Description Severity SYSLIB0042 ToXmlString and FromXmlString have no implementation for elliptic Warning curve cryptography (ECC) types, and are obsolete. Use a standard import and export format such as ExportSubjectPublicKeyInfo or ImportSubjectPublicKeyInfo for public keys, and ExportPkcs8PrivateKey or ImportPkcs8PrivateKey for private keys. SYSLIB0043 ECDiffieHellmanPublicKey.ToByteArray() and the associated constructor do not have a consistent and interoperable implementation on all Warning platforms. Use ECDiffieHellmanPublicKey.ExportSubjectPublicKeyInfo() instead. SYSLIB0044 AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Warning SYSLIB0045 Cryptographic factory methods accepting an algorithm name are Warning obsolete. Use the parameterless Create factory method on the algorithm type instead. SYSLIB0047 XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver Warning instead to forbid resolution of external XML resources. Version introduced .NET 7 Type of breaking change These obsoletions can affect source compatibility. Recommended action Follow the specific guidance provided for the each diagnostic ID using the URL link provided on the warning. Warnings or errors for these obsoletions can't be suppressed using the standard diagnostic ID for obsolete types or members; use the custom SYSLIBxxxx diagnostic ID value instead. Affected APIs SYSLIB0036 Regex.CompileToAssembly SYSLIB0037 AssemblyName.HashAlgorithm AssemblyName.ProcessorArchitecture AssemblyName.VersionCompatibility SYSLIB0038 System.Data.SerializationFormat.Binary SYSLIB0039 System.Security.Authentication.SslProtocols.Tls System.Security.Authentication.SslProtocols.Tls11 SYSLIB0040 System.Net.Security.EncryptionPolicy.AllowNoEncryption System.Net.Security.EncryptionPolicy.NoEncryption SYSLIB0041 Rfc2898DeriveBytes(String, Byte[]) Rfc2898DeriveBytes(String, Int32) Rfc2898DeriveBytes(Byte[], Byte[], Int32) Rfc2898DeriveBytes(String, Byte[], Int32) Rfc2898DeriveBytes(String, Int32, Int32) SYSLIB0042 System.Security.Cryptography.ECDiffieHellmanCng.FromXmlString(String, ECKeyXmlFormat) System.Security.Cryptography.ECDiffieHellmanCng.ToXmlString(ECKeyXmlFormat) System.Security.Cryptography.ECDiffieHellmanCngPublicKey.FromXmlString(String) System.Security.Cryptography.ECDiffieHellmanCngPublicKey.ToXmlString() System.Security.Cryptography.ECDiffieHellmanPublicKey.ToXmlString() System.Security.Cryptography.ECDsaCng.FromXmlString(String, ECKeyXmlFormat) System.Security.Cryptography.ECDsaCng.ToXmlString(ECKeyXmlFormat) SYSLIB0043 System.Security.Cryptography.ECDiffieHellmanPublicKey.ToByteArray() ECDiffieHellmanPublicKey(Byte[]) SYSLIB0045 System.Security.Cryptography.Aes.Create(String) System.Security.Cryptography.AsymmetricAlgorithm.Create(String) System.Security.Cryptography.DES.Create(String) System.Security.Cryptography.ECDiffieHellman.Create(String) System.Security.Cryptography.ECDsa.Create(String) System.Security.Cryptography.HashAlgorithm.Create(String) System.Security.Cryptography.KeyedHashAlgorithm.Create(String) System.Security.Cryptography.RandomNumberGenerator.Create(String) System.Security.Cryptography.RC2.Create(String) System.Security.Cryptography.Rijndael.Create(String) System.Security.Cryptography.RSA.Create(String) System.Security.Cryptography.SHA1.Create(String) System.Security.Cryptography.SHA256.Create(String) System.Security.Cryptography.SHA384.Create(String) System.Security.Cryptography.SHA512.Create(String) System.Security.Cryptography.SymmetricAlgorithm.Create(String) System.Security.Cryptography.TripleDES.Create(String) SYSLIB0047 System.Xml.XmlSecureResolver See also API obsoletions with non-default diagnostic IDs (.NET 6) API obsoletions with non-default diagnostic IDs (.NET 5) Obsolete features in .NET 5+ BrotliStream no longer allows undefined CompressionLevel values Article • 11/30/2022 The BrotliStream constructors that take a CompressionLevel argument no longer allow values that aren't defined in the CompressionLevel enumeration. If you pass an invalid value, an ArgumentException is thrown. Previous behavior BrotliStream allowed you to pass an arbitrary compression level to the constructor by casting the desired level directly to CompressionLevel. For example: C# BrotliStream brotli = new BrotliStream(baseStream, (CompressionLevel)5); // Use level 5 However, if an arbitrary level was provided, that was passed through as-is to the underlying library, resulting in inconsistent and potentially unexpected behavior. New behavior BrotliStream only allows the values defined in CompressionLevel. If you pass an undefined value to the constructor, an ArgumentException is thrown. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The purpose of the CompressionLevel enumeration is to let developers use compression algorithms without needing to understand the meaning of their tuning parameters. If an arbitrary level was provided, that was passed through as-is to the underlying library, resulting in inconsistent and potentially unexpected behavior. With this change, the behavior is aligned with other compression streams, for example, DeflateStream. With the new tuning of the CompressionLevel values and the addition of CompressionLevel.SmallestSize, it's now possible to have a variety of trade-offs in the compression algorithms. Users can continue to rely on CompressionLevel values as being abstractions of such trade-offs. Recommended action If you were relying on passing undefined values as the CompressionLevel, revisit your use case and decide which documented value is the most optimal for it. Affected APIs BrotliStream(Stream, CompressionLevel, Boolean) BrotliStream(Stream, CompressionLevel) C++/CLI projects in Visual Studio Article • 04/19/2023 .NET 7 includes generic math APIs that use static abstract interface members on primitive types, such as Int32. Earlier versions of the C++/CLI compiler were incompatible with such members. Because those members are used on many primitive types, compilation errors will occur when targeting net7.0 , even if you don't use the generic math features directly. Beyond C++/CLI, it's also possible that the introduction of static abstract interface members on primitive System types will surface issues in other tools that aren't forwardcompatible with the usage of this new language construct. If you're a tool author, you'll need to update any tools impacted by this change to accommodate the usage of static abstract interface members. If you need help, file an issue in the dotnet/runtime repo to request guidance. Previous behavior Previously, compiling .NET projects using C++/CLI did not result in errors related to members on primitive System types. New behavior Compiling a net7.0 project using C++/CLI in a release of Visual Studio prior to version 17.2 will result in many errors similar to this example: txt error C2253: 'System.Int32.Parse': pure specifier or abstract override specifier only allowed on virtual function Other than upgrading, there's no way to work around this compiler error. It's generated because of static abstract interface members on primitive System types. When you upgrade to Visual Studio 2022 version 17.2, the compilation errors will no longer occur. Implicitly implemented static abstract interface members can be invoked, but even with Visual Studio 2022 version 17.2, C++/CLI doesn't support invoking explicitly implemented static abstract interface members. Version introduced .NET 7 Type of breaking change This change can affect source compatibility. Reason for change .NET 7 includes the new API definitions for the generic math feature set. These APIs were introduced in .NET 6 as a preview feature and required you to install the System.Runtime.Experimental package to gain access. Starting in .NET 7, these generic math APIs are included "in box". Recommended action To continue using C++/CLI with .NET 7, upgrade to Visual Studio 2022 version 17.2 or a later version. Affected APIs N/A See also Visual Studio 2022 version 17.2 - release notes Collectible Assembly in non-collectible AssemblyLoadContext Article • 11/08/2022 .NET incorrectly allowed garbage-collectible assemblies to resolve into a non-collectible AssemblyLoadContext. In some cases, this lead to runtime crashes or unexpected NullReferenceException exceptions. This change prevents the incorrect behavior by throwing an exception when the AssemblyLoadContext.Load(AssemblyName) or AssemblyLoadContext.Resolving event returns a collectible Assembly and the AssemblyLoadContext is non-collectible. Previous behavior Returning a collectible Assembly in the AssemblyLoadContext.Load(AssemblyName) override or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext doesn't cause any exceptions to be thrown. New behavior Returning a collectible Assembly in the AssemblyLoadContext.Load(AssemblyName) override or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext throws a System.IO.FileLoadException with a NotSupportedException as the inner exception. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change This change fixes a bug. The collectible Assembly would be garbage-collected while the AssemblyLoadContext that has a reference to it is alive for the rest of the process lifetime. If the code running in that context references anything from that Assembly after it's collected, it would crash the runtime or result in a NullReferenceException, AccessViolationException, or other kinds of bad behavior. Recommended action Don't return collectible assemblies in AssemblyLoadContext.Load(AssemblyName) or the AssemblyLoadContext.Resolving event of a non-collectible AssemblyLoadContext. A possible workaround is to change the AssemblyLoadContext to be collectible by passing true for the isCollectible parameter in its constructor, and then keep a reference to that AssemblyLoadContext forever to make sure it's never collected. Affected APIs System.Runtime.Loader.AssemblyLoadContext.Load(AssemblyName) System.Runtime.Loader.AssemblyLoadContext.Resolving event See also Use collectible AssemblyLoadContext DateTime addition methods precision change Article • 02/03/2023 In .NET 6 and earlier versions, the value parameter of the DateTime addition methods was rounded to the nearest millisecond. In .NET 7 and later versions, the full Double precision of the value parameter is used. However, due to the inherent imprecision of floating-point math, the resulting precision will vary. Previous behavior Previously, the double value parameter of the DateTime Add* methods, for example, DateTime.AddDays(Double), was rounded to the nearest millisecond. New behavior Starting in .NET 7, the full precision of the double value parameter is used, improving the precision of the affected methods. Version introduced .NET 7 Type of breaking change This change is a behavioral change. Reason for change This change was made in response to a community request to improve the precision in DateTime. Recommended action No specific action unless you have code that depends on the precision of the Add* methods. In that case, review your code and retest it to avoid any surprises with the precision change. Affected APIs System.DateTime.AddDays(Double) System.DateTime.AddHours(Double) System.DateTime.AddMicroseconds(Double) System.DateTime.AddMilliseconds(Double) System.DateTime.AddMinutes(Double) System.DateTime.AddSeconds(Double) Equals method behavior change for NaN Article • 11/08/2022 The Equals(T other) instance method for the following types was updated to meet the IEquatable<T> implementation requirements. As a result, the method now correctly handles NaN. This change ensures the types can correctly be used alongside GetHashCode , Dictionary<TKey,TValue>, and other hash sets. System.Numerics.Matrix3x2 System.Numerics.Matrix4x4 System.Numerics.Plane System.Numerics.Quaternion System.Numerics.Vector2 System.Numerics.Vector3 System.Numerics.Vector4 System.Numerics.Vector<T> System.Runtime.Intrinsics.Vector64<T> System.Runtime.Intrinsics.Vector128<T> System.Runtime.Intrinsics.Vector256<T> Previous behavior Previously, the Equals(T other) instance method followed the IEEE 754 requirements and deferred to the == implementation. This meant that NaN != NaN , even when the two NaN are bitwise identical. For example: C# float f = float.NaN; Console.WriteLine(f == f); Console.WriteLine(f.Equals(f)); // False // True While for several of the listed types: C# Vector2 v = new Vector2(float.NaN); Console.WriteLine(v == v); // False Console.WriteLine(v.Equals(v)); // False This is problematic because using one of these types as a key in a dictionary meant that the key could never be resolved: C# Vector2 v = new Vector2(float.NaN); var s = new HashSet<Vector2>(); s.Add(v); Console.WriteLine(s.Contains(v)); // False New behavior The behavior is now the same as for the primitive floating-point types, which is that the == and != methods continue to follow the IEEE 754 requirements where NaN != NaN . But the Equals(T other) instance methods follow the IEquatable<T> requirements so that NaN.Equals(NaN) . For example (no change): C# float f = float.NaN; Console.WriteLine(f == f); Console.WriteLine(f.Equals(f)); // False // True While for several of the listed types (the second line now prints True ): C# Vector2 v = new Vector2(float.NaN); Console.WriteLine(v == v); // False Console.WriteLine(v.Equals(v)); // True And when used in some hash set (the output now prints True ): C# Vector2 v = new Vector2(float.NaN); var s = new HashSet<Vector2>(); s.Add(v); Console.WriteLine(s.Contains(v)); // True Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The previous implementation did not meet the implementation requirements of IEquatable<T> or object.Equals(object obj) . This resulted in the affected types not being usable in hash sets or with GetHashCode . Recommended action If you prefer the previous behavior, switch to using == or != instead of Equals(T other) . Affected APIs System.Numerics.Matrix3x2.Equals System.Numerics.Matrix4x4.Equals System.Numerics.Plane.Equals System.Numerics.Quaternion.Equals System.Numerics.Vector2.Equals System.Numerics.Vector3.Equals System.Numerics.Vector4.Equals System.Numerics.Vector<T>.Equals System.Runtime.Intrinsics.Vector64<T>.Equals System.Runtime.Intrinsics.Vector128<T>.Equals System.Runtime.Intrinsics.Vector256<T>.Equals EventSource callback behavior Article • 06/16/2023 For an EventCommand.Disable, the EventSource is now marked as disabled before the callback is issued. Previous behavior Previously, the EventSource.OnEventCommand(EventCommandEventArgs) callback was issued for an EventCommand.Disable prior to setting m_eventSourceEnabled=false . This meant that EventSource.IsEnabled() returned true in the OnEventCommand(EventCommandEventArgs) callback for a user EventSource, even if the command led to the EventSource being disabled. The callback happened after the ability to dispatch events was turned off though, so even if an EventSource tried to fire an event, it wasn't written. New behavior Now, the EventSource is marked as disabled before the callback is issued for an EventCommand.Disable. Version introduced .NET 6 servicing .NET 7 servicing Type of breaking change This change is a behavioral change. Reason for change This change was necessary to support multiple EventCounter instances. The ability to have multiple instances has been requested by multiple customers. In addition, EventCommand.Enable has always issued a consistent view: EventSource.IsEnabled() accurately reports the enabled status, and EventSource can write events from the OnEventCommand callback. This change makes the EventCommand.Disable behavior consistent with EventCommand.Enable . Recommended action It's unlikely that there's a scenario where the previous behavior is desired, and there's no way to revert the behavior. Affected APIs System.Diagnostics.Tracing.EventCommand.Disable Generic type constraint on PatternContext<T> Article • 11/08/2022 As part of annotating the .NET library for nullable reference types, a new generic constraint was added to PatternContext<TFrame>. If you're consuming this class directly, your code may break if the TFrame type is not a struct. Previous behavior Previously, PatternContext<TFrame> allowed any type to fill the TFrame type parameter. New behavior Starting in .NET 7, the generic type parameter on PatternContext<TFrame>, TFrame , is constrained to be a struct. Version introduced .NET 7 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change This change was necessary to annotate the type correctly for nullable contexts. Recommended action If you're currently using this type in your code, we recommend that you remove it. This type supports infrastructure and is not intended to be used directly from your code. Affected APIs Microsoft.Extensions.FileSystemGlobbing.Internal.PatternContexts.PatternContext< TFrame> Legacy FileStream strategy removed Article • 05/25/2023 The AppContext switch System.IO.UseNet5CompatFileStream and the ability to use the legacy FileStream implementation were removed. Previous behavior The legacy FileStream implementation was available and you could opt into it by using the UseNet5CompatFileStream switch or the DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM environment variable. New behavior Starting in .NET 7, you can no longer opt in to use the legacy FileStream implementation. Version introduced .NET 7 Preview 1 Type of breaking change This change can affect binary compatibility. Reason for change The UseNet5CompatFileStream switch and DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM environment variable were included in .NET 6 in case the new implementation caused breaking changes. Any breaking changes have now been fixed. Since there are no more bugs introduced by the FileStream changes, the compatibility mode was removed and with it all the legacy code, which makes the codebase easier to maintain. Recommended action If you're currently using the switch (or the DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM environment variable) to opt into legacy code and are upgrading to .NET 7, the switch will no longer have any effect and you should remove it. Affected APIs System.IO.FileStream System.IO.File.Create(String) System.IO.File.Create(String, Int32) System.IO.File.Create(String, Int32, FileOptions) System.IO.File.Create(String, Int32, FileOptions, FileSecurity) System.IO.File.Open(String, FileMode) System.IO.File.Open(String, FileStreamOptions) System.IO.File.Open(String, FileMode, FileAccess) System.IO.File.Open(String, FileMode, FileAccess, FileShare) System.IO.File.OpenRead(String) System.IO.File.OpenWrite(String) System.IO.FileSystemAclExtensions.Create(FileInfo, FileMode, FileSystemRights, FileShare, Int32, FileOptions, FileSecurity) System.IO.FileInfo.Create() System.IO.FileInfo.Open System.IO.FileInfo.OpenRead() System.IO.FileInfo.OpenWrite() See also FileStream no longer synchronizes file offset with OS (.NET 6) FileStream.Position updates after ReadAsync or WriteAsync completes (.NET 6) Library support for older frameworks Article • 11/08/2022 Installing the core libraries packages into projects whose target framework is older than the following versions is no longer supported: .NET Framework 4.6.2 .NET 6 .NET Standard 2.0 Previous behavior The latest non-prerelease core libraries packages that were part of the ".NET 6" wave were supported when used from projects targeting .NET Framework 4.6.1 or later, .NET Core 3.1 and later, or .NET Standard 2.0 or later. New behavior .NET 7 core libraries packages are supported for use in projects targeting .NET Framework 4.6.2 and later, .NET 6 and later, or .NET Standard 2.0 or later. Version introduced .NET 7 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change Building packages for all existing frameworks increases the complexity and size of a package. The following frameworks are now out-of-support and we no longer build packages for these frameworks: .NET Framework 4.6.1 .NET Core 3.1 .NET 5 Recommended action If your project is no longer being evolved and only maintained, simply don't upgrade the impacted packages. If your project is actively developed, upgrade it to one of the following frameworks: .NET Framework 4.6.2 .NET Core 6 .NET Standard 2.0 Affected APIs The following packages no longer ship old frameworks: Microsoft.Bcl.AsyncInterfaces Microsoft.Extensions.Caching.Abstractions Microsoft.Extensions.Caching.Memory Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.Abstractions Microsoft.Extensions.Configuration.Binder Microsoft.Extensions.Configuration.CommandLine Microsoft.Extensions.Configuration.EnvironmentVariables Microsoft.Extensions.Configuration.FileExtensions Microsoft.Extensions.Configuration.Ini Microsoft.Extensions.Configuration.Json Microsoft.Extensions.Configuration.UserSecrets Microsoft.Extensions.Configuration.Xml Microsoft.Extensions.DependencyInjection Microsoft.Extensions.DependencyInjection.Abstractions Microsoft.Extensions.DependencyInjection.Specification.Tests Microsoft.Extensions.DependencyModel Microsoft.Extensions.FileProviders.Abstractions Microsoft.Extensions.FileProviders.Composite Microsoft.Extensions.FileProviders.Physical Microsoft.Extensions.FileSystemGlobbing Microsoft.Extensions.Hosting Microsoft.Extensions.Hosting.Abstractions Microsoft.Extensions.Hosting.Systemd Microsoft.Extensions.Hosting.WindowsServices Microsoft.Extensions.Http Microsoft.Extensions.Logging Microsoft.Extensions.Logging.Abstractions Microsoft.Extensions.Logging.Configuration Microsoft.Extensions.Logging.Console Microsoft.Extensions.Logging.Debug Microsoft.Extensions.Logging.EventLog Microsoft.Extensions.Logging.EventSource Microsoft.Extensions.Logging.TraceSource Microsoft.Extensions.Options Microsoft.Extensions.Options.ConfigurationExtensions Microsoft.Extensions.Options.DataAnnotations Microsoft.Extensions.Primitives Microsoft.NET.WebAssembly.Threading Microsoft.NETCore.Platforms Microsoft.Win32.Registry.AccessControl Microsoft.Win32.SystemEvents Microsoft.Windows.Compatibility Microsoft.XmlSerializer.Generator System.CodeDom System.Collections.Immutable System.ComponentModel.Composition System.ComponentModel.Composition.Registration System.Composition System.Composition.AttributedModel System.Composition.Convention System.Composition.Hosting System.Composition.Runtime System.Composition.TypedParts System.Configuration.ConfigurationManager System.Data.Odbc System.Data.OleDb System.Diagnostics.DiagnosticSource System.Diagnostics.EventLog System.Diagnostics.PerformanceCounter System.DirectoryServices System.DirectoryServices.AccountManagement System.DirectoryServices.Protocols System.Drawing.Common System.Formats.Asn1 System.Formats.Cbor System.IO.Hashing System.IO.Packaging System.IO.Pipelines System.IO.Ports System.Management System.Memory.Data System.Net.Http.Json System.Net.Http.WinHttpHandler System.Numerics.Tensors System.Reflection.Context System.Reflection.Metadata System.Reflection.MetadataLoadContext System.Resources.Extensions System.Runtime.Caching System.Runtime.Serialization.Schema System.Security.Cryptography.Cose System.Security.Cryptography.Pkcs System.Security.Cryptography.ProtectedData System.Security.Cryptography.Xml System.Security.Permissions System.ServiceModel.Syndication System.ServiceProcess.ServiceController System.Speech System.Text.Encoding.CodePages System.Text.Encodings.Web System.Text.Json System.Threading.AccessControl System.Threading.Channels System.Threading.RateLimiting System.Threading.Tasks.Dataflow System.Windows.Extensions Maximum precision for numeric format strings Article • 11/08/2022 The maximum precision when formatting numbers as strings using ToString and TryFormat has been changed from Int32.MaxValue to 999,999,999. (The maximum precision was previously changed to Int32.MaxValue in .NET 6.) In addition, the maximum exponent allowed when parsing a BigInteger from a string has been limited to 999,999,999. Previous behavior In .NET 6, the standard numeric format parsing logic was limited to a precision of Int32.MaxValue or less. The intended behavior was to throw a FormatException for any precision larger than Int32.MaxValue. However, due to a bug, .NET 6 didn't throw that exception for some such inputs. The intended behavior was: C# double d = 123.0; d.ToString("E" + int.MaxValue.ToString()); // Doesn't throw. long intMaxPlus1 = (long)int.MaxValue + 1; string intMaxPlus1String = intMaxPlus1.ToString(); Assert.Throws<FormatException>(() => d.ToString("E" + intMaxPlus1String)); // Throws. In addition, there was no limit on the exponent size when parsing a BigInteger from a string. New behavior Starting in .NET 7, .NET supports precision up to 999,999,999. A FormatException is thrown if the precision is greater than 999,999,999. This change was implemented in the parsing logic that affects all numeric types. C# double d = 123.0; Assert.Throws<FormatException>(() => d.ToString("E" + int.MaxValue.ToString())); // Throws. long intMaxPlus1 = (long)int.MaxValue + 1; string intMaxPlus1String = intMaxPlus1.ToString(); Assert.Throws<FormatException>(() => d.ToString("E" + intMaxPlus1String)); // Throws. d.ToString("E999999999"); // Doesn't throw. d.ToString("E00000999999999"); // Doesn't throw. In addition, if you attempt to parse a BigInteger with an exponent greater than 999,999,999 from a string, a FormatException is thrown. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The behavior that was introduced in .NET 6 was intended to throw a FormatException for any precision larger than Int32.MaxValue. However, due to a bug, it did not throw that exception for some inputs larger than the maximum. This change fixes the bug by limiting the precision to 999,999,999. Recommended action In most cases, no action is necessary, because it's unlikely that you're already using a precision higher than 999,999,999 in your format strings. Affected APIs This change was implemented in the parsing logic that affects all numeric types. System.Numerics.BigInteger.ToString(String) System.Numerics.BigInteger.ToString(String, IFormatProvider) System.Numerics.BigInteger.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Int32.ToString(String) System.Int32.ToString(String, IFormatProvider) System.Int32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt32.ToString(String) System.UInt32.ToString(String, IFormatProvider) System.UInt32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Byte.ToString(String) System.Byte.ToString(String, IFormatProvider) System.Byte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.SByte.ToString(String) System.SByte.ToString(String, IFormatProvider) System.SByte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Int16.ToString(String) System.Int16.ToString(String, IFormatProvider) System.Int16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt16.ToString(String) System.UInt16.ToString(String, IFormatProvider) System.UInt16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Numerics.BigInteger.Parse System.Numerics.BigInteger.TryParse System.Int64.ToString(String) System.Int64.ToString(String, IFormatProvider) System.Int64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt64.ToString(String) System.UInt64.ToString(String, IFormatProvider) System.UInt64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Half.ToString(String) System.Half.ToString(String, IFormatProvider) System.Half.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Single.ToString(String) System.Single.ToString(String, IFormatProvider) System.Single.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Double.ToString(String) System.Double.ToString(String, IFormatProvider) System.Double.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Decimal.ToString(String) System.Decimal.ToString(String, IFormatProvider) System.Decimal.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) See also Standard numeric format parsing precision breaking change (.NET 6) Standard numeric format strings Character literals in custom format strings Changes to reflection invoke API exceptions Article • 11/08/2022 The exceptions thrown when calling reflection invoke APIs have changed. Previous behavior Previously, when an invoked method that returns a value by reference returned null , a NullReferenceException was thrown. For constructors, the following exceptions were thrown: Transient exceptions, including OutOfMemoryException. An OverflowException when a negative value was passed for the length parameter of an array. When null was passed for a byref-like parameter without the ref modifier (that is, passed by value), no exception was thrown, and the runtime substituted a default value for the null value. New behavior Starting in .NET 7: Instead of throwing the originating exception (including NullReferenceException and OutOfMemoryException mentioned in Previous behavior), TargetInvocationException is thrown in all cases after the initial Invoke() parameters are validated. The inner exception contains the originating exception. NotSupportedException is thrown when null is passed for a byref-like parameter when the parameter is declared as being "by value" (that is, it has no ref modifier). For the related case when the parameter is passed by reference (that is, it has the ref modifier), the previous and new behavior are the same: a NotSupportedException is thrown. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change Throwing TargetInvocationException instead of the originating exception makes the experience more consistent. It properly layers exceptions caused by the validation of the incoming parameters (which aren't wrapped with TargetInvocationException) versus exceptions thrown due to the implementation of the target method (which are wrapped). Consistent rules provide more consistent experiences across different implementations of the CLR and of Invoke APIs. The change to throw NotSupportedException when a byref-like type is passed to an Invoke() API fixes an oversight of the original implementation, which did not throw. The original implementation gave the appearance that ref struct types are supported by the Invoke() APIs, when they aren't. Since the current Invoke() APIs use System.Object for parameter types, and a ref struct type can't be boxed to System.Object, it's an unsupported scenario. Recommended action If you don't use BindingFlags.DoNotWrapExceptions when calling Invoke() , and you have catch statements around the Invoke() APIs for exceptions other than TargetInvocationException, consider changing or removing those catch statements. The other exceptions will no longer be thrown as a result of the invocation. If, however, you're catching exceptions from argument validation that happens before attempting to invoke the target method, you should keep those catch statements. Invalid arguments that are validated before attempting to invoke are thrown without being wrapped with TargetInvocationException and did not change semantics. Consider using BindingFlags.DoNotWrapExceptions so that TargetInvocationException is never thrown. In this case, the originating exception won't be wrapped by a TargetInvocationException. In most cases, not wrapping the exception improves the chances of the diagnosing the actual issue since not all exception reporting tools display the inner exception. In addition, by using BindingFlags.DoNotWrapExceptions, the same exceptions will be thrown as when calling the method directly (without reflection). This is desirable in most cases, since the choice of whether reflection is used or not can be arbitrary or an implementation detail that does not need to surface to the caller. In the rare case that you need to pass a default value to a method through reflection that contains a byref-like parameter that's passed "by value", you can add a wrapper method that omits the parameter and calls the target method with a default value for that parameter. Affected APIs System.Reflection.MethodBase.Invoke(Object, Object[]) System.Reflection.MethodBase.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) System.Reflection.ConstructorInfo.Invoke(Object[]) System.Reflection.ConstructorInfo.Invoke(BindingFlags, Binder, Object[], CultureInfo) System.Reflection.PropertyInfo.GetValue(Object) System.Reflection.PropertyInfo.GetValue(Object, Object[]) System.Reflection.PropertyInfo.GetValue(Object, BindingFlags, Binder, Object[], CultureInfo) System.Reflection.PropertyInfo.SetValue(Object, Object) System.Reflection.PropertyInfo.SetValue(Object, Object, Object[]) System.Reflection.PropertyInfo.SetValue(Object, Object, BindingFlags, Binder, Object[], CultureInfo) System.Reflection.Emit.DynamicMethod.Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) System.Activator.CreateInstance(Type, Object[]) System.Activator.CreateInstance(Type, Object[], Object[]) System.Activator.CreateInstance(Type, BindingFlags, Binder, Object[], CultureInfo) System.Activator.CreateInstance(Type, BindingFlags, Binder, Object[], CultureInfo, Object[]) System.Activator.CreateInstance(String, String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[]) System.Drawing.Common config switch removed Article • 05/22/2023 The System.Drawing.Common NuGet package has been attributed as a Windows- specific library since .NET 6 and using it resulted in compile-time warnings and run-time exceptions. The runtime configuration switch to re-enable usage of the package on nonWindows operating systems has been removed in .NET 7. Old behavior Prior to .NET 6, using the System.Drawing.Common package did not produce any compile-time warnings, and no run-time exceptions were thrown. In .NET 6, you could set the System.Drawing.EnableUnixSupport runtime configuration setting to re-enable non-Windows support. New behavior Starting in .NET 7, the System.Drawing.EnableUnixSupport switch has been removed and you can no longer use the System.Drawing.Common package on non-Windows operating systems. Version introduced .NET 7 Type of breaking change This change is a behavioral change. Reason for change The switch to re-enable functionality on non-Windows operating systems was added in .NET 6 to give customers time to migrate to an alternative, modern library. Now that .NET 7 has been released, the switch has been removed. For more information, see Reason for change (.NET 6 breaking change). Recommended action To use these APIs for cross-platform apps, migrate to an alternative library, such as one of the following: ImageSharp SkiaSharp Microsoft.Maui.Graphics Affected APIs See Affected APIs (.NET 6 breaking change). See also System.Drawing.Common only supported on Windows (.NET 6) System.Drawing.Common only supported on Windows - dotnet/designs System.Runtime.CompilerServices.Unsaf e NuGet package Article • 11/08/2022 New versions of the System.Runtime.CompilerServices.Unsafe NuGet package will no longer be produced. Previous behavior New versions of the System.Runtime.CompilerServices.Unsafe NuGet package were produced with each new .NET [Core] version. New behavior Starting in .NET 7, new functionality will ship as part of the shared framework for .NET. Version introduced .NET 7 Preview 3 Reason for change There were previously two different implementations of the Unsafe type: one that was referenced and used inside the core libraries, and one that shipped as a separate NuGet package. This duplicated code and was also a maintenance burden for JIT and AOT, so we unified the implementations. The NuGet package no longer needs to be produced, as the unified implementation of Unsafe ships as part of the shared framework for .NET. Recommended action You can continue to use older versions of the packages if you're targeting .NET 6 or earlier. But starting from .NET 7, you should remove the package dependency and instead use the API that comes as part of the shared framework. Affected APIs All of the APIs under System.Runtime.CompilerServices.Unsafe. Time fields on symbolic links Article • 11/04/2022 When changes are made to the following time-related fields on a symbolic link ("symlink"), the updates now affect the symlink itself and not the target: CreationTime CreationTimeUtc LastAccessTime LastAccessTimeUtc LastWriteTime LastWriteTimeUtc Previous behavior Previously, updating any of the time-related fields on a symlink affected the fields of the symlink's target. Consider the following program that prints the various time field values on a file and its symbolic link, updates the symlink's time field values to 1 day later, and then reprints the time field values on both the file and symlink. C# string filename = "file"; string linkname = "link"; // Create a file and symlink. File.Create(filename).Dispose(); File.CreateSymbolicLink(linkname, filename); Console.WriteLine("Before update:"); PrintMetadata(filename); PrintMetadata(linkname); UpdateMetadata(linkname); Console.WriteLine("\nAfter update:"); PrintMetadata(filename); PrintMetadata(linkname); static void UpdateMetadata(string filename) { DateTime tomorrow = DateTime.Now.AddDays(1); File.SetCreationTime(filename, tomorrow); File.SetLastAccessTime(filename, tomorrow); File.SetLastWriteTime(filename, tomorrow); File.SetAttributes(filename, File.GetAttributes(filename) | FileAttributes.Offline); } static void PrintMetadata(string filename) { Console.WriteLine($"---{filename}---"); Console.WriteLine("Creation:\t" + File.GetCreationTime(filename)); Console.WriteLine("Last access:\t" + File.GetLastAccessTime(filename)); Console.WriteLine("Last write:\t" + File.GetLastWriteTime(filename)); Console.WriteLine("Attributes:\t" + File.GetAttributes(filename)); } Previously, after updating the values on the symlink, only the target file's time fields were updated. The output of the preceding program was as follows: Output Before update: ---file--Creation: Last access: Last write: Attributes: ---link--Creation: Last access: Last write: Attributes: After update: ---file--Creation: Last access: Last write: Attributes: ---link--Creation: Last access: Last write: Attributes: 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM Archive 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM Archive, ReparsePoint 9/30/2022 10:35:40 AM 9/30/2022 10:35:40 AM 9/30/2022 10:35:40 AM Archive 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM 9/29/2022 10:35:40 AM Archive, ReparsePoint, Offline New behavior Starting in .NET 7, updating any of the time-related fields on a symlink affects the fields of the symlink itself and not the target file. The output of the program shown in the Previous behavior section is as follows: Output Before update: ---file--Creation: Last access: Last write: Attributes: ---link--Creation: Last access: Last write: Attributes: After update: ---file--Creation: Last access: Last write: Attributes: ---link--Creation: Last access: Last write: Attributes: 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM Archive 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM Archive, ReparsePoint 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM 9/29/2022 10:33:39 AM Archive 9/30/2022 10:33:39 AM 9/30/2022 10:33:39 AM 9/30/2022 10:33:39 AM Archive, ReparsePoint, Offline Version introduced .NET 7 Preview 1 Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior was unexpected and undesirable in some cases: It was inconsistent with the behavior of the properties and methods that get the same fields. It was also impossible to actually update the fields in the symlink itself using .NET APIs. Recommended action If you were relying on this behavior to set values on the symlink's target, setting one of the *Time fields in a symlink will no longer affect the target. You can use the new symbolic link APIs to obtain the target of a symlink and then update that file system object instead. C# FileSystemInfo? targetInfo = linkInfo.ResolveLinkTarget(returnFinalTarget: true); if (targetInfo != null) { // Update the properties accordingly. targetInfo.LastWriteTime = DateTime.Now; } Affected APIs System.IO.Directory.SetCreationTime(String, DateTime) System.IO.Directory.SetCreationTimeUtc(String, DateTime) System.IO.Directory.SetLastAccessTime(String, DateTime) System.IO.Directory.SetLastAccessTimeUtc(String, DateTime) System.IO.Directory.SetLastWriteTime(String, DateTime) System.IO.Directory.SetLastWriteTimeUtc(String, DateTime) System.IO.File.SetCreationTime(String, DateTime) System.IO.File.SetCreationTimeUtc(String, DateTime) System.IO.File.SetLastAccessTime(String, DateTime) System.IO.File.SetLastAccessTimeUtc(String, DateTime) System.IO.File.SetLastWriteTime(String, DateTime) System.IO.File.SetLastWriteTimeUtc(String, DateTime) System.IO.FileSystemInfo.CreationTime System.IO.FileSystemInfo.CreationTimeUtc System.IO.FileSystemInfo.LastAccessTime System.IO.FileSystemInfo.LastAccessTimeUtc System.IO.FileSystemInfo.LastWriteTime System.IO.FileSystemInfo.LastWriteTimeUtc Tracking linked cache entries Article • 11/08/2022 MemoryCache tracks linked cache entries so that options are propagated. In the following example, the expirationToken added for child is also applied to parent : C# using (var parent = cache.CreateEntry(key)) { parent.SetValue(obj); using (var child = cache.CreateEntry(key1)) { child.SetValue(obj); child.AddExpirationToken(expirationToken); } } For performance reasons, .NET 7 no longer tracks linked cache entries by default. However, you can enable tracking using a new option. Version introduced .NET 7 Previous behavior Prior to .NET 7, MemoryCache tracked linked cache entries to allow for options to be propagated. The tracking could not be disabled. New behavior Starting in .NET 7, MemoryCache does not track linked cache entries, by default. The MemoryCacheOptions.TrackLinkedCacheEntries option was added so you can control whether linked cache entries are tracked or not. Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced to improve performance. Tracking internally uses AsyncLocal<T>, which is expensive and adds non-trivial overhead. Recommended action If you want MemoryCache to continue tracking linked cache entries so options can be propagated, set MemoryCacheOptions.TrackLinkedCacheEntries to true . C# var options = new MemoryCacheOptions { TrackLinkedCacheEntries = true }; var cache = new MemoryCache(options); Affected APIs System.Runtime.Caching.MemoryCache Microsoft.Extensions.Caching.Memory.MemoryCacheOptions Validate CompressionLevel for BrotliStream Article • 11/08/2022 The CompressionLevel argument that's passed to BrotliStream constructors is now validated to be one of the defined values of the enumeration. Previous behavior Passing any value between 0 and 11 for the CompressionLevel parameter was considered valid. The value would either map to one of the enumeration's defined values or be passed as-is to the underlying Brotli implementation. New behavior The only valid values for the CompressionLevel parameter of BrotliStream constructors are: CompressionLevel.Optimal CompressionLevel.Fastest CompressionLevel.NoCompression CompressionLevel.SmallestSize If you pass any other value, an ArgumentException is thrown at run time. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change Being able to pass arbitrary values that aren't defined by the CompressionLevel enumeration is unexpected and undocumented, and is likely to lead to mistakes. Recommended action If necessary, change your code to pass in one of the valid CompressionLevel values. Affected APIs BrotliStream(Stream, CompressionLevel, Boolean) BrotliStream(Stream, CompressionLevel) System.diagnostics entry in app.config Article • 11/08/2022 For applications that have an app.config file, the <configuration><configSections> entry is no longer allowed to contain a <section name="system.diagnostics"> entry. If present, you must remove the entry. Having a <section name="system.diagnostics"> entry throws the following run-time exception when the configuration system is first used: ConfigurationErrorsException: Section or group name 'system.diagnostics' is already defined. Updates to this may only occur at the configuration level where it is defined. For example, the following app.config file contains the unnecessary entry: XML <configuration> <configSections> <section name="system.diagnostics" type="System.Diagnostics.SystemDiagnosticsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> </configSections> This break will likely only occur for apps that: Were migrated from .NET Framework to .NET. Had explicitly added <section name="system.diagnostics"> to the app.config file to support manual reading of the <system.diagnostics> section. Were upgraded to .NET 7, which has an implicit <section name="system.diagnostics"> entry. Previous behavior Specifying <section name="system.diagnostics"> was allowed and necessary if there was a later <system.diagnostics> configuration section like the following: XML <configuration> <system.diagnostics> However, the section wasn't automatically read. That's because System.Diagnostics did not yet support the feature to add listeners and configure other diagnostic features by processing that section. .NET Framework, however, does support processing of a <system.diagnostics> section and has a <section name="system.diagnostics"> entry in the machine.config file. New behavior System.Diagnostics now supports reading the <system.diagnostics> section from the config file and adds an implicit <section name="system.diagnostics"> entry. Having an explicit <section name="system.diagnostics"> entry in the app.config file causes a duplicate entry, which throws ConfigurationErrorsException. Version introduced .NET 7 RC 1 Type of breaking change This change can affect binary compatibility. Reason for change To support a new feature where System.Diagnostics reads from the app.config file, we had to add the implicit <section name="system.diagnostics"> element. Recommended action Remove the unnecessary <section name="system.diagnostics" ... > section. Affected APIs N/A Dynamic X509ChainPolicy verification time Article • 11/08/2022 In previous versions of .NET, the X509ChainPolicy.VerificationTime value was assigned to DateTime.Now when the X509ChainPolicy object was constructed. Using the same X509ChainPolicy object for multiple calls to X509Chain.Build(X509Certificate2) resulted in all chain builds using that same value as the verification time, no matter how much time had passed since the object was created. The new default behavior is to use the value of DateTime.Now when X509Chain.Build() is invoked as the verification time. This change doesn't affect chain builds that explicitly assign X509ChainPolicy.VerificationTime . Previous behavior The X509ChainPolicy.VerificationTime value was assigned to DateTime.Now when the X509ChainPolicy object was constructed. This value was used in all subsequent X509Chain.Build(X509Certificate2) calls (unless or until the value was reassigned at a later time). New behavior The X509ChainPolicy.VerificationTime value is assigned to DateTime.Now when the X509ChainPolicy object is constructed, but the new X509ChainPolicy.VerificationTimeIgnored property defaults to true . When this property has a value of true , the X509Chain.Build(X509Certificate2) method uses DateTime.Now as the verification time instead of X509ChainPolicy.VerificationTime when building the chain. Assigning a value to the X509ChainPolicy.VerificationTime property automatically sets VerificationTimeIgnored to false . Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change Callers who cache configured X509ChainPolicy objects were often surprised that their validation was slowly moving further back in time. This change makes long-lived X509ChainPolicy objects easier to work with and doesn't significantly impact short-lived objects. Recommended action The following callers aren't impacted by the change: Callers that don't have long-lived X509ChainPolicy objects. Callers that explicitly assign the X509ChainPolicy.VerificationTime property. Callers that have a long-lived X509ChainPolicy object that wish to use the previous behavior can either assign the new X509ChainPolicy.VerificationTimeIgnored property to false or assign the X509ChainPolicy.VerificationTime property to DateTime.Now . C# var policy = new X509ChainPolicy { // ... VerificationTime = DateTime.Now, }; or C# var policy = new X509ChainPolicy { // ... VerificationTimeIgnored = false, }; Affected APIs System.Security.Cryptography.X509Certificates.X509ChainPolicy System.Security.Cryptography.X509Certificates.X509ChainPolicy.VerificationTime System.Security.Cryptography.X509Certificates.X509ChainPolicy.VerificationTime Ignored Decrypting EnvelopedCms doesn't double unwrap Article • 11/08/2022 In .NET Core 2.0 on macOS and Linux, the EnvelopedCms implementation incorrectly wrapped content in an extra ASN.1 OCTET STRING value. To maintain compatibility when processing content created with this error, the EnvelopedCms class still looked at the decrypted content and tried to remove the extra data. EnvelopedCms removed the extra data on Windows when using an external private key, and on all other operating systems for any decryption. Unfortunately, this opportunistic compatibility code cannot distinguish between documents that were created incorrectly and documents that were created correctly but have the same data shape. Previous behavior Previously, if the decrypted content started with the byte value 0x04 and a legally encoded ASN.1 BER length value that was less than or equal to the number of bytes remaining in the content, the data provided in the envelopedCms.ContentInfo.Content property only received the data associated with the content octets portion of the value when treated as an ASN.1 OCTET STRING. For example, if the initially decrypted content was the byte series { 0x04, 0x03, 0x01, 0x02, 0x03 } or { 0x04, 0x03, 0x01, 0x02, 0x03, [continued content] } , the value of envelopedCms.ContentInfo.Content was the byte series { 0x01, 0x02, 0x03 } . Values that did not start with 0x04 , or started with 0x04 but were not followed by an acceptably encoded length value, were fully reported. For some overloads of EnvelopedCms.Decrypt, this behavior only occurred on nonWindows operating systems. For more information, see Affected APIs. New behavior The EnvelopedCms class no longer attempts to work around the previous issue, and always reports the decrypted content faithfully. If you're processing documents that were created by the .NET Core 2.0 version of the EnvelopedCms class on macOS or Linux, you'll see extra data at the beginning of the content. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The compatibility code could not differentiate between incorrectly created documents and documents that were legitimately transporting data that looked like a BER-encoded ASN.1 OCTET STRING. Due to the nature of the BER encoding, callers that were negatively impacted by this compatibility code could not easily recover their missing data. Recommended action Callers that read documents created with EnvelopedCms on .NET Core 2.0 for macOS or Linux can add code to remove the extra data. To remove it, use the AsnDecoder class from the System.Formats.Asn1 NuGet package , which is already a dependency of the EnvelopedCms class. C# envelopedCms.Decrypt(...); byte[] content = envelopedCms.ContentInfo.Content; if (envelopedCms.ContentInfo.Oid.Value == "1.2.840.113549.1.7.1") { if (content?.Length > 0 && content[0] == 0x04) { try { content = AsnDecoder.ReadOctetString(content, AsnEncodingRules.BER, out _); } catch (AsnContentException) { } } } Affected APIs System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt(RecipientInfo, AsymmetricAlgorithm) System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt(RecipientInfo, X509Certificate2Collection) (non-Windows only) System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt(RecipientInfo) (nonWindows only) System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt(X509Certificate2Collecti on) (non-Windows only) X500DistinguishedName parsing of friendly names Article • 11/08/2022 On Linux and macOS, a distinguished name with a relative distinguished name component that is prefixed with "OID." followed by a friendly name will no longer parse. For example, OID.STREET=MainStreet no longer parses. Previous behavior On Linux and macOS only, a distinguished name would successfully parse even if the object identifier (OID) was a friendly name. New behavior Attempting to parse a distinguished name with a component prefixed with "OID." but not followed by a well-formed, dotted-decimal OID throws a CryptographicException. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change Windows does not permit distinguished names with friendly name OIDs, and that it worked in Linux and macOS was coincidence and not intentional. To bring consistency throughout platforms, the parsing logic was improved to not accept this form. Recommended action Change "OID."-prefixed relative distinguished name components to use an OID, such as OID.1.2.3.4=MyValue . Affected APIs X500DistinguishedName(String) X500DistinguishedName(String, X500DistinguishedNameFlags) All assemblies trimmed by default Article • 11/08/2022 Trimming now trims all assemblies in console apps, by default. This change only affects apps that are published with PublishTrimmed=true , and it only breaks apps that had existing trim warnings. It also only affects plain .NET apps that don't use the Windows Desktop, Android, iOS, WASM, or ASP.NET SDK. Previous behavior Previously, only assemblies that were opted-in with <IsTrimmable>true</IsTrimmable> in the library project file were trimmed. New behavior Starting in .NET 7, trimming trims all the assemblies in the app by default. Apps that may have previously worked with PublishTrimmed may not work in .NET 7. However, only apps with trim warnings will be affected. If your app has no trim warnings, the change in behavior should not cause any adverse effects, and will likely decrease the app size. If your app did have trim warnings, you may see changes in behavior or exceptions. For example, an app that uses Newtonsoft.Json or System.Text.Json without source generation to serialize and deserialize a type in the user project may have functioned before the change, because types in the user project were fully preserved. However, one or more trim warnings (warning codes ILxxxx ) would have been present. Now, types in the user project are trimmed, and serialization may fail or produce unexpected results. Version introduced .NET 7 Type of breaking change This change can affect source compatibility. Reason for change This change helps to decrease app size without users having to explicitly opt in and aligns with user expectations that the entire app is trimmed unless noted otherwise. Recommended action The best resolution is to resolve all the trim warnings in your application. For information about resolving the warnings in your own libraries, see Introduction to trim warnings. For other libraries, contact the author to request that they resolve the warnings, or choose a different library that already supports trimming. For example, you can switch to System.Text.Json with source generation, which supports trimming, instead of Newtonsoft.Json . To revert to the previous behavior, set the TrimMode property to partial , which is the pre-.NET 7 behavior. XML <TrimMode>partial</TrimMode> The default .NET 7+ value is full : XML <TrimMode>full</TrimMode> Affected APIs None. See also Trimming options Multi-level lookup is disabled Article • 11/08/2022 On Windows, framework-dependent .NET applications no longer search for frameworks in multiple install locations. Previous behavior In previous versions, a framework-dependent .NET application searched for frameworks in multiple install locations on Windows. The locations were: When running the application through dotnet, subdirectories relative to the dotnet executable. When running the application through its executable ( apphost ), the location specified by the value of the DOTNET_ROOT environment variable (if set). The globally registered install location in HKLM\SOFTWARE\dotnet\Setup\InstalledVersions<arch>\InstallLocation (if set). The default install location of %ProgramFiles%\dotnet (or %ProgramFiles(x86)%\dotnet for 32-bit processes on 64-bit Windows). This multi-level lookup behavior was enabled by default but could be disabled by setting the environment variable DOTNET_MULTILEVEL_LOOKUP=0 . New behavior Applications that target .NET 7 or a later version only look for frameworks in one location, which is the first location where a .NET installation is found. When running an application through dotnet, frameworks are only searched for in subdirectories relative to the dotnet executable. When running an application through its executable ( apphost ), frameworks are only searched for in the first of the following locations where .NET is found: The location specified by the value of the DOTNET_ROOT environment variable (if set). The globally registered install location in HKLM\SOFTWARE\dotnet\Setup\InstalledVersions<arch>\InstallLocation (if set). The default install location of %ProgramFiles%\dotnet (or %ProgramFiles(x86)%\dotnet for 32-bit processes on 64-bit Windows). Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change There've been numerous issues caused by multi-level lookup: Confusion for users: application can pick a global or default install location despite running .NET from a private install. Inconsistency between platforms (Windows versus non-Windows). Behavior breaks, often in automated systems: a new global .NET install can affect otherwise isolated builds and tests. Performance issues. Recommended action Make sure the required version of .NET is installed at the single .NET install location. The error messages that are emitted on failure to launch include the expected location. Affected APIs None. x86 host path on 64-bit Windows Article • 06/13/2023 The x86 versions of .NET installers for Windows have been modified to no longer add the x86 host location (Program Files (x86)\dotnet) to the PATH environment variable on 64-bit Windows systems. With this change, if the x86 host location was added to PATH by a prior version of .NET, the x86 versions of .NET installers and .NET updates will remove it on upgrade. This change affects .NET Core 3.1, .NET 6, .NET 7, and future versions. This change only affects the dotnet host. It doesn't affect 32-bit/x86 application hosts, like myapp.exe. Those hosts will continue to find the x86 runtime correctly (assuming it's installed). Previous behavior The x86 host location was added to PATH , even on x64/Arm64 systems. Depending on which .NET architecture installer was run first, a user's machine could have either the native (x64/Arm64) or x86 host listed first in PATH . New behavior Going forward, the x86 host location is only added to the PATH environment variable on x86 systems and will be removed on upgrade of .NET or Visual Studio on any x64 and arm64 systems. Version introduced .NET 7 Reason for change Currently, the x86 host location is added to PATH , even on x64/Arm64 systems. Depending on which .NET architecture installer is run first, a user's machine could have either the native (x64/Arm64) or the x86 host as the first location in the PATH list. This ambiguity causes problems with the initial .NET installation and during .NET servicing events. Any of these installation scenarios can modify the order of .NET hosts in PATH , making it non-deterministic. There's a high chance of behavior regression of the .NET runtime. This change streamlines the dotnet host experience on Windows 64-bit systems. Only 64-bit hosts will be available in the system's PATH environment variable: the x64 host on x64 systems and the Arm64 host on Arm64 systems. We removed the ambiguity in the order of dotnet hosts in PATH , and only one host will be present. Recommended action If you need the x86 host in the PATH environment variable on x64/Arm64 systems, add the host location to PATH manually. Affected APIs None. MSBuild property TrimmerDefaultAction is deprecated Article • 01/20/2023 The value of the TrimmerDefaultAction property is now ignored by the publish process. Previous behavior Previously, only assemblies that were opted-in with <IsTrimmable>true</IsTrimmable> in the library project file were trimmed with the action specified by the TrimmerDefaultAction . In .NET 6, the default value for that property was copy . While apps with trim warnings were more likely to work with this default, run-time behavior could still be affected. In addition, the copy action caused apps to be larger than if the entire app was trimmed. New behavior Starting in .NET 7, the property TrimmerDefaultAction is ignored and publishing behaves as if it was set to link all the time. This means all assemblies are fully trimmed, whether they opt in or not. As a result, applications with trim warnings may see changes in behavior or run-time exceptions. For more information and instructions for restoring the previous behavior, see All assemblies trimmed by default. Version introduced .NET 7 Type of breaking change This change can affect source compatibility. Reason for change This change streamlines trimming options. Recommended action The best resolution is to resolve all the trim warnings in your application. For information about resolving the warnings in your own libraries, see Introduction to trim warnings. For other libraries, contact the author to request that they resolve the warnings, or choose a different library that already supports trimming. For example, you can switch to System.Text.Json with source generation, which supports trimming, instead of Newtonsoft.Json . With that library, you should no longer need to use TrimmerDefaultAction . To revert to the previous behavior, use global.json to pin your project to .NET 6 SDK. See also Trimming options All assemblies trimmed by default Breaking changes in EF Core 7.0 (EF7) Article • 03/27/2023 The following API and behavior changes have the potential to break existing applications updating to EF Core 7.0. Target Framework EF Core 7.0 targets .NET 6. This means that existing applications that target .NET 6 can continue to do so. Applications targeting older .NET, .NET Core, and .NET Framework versions will need to target .NET 6 or .NET 7 to use EF Core 7.0. Summary Breaking change Impact Encrypt defaults to true for SQL Server connections High Some warnings will again throw exceptions by default High SQL Server tables with triggers or certain computed columns now require special EF Core configuration High SQLite tables with AFTER triggers and virtual tables now require special EF Core configuration High Orphaned dependents of optional relationships are not automatically deleted Medium Cascade delete is configured between tables when using TPT mapping with SQL Server Medium Key properties may need to be configured with a provider value comparer Low Check constraints and other table facets are now configured on the table Low Navigations from new entities to deleted entities are not fixed up Low Using FromSqlRaw and related methods from the wrong provider throws Low Scaffolded OnConfiguring no longer calls IsConfigured Low High-impact changes Encrypt defaults to true for SQL Server connections Tracking Issue: SqlClient #1210 ) Important This is a severe breaking change in the Microsoft.Data.SqlClient package. There is nothing that can be done in EF Core to revert or mitigate this change. Please direct feedback to the Microsoft.Data.SqlClient GitHub Repo Microsoft Support Professional or contact a for additional questions or help. Old behavior SqlClient connection strings use Encrypt=False by default. This allows connections on development machines where the local server does not have a valid certificate. New behavior SqlClient connection strings use Encrypt=True by default. This means that: The server must be configured with a valid certificate The client must trust this certificate If these conditions are not met, then a SqlException will be thrown. For example: A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.) Why This change was made to ensure that, by default, either the connection is secure or the application will fail to connect. Mitigations There are three ways to proceed: 1. Install a valid certificate on the server. Note that this is an involved process and requires obtaining a certificate and ensuring it is signed by an authority trusted by the client. 2. If the server has a certificate, but it is not trusted by the client, then TrustServerCertificate=True to allow bypassing the normal trust mechanims. 3. Explicitly add Encrypt=False to the connection string. 2 Warning Options 2 and 3 both leave the server in a potentially insecure state. Some warnings throw exceptions by default again Tracking Issue #29069 Old behavior In EF Core 6.0, a bug in the SQL Server provider meant that some warnings that are configured to throw exceptions by default were instead being logged but not throwing exceptions. These warnings are: EventId Description RelationalEventId.AmbientTransactionWarning An application may have expected an ambient transaction to be used when it was actually ignored. RelationalEventId.IndexPropertiesBothMappedAndNotMappedToTable An index specifies properties some of which are mapped and some of which are not mapped to a column in a table. RelationalEventId.IndexPropertiesMappedToNonOverlappingTables An index specifies properties which map to columns on nonoverlapping tables. RelationalEventId.ForeignKeyPropertiesMappedToUnrelatedTables A foreign key specifies properties which don't map to the related tables. New behavior Starting with EF Core 7.0, these warnings again, by default, result in an exception being thrown. Why These are issues that very likely indicate an error in the application code that should be fixed. Mitigations Fix the underlying issue that is the reason for the warning. Alternately, the warning level can be changed so that it is logged only or suppressed entirely. For example: C# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .ConfigureWarnings(b => b.Ignore(RelationalEventId.AmbientTransactionWarning)); SQL Server tables with triggers or certain computed columns now require special EF Core configuration Tracking Issue #27372 Old behavior Previous versions of the SQL Server provider saved changes via a less efficient technique which always worked. New behavior By default, EF Core now saves changes via a significantly more efficient technique; unfortunately, this technique is not supported on SQL Server if the target table has database triggers, or certain types of computed columns. See the SQL Server documentation for more details. Why The performance improvements linked to the new method are significant enough that it's important to bring them to users by default. At the same time, we estimate usage of database triggers or the affected computed columns in EF Core applications to be low enough that the negative breaking change consequences are outweighed by the performance gain. Mitigations You can let EF Core know that the target table has a trigger; doing so will revert to the previous, less efficient technique. This can be done by configuring the corresponding entity type as follows: C# protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .ToTable(tb => tb.HasTrigger("SomeTrigger")); } Note that doing this doesn't actually make EF Core create or manage the trigger in any way - it currently only informs EF Core that triggers are present on the table. As a result, any trigger name can be used, and this can also be used if an unsupported computed column is in use (regardless of triggers). If most or all of your tables have triggers, you can opt out of using the newer, efficient technique for all your model's tables by using the following model building convention: C# public class BlankTriggerAddingConvention : IModelFinalizingConvention { public virtual void ProcessModelFinalizing( IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context) { foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) { var table = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table); if (table != null && entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(table.Value) == null)) { entityType.Builder.HasTrigger(table.Value.Name + "_Trigger"); } foreach (var fragment in entityType.GetMappingFragments(StoreObjectType.Table)) { if (entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(fragment.StoreObject) == null)) { entityType.Builder.HasTrigger(fragment.StoreObject.Name + "_Trigger"); } } } } } Use the convention on your DbContext by overriding ConfigureConventions : C# protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.Conventions.Add(_ => new BlankTriggerAddingConvention()); } This effectively calls HasTrigger on all your model's tables, instead of you having to do it manually for each and every table. SQLite tables with AFTER triggers and virtual tables now require special EF Core configuration Tracking Issue #29916 Old behavior Previous versions of the SQLite provider saved changes via a less efficient technique which always worked. New behavior By default, EF Core now saves changes via a more efficient technique, using the RETURNING clause. Unfortunately, this technique is not supported on SQLite if target table is has database AFTER triggers, is virtual, or if older versions of SQLite are being used. See the SQLite documentation Why for more details. The simplifications and performance improvements linked to the new method are significant enough that it's important to bring them to users by default. At the same time, we estimate usage of database triggers and virtual tables in EF Core applications to be low enough that the negative breaking change consequences are outweighed by the performance gain. Mitigations In EF Core 8.0, a mechanism will be introduced that will allow specifying whether to use the new mechanism on a table-by-table basis. With EF Core 7.0, it's possible to revert to the old mechanism for the entire application by inserting the following code in your context configuration: c# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseSqlite(...) .ReplaceService<IUpdateSqlGenerator, SqliteLegacyUpdateSqlGenerator> (); Medium-impact changes Orphaned dependents of optional relationships are not automatically deleted Tracking Issue #27217 Old behavior A relationship is optional if its foreign key is nullable. Setting the foreign key to null allows the dependent entity exist without any related principal entity. Optional relationships can be configured to use cascade deletes, although this is not the default. An optional dependent can be severed from its principal by either setting its foreign key to null, or clearing the navigation to or from it. In EF Core 6.0, this would cause the dependent to be deleted when the relationship was configured for cascade delete. New behavior Starting with EF Core 7.0, the dependent is no longer deleted. Note that if the principal is deleted, then the dependent will still be deleted since cascade deletes are configured for the relationship. Why The dependent can exist without any relationship to a principal, so severing the relationship should not cause the entity to be deleted. Mitigations The dependent can be explicitly deleted: C# context.Remove(blog); Or SaveChanges can be overridden or intercepted to delete dependents with no principal reference. For example: C# context.SavingChanges += (c, _) => { foreach (var entry in ((DbContext)c!).ChangeTracker .Entries<Blog>() .Where(e => e.State == EntityState.Modified)) { if (entry.Reference(e => e.Author).CurrentValue == null) { entry.State = EntityState.Deleted; } } }; Cascade delete is configured between tables when using TPT mapping with SQL Server Tracking Issue #28532 Old behavior When mapping an inheritance hierarchy using the TPT strategy, the base table must contain a row for every entity saved, regardless of the actual type of that entity. Deleting the row in the base table should delete rows in all the other tables. EF Core configures a cascade deletes for this. In EF Core 6.0, a bug in the SQL Server database provider meant that these cascade deletes were not being created. New behavior Starting with EF Core 7.0, the cascade deletes are now being created for SQL Server just as they always were for other databases. Why Cascade deletes from the base table to the sub-tables in TPT allow an entity to be deleted by deleting its row in the base table. Mitigations In most cases, this change should not cause any issues. However, SQL Server is very restrictive when there are multiple cascade behaviors configured between tables. This means that if there is an existing cascading relationship between tables in the TPT mapping, then SQL Server may generate the following error: Microsoft.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FK_Blogs_People_OwnerId". The conflict occurred in database "Scratch", table "dbo.Blogs", column 'OwnerId'. The statement has been terminated. For example, this model creates a cycle of cascading relationships: C# [Table("FeaturedPosts")] public class FeaturedPost : Post { public int ReferencePostId { get; set; } public Post ReferencePost { get; set; } = null!; } [Table("Posts")] public class Post { public int Id { get; set; } public string? Title { get; set; } public string? Content { get; set; } } One of these will need to be configured to not use cascade deletes on the server. For example, to change the explicit relationship: C# modelBuilder .Entity<FeaturedPost>() .HasOne(e => e.ReferencePost) .WithMany() .OnDelete(DeleteBehavior.ClientCascade); Or to change the implicit relationship created for the TPT mapping: C# modelBuilder .Entity<FeaturedPost>() .HasOne<Post>() .WithOne() .HasForeignKey<FeaturedPost>(e => e.Id) .OnDelete(DeleteBehavior.ClientCascade); Low-impact changes Key properties may need to be configured with a provider value comparer Tracking Issue #27738 Old behavior In EF Core 6.0, key values taken directly from the properties of entity types were used for comparison of key values when saving changes. This would make use of any custom value comparer configured on these properties. New behavior Starting with EF Core 7.0, database values are used for these comparisons. This "just works" for the vast majority of cases. However, if the properties were using a custom comparer, and that comparer cannot be applied to the database values, then a "provider value comparer" may be needed, as shown below. Why Various entity-splitting and table-splitting can result in multiple properties mapped to the same database column, and vice-versa. This requires values to be compared after conversion to value that will be used in the database. Mitigations Configure a provider value comparer. For example, consider the case where a value object is being used as a key, and the comparer for that key uses case-insensitive string comparisons: C# var blogKeyComparer = new ValueComparer<BlogKey>( (l, r) => string.Equals(l.Id, r.Id, StringComparison.OrdinalIgnoreCase), v => v.Id.ToUpper().GetHashCode(), v => v); var blogKeyConverter = new ValueConverter<BlogKey, string>( v => v.Id, v => new BlogKey(v)); modelBuilder.Entity<Blog>() .Property(e => e.Id).HasConversion( blogKeyConverter, blogKeyComparer); The database values (strings) cannot directly use the comparer defined for BlogKey types. Therefore, a provider comparer for case-insensitive string comparisons must be configured: C# var caseInsensitiveComparer = new ValueComparer<string>( (l, r) => string.Equals(l, r, StringComparison.OrdinalIgnoreCase), v => v.ToUpper().GetHashCode(), v => v); var blogKeyComparer = new ValueComparer<BlogKey>( (l, r) => string.Equals(l.Id, r.Id, StringComparison.OrdinalIgnoreCase), v => v.Id.ToUpper().GetHashCode(), v => v); var blogKeyConverter = new ValueConverter<BlogKey, string>( v => v.Id, v => new BlogKey(v)); modelBuilder.Entity<Blog>() .Property(e => e.Id).HasConversion( blogKeyConverter, blogKeyComparer, caseInsensitiveComparer); Check constraints and other table facets are now configured on the table Tracking Issue #28205 Old behavior In EF Core 6.0, HasCheckConstraint , HasComment , and IsMemoryOptimized were called directly on the entity type builder. For example: C# modelBuilder .Entity<Blog>() .HasCheckConstraint("CK_Blog_TooFewBits", "Id > 1023"); modelBuilder .Entity<Blog>() .HasComment("It's my table, and I'll delete it if I want to."); modelBuilder .Entity<Blog>() .IsMemoryOptimized(); New behavior Starting with EF Core 7.0, these methods are instead called on the table builder: C# modelBuilder .Entity<Blog>() .ToTable(b => b.HasCheckConstraint("CK_Blog_TooFewBits", "Id > 1023")); modelBuilder .Entity<Blog>() .ToTable(b => b.HasComment("It's my table, and I'll delete it if I want to.")); modelBuilder .Entity<Blog>() .ToTable(b => b.IsMemoryOptimized()); The existing methods have been marked as Obsolete . They currently have the same behavior as the new methods, but will be removed in a future release. Why These facets apply to tables only. They will not be applied to any mapped views, functions, or stored procedures. Mitigations Use the table builder methods, as shown above. Navigations from new entities to deleted entities are not fixed up Tracking Issue #28249 Old behavior In EF Core 6.0, when a new entity is tracked either from a tracking query or by attaching it to the DbContext , then navigations to and from related entities in the Deleted state are fixed up. New behavior Starting with EF Core 7.0, navigations to and from Deleted entities are not fixed up. Why Once an entity is marked as Deleted it rarely makes sense to associate it with nondeleted entities. Mitigations Query or attach entities before marking entities as Deleted , or manually set navigation properties to and from the deleted entity. Using FromSqlRaw and related methods from the wrong provider throws use-the-correct-method Tracking Issue #26502 Old behavior In EF Core 6.0, using the Azure Cosmos DB FromSqlRaw extension method when using a relational provider, or the relational FromSqlRaw extension method when using the Azure Cosmos DB provider could silently fail. New behavior Starting with EF Core 7.0, using the wrong extension method will throw an exception. Why The correct extension method must be used for it to function correctly in all situations. Mitigations Use the correct extension method for the provider being used. If multiple providers are referenced, then call the extension method as a static method. For example: C# var result = CosmosQueryableExtensions.FromSqlRaw(context.Blogs, "SELECT ...").ToList(); Or: C# var result = RelationalQueryableExtensions.FromSqlRaw(context.Blogs, "SELECT ...").ToList(); Scaffolded OnConfiguring no longer calls IsConfigured Tracking Issue #4274 Old behavior In EF Core 6.0, the DbContext type scaffolded from an existing database contained a call to IsConfigured . For example: C# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/? LinkId=723263. optionsBuilder.UseNpgsql("MySecretConnectionString"); } } New behavior Starting with EF Core 7.0, the call to IsConfigured is no longer included. Why There are very limited scenarios where the database provider is configured inside your DbContext in some cases, but only if the context is not configured already. Instead, leaving OnConfiguring here makes it more likely that a connection string containing sensitive information is left in the code, despite the compile-time warning. Thus the extra safely and cleaner code from removing this was deemed worthwhile, especially given that the --no-onconfiguring (.NET CLI) or -NoOnConfiguring (Visual Studio Package Manager Console) flag can be used to prevent scaffolding of the OnConfiguring method, and that customizable templates exist to add back IsConfigured if it is really needed. Mitigations Either: Use the --no-onconfiguring (.NET CLI) or -NoOnConfiguring (Visual Studio Package Manager Console) argument when scaffolding from an existing database. Customize the T4 templates to add back the call to IsConfigured . Globalization APIs use ICU libraries on Windows Server 2019 Article • 08/29/2023 .NET 7 and later versions use International Components for Unicode (ICU) libraries for globalization functionality when running on Windows Server 2019. Non-server editions of Windows have been using ICU since .NET 5. However, .NET 7 introduced support for loading ICU in earlier Windows client versions, specifically Windows 10 versions 1703, 1709, 1803, and 1809. Previous behavior In .NET 5 and .NET 6, the .NET libraries used National Language Support (NLS) APIs for globalization functionality on Windows Server 2019. For example, NLS functions were used to compare strings, get culture information, and perform string casing in the appropriate culture. This behavior also applied to Windows 10 client versions, such as 1703, 1709, 1803, and 1809. New behavior Starting in .NET 7, if an app is running on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, .NET libraries use ICU globalization APIs, by default. (Non-server Windows versions have already been using ICU since .NET 5, so there is no change for these versions.) Behavioral differences You might see changes in your app even if you don't realize you're using globalization facilities. The following example shows one of the behavioral changes you might see, but there are others too. Currency symbol Consider the following code that formats a string using the currency format specifier C . The current thread's culture is set to a culture that includes only the language and not the country or region. C# System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de"); string text = string.Format("{0:C}", 100); In .NET 5 and .NET 6 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, the value of text is "100,00 €" . In .NET 7 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, and 1809, the value of text is "100,00 ¤" , which uses the international currency symbol instead of the euro. In ICU, the design is that a currency is a property of a country or region, not a language. Reason for change .NET introduced some APIs that depend on ICU libraries, for example, TimeZoneInfo.TryConvertIanaIdToWindowsId(String, String). Users who wanted to use such APIs on Windows Server 2019 were required to manually deploy ICU libraries with their binaries, using the ICU App Local feature. This wasn't a great solution, because the code can be in a library that can't control forcing ICU libraries to be installed with whatever app or service is using the library. If Windows Server 2019 is automatically provided by a cloud platform (like Azure), the deployed service doesn't necessarily know it's going to run on such a server. Also, the service owner has to manage if/when to deploy ICU binaries. In addition, every service deployed to the cloud using Windows Server 2019 that wants to use the new .NET ICU-dependent APIs needs to deploy the ICU binaries with the service. This can bloat the size on the disk on the server. Some users prefer using ICU by default because it conforms more to the Unicode Standard. Version introduced .NET 7 Recommended action If you're using .NET 7 on Windows Server 2019 or Windows 10 client versions 1703, 1709, 1803, or 1809, we recommend testing your app or service before shipping it to ensure the behavior is as expected and doesn't break any users. If you wish to continue using NLS globalization APIs, you can set a run-time switch to revert to that behavior. For more information about the available switches, see the .NET globalization and ICU article. Affected APIs System.Span<T> System.String Most types in the System.Globalization namespace System.Array.Sort (when sorting an array of strings) System.Collections.Generic.List<T>.Sort() (when the list elements are strings) System.Collections.Generic.SortedDictionary<TKey,TValue> (when the keys are strings) System.Collections.Generic.SortedList<TKey,TValue> (when the keys are strings) System.Collections.Generic.SortedSet<T> (when the set contains strings) See also Globalization APIs use ICU libraries on Windows 10 Binding config to dictionary extends values Article • 08/03/2023 When binding a configuration using a Dictionary<TKey,TValue> object where the value is a mutable collection type, binding to the same key more than once now extends the values collection instead of replacing the whole collection with the new value. Version introduced .NET 7 Previous behavior Consider the following code that binds a configuration that has a single key named Key to a dictionary multiple times. C# using Microsoft.Extensions.Configuration; IConfiguration config = new ConfigurationBuilder() .AddInMemoryCollection() .Build(); config["Key:0"] = "NewValue"; var dict = new Dictionary<string, string[]>() { { "Key", new[] { "InitialValue" } } }; Console.WriteLine($"Initially: {String.Join(", ", dict["Key"])}"); config.Bind(dict); Console.WriteLine($"Bind: {String.Join(", ", dict["Key"])}"); config.Bind(dict); Console.WriteLine($"Bind again: {String.Join(", ", dict["Key"])}"); Prior to .NET 7, the value for Key was overwritten one each bind. The code produced the following output: Output Initially: InitialValue Bind: NewValue Bind again: NewValue New behavior Starting in .NET 7, the dictionary value is extended each time the same key is bound, adding the new value but also keeping any existing values in the array. The same code from the Previous behavior section produces the following output: Output Initially: InitialValue Bind: InitialValue, NewValue Bind again: InitialValue, NewValue, NewValue Type of breaking change This change is a behavioral change. Reason for change This change improves binding behavior by not overriding previously added values in dictionary value arrays. Recommended action If the new behavior is not satisfactory, you can manually manipulate the values inside the array after binding. Affected APIs ConfigurationBinder methods ContentRootPath for apps launched by Windows Shell Article • 11/08/2022 The IHostEnvironment.ContentRootPath property represents the default directory where appsettings.json and other content files are loaded in a hosted application, including ASP.NET apps. This property's value defaults to Environment.CurrentDirectory, which is the current working directory of the application. This behavior allows the same app to be executed under different working directories and use the content from each directory. When a Windows process (either application or service) is launched without specifying a working directory, the working directory of the process that created it is used. The working directory of Windows Shell or services.exe is %windir%\system32 (or the System special folder). When either of those processes launches a hosted app, the ContentRootPath property is set to %windir%\system32. This behavior is confusing and causes hosted applications to fail, because the application tries to load files from the %windir%\system32 directory, but it doesn't exist. For example, the appsettings.json file is not found at run time and the settings aren't applied. Starting with .NET 7, when a hosted application is launched with the current directory set to the System special folder, it defaults the ContentRootPath property to AppContext.BaseDirectory. Version introduced .NET 7 Previous behavior Host.CreateDefaultBuilder defaulted the ContentRootPath property to Environment.CurrentDirectory regardless of the value of the current directory. New behavior Host.CreateDefaultBuilder no longer defaults the ContentRootPath property to the current directory if it's the System special folder on Windows. Instead, the base directory of the application is used. Type of breaking change This change can affect binary compatibility. Reason for change App developers weren't expecting ContentRootPath to be C:\Windows\system32 when their application was launched by Windows in certain cases (for example, when the app was packaged as an MSIX or started from the Start Menu). In these cases, it's better to default the ContentRootPath property to the base directory of the application. Recommended action If you want to use the previous behavior, you can set the ContentRootPath property explicitly when creating the IHostBuilder: C# Host .CreateDefaultBuilder() .UseContentRoot(Environment.CurrentDirectory) .... Affected APIs Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder Environment variable prefixes Article • 11/08/2022 Hierarchical data is represented using : as the level delimiter. However, for environmental variables, the : character is normalized to __ , because the latter is supported on all platforms. This change affects how normalized and non-normalized prefixes and keys are compared. Specifically, you can now add environment variables by specifying a prefix containing either : or __ as the delimiter. Either syntax will match any environment variables with a matching prefix followed by either a : or __ . Some environment variables that theoretically didn't match the filter previously may now match the filter. Version introduced .NET 7 Preview 4 Previous behavior Previously, the following code printed False : C# using Microsoft.Extensions.Configuration; const string myValue = "value1"; Environment.SetEnvironmentVariable("MY_PREFIX__ConfigKey", myValue); IConfiguration config = new ConfigurationBuilder() .AddEnvironmentVariables(prefix: "MY_PREFIX__") .Build(); var loadedValue = config.GetValue<string?>("ConfigKey", null); Console.WriteLine(String.Equals(myValue, loadedValue)); // False In order for the MY_PREFIX__ConfigKey environment variable to be added to the configuration, you had to add environment variables using a delimiter of : instead of __ : C# using Microsoft.Extensions.Configuration; const string myValue = "value1"; Environment.SetEnvironmentVariable("MY_PREFIX__ConfigKey", myValue); IConfiguration config = new ConfigurationBuilder() .AddEnvironmentVariables(prefix: "MY_PREFIX:") .Build(); var loadedValue = config.GetValue<string?>("ConfigKey", null); Console.WriteLine(String.Equals(myValue, loadedValue)); // True New behavior Starting in .NET 7, the following code prints True : C# using Microsoft.Extensions.Configuration; const string myValue = "value1"; Environment.SetEnvironmentVariable("MY_PREFIX__ConfigKey", myValue); IConfiguration config = new ConfigurationBuilder() .AddEnvironmentVariables(prefix: "MY_PREFIX__") .Build(); var loadedValue = config.GetValue<string?>("ConfigKey", null); Console.WriteLine(String.Equals(myValue, loadedValue)); // True Type of breaking change This change can affect binary compatibility. Reason for change This change was made to fix an unintentional behavior change for normalizing environment variable prefix filters in .NET 6. The new behavior matches the .NET 5 behavior. Recommended action Most developers won't be affected by this change, since it corrects previously erroneous behavior. In the unlikely case that you relied on the fact that a prefix containing __ didn't match an environment variable containing __ , consider changing the prefixes of those variables. Affected APIs Microsoft.Extensions.Configuration.EnvironmentVariablesExtensions.AddEnvironme ntVariables(IConfigurationBuilder, String) See also Configuration in .NET RuntimeInformation.OSArchitecture under emulation Article • 09/14/2022 System.Runtime.InteropServices.RuntimeInformation.OSArchitecture now returns the correct value under emulation. Previous behavior Previously, RuntimeInformation.OSArchitecture returned Architecture.X64 in emulated processes on Windows Arm 64-bit and macOS Apple Silicon systems. New behavior Starting in .NET 7, RuntimeInformation.OSArchitecture returns Architecture.Arm64 in emulated processes on Windows Arm 64-bit and macOS Apple Silicon systems. Version introduced 7 Preview 6 Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior was incorrect. Recommended action Code that expects the process architecture should be changed to call RuntimeInformation.ProcessArchitecture instead. Affected APIs System.Runtime.InteropServices.RuntimeInformation.OSArchitecture Constructors accept base interface instead of concrete type Article • 11/16/2022 The constructors of the following types now accept the base interface ( IWebViewHandler ) instead of a specific, concrete type that implements the interface ( WebViewHandler ): Microsoft.Maui.Platform.MauiWebChromeClient Microsoft.Maui.Platform.MauiWebViewNavigationDelegate Version introduced .NET 7 Previous behavior The constructors of MauiWebChromeClient and MauiWebViewNavigationDelegate required the caller to pass in a concrete Microsoft.Maui.Handlers.WebViewHandler instance. New behavior The constructors of MauiWebChromeClient and MauiWebViewNavigationDelegate now accept any implementation of the interface Microsoft.Maui.Handlers.IWebViewHandler . Type of breaking change This change can affect binary compatibility. Reason for change The original constructors required the caller to pass in a concrete type that's not usercontrollable and could throw at any point depending on the library author or order of imports. The new implementation just requires the base interface, which is something a developer can actually use. Recommended action If you've overridden the WKUIDelegate mapper for the iOS or Mac Catalyst WebViewHandler , multi-target net6.0-ios and net7.0-ios or net6.0-maccatalyst and net7.0-maccatalyst . If you've overridden the WebChromeClient mapper for the Android WebViewHandler , multi-target net6.0-android and net7.0-android . Otherwise, no action is necessary. Affected APIs Microsoft.Maui.Platform.MauiWebChromeClient constructor Microsoft.Maui.Platform.MauiWebViewNavigationDelegate constructor Flow direction helper methods removed Article • 11/16/2022 The entire system for flow direction was rewritten and the following APIs have been removed: Microsoft.Maui.IViewExtensions Microsoft.Maui.IViewExtensions.GetEffectiveFlowDirection(Microsoft.Maui.IView ) Microsoft.Maui.Layouts.LayoutExtensions.ShouldArrangeLeftToRight(Microsoft.Mau i.IView) Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(UIKit.U ITextAlignment,Microsoft.Maui.IView) Version introduced .NET 7 Previous behavior These helper methods existed to calculate the flow direction of test and UI components. New behavior The methods have been removed. Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change The previous implementation was incorrect and a performance bottleneck. The entire system for flow direction was rewritten for .NET 7 and the affected APIS no longer had any value or performed any function, so they were removed. Recommended action If you were calling these APIs, remove the calls. Affected APIs Microsoft.Maui.IViewExtensions Microsoft.Maui.IViewExtensions.GetEffectiveFlowDirection(Microsoft.Maui.IView ) Microsoft.Maui.Layouts.LayoutExtensions.ShouldArrangeLeftToRight(Microsoft.Mau i.IView) Microsoft.Maui.Platform.TextAlignmentExtensions.AdjustForFlowDirection(UIKit.U ITextAlignment,Microsoft.Maui.IView) New UpdateBackground parameter Article • 11/16/2022 When updating the button background on iOS, the border was also required to be drawn. This change adds a new parameter to ViewExtensions.UpdateBackground() to pass in the stroke information. Version introduced .NET 7 Previous behavior Previously there was no way to draw the border on buttons if there was a gradient or complex background. New behavior The new, optional parameter now allows for additional border information. Type of breaking change This change can affect binary compatibility. Reason for change We need more information when drawing the button background or border, so we added a new parameter to pass this information. Recommended action No action is required if you're calling from source. Otherwise, multi-target to support net6.0-ios or net6.0-maccatalyst . Affected APIs Microsoft.Maui.Platform.ViewExtensions.UpdateBackground(UIKit.UIView,Microsoft .Maui.Graphics.Paint) ScrollToRequest property renamed Article • 11/16/2022 The ScrollToRequest.HoriztonalOffset property has been renamed to HorizontalOffset . Version introduced .NET 7 Previous behavior The property name was misspelled. New behavior The property name and a corresponding constructor parameter name have been changed to correct a typo. Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change There was a typo in the property name. Renaming a C# record requires a fair amount of work and this API is both new and rarely used by developers. Recommended action If you don't have a custom command mapper for RequestScrollTo in the Microsoft.Maui.Handlers.ScrollViewHandler handler, then no action is needed. Otherwise, update your code to use the new spelling. Affected APIs Microsoft.Maui.ScrollToRequest.HorizontalOffset property ScrollToRequest(double,double,bool) constructor Some Windows APIs are removed Article • 11/16/2022 The following APIs have been removed: Microsoft.Maui.ApplicationModel.IWindowStateManager.ActiveWindowDisplayChange d event Microsoft.Maui.ApplicationModel.IWindowStateManager.OnWindowMessage(System.Int Ptr,uint,System.IntPtr,System.IntPtr) method Microsoft.Maui.ApplicationModel.Platform.OnWindowMessage(System.IntPtr,uint,Sy stem.IntPtr,System.IntPtr) method Version introduced .NET 7 Previous behavior Previously, the IWindowStateManager.OnWindowMessage() method was an implementation detail that ran a check on the parameters to determine if the ActiveWindowDisplayChanged event should be raised. The ActiveWindowDisplayChanged event could be invoked if the concrete type was able to observe changes of the display that contained the currently active window. You could call the Platform.OnWindowMessage() method to pass messages. This method called into IWindowStateManager.OnWindowMessage() and then that would optionally cause the ActiveWindowDisplayChanged event to fire. New behavior The APIs are now removed. Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change The ActiveWindowDisplayChanged event should never have been public because it was an implementation detail and provided no additional information that "something had changed". We removed it to avoid confusion with the MainDisplayInfoChanged event and to reduce potential implementation complexity for both users and the SDK itself. The IWindowStateManager.OnWindowMessage() method was also an implementation detail and should never have been public. This API no longer does anything and thus was removed. The Platform.OnWindowMessage() method was implemented to work around a limitation of Xamarin.Forms and Xamarin.Essentials. It was brought forward into .NET MAUI to aid migration and used in .NET 6. However, in .NET 7, this API no longer does anything and was removed. Recommended action If you're not building your app for Windows, no action is necessary. If you were using ActiveWindowDisplayChanged , use Microsoft.Maui.Devices.DeviceDisplay.Current.MainDisplayInfoChanged instead. If you were calling either of the OnWindowMessage() methods, remove the call. Affected APIs Microsoft.Maui.ApplicationModel.IWindowStateManager.ActiveWindowDisplayChange d Microsoft.Maui.ApplicationModel.IWindowStateManager.OnWindowMessage(System.Int Ptr,uint,System.IntPtr,System.IntPtr) Microsoft.Maui.ApplicationModel.Platform.OnWindowMessage(System.IntPtr,uint,Sy stem.IntPtr,System.IntPtr) AllowRenegotiation default is false Article • 11/08/2022 The default value of SslServerAuthenticationOptions.AllowRenegotiation has been changed to false . Previous behavior In previous versions, client-side renegotiation was allowed by the server by default. New behavior Starting in .NET 7, client-side renegotiation must be explicitly enabled on the server side. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change Client-side renegotiation is viewed as insecure by the industry. For example, it has been removed from TLS 1.3 entirely. Therefore, we should disable it by default. Recommended action If client-side renegotiation is required, set SslServerAuthenticationOptions.AllowRenegotiation to true when initializing the server side of the SslStream. Affected APIs System.Net.Security.SslServerAuthenticationOptions System.Net.Security.SslStream.AuthenticateAsServer(X509Certificate, Boolean, Boolean) System.Net.Security.SslStream.AuthenticateAsServer(X509Certificate, Boolean, SslProtocols, Boolean) System.Net.Security.SslStream.AuthenticateAsServer(X509Certificate) Custom ping payloads on Linux Article • 11/08/2022 On Linux, non-privileged processes can't send raw IP packets. Ping functionality is implemented by interfacing with the ping utility. However, this utility doesn't support specifying a custom payload for the Internet Control Message Protocol (ICMP) ping packets. .NET 7 adds a check for such cases and throws an exception if a custom payload is specified. Previous behavior In previous versions, the ping packet payload was silently ignored (that is, it wasn't sent) on non-privileged Linux processes. New behavior Starting in .NET 7, a PlatformNotSupportedException is thrown if you attempt to send a custom ping packet payload when running in non-privileged Linux process. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change It's better to signal to the user that the operation cannot be performed instead of silently dropping the payload. Recommended action If a ping payload is necessary, run the application as root , or grant the cap_net_raw capability using the setcap utility. Otherwise, use an overload of Ping.SendPingAsync that does not accept a custom payload, or pass in an empty array. Affected APIs System.Net.NetworkInformation.Ping.Send(IPAddress, Int32, Byte[], PingOptions) System.Net.NetworkInformation.Ping.Send(IPAddress, Int32, Byte[]) System.Net.NetworkInformation.Ping.Send(String, Int32, Byte[], PingOptions) System.Net.NetworkInformation.Ping.Send(String, Int32, Byte[]) System.Net.NetworkInformation.Ping.SendAsync(IPAddress, Int32, Byte[], PingOptions, Object) System.Net.NetworkInformation.Ping.SendAsync(IPAddress, Int32, Byte[], Object) System.Net.NetworkInformation.Ping.SendAsync(String, Int32, Byte[], PingOptions, Object) System.Net.NetworkInformation.Ping.SendAsync(String, Int32, Byte[], Object) System.Net.NetworkInformation.Ping.SendPingAsync(IPAddress, Int32, Byte[], PingOptions) System.Net.NetworkInformation.Ping.SendPingAsync(IPAddress, Int32, Byte[]) System.Net.NetworkInformation.Ping.SendPingAsync(String, Int32, Byte[], PingOptions) System.Net.NetworkInformation.Ping.SendPingAsync(String, Int32, Byte[]) Socket.End methods don't throw ObjectDisposedException Article • 11/08/2022 System.Net.Sockets.Socket.End* methods (for example, EndSend) throw a SocketException instead of an ObjectDisposedException if the socket is closed. Previous behavior Previously, the affected methods threw an ObjectDisposedException for closed sockets. New behavior Starting in .NET 7, the affected methods throw a SocketException with SocketErrorCode set to SocketError.OperationAborted for closed sockets. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The asynchronous programming model (APM) APIs are those named Begin* and End* . Starting with .NET 6, these legacy APIs are backed with a Task -based implementation as part of an effort to consolidate and simplify the Socket codebase. Unfortunately, with the 6.0 implementation, unexpected events were sometimes raised on TaskScheduler.UnobservedTaskException. This happened even when the APIs were used correctly, meaning that the calling code always invoked the End* methods, including when the socket was closed. The change to throw a SocketException was made to ensure that no unobserved exceptions are leaked in such cases. Recommended action If your code catches an ObjectDisposedException from any of the Socket.End* methods, change it to catch SocketException and refer to SocketException.SocketErrorCode to query the underlying reason. 7 Note APM code should always make sure that End* methods are invoked after the corresponding Begin* methods, even if the socket is closed. Affected APIs System.Net.Sockets.Socket.EndConnect(IAsyncResult) System.Net.Sockets.Socket.EndDisconnect(IAsyncResult) System.Net.Sockets.Socket.EndSend System.Net.Sockets.Socket.EndSendFile(IAsyncResult) System.Net.Sockets.Socket.EndSendTo(IAsyncResult) System.Net.Sockets.Socket.EndReceive System.Net.Sockets.Socket.EndAccept Automatic RuntimeIdentifier for certain projects Article • 01/14/2023 Projects that specify any of the following properties now get a runtime identifier (RID) automatically. An RID enables publishing a self-contained deployment. SelfContained PublishAot PublishReadyToRun PublishSingleFile PublishSelfContained (.NET SDK 7.0.200 and later versions only) The following projects might be affected by this change: Old projects that circumvented the missing runtime identifier error. Projects that have RuntimeIdentifiers but not RuntimeIdentifier . Projects that use hard-coded paths without RIDs. Projects that had these properties but used a build instead of a publish and accepted publish being in a broken state. There are other potential nuances that could break individual situations that we're not yet aware of. 7 Note This change was restricted to the dotnet publish command in .NET 7.0.200 SDK. For more information, see Automatic RuntimeIdentifier for publish only. Version introduced .NET 7 Previous behavior Previously, these projects failed to publish with errors such as: It is not supported to publish an application to a single-file without specifying a RuntimeIdentifier. Please either specify a RuntimeIdentifier or set PublishSingleFile to false. OR error NETSDK1031: It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier. You must either specify a RuntimeIdentifier or set SelfContained to false. In some cases, such as PublishSingleFile or with special RuntimeIdentifiers logic, projects might have built successfully without a RuntimeIdentifier . New behavior Projects that specify any of the properties listed at the beginning of this article get a RuntimeIdentifier automatically. This new behavior can cause build failures on projects that rely on RuntimeIdentifiers but not RuntimeIdentifier , because RuntimeIdentifier can affect the output path distinctly from RuntimeIdentifiers . It can also cause failures on AnyCPU projects that rely on PublishSingleFile but don't always give a RuntimeIdentifier when taking other actions. These failures can appear as follows: The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. Type of breaking change This change can affect source compatibility. Reason for change A majority of .NET projects fail to publish using the mentioned properties without RuntimeIdentifier set. This change reduces the need to add the RID manually every time you use the mentioned properties. Recommended action If your project is impacted, you can disable the automatic RuntimeIdentifier by adding <UseCurrentRuntimeIdentifier>false</UseCurrentRuntimeIdentifier> to your project file. If you encounter a break due to the output path changing, add <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> to your project file. See also Automatic RuntimeIdentifier for publish only Automatic RuntimeIdentifier for publish only Article • 01/14/2023 In the 7.0.100 SDK, there was a change to automatically add <RuntimeIdentifier> to projects with properties that require a runtime identifier (RID). Those properties are as follows: SelfContained PublishAot PublishReadyToRun PublishSingleFile PublishSelfContained However, all of these properties except for SelfContained are only used for publishing. Yet the implicit <RuntimeIdentifier> was added for any dotnet operation if these properties were in the project file or specified as part of the dotnet command. Now, the automatic RID for these properties, excluding SelfContained , is only added during publish. In addition, the automatic RID is only added when using the dotnet publish CLI command. It's not added when you publish from Visual Studio or msbuild , as those are separate mechanisms, and Visual Studio should provide its own RID. Version introduced .NET 7.0.200 SDK Previous behavior Previously, if you specified any of the mentioned properties, the RID was automatically added to the project. New behavior The RID is only automatically added for the dotnet publish command. If you performed a restore without an RID in .NET 7 and use it to restore for a publish -no-restore command on a project with one of the mentioned properties, you'll need to specify an RID using dotnet restore -r <RID> . Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change The RID change was a breaking change, and there was no need for a publish property change to break dotnet build and other non-publish-related commands. Recommended action For an action like restore followed by publish --no-restore , you must add the RID by using dotnet restore -r RID . In this case, it's also better to be explicit when you publish so the publish has the same RID (using dotnet publish -r RID ). Alternatively, you can remove --no-restore from the publish command. For everything else, no action is needed. However, if you want to keep the RID, add it to the project file as follows: <RuntimeIdentifier>win-x64</RuntimeIdentifier> . See also Automatic RuntimeIdentifier for certain projects CLI console output uses UTF-8 Article • 04/06/2023 If the DOTNET_CLI_UI_LANGUAGE or VSLANG environment variable is set, the .NET CLI console output and input encoding changes to UTF-8, so that the code page can change to UTF-8 as well. This new behavior allows characters from languages set by those environment variables to be rendered correctly. This change only affects Windows operating systems (the encoding was okay on other platforms). Moreover, it only applies to Windows 10 and later versions where the UI culture set by the user is non-English. Previous behavior Characters in certain languages, including Chinese, German, Japanese, and Russian, would sometimes display as garbled characters or as ? in the console. For example: Console C:\>dotnet build MSBuild version 17.3.0-preview[...] for .NET ???????????????... New behavior Starting in .NET 7 (version 7.0.3xx) and .NET 8, characters render correctly. Both the encoding and the code page change. For example: Console C:\>dotnet build MSBuild version 17.3.0-preview[...] for .NET 正在确定要还原的项目… Versions of Windows older than Windows 10 1909 don't fully support UTF-8 and may experience issues after this change. (Starting in .NET 8 Preview 3 and .NET 7.0.300 SDK, the .NET SDK no longer changes the encoding to UTF-8 on these versions, by default. To opt back into using UTF-8 even on Windows 10 versions that don't support it, use the DOTNET_CLI_FORCE_UTF8_ENCODING environment variable.) In addition, there was an existing bug where the SDK can affect the encoding of other commands and programs called in the same command prompt after the SDK has finished execution. Now that the SDK more frequently changes the encoding, the impact of this bug may increase. However, the bug was fixed in .NET 8 Preview 3 and .NET 7.0.300 SDK. For more information, see SDK no longer changes console encoding after completion. Version introduced 7.0.3xx .NET 8 Preview 1 Type of breaking change This change can affect source compatibility and binary compatibility. It's also a behavioral change. Reason for change Using the .NET CLI in non-English languages provided a poor experience. Developers that weren't already using the VSLANG and DOTNET_CLI_UI_LANGUAGE variables aren't impacted. The impact should be minimal, as this language setting wouldn't have worked well in the first place due to garbled characters. Also, only developers using Windows 10 or later might be impacted, most of which are likely using version 1909 or later. The legacy scenarios are already less likely to support the broken languages, so it's unlikely you'd want to use another language that might expose this break anyway. Recommended action If you're using an older version of windows 10, upgrade to version 1909 or later. If you want to use a legacy console or are facing build issues or others due to the encoding change, unset VSLANG and DOTNET_CLI_UI_LANGUAGE to disable this change. See also SDK no longer changes console encoding when finished Version requirements for .NET 7 SDK Article • 03/24/2023 Certain .NET SDK versions require newer versions of Visual Studio and MSBuild. Version introduced .NET SDK 7 Change description The following table shows the minimum version of Visual Studio and MSBuild you need to use the .NET 7.0.100 or 7.0.200 SDK. NET SDK version Minimum Visual Studio and MSBuild version 7.0.100 17.4 7.0.200 17.4 1In addition, scenarios that use a source generator could fail when using a Visual Studio or MSBuild version earlier than version 17.2. For more information about minimum supported versions, see Targeting and support rules. Reason for change Changes were made to features within the SDK that aren't compatible with previous Visual Studio versions. In addition, it enables .NET SDK partners to have a reliable minimum version of Visual Studio that they can expect to work against. Recommended action Upgrade your Visual Studio version to the required version. Alternatively, you can use a global.json file to pin to an older standalone SDK install. Affected APIs N/A See also Targeting and support rules SDK no longer calls ResolvePackageDependencies Article • 07/18/2023 Previously, the .NET SDK called the ResolvePackageDependencies target in order to generate PackageDependencies and PackageDefinitions . However, that data was already available from a different target. Instead, those two items are now added from PreprocessPackageDependenciesDesignTime into the design-time build cache and the prior target isn't called. Version introduced .NET SDK 7.0.200 Type of change This change can affect source compatibility. Previous behavior An existing .NET SDK target was called to get information on packages that were already available. New behavior Package information is added from PreprocessPackageDependenciesDesignTime into the design-time build cache. If you depended on PackageDependencies and PackageDefinitions in your build, you'll see build errors such as No dependencies found. Reason for change In some situations, performance was particularly slow for the prior target. Solutions that have large NuGet dependency graphs will see faster IntelliSense after solution loads, branch switches, or when making solution-wide changes while using the Central Package Management feature. Recommended action If your build depends on the previous behavior, add the <EmitLegacyAssetsFileItems>true</EmitLegacyAssetsFileItems> property to your project to return to the legacy behavior. We expect this to only impact a small number of users. XML <PropertyGroup> <EmitLegacyAssetsFileItems>true</EmitLegacyAssetsFileItems> </PropertyGroup> BinaryFormatter serialization of custom BuildEventArgs and ITaskItems removed for .NET 7 Article • 05/12/2022 MSBuild in .NET 7 doesn't support serialization of custom BuildEventArgs -derived and ITaskItem -derived types via the BinaryFormatter serializer. Version introduced MSBuild 17.4 (.NET SDK 7.0.100) Old behavior MSBuild used BinaryFormatter to preserve custom types that derived from BuildEventArgs and ITaskItem across certain boundaries, most notably when running in a multi-process environment. New behavior MSBuild will no longer support this mechanism, so code that used custom types derived from BuildEventArgs and ITaskItem may fail. Reason for change BinaryFormatter was made obsolete in .NET 5 . Per this plan, all first-party code in the dotnet GitHub organization must migrate away from its use by .NET 7. This change impacts user-exposed functionality of MSBuild. Recommended action Engage with the MSBuild team on this GitHub discussion about your specific use cases and how you can migrate away from the TranslateDotNet mechanism. Avoid returning custom derived types from tasks or when logging. Side-by-side SDK installations Article • 02/21/2023 If a preview .NET 7 SDK is installed alongside the general availability (GA) version of the .NET 7 SDK, projects with workload dependencies such as microsoft.net.workload.mono.toolchain may fail to build, load, or run. The error is similar to: The SDK resolver "Microsoft.DotNet.MSBuildSdkResolver" failed while attempting to resolve the SDK "Microsoft.NET.Sdk". Exception: "Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadManifestCompositionExcepti on: Workload definition 'wasm-tools' in manifest 'microsoft.net.workload.mono.toolchain'. 7 Note This behavior was fixed in .NET SDK 7.0.101. Version introduced .NET 7 Previous behavior Building, loading, or running an affected project worked fine. New behavior Building, loading, or running an affected project fails. Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change .NET 7 preview SDKs are incompatible with the GA version because the mono.toolchain workload was renamed. Recommended action Choose one of the following actions: Uninstall any .NET 7 preview SDKs. For detailed instructions, see How to remove the .NET Runtime and SDK. For example, on Windows, you can uninstall .NET preview SDKs using Add or remove programs in Control panel. You can also use the dotnet-core-uninstall tool to uninstall preview SDKs. For file-based installs, you can delete the folder %ProgramFiles%/dotnet/sdkmanifests/7.0.100/microsoft.net.workload.mono.toolchain. Solution-level --output option no longer valid for build-related commands Article • 02/24/2023 In the 7.0.200 SDK, there was a change to no longer accept the --output / -o option when using a solution file with the following commands: build clean pack publish store test vstest This is because the semantics of the OutputPath property, which is controlled by the -output / -o option, aren't well defined for solutions. Projects built in this way will have their output placed in the same directory, which is inconsistent and has led to a number of user-reported issues. This change was reduced to a warning level of severity in the 7.0.201 SDK, and pack was removed from the list of commands that are affected. Version introduced .NET 7.0.200 SDK, reduced to a warning only in the 7.0.201 SDK. Previous behavior Previously, if you specified --output / -o when using a solution file, the output for all built projects would be placed in the specified directory in an undefined and inconsistent order. New behavior The dotnet CLI will error if the --output / -o option is used with a solution file. Starting in the 7.0.201 SDK, a warning will be emitted instead, and in the case of dotnet pack no warning or error will be generated. Type of breaking change This breaking change may require modifications to build scripts and continuous integration pipelines. As a result it affects both binary and source compatibility. Reason for change This change was made because the semantics of the OutputPath property, which is controlled by the --output / -o option, aren't well defined for solutions. Projects built in this way will have their output placed in the same directory, which is inconsistent and has led to a number of user-reported issues. When a solution is built with the --output option, the OutputPath property is set to the same value for all projects, which means that all projects will have their output placed in the same directory. Depending on the complexity of the projects in the solution, different and inconsistent results may occur. Let's take a look at some examples of different solution shapes and how they are affected by a shared OutputPath . Single project, single TargetFramework Imagine a solution that contains a single project targeting a single TargetFramework , net7.0 . In this case, providing the --output option is equivalent to setting the OutputPath property in the project file. During a build (or other commands, but let's scope the discussion to build for now), all of the outputs for the project will be placed in the specified directory. Single project, multiple TargetFrameworks Now imagine a solution that contains a single project with multiple TargetFrameworks , net6.0 and net7.0 . Because of multi-targeting, the project will be build twice, once for each TargetFramework . For each of these 'inner' builds the OutputPath will be set to the same value, and so the outputs for each of the inner builds will be placed in the same directory. This means that whichever build completes last will overwrite the outputs of the other build, and in a parallel-build system like MSBuild operates in by default, 'last' is indeterminate. Library => Console => Test, single TargetFramework Now imagine a solution that contains a library project, a console project that references the library project, and a test project that references the console project. All of these projects target a single TargetFramework , net7.0 . In this case, the library project will be built first, and then the console project will be built. The test project will be built last, and will reference the console project. For each built project, the outputs of each build will be copied into the directory specified by the OutputPath , and so the final directory will contain assets from all three projects. This works for testing, but for publishing may result in test assets being sent to production. Library => Console => Test, multiple TargetFrameworks Now take the same chain of projects and add a net6.0 TargetFramework build to them in addition to the net7.0 build. The same problem as the single-project, multi-targeted build occurs - inconsistent copying of TFM-specific assets to the specified directory. Multiple apps So far we have been looking at scenarios with a linear dependency graph - but many solutions may contain multiple related applications. This means that multiple apps may be built concurrently to the same output folder. If the apps include a dependency file with the same name, then the build may intermittently fail when multiple projects try to write to that file in the output path concurrently. If multiple apps depend on different versions of a file, then even if the build succeeds, which version of the file is copied to the output path may be non-deterministic. This can happen when the projects depend (possibly transitively) on different versions of a NuGet package. Within a single project, NuGet helps ensure that its dependencies (including any transitive dependencies through NuGet packages and/or project references) are unified to the same version. Because the unification is done within the context of a single project and its dependent projects, this means it is possible to resolve different versions of a package when two separate top-level projects are built. If the project that depends on the higher version copies the dependency last, then often the apps will run successfully. However, if the lower version is copied last, then the app that was compiled against the higher version will fail to load the assembly at runtime. Because the version that is copied can be non-deterministic, this can lead to sporadic, unreliable builds where it is very difficult to diagnose the issue. Other examples For more examples of how this underlying error presents in practice, see the discussion on dotnet/sdk#15607 . Recommended action The general recommendation is to perform the action that you previously took without the --output / -o option, and then move the output to the desired location after the command has completed. It's also possible to perform the action at a specific project and still apply the --output / -o option, as that has more well-defined semantics. If you want to maintain the existing behavior exactly, then you can use the --property flag to set a MSBuild property to the desired directory. The property to use varies based on the command: Command Property Example build OutputPath dotnet build --property:OutputPath=DESIRED_PATH clean OutputPath dotnet clean --property:OutputPath=DESIRED_PATH pack PackageOutputPath dotnet pack --property:PackageOutputPath=DESIRED_PATH publish PublishDir dotnet publish --property:PublishDir=DESIRED_PATH store OutputPath dotnet store --property:OutputPath=DESIRED_PATH test TestResultsDirectory dotnet test --property:OutputPath=DESIRED_PATH NOTE For best results, the DESIRED_PATH should be an absolute path. Relative paths will be 'anchored' (i.e. made absolute) in ways that you may not expect, and may not work the same with all commands. Tool manifests in root folder Article • 08/01/2023 .NET no longer looks for local tool manifest files in the root folder on Windows, unless overridden via the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable. This change does not impact Linux or macOS. Previous behavior Previously, .NET SDK local tools checked the root folder on all platforms when searching for a tool manifest. The search continued from the current directory up the directory tree to the root folder until it found a manifest. At each level, .NET searches for the tool manifest, named dotnet-tools.json, in a .config subfolder. On a Windows system, if no other tool manifest was found, the SDK ultimately looked for a tool manifest in C:\.config\dotnet-tools.json. New behavior .NET no longer searches in the root folder of the current directory tree by default on Windows, unless overridden via the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable. DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT is set to false by default. Version introduced .NET SDK 7.0.3xx .NET SDK 7.0.1xx .NET SDK 6.0.4xx .NET SDK 6.0.3xx .NET SDK 6.0.1xx .NET SDK 3.1.4xx Type of breaking change This change is a behavioral change. Reason for change This change was made to address a security concern. Since all users can create files and folders in the C:\ directory on Windows, low-privilege attackers can hijack the C:\.config\dotnet-tools.json file. When an administrator runs a dotnet tool command, the tool could potentially read malicious configuration information from the file and download and run malicious tools. Recommended action To disable the new behavior, set the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable to true or 1 . See also Tutorial: Install and use a .NET local tool using the .NET CLI BinaryFormatter serialization APIs produce compiler errors Article • 05/17/2023 As part of the BinaryFormatter long-term deprecation plan , we continue to cull BinaryFormatter functionality from our libraries and to wean developers off of the type. Starting in .NET 7, calls to the following APIs produce compile-time errors across all C# and Visual Basic project types: System.Exception.SerializeObjectState event BinaryFormatter.Serialize method BinaryFormatter.Deserialize method Formatter.Serialize(Stream, Object) method Formatter.Deserialize(Stream) method IFormatter.Serialize(Stream, Object) method IFormatter.Deserialize(Stream) method Previous behavior Since .NET 5, using the affected Serialize and Deserialize methods produced a compiler warning with ID SYSLIB0011 . For more information, see BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps (.NET 5). Using the Exception.SerializeObjectState event did not produce an error. New behavior Starting in .NET 7, using any of the affected APIs in code produces a compiler error with the same ID, SYSLIB0011 . Your project will be affected if it meets all of the following criteria: It's a C# or Visual Basic project. It targets net7.0 or higher. It directly calls one of the affected APIs. It's not already suppressing the SYSLIB0011 warning code. Version introduced .NET 7 Type of breaking change This change can affect source compatibility. Reason for change As part of the BinaryFormatter long-term deprecation plan , we continue to cull BinaryFormatter functionality from our libraries and to wean developers off of the type. Recommended action The best course of action is to migrate away from BinaryFormatter due to its security and reliability flaws. BinaryFormatter may be removed from .NET in a future release. The .NET libraries team has already taken a stance that recent types such as System.Half and System.DateOnly won't be compatible with BinaryFormatter . If you must suppress the errors, you can do so by following the guidelines in the original obsoletion article. You can also disable the error project-wide by setting a project property that converts the error back to a warning (to match the .NET 5/6 behavior). 2 Warning Setting this property might change host behavior. See <EnableUnsafeBinaryFormatterSerialization> property. C# <PropertyGroup> ... <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterS erialization> </PropertyGroup> 7 Note If your project compiles with "warnings as errors" enabled, compilation will still fail. (This matches the behavior that shipped in the .NET 5 and .NET 6 SDKs.) If that's the case, you'll still need to suppress the SYSLIB0011 warning in source or in your project file's <NoWarn> element. <EnableUnsafeBinaryFormatterSerialization> property The <EnableUnsafeBinaryFormatterSerialization property was introduced in .NET 5. With .NET 7, the behavior of this switch has changed to control both compilation and host run-time behavior. The meaning of this switch differs based on the project type, as described in the following table. Type of project Property set to true Property set to false Property omitted Library/shared component1 The affected APIs are obsolete as warning. The affected APIs are obsolete as error, and (Same as for false .) Compilation will succeed calls from your code to unless you have "warnings those APIs will fail at as errors" enabled for your application or you've compile time unless the error is suppressed. suppressed the SYSLIB0011 warning code. Blazor and MAUI apps2 ASP.NET app Calls to BinaryFormatter Calls to Calls to will fail at run time. BinaryFormatter will BinaryFormatter will fail at run time. fail at run time. The affected APIs are The affected APIs are (Same as for false .) obsolete as warning. Compilation will succeed obsolete as error, and calls from your code to unless you have "warnings as errors" enabled for your application or you've those APIs will fail at compile time unless the error is suppressed. suppressed the SYSLIB0011 The runtime will forbid calls to BinaryFormatter , warning code. The runtime will allow calls to BinaryFormatter , regardless of whether the call originates from your code or from a dependency that you consume. regardless of whether the call originates from your code or from a dependency that you consume. Type of project Property set to true Property set to false Property omitted Desktop apps The affected APIs are The affected APIs are The affected APIs are and all other app types obsolete as warning. Compilation will succeed unless you have "warnings obsolete as error, and calls from your code to those APIs will fail at obsolete as error, and calls from your code to those APIs will fail at as errors" enabled for your application or you've suppressed the SYSLIB0011 compile time unless the error is suppressed. The runtime will forbid compile time unless the error is suppressed. The runtime will allow calls warning code. The runtime calls to to BinaryFormatter , will allow calls to BinaryFormatter , regardless BinaryFormatter , regardless of whether the call originates from your code or from a of whether the call originates from your code or from a dependency that you consume. 1 regardless of whether the call originates from your code or from a dependency that you consume. dependency that you consume. Runtime policy is controlled by the app host. Calls into BinaryFormatter might still fail at run time even if <EnableUnsafeBinaryFormatterSerialization> is set to true within your library's project file. Libraries can't override the app host's runtime policy. 2 The Blazor and MAUI runtimes forbid calls to BinaryFormatter . Regardless of any value you set for <EnableUnsafeBinaryFormatterSerialization> , the calls will fail at run time. Don't call these APIs from Blazor or MAUI applications or from libraries intended to be consumed by Blazor or MAUI apps. Affected APIs System.Exception.SerializeObjectState System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize System.Runtime.Serialization.Formatter.Serialize(Stream, Object) System.Runtime.Serialization.Formatter.Deserialize(Stream) System.Runtime.Serialization.IFormatter.Serialize(Stream, Object) System.Runtime.Serialization.IFormatter.Deserialize(Stream) See also dotnet/runtime issue 72132 BinaryFormatter serialization methods are obsolete (.NET 5) SerializationFormat.Binary is obsolete (.NET 7) BinaryFormatter disabled across most project types (.NET 8) SerializationFormat.Binary is obsolete Article • 05/17/2023 SerializationFormat.Binary is obsolete for DataTable and DataSet. Binary serialization relies on BinaryFormatter, which is insecure. If you use SerializationFormat.Binary in your code, obsoletion warning SYSLIB0038 will be generated at compile time. In addition, an InvalidEnumArgumentException is thrown at run time if you: Set DataSet.RemotingFormat or DataTable.RemotingFormat to SerializationFormat.Binary. Call one of the deserialization constructors for DataTable or DataSet with binary data. Previous behavior Previously, DataTable and DataSet could be serialized and deserialized with their RemotingFormat property set to SerializationFormat.Binary, which used BinaryFormatter under the hood. New behavior Starting in .NET 7, if you attempt to serialize or deserialize DataTable and DataSet with their RemotingFormat property set to SerializationFormat.Binary, an InvalidEnumArgumentException is thrown. Version introduced .NET 7 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change SerializationFormat.Binary is implemented via BinaryFormatter, which is insecure and being obsoleted across the entire .NET stack. Recommended action If your code uses SerializationFormat.Binary, switch to using SerializationFormat.Xml or use another method of serialization. Otherwise, you can set the Switch.System.Data.AllowUnsafeSerializationFormatBinary AppContext switch. This switch lets you opt in to allowing the use of SerializationFormat.Binary, so that code can work as before. However, this switch will be removed in .NET 8. For information about setting the switch, see AppContext for library consumers. Affected APIs System.Data.SerializationFormat.Binary DataSet.RemotingFormat DataTable.RemotingFormat DataSet(SerializationInfo, StreamingContext) DataSet(SerializationInfo, StreamingContext, Boolean) DataTable(SerializationInfo, StreamingContext) See also BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps DataContractSerializer retains sign when deserializing -0 Article • 11/08/2022 DataContractSerializer and DataContractJsonSerializer previously discarded the sign when deserializing the input "-0" as a float or double. Both serializers have always done the right thing when given "-0.0" as an input, but with an input of "-0", the sign was lost. This behavior is both inconsistent and results in data loss. In addition, these serializers write a value of negative zero out as "-0" during serialization. Previous behavior Previously, the negative sign was lost when deserializing "-0" (but not "-0.0") as a float or double using DataContractSerializer. New behavior The negative sign is now preserved when deserializing "-0" as a float or double. Version introduced .NET 6.0.11 (servicing release) .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior was inconsistent and resulted in data loss. Recommended action In most cases, no action is needed. If your code was affected by the bug, then this is a good change. Or, you've already worked around the bug in a way that's unlikely to be broken by this change. Affected APIs System.Runtime.Serialization.DataContractSerializer.ReadObject System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject Deserialize Version type with leading or trailing whitespace Article • 11/08/2022 JsonSerializer now throws an exception while deserializing Version types that have leading or trailing whitespace. Previous behavior Prior to .NET 7, deserializing Version types that have leading or trailing whitespace was permitted. New behavior Started in .NET 7, JsonSerializer throws a FormatException when deserializing Version types that have leading or trailing whitespace. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change .NET has optimized the implementation of the underlying Version converter. This resulted in the implementation being made to align with the behavior for other primitive types supported by System.Text.Json, for example, DateTime and Guid, which also disallow leading and trailing spaces. Recommended action To get the old behavior back, add a custom converter for the Version type that permits whitespace: C# internal sealed class VersionConverter : JsonConverter<Version> { public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string? versionString = reader.GetString(); if (Version.TryParse(versionString, out Version? result)) { return result; } ThrowHelper.ThrowJsonException(); return null; } public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); } } Affected APIs System.Text.Json.JsonSerializer.Deserialize System.Text.Json.JsonSerializer.DeserializeAsync JsonSerializerOptions copy constructor includes JsonSerializerContext Article • 11/08/2022 With the release of source generation in .NET 6, the JsonSerializerOptions copy constructor was intentionally made to ignore its JsonSerializerContext state. This made sense at the time since JsonSerializerContext was designed to have a 1:1 relationship with JsonSerializerOptions instances. In .NET 7, IJsonTypeInfoResolver replaces JsonSerializerContext to generalize the context, which removes the need for tight coupling between JsonSerializerOptions and JsonSerializerContext. The copy constructor now includes the IJsonTypeInfoResolver/JsonSerializerContext information, which could manifest as a breaking change for some scenarios. Previous behavior In .NET 6, the following code serializes successfully. The MyContext configuration (which doesn't support Poco2 ) is discarded by the copy constructor, and serialization succeeds because the new options instance defaults to using reflection-based serialization. C# var options = new JsonSerializerOptions(MyContext.Default.Options); JsonSerializer.Serialize(new Poco2(), options); [JsonSerializable(typeof(Poco1))] public partial class MyContext : JsonSerializerContext {} public class Poco1 {} public class Poco2 {} New behavior Starting in .NET 7, the same code as shown in the Previous behavior section throws an InvalidOperationException. That's because the copy constructor now incorporates MyContext metadata, which doesn't support Poco2 contracts. Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change JsonSerializerContext was the only setting ignored by the copy constructor. This behavior was surprising for some users. Recommended action If you depend on the .NET 6 behavior, you can manually unset the TypeInfoResolver property to get back reflection-based contract resolution: C# var options = new JsonSerializerOptions(MyContext.Default.Options); options.TypeInfoResolver = null; // Unset `MyContext.Default` as the resolver for the options instance. Affected APIs System.Text.Json.JsonSerializerOptions.JsonSerializerOptions(JsonSerializerOptions) Polymorphic serialization for object types Article • 11/08/2022 Using default configuration, System.Text.Json serializes values of type object using polymorphism. This behavior becomes less consistent if you register a custom converter for object . System.Text.Json has historically hardcoded polymorphism for root-level object values but not for nested object values. Starting with .NET 7, this behavior has changed so that custom converters never use polymorphism. Previous behavior Consider the following custom object converter: C# public class CustomObjectConverter : JsonConverter<object> { public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) => writer.WriteNumberValue(42); public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); } In previous versions, the following code serialized as 0. That's because the serializer used polymorphism and ignored the custom converter. C# var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } }; JsonSerializer.Serialize<object>(0, options); However, the following code serialized as 42 because the serializer honored the custom converter. C# var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } }; JsonSerializer.Serialize<object[]>(new object[] { 0 }, options); New behavior Starting in .NET 7, using the custom object converter defined in the Previous behavior section, the following code serializes as 42. That's because the serializer will always consult the custom converter and not use polymorphism. C# var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } }; JsonSerializer.Serialize<object>(0, options); Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change This change was made due to inconsistent serialization contracts for a type, depending on whether it was being serialized as a root-level value or a nested value. Recommended action If desired, you can get back polymorphism for root-level values by invoking one of the untyped serialization methods: C# var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } }; JsonSerializer.Serialize(0, inputType: typeof(int), options); // Serializes as 0. Affected APIs System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize<TValue>(Stream, TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize<TValue>(Utf8JsonWriter, TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.SerializeAsync<TValue>(Stream, TValue, JsonSerializerOptions, CancellationToken) System.Text.Json source generator fallback Article • 11/08/2022 When using one of the JsonSerializer methods that accepts JsonSerializerOptions, the System.Text.Json source generator will no longer implicitly fall back to reflection-based serialization for unrecognized types. Previous behavior Consider the following source generation example in .NET 6: C# JsonSerializer.Serialize(new Poco2(), typeof(Poco2), MyContext.Default); [JsonSerializable(typeof(Poco1))] public partial class MyContext : JsonSerializerContext {} public class Poco1 { } public class Poco2 { } Since MyContext does not include Poco2 in its serializable types, the serialization will correctly fail with the following exception: Output System.InvalidOperationException: 'Metadata for type 'Poco2' was not provided to the serializer. The serializer method used does not support reflection-based creation of serialization-related type metadata. If using source generation, ensure that all root types passed to the serializer have been indicated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically. Now consider the following call, which tries to serialize the same type ( MyContext ) using the JsonSerializerOptions instance constructed by the source generator: C# JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options); The options instance silently incorporates the default reflection-based contract resolver as a fallback mechanism, and as such, the type serializes successfully—using reflection. The same fallback logic applies to JsonSerializerOptions.GetConverter(Type) for options instances that are attached to a JsonSerializerContext. The following statement will return a converter using the built-in reflection converter: C# JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2)); New behavior Starting in .NET 7, the following call fails with the same exception (InvalidOperationException) as when using the JsonSerializerContext overload: C# JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options); In addition, the following statement will fail with a NotSupportedException: C# JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2)); Version introduced .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior violates the principle of least surprise and ultimately defeats the purpose of source generation. With the release of a feature that allows you to customize the JSON serialization contracts of your types , you have the ability to fine tune the sources of your contract metadata. With this in mind, silently introducing alternative sources becomes even less desirable. Recommended action You might depend on the previous behavior, either intentionally or unintentionally. The recommended course of action is to update your JsonSerializerContext definition so that it includes all type dependencies: C# [JsonSerializable(typeof(Poco1))] [JsonSerializable(typeof(Poco2))] public partial class MyContext : JsonSerializerContext {} This will let your application take full advantage of the benefits of source generation, including trim safety. In certain cases, however, making such a change might not be practical or possible. Even though it's not recommended, there are a couple of ways you can re-enable reflection fallback in your source-generated serializer. Use a custom contract resolver You can use the new contract customization feature to build a custom contract resolver that falls back to reflection-based resolution where required: C# var options = new JsonSerializerOptions { TypeInfoResolver = JsonTypeInfoResolver.Combine(MyContext.Default, new DefaultJsonTypeInfoResolver()); } JsonSerializer.Serialize(new Poco2(), options); // Contract resolution falls back to the default reflection-based resolver. options.GetConverter(typeof(Poco2)); // Returns the reflection-based converter. Use an AppContext switch Starting in .NET 7, you can re-enable reflection fallback globally using the provided AppContext compatibility switch. Add the following entry to your application's project file to re-enable reflection fallback for all source-generated contexts in your app. For more information on using AppContext switches, see the article on .NET runtime configuration settings. XML <ItemGroup> <RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.EnableSourceGenReflectionFallback" Value="true" /> </ItemGroup> Affected APIs System.Text.Json.JsonSerializerOptions.GetConverter(Type) System.Text.Json.JsonSerializer.Serialize(Stream, Object, Type, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize(Object, Type, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize(Utf8JsonWriter, Object, Type, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize<TValue>(Stream, TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize<TValue>(Utf8JsonWriter, TValue, JsonSerializerOptions) System.Text.Json.JsonSerializer.SerializeAsync(Stream, Object, Type, JsonSerializerOptions, CancellationToken) System.Text.Json.JsonSerializer.SerializeAsync<TValue>(Stream, TValue, JsonSerializerOptions, CancellationToken) XmlSecureResolver is obsolete Article • 11/08/2022 The method System.Xml.XmlSecureResolver.GetEntity(Uri, String, Type) unconditionally throws an XmlException at run time. If your application utilizes XmlSecureResolver and you attempt to resolve an XML resource through it, resolution will fail with an exception. Additionally, the entire System.Xml.XmlSecureResolver type is obsolete. All references to this type will result in a SYSLIB0047 warning at build time. If you've enabled warnings as errors, this will cause a build break if your application references XmlSecureResolver. C# using System.Xml; // Compiler warning SYSLIB0047: XmlSecureResolver type is obsolete. XmlResolver resolver = new XmlSecureResolver( resolver: new XmlUrlResolver(), securityUrl: "https://www.example.com/"); // Call to XmlSecureResolver.GetEntity below throws XmlException at run time. object entity = resolver.GetEntity( absoluteUri: new Uri("https://www.example.com/some-entity"), role: null, ofObjectToReturn: null); Previous behavior In .NET Framework, XmlSecureResolver.GetEntity(Uri, String, Type) constructs a Code Access Security (CAS) sandbox to restrict the external XML resource resolution process. If policy is violated, a SecurityException is thrown. In .NET Core 3.1, and .NET 6, XmlSecureResolver.GetEntity(Uri, String, Type) doesn't restrict external XML resource resolution at all. External resource resolution is allowed to proceed with no limitations. New behavior Starting in .NET 7, XmlSecureResolver.GetEntity(Uri, String, Type) unconditionally throws an XmlException. It does not construct a CAS sandbox and does not attempt to resolve the external resource. Version introduced .NET 7 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change This change improves the security of the .NET ecosystem. This obsoletion moves the behavior of XmlSecureResolver from fail-dangerous (always perform resolution) to failsafe (never perform resolution) when running on .NET 7 or later. Recommended action Consider instead using the newly introduced static property XmlResolver.ThrowingResolver. This property provides an XmlResolver instance that forbids external resource resolution. C# using System.Xml; // BAD: Do not use XmlSecureResolver. // XmlResolver resolver = new XmlSecureResolver( // resolver: new XmlUrlResolver(), // securityUrl: "https://www.example.com/"); // GOOD: Use XmlResolver.ThrowingResolver instead. XmlResolver resolver = XmlResolver.ThrowingResolver; Affected APIs System.Xml.XmlSecureResolver System.Xml.XmlSecureResolver.GetEntity(Uri, String, Type) Some APIs throw ArgumentNullException (.NET 7) Article • 05/13/2022 Some APIs now validate input parameters and throw an ArgumentNullException where previously they threw a NullReferenceException, if invoked with null input arguments. Previous behavior In previous .NET versions, the affected APIs throw a NullReferenceException if invoked with an argument that's null . New behavior Starting in .NET 7, the affected APIs throw an ArgumentNullException if invoked with an argument that's null . Change category This change affects binary compatibility. Reason for change Throwing ArgumentNullException conforms to .NET Runtime behavior. It provides a better debug experience by clearly communicating which argument caused the exception. Version introduced .NET 7 Recommended action Review and, if necessary, update your code to prevent passing null input arguments to the affected APIs. If your code handles NullReferenceException, replace or add an additional handler for ArgumentNullException. Affected APIs The following table lists the affected APIs and specific parameters. Method/property Parameter name Change version ComboBox.ChildAccessibleObject(ComboBox, IntPtr) owner Preview 1 ControlPaint.CreateHBitmap16Bit(Bitmap, Color) bitmap Preview 1 ControlPaint.CreateHBitmapColorMask(Bitmap, IntPtr) bitmap Preview 1 DataGridViewEditingControlShowingEventArgs(Control, control or Preview 1 DataGridViewCellStyle) cellStyle ToolStripArrowRenderEventArgs(Graphics, ToolStripItem, Rectangle, Color, ArrowDirection) g Preview 1 ToolStripContentPanelRenderEventArgs(Graphics, ToolStripContentPanel) g or Preview 1 ToolStripItemRenderEventArgs(Graphics, ToolStripItem) g or item Preview 1 ToolStripPanelRenderEventArgs(Graphics, ToolStripPanel) g or Preview 1 contentPanel toolStripPanel ListView.CheckedIndexCollection(ListView) owner Preview 5 Windows Forms obsoletions and warnings (.NET 7) Article • 09/14/2022 Some Windows Forms APIs have been marked as obsolete, starting in .NET 7. Other APIs aren't obsolete but will cause a compile-time warning if you reference them. Previous behavior In previous .NET versions, these APIs can be used without any build warning. New behavior In .NET 7 and later versions, use of these APIs produces a compile-time warning or error with a custom diagnostic ID. The use of custom diagnostic IDs allows you to suppress the warnings individually instead of blanket-suppressing all obsoletion warnings. The following table lists the custom diagnostic IDs and their corresponding warning messages. Diagnostic Description Severity ID WFDEV001 Version introduced Casting to/from IntPtr is unsafe. Use WParamInternal , LParamInternal , or Warning Preview 1 ResultInternal instead. WFDEV002 System.Windows.Forms.DomainUpDown.DomainUpDownAccessibleObject is no longer used to provide accessible support for DomainUpDown controls. Use AccessibleObject instead. Warning RC 1 WFDEV003 System.Windows.Forms.DomainUpDown.DomainItemAccessibleObject is no longer used to provide accessible support for DomainUpDown items. Use AccessibleObject instead. Warning RC 1 Version introduced .NET 7 Type of breaking change These obsoletions and warnings can affect source compatibility. Recommended action Follow the specific guidance provided for the each diagnostic ID using the URL link provided on the warning. If necessary, you can suppress the warning using the custom WFDEVxxx diagnostic ID value. Affected APIs WFDEV001 System.Windows.Forms.Message.WParam System.Windows.Forms.Message.LParam System.Windows.Forms.Message.Result WFDEV002 System.Windows.Forms.DomainUpDown.DomainUpDownAccessibleObject WFDEV003 System.Windows.Forms.DomainUpDown.DomainItemAccessibleObject See also Obsolete Windows Forms features in .NET 7+ Breaking changes in .NET 6 Article • 07/28/2023 If you're migrating an app to .NET 6, the breaking changes listed here might affect you. Changes are grouped by technology area, such as ASP.NET Core or Windows Forms. This article indicates whether each breaking change is binary compatible or source compatible: Binary compatible - Existing binaries will load and execute successfully without recompilation, and the run-time behavior won't change. Source compatible - Source code will compile successfully without changes when targeting the new runtime or using the new SDK or component. ASP.NET Core Title Binary compatible Source compatible ActionResult<T> sets StatusCode to 200 ✔️ ❌ AddDataAnnotationsValidation method made obsolete ✔️ ❌ Assemblies removed from Microsoft.AspNetCore.App shared framework ❌ ✔️ Blazor: Parameter name changed in RequestImageFileAsync method ✔️ ❌ Blazor: WebEventDescriptor.EventArgsType property replaced ❌ ❌ Blazor: Byte array interop ✔️ ❌ Changed MessagePack library in ❌ ✔️ ✔️ ❌ EndpointName metadata not set automatically ✔️ ❌ Identity: Default Bootstrap version of UI changed ❌ ❌ Kestrel: Log message attributes changed ✔️ ❌ @microsoft/signalr-protocol-msgpack ClientCertificate property doesn't trigger renegotiation for HttpSys Introduced Preview 1 Preview 6 RC 2 Title Binary compatible Source compatible Microsoft.AspNetCore.Http.Features split ❌ ✔️ Middleware: HTTPS Redirection Middleware throws exception on ambiguous HTTPS ports ✔️ ❌ Middleware: New Use overload ✔️ ❌ Preview 4 Minimal API renames in RC 1 ❌ ❌ RC 1 Minimal API renames in RC 2 ❌ ❌ RC 2 MVC doesn't buffer IAsyncEnumerable types when ✔️ ❌ Preview 4 Nullable reference type annotations changed ✔️ ❌ Obsoleted and removed APIs ✔️ ❌ PreserveCompilationContext not configured by default ❌ ✔️ Razor: Compiler no longer produces a Views assembly ✔️ ❌ Preview 3 Razor: Logging ID changes ❌ ✔️ RC1 Razor: RazorEngine APIs marked obsolete ✔️ ❌ Preview 1 SignalR: Java Client updated to RxJava3 ❌ ✔️ Preview 4 TryParse and BindAsync methods are validated ❌ ❌ RC 2 using System.Text.Json Introduced Preview 1 Containers Title Default console logger formatting in container images Binary compatible Source compatible ✔️ ❌ Introduced Servicing 6.0.6 For information on other breaking changes for containers in .NET 6, see .NET 6 Container Release Notes . Core .NET libraries Title Binary Source compatible compatible API obsoletions with non-default diagnostic IDs ✔️ ❌ Preview 1 Changes to nullable reference type annotations ✔️ ❌ Preview 1-2 Conditional string evaluation in Debug methods ✔️ ❌ RC 1 Environment.ProcessorCount behavior on Windows ✔️ ❌ Preview 2 EventSource callback behavior ✔️ ✔️ Servicing File.Replace on Unix throws exceptions to match Windows ✔️ ❌ Preview 7 FileStream locks files with shared lock on Unix ❌ ✔️ Preview 1 FileStream no longer synchronizes file offset with OS ❌ ❌ Preview 4 FileStream.Position updates after ReadAsync or ❌ ❌ Preview 4 New diagnostic IDs for obsoleted APIs ✔️ ❌ Preview 5 New nullable annotation in AssociatedMetadataTypeTypeDescriptionProvider ✔️ ❌ RC 2 New System.Linq.Queryable method overloads ✔️ ❌ Preview 3-4 Older framework versions dropped from package ❌ ✔️ Preview 5 Parameter names changed ✔️ ❌ Preview 1 Parameter names in Stream-derived types ✔️ ❌ Preview 1 Partial and zero-byte reads in DeflateStream, GZipStream, and CryptoStream ✔️ ❌ Preview 6 Set timestamp on read-only file on Windows ❌ ✔️ Servicing Standard numeric format parsing precision ✔️ ❌ Preview 2 Static abstract members in interfaces ❌ ✔️ Preview 7 StringBuilder.Append overloads and evaluation ❌ ✔️ RC 1 ❌ ✔️ Preview 4 WriteAsync completes order Strong-name APIs throw PlatformNotSupportedException Introduced 6.0.2 Title Binary compatible Source compatible ❌ ❌ Preview 7 System.Security.SecurityContext is marked obsolete ✔️ ❌ RC 1 Task.FromResult may return singleton ❌ ✔️ Preview 1 Unhandled exceptions from a BackgroundService ✔️ ❌ Preview 4 System.Drawing.Common only supported on Windows Introduced Cryptography Title CreateEncryptor methods throw exception for incorrect feedback size Binary compatible Source compatible ❌ ✔️ Introduced Preview 7 Deployment Title Binary compatible Source compatible ✔️ ✔️ x86 host path on 64-bit Windows Introduced Servicing release Entity Framework Core Breaking changes in EF Core 6 Extensions Title Binary Source Introduced compatible compatible AddProvider checks for non-null provider ✔️ ❌ RC 1 FileConfigurationProvider.Load throws InvalidDataException ✔️ ❌ RC 1 Repeated XML elements include index ❌ ✔️ Resolving disposed ServiceProvider throws ✔️ ❌ RC 1 Title Binary Source compatible compatible Introduced exception Globalization Title Binary compatible Source compatible Culture creation and case mapping in globalization-invariant mode Introduced Preview 7 Interop Title Binary compatible Source compatible ❌ ✔️ Static abstract members in interfaces Introduced Preview 7 JIT compiler Title Coerce call arguments according to ECMA-335 Binary compatible Source compatible ✔️ ✔️ Introduced Preview 1 Networking Title Binary compatible Source compatible Port removed from SPN for Kerberos and Negotiate ❌ ✔️ RC 1 WebRequest, WebClient, and ServicePoint are obsolete ✔️ ❌ Preview 1 SDK Introduced Title Binary compatible Source compatible -p option for dotnet run is deprecated ✔️ ❌ Preview 6 C# code in templates not supported by earlier versions ✔️ ✔️ Preview 7 EditorConfig files implicitly included ✔️ ❌ Generate apphost for macOS ✔️ ❌ Preview 6 Generate error for duplicate files in publish output ❌ ✔️ Preview 1 GetTargetFrameworkProperties and GetNearestTargetFramework removed from ProjectReference protocol ❌ ✔️ Preview 1 Install location for x64 emulated on Arm64 ✔️ ❌ RC 2 MSBuild no longer supports calling GetType() Introduced RC 1 OutputType not automatically set to WinExe ✔️ ❌ RC 1 Publish ReadyToRun with --no-restore requires changes ✔️ ❌ 6.0.100 runtimeconfig.dev.json file not generated ❌ ✔️ 6.0.100 RuntimeIdentifier warning if self-contained is ✔️ ❌ RC 1 Tool manifests in root folder ✔️ ✔️ 6.0.4xx, 6.0.3xx, 6.0.1xx Version requirements for .NET 6 SDK ✔️ ✔️ 6.0.300 .version file includes build version ✔️ ✔️ 6.0.401 Write reference assemblies to IntermediateOutputPath ❌ ✔️ 6.0.200 unspecified Serialization Title Binary Source compatible compatible DataContractSerializer retains sign when deserializing -0 ❌ ✔️ Servicing 6.0.11 Default serialization format for TimeSpan ❌ ✔️ Servicing 6.0.2 IAsyncEnumerable serialization ✔️ ❌ Preview 4 JSON source-generation API refactoring ❌ ✔️ RC 2 JsonNumberHandlingAttribute on collection properties ❌ ✔️ RC 1 New JsonSerializer source generator ❌ ✔️ Preview 6 overloads Introduced Windows Forms Title Binary compatible Source compatible C# templates use application bootstrap ✔️ ❌ RC 1 Selected TableLayoutSettings properties throw InvalidEnumArgumentException ❌ ✔️ Preview 1 DataGridView-related APIs now throw ❌ ✔️ Preview 4 ListViewGroupCollection methods throw new InvalidOperationException ❌ ✔️ RC 2 NotifyIcon.Text maximum text length increased ❌ ✔️ Preview 1 ScaleControl called only when needed ✔️ ❌ Servicing 6.0.101 Some APIs throw ArgumentNullException ❌ ✔️ Preview 1-4 TreeNodeCollection.Item throws exception if ❌ ✔️ Preview 1 InvalidOperationException node is assigned elsewhere XML and XSLT Introduced Title XmlDocument.XmlResolver nullability change XNodeReader.GetAttribute behavior for invalid index See also What's new in .NET 6 Binary compatible Source compatible Introduced ❌ ✔️ RC 1 ✔️ ❌ Preview 2 ActionResult<T> sets StatusCode to 200 Article • 05/25/2022 When returning a T in an MVC/API controller action that declares the return type as ActionResult<TValue>, the ObjectResult.StatusCode is always set to 200, except when the T is a ProblemDetails. This change can cause unexpected behavior in some scenarios where you set the status code manually, since previously the ObjectResult.StatusCode was null . Also, an action filter could be affected by this change if it expects a null value instead of 200. Version introduced ASP.NET Core 6.0 Previous behavior Previously, a controller's action that returns T and sets Response.StatusCode manually generated the specified response status code. For example, the following controller's action will generate a 202 Accepted response. C# // Generates a 202 Accepted response public ActionResult<Model> Get() { Response.StatusCode = StatusCodes.Status202Accepted; return new Model(); } New behavior Now, the same controller's action that returns T and sets Response.StatusCode manually always generates a 200 OK response. C# // Generates a 200 OK response public ActionResult<Model> Get() { Response.StatusCode = StatusCodes.Status202Accepted; return new Model(); } Type of breaking change This change can affect source compatibility. Reason for change Returning a status code of 200 OK is documented since ASP.NET Core 3.1. However, it keeps StatusCode as null and eventually generates a 200 OK response only because it's the default. Since the default internal behavior could change, we decided to avoid relying on the default and to explicitly set StatusCode to the expected 200 OK . Recommended action If your code sets the status code manually and is broken by this change, you'll need to change your controller action. For example, the following code snippet sets a status code of 202 and is broken by this change. C# public ActionResult<Model> Get() { Response.StatusCode = StatusCodes.Status202Accepted; return new Model(); } To retain the desired behavior of a 202 status code, the following code snippets show some options. C# public ActionResult<Model> Get() { return Accepted(new Model()); } // or public ActionResult<Model> Get() { return StatusCode(StatusCodes.Status202Accepted, new Model()); } // or public Model Get() { Response.StatusCode = StatusCodes.Status202Accepted; return new Model(); } Affected APIs MVC/API controller actions See also ActionResult<T> type AddDataAnnotationsValidation method made obsolete Article • 09/15/2021 The extension method EditContextDataAnnotationsExtensions.AddDataAnnotationsValidation(EditContext) is marked as obsolete starting in ASP.NET Core 6. Developers should use the new extension method EditContextDataAnnotationsExtensions.EnableDataAnnotationsValidation instead. The only difference between these two APIs is their return value: C# EditContext AddDataAnnotationsValidation(this EditContext editContext) { ... } IDisposable EnableDataAnnotationsValidation(this EditContext editContext) { ... } Version introduced ASP.NET Core 6.0 Old behavior The older API, AddDataAnnotationsValidation(EditContext), returns its EditContext (as a kind of fluent API). New behavior The new API, EnableDataAnnotationsValidation , returns an IDisposable whose disposal can be used to remove the data-annotations validation support from the EditContext . Reason for change There are cases where it's desirable to remove the data-annotations validation support after adding it. This was not possible with the older API because there was no place to store the internal event subscriptions. The new API returns an object that holds the state necessary to remove data-annotations validation support on disposal. Recommended action Most applications don't need to be changed. The direct use of these extension methods is a rare and advanced case. If your app uses the <DataAnnotationsValidator> component instead of calling this method directly, it doesn't need to be changed. However, if you do call editContext.AddDataAnnotationsValidation() , then replace that call with editContext.EnableDataAnnotationsValidation() . Optionally, capture the new returned IDisposable object and dispose it later if you want to undo the effects of the call. Affected APIs Microsoft.AspNetCore.Components.Forms.EditContextDataAnnotationsExtensions. AddDataAnnotationsValidation(EditContext) Assemblies removed from Microsoft.AspNetCore.App shared framework Article • 09/15/2021 The following two assemblies were removed from the ASP.NET Core targeting pack: System.Security.Permissions System.Windows.Extensions In addition, the following assemblies were removed from the ASP.NET Core runtime pack: Microsoft.Win32.SystemEvents System.Drawing.Common System.Security.Permissions System.Windows.Extensions Version introduced ASP.NET Core 6.0 Old behavior Applications could use APIs provided by these libraries by referencing the Microsoft.AspNetCore.App shared framework. New behavior If you use APIs from the affected assemblies without having a PackageReference in your project file, you might see run-time errors. For example, an application that uses reflection to access APIs from one of these assemblies without adding an explicit reference to the package will have run-time errors. The PackageReference ensures that the assemblies are present as part of the application output. For discussion, see https://github.com/dotnet/aspnetcore/issues/31007 . Reason for change This change was introduced to reduce the size of the ASP.NET Core shared framework. Recommended action To continue using these APIs in your project, add a PackageReference. For example: XML <PackageReference Include="System.Security.Permissions" Version="6.0.0" /> Affected APIs System.Security.Permissions System.Media System.Security.Cryptography.X509Certificates.X509Certificate2UI System.Xaml.Permissions.XamlAccessLevel Blazor: Parameter name changed in RequestImageFileAsync method Article • 12/02/2021 The RequestImageFileAsync method's maxWith parameter was renamed from maxWith to maxWidth . Version introduced ASP.NET Core 6.0 Old behavior The parameter name is spelled maxWith . New behavior The parameter name is spelled maxWidth . Reason for change The original parameter name was a typographical error. Recommended action If you're using named parameters in the RequestImageFile API, update the maxWith parameter name to maxWidth . Otherwise, no change is necessary. Affected APIs BrowserFileExtensions.RequestImageFileAsync Blazor: WebEventDescriptor.EventArgsType property replaced Article • 09/15/2021 The WebEventDescriptor class is part of Blazor's internal protocol for communicating events from JavaScript into .NET. This class isn't typically used by app code, but rather by platform authors. Starting in ASP.NET Core 6.0, the EventArgsType property on WebEventDescriptor is being replaced by a new EventName property. This change is unlikely to affect any app code, as it's a low-level platform implementation detail. Version introduced ASP.NET Core 6.0 Old behavior In ASP.NET Core 5.0 and earlier, the property EventArgsType describes a nonstandard, Blazor-specific category name for groups of DOM event types. For example, the click and mousedown events were both mapped to an EventArgsType value of mouse . Similarly, cut , copy , and paste events are mapped to an EventArgsType value of clipboard . These category names are used to determine the .NET type to use for deserializing the incoming event arguments data. New behavior Starting in ASP.NET Core 6.0, the new property EventName only specifies the original event's name. For example, click , mousedown , cut , copy , or paste . There's no longer a need to supply a Blazor-specific category name. For that reason, the old property EventArgsType is removed. Reason for change In pull request dotnet/aspnetcore#29993 , support for custom event arguments classes was introduced. As part of this support, the framework no longer relies on all events fitting into a predefined set of categories. The framework now only needs to know the original event name. Recommended action App code should be unaffected and doesn't need to change. If building a custom Blazor rendering platform, you may need to update the mechanism for dispatching events into the Renderer . Replace any hardcoded rules about event categories with simpler logic that supplies the original, raw event name. Affected APIs WebEventDescriptor.EventArgsType Blazor: Byte-array interop Article • 03/25/2023 Blazor now supports optimized byte-array interop, which avoids encoding and decoding byte-arrays into Base64 and facilitates a more efficient interop process. This applies to both Blazor Server and Blazor WebAssembly. Version introduced ASP.NET Core 6.0 Receive byte array in JavaScript from .NET Old behavior TypeScript function receivesByteArray(data) { // Previously, data was a Base64-encoded string representing the byte array. } New behavior TypeScript function receivesByteArray(data) { // Data is a Uint8Array (no longer requires processing the Base64 encoding). } Reason for change This change was made to create a more efficient interop mechanism for byte arrays. Recommended action Receive byte array in JavaScript from .NET Consider this .NET interop, where you call into JavaScript passing a byte array: C# var bytes = new byte[] { 1, 5, 7 }; await _jsRuntime.InvokeVoidAsync("receivesByteArray", bytes); In the preceding code example, you'd treat the incoming parameter in JavaScript as a byte array instead of a Base64-encoded string. Return byte array from JavaScript to .NET If .NET expects a byte[] , JavaScript should provide a Uint8Array . It's still possible to provide a Base64-encoded array using btoa , however that is less performant. For example, if you have the following code, then you should provide a Uint8Array from JavaScript that's not Base64-encoded: C# var bytes = await _jsRuntime.InvokeAsync<byte[]> ("someJSMethodReturningAByteArray"); ClientCertificate property no longer triggers renegotiation for HttpSys Article • 09/15/2021 The HttpContext.Connection.ClientCertificate property no longer triggers TLS renegotiations for HttpSys. Version introduced ASP.NET Core 6.0 Old behavior Setting HttpSysOptions.ClientCertificateMethod = ClientCertificateMethod.AllowRenegotiation allowed renegotiation to be triggered by both HttpContext.Connection.ClientCertificate and HttpContext.Connection.GetClientCertificateAsync . New behavior Setting HttpSysOptions.ClientCertificateMethod = ClientCertificateMethod.AllowRenegotiation allows renegotiation to be triggered only by HttpContext.Connection.GetClientCertificateAsync . HttpContext.Connection.ClientCertificate returns the current certificate if available, but does not renegotiate with the client to request the certificate. Reason for change When implementing the same features for Kestrel, it became clear that applications need to be able to check the state of the client certificate before triggering a renegotiation. For issues like the request body conflicting with the renegotiation, checking the state enables the following usage pattern to deal with the issue: C# if (connection.ClientCertificate == null) { await BufferRequestBodyAsync(); await connection.GetClientCertificateAsync(); } Recommended action Apps that use delayed client-certificate negotiation should call GetClientCertificateAsync(CancellationToken) to trigger renegotiation. Affected APIs Microsoft.AspNetCore.Server.HttpSys.HttpSysOptions.ClientCertificateMethod Microsoft.AspNetCore.Http.ConnectionInfo.ClientCertificate Microsoft.AspNetCore.Http.ConnectionInfo.GetClientCertificateAsync(CancellationT oken) See also dotnet/aspnetcore issue number 34124 EndpointName metadata not set automatically Article • 10/27/2021 Behavior that was introduced in .NET 6 RC 1 to automatically set IEndpointNameMetadata for endpoints has been reverted. IEndpointNameMetadata is no longer set automatically to avoid issues with duplicate endpoint names. Version introduced ASP.NET Core 6 RC 2 Previous behavior In ASP.NET Core 6 RC 1, IEndpointNameMetadata was automatically set for endpoints that referenced a method group. For example, the following code produced an endpoint for /foo with EndpointName set to GetFoo . C# app.MapGet("/foo", GetFoo); New behavior Starting in ASP.NET Core 6 RC 2, IEndpointNameMetadata is not automatically set. The following code does not generate any IEndpointNameMetadata . C# app.MapGet("/foo", GetFoo); Type of breaking change This change can affect source compatibility. Reason for change The behavior of automatically setting endpoint name metadata was not robust and resulted in issues where the same name was set for different endpoints. For more information, see dotnet/aspnetcore#36487 . Recommended action We recommend that you manually set IEndpointNameMetadata using the WithName extension method to set the metadata. C# app.MapGet("/foo", GetFoo).WithName("GetFoo"); Affected APIs N/A Identity: Default Bootstrap version of UI changed Article • 02/18/2022 Starting in ASP.NET Core 6.0, Identity UI defaults to using version 5 of Bootstrap . ASP.NET Core 3.0 to 5.0 used version 4 of Bootstrap. Version introduced ASP.NET Core 6.0 Behavior AddDefaultIdentity<TUser>(IServiceCollection) calls the internal private method TryResolveUIFramework . TryResolveUIFramework reads the UIFramework from the application assembly. The UIFramework version defaults to: Bootstrap 5 for the .NET 6 SDK Bootstrap 4 for the .NET Core 3.1 and .NET 5 SDK Template-created ASP.NET Core 3.1 and 5.0 apps contain Bootstrap 4 in wwwroot\lib\bootstrap. Template-created ASP.NET Core 6 apps use Bootstrap 5. When an ASP.NET Core 3.1 or 5.0 app is migrated to .NET 6, the application detects UIFramework version 5, while wwwroot\lib\bootstrap contains version 4. This version mismatch renders the Identity templates incorrectly. Reason for change Bootstrap 5 was released during the ASP.NET Core 6.0 timeframe. Recommended action Apps that are impacted by this change use the default Identity UI and have added it in Startup.ConfigureServices as shown in the following code: C# services.AddDefaultIdentity<IdentityUser>() Take one of the following actions: Add the MSBuild property IdentityUIFrameworkVersion in the project file and specify Bootstrap 4: XML <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <IdentityUIFrameworkVersion>Bootstrap4</IdentityUIFrameworkVersion> </PropertyGroup> The preceding markup sets the UIFramework version to Bootstrap 4, the same Bootstrap version as used in ASP.NET Core 3.1 and 5.0. Rename or delete the wwwroot\lib\bootstrap folder and replace it with the wwwroot\lib\bootstrap folder from an ASP.NET Core 6 template-generated app. The Identity templates work with this change but apps using Bootstrap may need to refer to the Bootstrap 5 migration guide . Affected APIs AddDefaultIdentity<TUser>(IServiceCollection) Kestrel: Log message attributes changed Article • 09/15/2021 Kestrel log messages have associated IDs and names. These attributes uniquely identify different kinds of log messages. Some of those IDs and names were incorrectly duplicated. This duplication problem is fixed in ASP.NET Core 6.0. Version introduced ASP.NET Core 6.0 Old behavior The following table shows the state of the affected log messages before ASP.NET Core 6.0. Message description Name ID HTTP/2 connection closed log messages Http2ConnectionClosed 36 HTTP/2 frame sending log messages Http2FrameReceived 37 New behavior The following table shows the state of the affected log messages in ASP.NET Core 6.0. Message description Name ID HTTP/2 connection closed log messages Http2ConnectionClosed 48 HTTP/2 frame sending log messages Http2FrameSending 49 Reason for change Log IDs and names should be unique so different message types can be identified. Recommended action If you have code or configuration that references the old IDs and names, update those references to use the new IDs and names. Changed MessagePack library in @microsoft/signalr-protocol-msgpack Article • 09/15/2021 The @microsoft/signalr-protocol-msgpack npm package now references @msgpack/msgpack instead of msgpack5 . Additionally, the available options that can optionally be passed into the MessagePackHubProtocol have changed. The MessagePackOptions.disableTimestampEncoding and MessagePackOptions.forceFloat64 properties were removed, and some new options were added. For discussion, see https://github.com/dotnet/aspnetcore/issues/30471 . Version introduced ASP.NET Core 6.0 Old behavior In previous versions, you must include three script references to use the MessagePack Hub Protocol in the browser: HTML <script src="~/lib/signalr/signalr.js"></script> <script src="~/lib/msgpack5/msgpack5.js"></script> <script src="~/lib/signalr/signalr-protocol-msgpack.js"></script> New behavior Starting in ASP.NET Core 6, you only need two script references to use the MessagePack Hub Protocol in the browser: HTML <script src="~/lib/signalr/signalr.js"></script> <script src="~/lib/signalr/signalr-protocol-msgpack.js"></script> Instead of the msgpack5 package, the @msgpack/msgpack package is downloaded to your node_modules directory if you want to use it directly in your app. Finally, MessagePackOptions has new, additional properties, and the disableTimestampEncoding and forceFloat64 properties are removed. Reason for change This change was made to reduce asset size, make it simpler to consume the package, and add more customizability. Recommended action If you were previously using msgpack5 in your app, you'll need to add a direct reference to the library in your package.json file. Affected APIs The following APIs were removed: MessagePackOptions.disableTimestampEncoding MessagePackOptions.forceFloat64 Microsoft.AspNetCore.Http.Features split Article • 12/02/2021 Microsoft.AspNetCore.Http.Features has been split into the following two assemblies: Microsoft.AspNetCore.Http.Features Microsoft.Extensions.Features For discussion, see GitHub issue dotnet/aspnetcore#32307 . Version introduced ASP.NET Core 6.0 Old behavior Microsoft.AspNetCore.Http.Features 5.0 shipped both in the ASP.NET shared framework and as a NuGet package. Microsoft.AspNetCore.Http.Features 5.0 targeted .NET 4.6.1, .NET Standard 2.0, and .NET 5. New behavior Microsoft.AspNetCore.Http.Features 6.0 ships only in the ASP.NET shared framework, not as a NuGet package. It targets .NET 6 only. Microsoft.Extensions.Features 6.0 ships in both the ASP.NET shared framework and as a NuGet package. It targets .NET 4.6.1, .NET Standard 2.0, and .NET 6. The following types have been moved to the new Microsoft.Extensions.Features assembly: IFeatureCollection FeatureCollection FeatureReference<T> FeatureReferences<TCache> These types are still in the Microsoft.AspNetCore.Http.Features namespace, and type forwards have been added for compatibility. Reason for change This change was introduced for two reasons: Allows the core types to be shared more broadly across components. Allows the remaining Http-specific components in Microsoft.AspNetCore.Http.Features to take advantage of new runtime and language features. Recommended action When upgrading to ASP.NET Core 6.0, remove any packages references for Microsoft.AspNetCore.Http.Features. Add a package reference for Microsoft.Extensions.Features only if required. For class libraries that need to consume the types from Microsoft.AspNetCore.Http.Features, add a FrameworkReference instead: XML <ItemGroup> <FrameworkReference Include="Microsoft.AspNetCore.App" /> </ItemGroup> For more information about adding the framework reference, see Use the ASP.NET Core shared framework. Libraries with out of date references may encounter a TypeLoadException or the following error: Error CS0433 The type 'IFeatureCollection' exists in both 'Microsoft.AspNetCore.Http.Features, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' and 'Microsoft.Extensions.Features, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' To resolve the error, add a FrameworkReference to Microsoft.AspNetCore.App to any of the affected projects. For questions, see dotnet/aspnetcore#32307 . Affected APIs Microsoft.AspNetCore.Http.Features.IFeatureCollection Microsoft.AspNetCore.Http.Features.FeatureCollection Microsoft.AspNetCore.Http.Features.FeatureReference<T> Microsoft.AspNetCore.Http.Features.FeatureReferences<TCache> Middleware: HTTPS Redirection Middleware throws exception on ambiguous HTTPS ports Article • 09/15/2021 In ASP.NET Core 6.0, the HTTPS Redirection Middleware throws an exception of type InvalidOperationException when it finds multiple HTTPS ports in the server configuration. The exception's message contains the text "Cannot determine the https port from IServerAddressesFeature, multiple values were found. Set the desired port explicitly on HttpsRedirectionOptions.HttpsPort." For discussion, see GitHub issue dotnet/aspnetcore#29222 . Version introduced ASP.NET Core 6.0 Old behavior When the HTTPS Redirection Middleware isn't explicitly configured with a port, it searches IServerAddressesFeature during the first request to determine the HTTPS port to which it should redirect. If there are no HTTPS ports or multiple distinct ports, it's unclear which port should be used. The middleware logs a warning and disables itself. HTTP requests are processed normally. New behavior When the HTTPS Redirection Middleware isn't explicitly configured with a port, it searches IServerAddressesFeature during the first request to determine the HTTPS port to which it should redirect. If there are no HTTPS ports, the middleware still logs a warning and disables itself. HTTP requests are processed normally. This behavior supports: Development scenarios without HTTPS. Hosted scenarios in which TLS is terminated before reaching the server. If there are multiple distinct ports, it's unclear which port should be used. The middleware throws an exception and fails the HTTP request. Reason for change This change prevents potentially sensitive data from being served over unencrypted HTTP connections when HTTPS is known to be available. Recommended action To enable HTTPS redirection when the server has multiple distinct HTTPS ports, you must specify one port in the configuration. For more information, see Port configuration. If you don't need the HTTPS Redirection Middleware in your app, remove UseHttpsRedirection from Startup.cs. If you need to select the correct HTTPS port dynamically, provide feedback in GitHub issue dotnet/aspnetcore#21291 . Affected APIs HttpsPolicyBuilderExtensions.UseHttpsRedirection Middleware: New Use overload Article • 12/02/2021 A new overload of app.Use has been introduced. If you call app.Use but never call the next middleware, you'll now get compiler error CS0121: The call is ambiguous between the following methods or properties: 'UseExtensions.Use(IApplicationBuilder, Func<HttpContext, Func, Task>)' and 'UseExtensions.Use(IApplicationBuilder, Func<HttpContext, RequestDelegate, Task>)' To resolve the error, use app.Run instead of app.Use . For discussion, see GitHub issue dotnet/aspnetcore#32020 Version introduced ASP.NET Core 6.0 Old behavior C# app.Use(async (context, next) => { await next(); }); or C# app.Use(async (context, next) => { await SomeAsyncWork(); // next not called... }); New behavior You can now pass context to the next delegate: . C# app.Use(async (context, next) => { await next(context); }); Use app.Run when your middleware never calls next : C# app.Run(async (context) => { await SomeAsyncWork(); // next never called }); Reason for change The previous Use method allocates two objects per request. The new overload avoids these allocations with a small change to how you invoke the next middleware. Recommended action If you get a compile error, it means you are calling app.Use without using the next delegate. Switch to app.Run to fix the error. Affected APIs None. Minimal API renames in RC 1 Article • 06/07/2022 Some APIs were renamed to improve the consistency of type names and to remove "minimal" and "action" from the API names. Version introduced ASP.NET Core 6.0 RC 1 Old and new behavior The Microsoft.AspNetCore.Builder.MinimalActionEndpointConventionBuilder class was renamed to Microsoft.AspNetCore.Builder.DelegateEndpointConventionBuilder . 7 Note This class was renamed again in RC 2 to Microsoft.AspNetCore.Builder.RouteHandlerBuilder. The Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions class was renamed to Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions . 7 Note This class was merged with Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions in RC 2. The RequestDelegate parameter to Map , MapGet , MapPost , MapPut , MapDelete , MapMethod , MapFallback , and RequestDelegateFactory.Create(Delegate, RequestDelegateFactoryOptions) was renamed from action to handler . Change category This change affects binary compatibility and source compatibility. Reason for change This change was made to improve the consistency of type names and to remove "minimal" and "action" from the API names. Recommended action Recompile any projects built with an earlier SDK. For most projects, this should be all that's necessary. If your code references any of these type or parameter names directly by name, updated the code to reflect the new names. Affected APIs Microsoft.AspNetCore.Builder.MinimalActionEndpointConventionBuilder Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.Map( ) Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapG et() Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapP ost() Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapP ut() Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapDe lete() Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapMe thod() Microsoft.AspNetCore.Builder.MinimalActionEndpointRouteBuilderExtensions.MapFa llback() Microsoft.AspNetCore.Http.RequestDelegateFactory.Create(Delegate action, RequestDelegateFactoryOptions? options = null) Minimal API renames in RC 2 Article • 10/27/2021 To improve the consistency of type names, two classes were renamed, and one class was removed and its methods merged into the existing EndpointRouteBuilderExtensions class. Version introduced ASP.NET Core 6.0 RC 2 Old and new behavior The Microsoft.AspNetCore.Builder.DelegateEndpointConventionBuilder class was renamed to Microsoft.AspNetCore.Builder.RouteHandlerBuilder. The Microsoft.AspNetCore.Http.OpenApiDelegateEndpointConventionBuilderExtensions class was renamed to Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions. The Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions class was removed and all of its methods were merged into the existing Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions class. Change category This change affects binary compatibility and source compatibility. Reason for change This change was made to improve the consistency of type names. Now that there is a new RouteHandlerOptions class, we wanted to replace DelegateEndpoint with RouteHandler . Recommended action Recompile any projects built with an earlier SDK. For most projects, this should be all that's necessary. If your code references any of these type names directly by name, updated the code to reflect the new names. Affected APIs Microsoft.AspNetCore.Builder.DelegateEndpointConventionBuilder Microsoft.AspNetCore.Http.OpenApiDelegateEndpointConventionBuilderExtensions Microsoft.AspNetCore.Builder.DelegateEndpointRouteBuilderExtensions MVC doesn't buffer IAsyncEnumerable types when using System.Text.Json Article • 12/02/2021 In ASP.NET Core 5, MVC added support for output formatting IAsyncEnumerable<T> types by buffering the sequence in memory and formatting the buffered collection. In ASP.NET Core 6, when formatting using System.Text.Json, MVC no longer buffers IAsyncEnumerable<T> instances. Instead, MVC relies on the support that System.Text.Json added for these types. In most cases, the absence of buffering would not be observable by the application. However, some scenarios may have inadvertently relied on the buffering semantics to correctly serialize. For example, returning an IAsyncEnumerable<T> that's backed by an Entity Framework query on a type with lazy-loaded properties can result in concurrent query execution, which might not be supported by the provider. This change does not affect output formatting using Newtonsoft.Json or with XMLbased formatters. Version introduced ASP.NET Core 6.0 Old behavior IAsyncEnumerable<T> instances returned from an MVC action as a value to be formatted using ObjectResult or a JsonResult are buffered before being serialized as a synchronous collection. New behavior When formatting using System.Text.Json, MVC no longer buffers IAsyncEnumerable<T> instances. Reason for change System.Text.Json added support for streaming IAsyncEnumerable<T> types. This allows for a smaller memory footprint during serialization. Recommended action If your application requires buffering, consider manually buffering the IAsyncEnumerable<T> object: C# // Before public IActionResult Get() { return Ok(dbContext.Blogs); } // After public async Task<IActionResult> Get() { return Ok(await dbContext.Blogs.ToListAsync()); } Nullable reference type annotations changed Article • 09/15/2021 This issue represents a work-in-progress. All breaking changes to nullability annotations will be aggregated into this issue throughout the course of ASP.NET Core 6.0. Starting in ASP.NET Core 5.0, nullability annotations have been applied to parts of the code. From the outset of this effort, mistakes were expected in these annotations and fixes would need to be made. In ASP.NET Core 6.0, some previously applied annotations are being updated. Some of these changes are considered source breaking changes. The changes lead to the APIs being incompatible or more restrictive. The updated APIs may result in build-time warnings when used in projects that have nullable reference types enabled. For discussion, see GitHub issue dotnet/aspnetcore#27564 . Version introduced ASP.NET Core 6.0 Old behavior The affected APIs have incorrect nullable reference type annotations. Build warnings are either absent or incorrect. New behavior New build warnings are produced. Incorrect build warnings are no longer produced for the affected APIs. Reason for change Through feedback and further testing, the nullable annotations for the affected APIs were determined to be inaccurate. The updated annotations now correctly represent the nullability contracts for the APIs. Recommended action Update code calling these APIs to reflect the revised nullability contracts. Affected APIs ParameterView.FromDictionary Renderer.DispatchEventAsync RenderTreeEdit.RemovedAttributeName AuthenticationSchemeOptions.ForwardDefaultSelector RangeConditionHeaderValue.RangeConditionHeaderValue IConnectionListener.AcceptAsync IApplicationDiscriminator.Discriminator DataProtectionOptions.ApplicationDiscriminator AuthenticatedEncryptorFactory.CreateEncryptorInstance CngCbcAuthenticatedEncryptorFactory.CreateEncryptorInstance CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance IAuthenticatedEncryptorFactory.CreateEncryptorInstance ManagedAuthenticatedEncryptorFactory.CreateEncryptorInstance IKey.CreateEncryptor KeyManagementOptions.AuthenticatedEncryptorConfiguration KeyManagementOptions.XmlEncryptor KeyManagementOptions.XmlRepository ICertificateResolver.ResolveCertificate DataProtectionUtilityExtensions.GetApplicationUniqueIdentifier FileSystemXmlRepository.DefaultKeyStorageDirectory RegistryXmlRepository.DefaultRegistryKey CertificateResolver.ResolveCertificate Endpoint.Endpoint Endpoint.RequestDelegate RouteValueDictionary.TryAdd LinkGenerator.GetUriByAddress IFeatureCollection.Set FeatureCollection.Set IFeatureCollection.Get ITicketStore.RetrieveAsync IFeatureCollection.Get<TFeature>() IFeatureCollection.Set<TFeature>(TFeature) FeatureCollection.Set<TFeature>(TFeature) ModelStateDictionary.SetModelValue(String, Object, String) ModelStateDictionary.Item[String] ClientValidatorItem.ClientValidatorItem ClientValidatorItem.Validator Endpoint.Endpoint RouteValueDictionary.TryAdd(String, Object)> LinkGenerator.GetUriByAddress<TAddress>(TAddress, RouteValueDictionary, String, HostString, PathString, FragmentString, LinkOptions) IApplicationDiscriminator.Discriminator DataProtectionOptions.ApplicationDiscriminator AuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey) CngCbcAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey) CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey) IAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey) ManagedAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey) IKey.CreateEncryptor() KeyManagementOptions.AuthenticatedEncryptorConfiguration KeyManagementOptions.XmlEncryptor KeyManagementOptions.XmlRepository ICertificateResolver.ResolveCertificate(String) DataProtectionUtilityExtensions.GetApplicationUniqueIdentifier(IServiceProvider) FileSystemXmlRepository.DefaultKeyStorageDirectory RegistryXmlRepository.DefaultRegistryKey CertificateResolver.ResolveCertificate(String) IConnectionListener.AcceptAsync(CancellationToken) AuthenticationSchemeOptions.ForwardDefaultSelector RangeConditionHeaderValue.RangeConditionHeaderValue(EntityTagHeaderValue) IHttpContextFeature.HttpContext CompletionMessage.WithError CompletionMessage.WithResult HubMethodInvocationMessage.Arguments HubMethodInvocationMessage.HubMethodInvocationMessage(String, String, Object[]) HubMethodInvocationMessage.HubMethodInvocationMessage(String, String, Object[], String[]) InvocationMessage.InvocationMessage(String, Object[]) InvocationMessage.InvocationMessage(String, String, Object[]) InvocationMessage.InvocationMessage(String, String, Object[], String[]) StreamInvocationMessage.StreamInvocationMessage(String, String, Object[]) StreamInvocationMessage.StreamInvocationMessage(String, String, Object[], String[]) IHubProtocol.TryParseMessage(ReadOnlySequence<Byte>, IInvocationBinder, HubMessage) DefaultHubLifetimeManager<THub>.SendAllAsync(String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendAllExceptAsync(String, Object[], IReadOnlyList<String>, CancellationToken) DefaultHubLifetimeManager<THub>.SendConnectionAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendConnectionsAsync(IReadOnlyList<String >, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupExceptAsync(String, String, Object[], IReadOnlyList<String>, CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupsAsync(IReadOnlyList<String>, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendUserAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendUsersAsync(IReadOnlyList<String>, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendAllAsync(String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendAllExceptAsync(String, Object[], IReadOnlyList<String>, CancellationToken) DefaultHubLifetimeManager<THub>.SendConnectionAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendConnectionsAsync(IReadOnlyList<String >, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupExceptAsync(String, String, Object[], IReadOnlyList<String>, CancellationToken) DefaultHubLifetimeManager<THub>.SendGroupsAsync(IReadOnlyList<String>, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendUserAsync(String, String, Object[], CancellationToken) DefaultHubLifetimeManager<THub>.SendUsersAsync(IReadOnlyList<String>, String, Object[], CancellationToken) IClientProxy.SendCoreAsync HubConnectionContext.User QueryHelpers.ParseNullableQuery(String) QueryHelpers.ParseQuery(String) See also Nullable reference type annotation changes in core .NET libraries Obsoleted and removed APIs Article • 12/10/2022 Several APIs have been either removed or marked as obsolete. Version introduced ASP.NET Core 6.0 Old behavior In ASP.NET Core 5.0 and previous versions, the APIs weren't removed or obsolete. New behavior The APIs are removed or obsoleted. Reason for change The APIs are either no longer used or don't function anymore. Recommended action Use the recommended replacement APIs. Affected APIs Removed Microsoft.AspNetCore.Http.Connections.NegotiateProtocol.ParseResponse. Use NegotiateProtocol.ParseResponse(ReadOnlySpan<Byte>) instead. Removed Microsoft.AspNetCore.SignalR.HubInvocationContext. Use HubInvocationContext.HubInvocationContext(HubCallerContext, IServiceProvider, Hub, MethodInfo, IReadOnlyList<Object>) instead. Removed Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature. Use Microsoft.AspNetCore.Http.Features.IHttpResponseBodyFeature instead. Removed Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature. Use Microsoft.AspNetCore.Http.Features.IHttpResponseBodyFeature instead. Removed argument-less constructor of Microsoft.AspNetCore.StaticFiles.StaticFileResponseContext. Use StaticFileResponseContext.StaticFileResponseContext(HttpContext, IFileInfo) instead. Removed the constructor Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor. Use ObjectResultExecutor.ObjectResultExecutor(OutputFormatterSelector, IHttpResponseStreamWriterFactory, ILoggerFactory, IOptions<MvcOptions>) instead. Removed Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor.AllowShortCir cuitingValidationWhenNoValidatorsArePresent. Removed Microsoft.AspNetCore.Mvc.ViewFeatures.ViewComponentResultExecutor. Use ViewComponentResultExecutor.ViewComponentResultExecutor(IOptions<MvcView Options>, ILoggerFactory, HtmlEncoder, IModelMetadataProvider, ITempDataDictionaryFactory, IHttpResponseStreamWriterFactory) instead. Obsoleted CompatibilityVersion PreserveCompilationContext not configured by default Article • 09/15/2021 PreserveCompilationContext is an MSBuild property that causes .NET Core projects to emit additional content to the application's dependency (.deps) file about how the app was compiled. This is primarily used to support run-time compilation scenarios. Prior to .NET 6, PreserveCompilationContext was set to true for all apps that target the Razor (Microsoft.NET.Sdk.Razor) and Web (Microsoft.NET.Sdk.Web) SDKs. Starting in .NET 6, this property is no longer configured by default. However, packages such as Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation configure this property as required. Version introduced ASP.NET Core 6.0 Old behavior The dependency file contains compilation context. New behavior The dependency file no longer contains compilation context. Reason for change This change improves build performance and startup time, and reduces the size of ASP.NET Core's build output. Recommended action If your app requires this feature and does not reference a package that configures the property, add the PreserveCompilationContext property to your project file. XML <PropertyGroup> <PreserveCompilationContext>true</PreserveCompilationContext> </PropertyGroup> Affected APIs None. Razor: Compiler no longer produces a Views assembly Article • 09/08/2022 The Razor compiler no longer produces a separate Views.dll file that contains the CSHTML views defined in an application. Version introduced ASP.NET Core 6.0 Old behavior In previous versions, the Razor compiler utilizes a two-step compilation process that produces two files: A main AppName.dll assembly that contains application types. An AppName.Views.dll assembly that contains the generated views that are defined in the app. Generated view types are public and under the AspNetCore namespace. New behavior Both views and application types are included in a single AppName.dll assembly. View types have the accessibility modifiers internal and sealed and are included under the AspNetCoreGeneratedDocument namespace. Reason for change Removing the two-step compilation process: Improves build performance for applications that use Razor views. Allows Razor views to participate in the "hot reload" experience for Visual Studio. Recommended action None. Affected APIs None. Razor: Logging ID changes Article • 09/15/2021 Razor Pages log messages have associated IDs and names. These are used to uniquely identify different kinds of log messages. Some of those IDs were incorrectly duplicated. This .NET 6 change corrects the duplication. Version introduced ASP.NET Core 6.0 RC1 Old and new behavior Event name Previous event ID New event ID ExecutedHandlerMethod 102 108 ExecutingImplicitHandlerMethod 103 107 ExecutedImplicitHandlerMethod 104 109 NotMostEffectiveFilter 1 4 Change category This change affects binary compatibility. Reason for change Log IDs should be unique so different message types can be identified. Recommended action If you have code or configuration that references the old IDs, update those references to use the new IDs. Affected APIs N/A. Razor: RazorEngine APIs marked obsolete Article • 07/15/2022 Types related to the Microsoft.AspNetCore.Razor.Language.RazorEngine type in Blazor have been marked as obsolete. Version introduced ASP.NET Core 6.0 Old behavior The RazorEngine APIs weren't obsolete. New behavior The RazorEngine APIs are obsolete. Reason for change The RazorEngine type has been deprecated as compatibility can't be guaranteed. Recommended action Don't use RazorEngine APIs in your code. Affected APIs Microsoft.AspNetCore.Mvc.Razor.Extensions.InjectDirective.Register Microsoft.AspNetCore.Mvc.Razor.Extensions.ModelDirective.Register Microsoft.AspNetCore.Mvc.Razor.Extensions.PageDirective.Register Microsoft.AspNetCore.Razor.Language.Extensions.FunctionsDirective.Register Microsoft.AspNetCore.Razor.Language.Extensions.InheritsDirective.Register Microsoft.AspNetCore.Razor.Language.Extensions.SectionDirective.Register Microsoft.AspNetCore.Razor.Language.IRazorEngineBuilder SignalR: Java Client updated to RxJava3 Article • 12/02/2021 The SignalR Java Client is now RxJava3. Version introduced ASP.NET Core 6.0 Old behavior The RxJava package reference in the library was RxJava2. New behavior The RxJava package reference in the library is now RxJava3. For information about what changed in RxJava, see What's different in 3.0 . Reason for change The previous dependency (RxJava2) is no longer maintained. Support for RxJava2 ended in February 2021. Recommended action If you were using RxJava2 in your app or library, you might need to update to RxJava3. For more information, see What's different in 3.0 . Affected APIs None. TryParse and BindAsync methods are validated Article • 09/23/2021 ASP.NET Core now validates TryParse and BindAsync methods on parameter types for Map* methods. If no valid method is found, ASP.NET Core looks for invalid methods and throws an exception at startup if one is found. The exception helps to avoid unexpected behavior by alerting you that your method signature may be incorrect. Version introduced ASP.NET Core 6.0 RC 2 Previous behavior In previous versions of ASP.NET Core 6, if a TryParse or BindAsync method has an invalid signature, no exception was thrown, and the framework tried to bind JSON from the body. C# // Todo.TryParse is not in a valid format. // Will try to bind from body as JSON instead. app.MapPost("/endpoint", (Todo todo) => todo.Item); public class Todo { public string Item { get; set; } public static bool TryParse(string value) => true; } New behavior If ASP.NET Core finds a public TryParse or BindAsync method that doesn't match the expected syntax, an exception is thrown on startup. The previous example produces an error similar to: txt TryParse method found on Todo with incorrect format. Must be a static method with format bool TryParse(string, IFormatProvider, out Todo) bool TryParse(string, out Todo) but found Boolean TryParse(System.String) Type of breaking change This change can affect binary compatibility and source compatibility. Reason for change This change was made so that developers are made aware of BindAsync and TryParse methods that have an invalid format. Previously, the framework would fall back to assuming the parameter is JSON from the body. This assumption can result in unexpected behavior. Recommended action If your type has a BindAsync or TryParse method with different syntax for a reason other than parameter binding, you'll now encounter an exception at startup. To avoid this behavior, there are multiple strategies available: Change your BindAsync or TryParse method to be internal or private . Add a new BindAsync or TryParse method that has the syntax the framework looks for—invalid methods are ignored if a valid one is found. Mark your parameter as [FromBody] . Affected APIs RequestDelegateFactory.Create() All IEndpointRouteBuilder.Map*() methods, for example, app.MapGet() and app.MapPost() Default console logger formatting in container images Article • 06/24/2022 The default console formatter that's configured in aspnet containers has changed. Previous behavior In previous servicing releases of .NET 6, aspnet container images were configured with the Logging__Console__FormatterName environment variable set to Json . This resulted in console output formatted similarly to the following: txt {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Now listening on: http://localhost:7000/","State": {"Message":"Now listening on: http://localhost:7000/","address":"http://localhost:7000/"," {OriginalFormat}":"Now listening on: {address}"}} {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Now listening on: http://localhost:7001/","State": {"Message":"Now listening on: http://localhost:7001/","address":"http://localhost:7001/"," {OriginalFormat}":"Now listening on: {address}"}} {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Now listening on: http://localhost:7002/","State": {"Message":"Now listening on: http://localhost:7002/","address":"http://localhost:7002/"," {OriginalFormat}":"Now listening on: {address}"}} {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Application started. Press Ctrl\u002BC to shut down.","State": {"Message":"Application started. Press Ctrl\u002BC to shut down."," {OriginalFormat}":"Application started. Press Ctrl\u002BC to shut down."}} {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Hosting environment: Development","State":{"Message":"Hosting environment: Development","envName":"Development"," {OriginalFormat}":"Hosting environment: {envName}"}} {"EventId":0,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime ","Message":"Content root path: C:\\source\\temp\\web50","State": {"Message":"Content root path: C:\\source\\temp\\web50","contentRoot":"C:\\source\\temp\\web50"," {OriginalFormat}":"Content root path: {contentRoot}"}} New behavior Starting in .NET 6.0.5, aspnet container images have the Logging__Console__FormatterName environment variable unset by default. This results in simple, multiline, human-readable console output similar to the following: txt warn: Microsoft.AspNetCore.Server.HttpSys.MessagePump[37] Overriding address(es) ''. Binding to endpoints added to UrlPrefixes instead. info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:7000/ info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:7001/ info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:7002/ info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: C:\source\temp\web50 Version introduced .NET 6.0.5 (May 2022 servicing) Type of breaking change This change can affect source compatibility. Reason for change When the change to use JSON formatting was introduced in the .NET 6 GA release, it broke many scenarios that relied on the original, simple formatting as described in dotnet/dotnet-docker#2725 . Recommended action If you want to continue using the JSON formatting, you can configure your container to use it by setting the Logging__Console__FormatterName environment variable value to Json . Affected APIs None. See also dotnet/dotnet-docker#3706 API obsoletions with non-default diagnostic IDs (.NET 6) Article • 06/07/2022 Some APIs have been marked as obsolete, starting in .NET 6. This breaking change is specific to APIs that have been marked as obsolete with a custom diagnostic ID. Suppressing the default obsoletion diagnostic ID, which is CS0618 for the C# compiler, does not suppress the warnings that the compiler generates when these APIs are used. Change description In previous .NET versions, these APIs can be used without any build warning. In .NET 6 and later versions, use of these APIs produces a compile-time warning or error with a custom diagnostic ID. The use of custom diagnostic IDs allows you to suppress the obsoletion warnings individually instead of blanket-suppressing all obsoletion warnings. The following table lists the custom diagnostic IDs and their corresponding warning messages for obsoleted APIs. Diagnostic ID Description Severity SYSLIB0013 Uri.EscapeUriString(String) can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString(String) for query string components instead. Warning SYSLIB0014 WebRequest, HttpWebRequest, ServicePoint, and WebClient are Warning obsolete. Use HttpClient instead. SYSLIB0015 DisablePrivateReflectionAttribute has no effect in .NET 6+. Warning SYSLIB0016 Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations. Warning SYSLIB0017 Strong-name signing is not supported and throws PlatformNotSupportedException. Warning SYSLIB0018 Reflection-only loading is not supported and throws PlatformNotSupportedException. Warning SYSLIB0019 The System.Runtime.InteropServices.RuntimeEnvironment members SystemConfigurationFile, GetRuntimeInterfaceAsIntPtr(Guid, Guid), and GetRuntimeInterfaceAsObject(Guid, Guid) are no longer supported and Warning throw PlatformNotSupportedException. Diagnostic ID Description Severity SYSLIB0020 JsonSerializerOptions.IgnoreNullValues is obsolete. To ignore null values when serializing, set DefaultIgnoreCondition to Warning JsonIgnoreCondition.WhenWritingNull. SYSLIB0021 Derived cryptographic types are obsolete. Use the Create method on Warning the base type instead. SYSLIB0022 The Rijndael and RijndaelManaged types are obsolete. Use Aes instead. Warning SYSLIB0023 RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead. Warning SYSLIB0024 Creating and unloading AppDomains is not supported and throws an Warning exception. SYSLIB0025 SuppressIldasmAttribute has no effect in .NET 6+. Warning SYSLIB0026 X509Certificate and X509Certificate2 are immutable. Use the appropriate constructor to create a new certificate. Warning SYSLIB0027 PublicKey.Key is obsolete. Use the appropriate method to get the public key, such as GetRSAPublicKey(). Warning SYSLIB0028 X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as Warning RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2), or use the X509Certificate2.CopyWithPrivateKey(ECDiffieHellman) method to create a new instance with a private key. SYSLIB0029 ProduceLegacyHmacValues is obsolete. Producing legacy HMAC values is Warning no longer supported. SYSLIB0030 HMACSHA1 always uses the algorithm implementation provided by the Warning platform. Use a constructor without the useManagedSha1 parameter. SYSLIB0031 CryptoConfig.EncodeOID(String) is obsolete. Use the ASN.1 functionality Warning provided in System.Formats.Asn1. SYSLIB0032 Recovery from corrupted process state exceptions is not supported; Warning HandleProcessCorruptedStateExceptionsAttribute is ignored. SYSLIB0033 Rfc2898DeriveBytes.CryptDeriveKey(String, String, Int32, Byte[]) is Warning obsolete and is not supported. Use PasswordDeriveBytes.CryptDeriveKey(String, String, Int32, Byte[]) instead. SYSLIB0034 CmsSigner(CspParameters) is obsolete. Use an alternative constructor instead. Warning Diagnostic Description Severity SignerInfo.ComputeCounterSignature() is obsolete. Use the overload Warning ID SYSLIB0035 that accepts a CmsSigner instead. Version introduced .NET 6 Recommended action Follow the specific guidance provided for the each diagnostic ID using the URL link provided on the warning. Warnings or errors for these obsoletions can't be suppressed using the standard diagnostic ID for obsolete types or members; use the custom SYSLIBxxxx diagnostic ID value instead. Affected APIs SYSLIB0013 System.Uri.EscapeUriString(String) SYSLIB0014 System.Net.WebRequest System.Net.HttpWebRequest System.Net.ServicePoint System.Net.WebClient SYSLIB0015 System.Runtime.CompilerServices.DisablePrivateReflectionAttribute SYSLIB0016 System.Drawing.Graphics.GetContextInfo() SYSLIB0017 System.Reflection.AssemblyName.KeyPair System.Reflection.StrongNameKeyPair SYSLIB0018 System.Reflection.Assembly.ReflectionOnlyLoad System.Reflection.Assembly.ReflectionOnlyLoadFrom(String) System.Type.ReflectionOnlyGetType(String, Boolean, Boolean) SYSLIB0019 System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeInterfaceAsIntPtr( Guid, Guid) System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeInterfaceAsObjec t(Guid, Guid) SYSLIB0020 System.Text.Json.JsonSerializerOptions.IgnoreNullValues SYSLIB0021 System.Security.Cryptography.AesCryptoServiceProvider System.Security.Cryptography.AesManaged System.Security.Cryptography.DESCryptoServiceProvider System.Security.Cryptography.MD5CryptoServiceProvider System.Security.Cryptography.RC2CryptoServiceProvider System.Security.Cryptography.SHA1CryptoServiceProvider System.Security.Cryptography.SHA1Managed System.Security.Cryptography.SHA256Managed System.Security.Cryptography.SHA256CryptoServiceProvider System.Security.Cryptography.SHA384Managed System.Security.Cryptography.SHA384CryptoServiceProvider System.Security.Cryptography.SHA512Managed System.Security.Cryptography.SHA512CryptoServiceProvider System.Security.Cryptography.TripleDESCryptoServiceProvider SYSLIB0022 System.Security.Cryptography.Rijndael System.Security.Cryptography.RijndaelManaged SYSLIB0023 RNGCryptoServiceProvider SYSLIB0024 System.AppDomain.CreateDomain(String) System.AppDomain.Unload(AppDomain) SYSLIB0025 System.Runtime.CompilerServices.SuppressIldasmAttribute SYSLIB0026 X509Certificate() X509Certificate.Import X509Certificate2() X509Certificate2.Import SYSLIB0027 PublicKey.Key SYSLIB0028 X509Certificate2.PrivateKey SYSLIB0029 HMACSHA384.ProduceLegacyHmacValues HMACSHA512.ProduceLegacyHmacValues SYSLIB0030 HMACSHA1(Byte[], Boolean) SYSLIB0031 CryptoConfig.EncodeOID(String) SYSLIB0032 System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribut e SYSLIB0033 Rfc2898DeriveBytes.CryptDeriveKey(String, String, Int32, Byte[]) SYSLIB0034 CmsSigner(CspParameters) SYSLIB0035 ComputeCounterSignature() See also API obsoletions with non-default diagnostic IDs (.NET 7) API obsoletions with non-default diagnostic IDs (.NET 5) Obsolete features in .NET 5+ Conditional string evaluation in Debug methods Article • 10/27/2021 It's common to use interpolated strings as assert messages, for example: C# Debug.Assert(result != x, $"Unexpected result {result}"); However, in previous versions, this causes a string to be created for the message, including formatting result, on every call, even if the condition is true . And the typical use for asserts is that they're about a condition that should always be true. C# 10 adds support for better string interpolation , including the ability to target custom "handlers" in addition to strings. In .NET 6, the Debug class has new overloads of Assert, WriteIf, and WriteLineIf that utilize this functionality to conditionally evaluate the interpolated string formatting items only if the message is required. The C# compiler will prefer these new overloads. If the formatting items were mutating state and the program was relying on those mutations to be visible even if the assert didn't fire, you could observe a difference in behavior. Previous behavior In the following code, r.ToString() would always be invoked. C# Debug.Assert(true, $"{r.ToString()}"); New behavior In the following code, r.ToString() will never be invoked, because the message is only needed if the condition is false . C# Debug.Assert(true, $"{r.ToString()}"); Version introduced 6.0 RC 1 Type of breaking change This change can affect source compatibility. Reason for change This change was introduced to improve performance. Recommended action Interpolated strings used with Debug methods should not mutate shared state. (These methods are also conditional on the DEBUG compilation constant.) If, for some reason, it's critical to maintain the old behavior, add a (string) cast before the interpolated string. This cast forces the compiler to bind to the existing overload and ensures that the string is always materialized. Affected APIs System.Diagnostics.Debug.Assert(Boolean, String) System.Diagnostics.Debug.Assert(Boolean, String, String) System.Diagnostics.Debug.Assert(Boolean, String, String, Object[]) System.Diagnostics.Debug.WriteIf(Boolean, String) System.Diagnostics.Debug.WriteIf(Boolean, String, String) System.Diagnostics.Debug.WriteIf(Boolean, Object, String) System.Diagnostics.Debug.WriteLineIf(Boolean, String) System.Diagnostics.Debug.WriteLineIf(Boolean, String, String) System.Diagnostics.Debug.WriteLineIf(Boolean, Object, String) Environment.ProcessorCount behavior on Windows Article • 09/15/2021 On Windows, the Environment.ProcessorCount property now respects process affinity and the job object's hard limit on CPU utilization. Change description In previous .NET versions, the Environment.ProcessorCount property on Windows returns the number of logical processors on the machine. The property ignores process affinity and the job object's hard limit on CPU utilization. That Windows behavior is inconsistent with the behavior on Unix-based operating systems, where those limits are respected. Starting with .NET 6, the behavior of Environment.ProcessorCount on Windows is consistent with the behavior on Unix-based operating system. In general, Environment.ProcessorCount returns the minimum of: The number of logical processors on the machine. If the process is running with CPU affinity, the number of processors that the process is affinitized to. If the process is running with a CPU utilization limit, the CPU utilization limit rounded up to the next whole number. The following table shows how the value of Environment.ProcessorCount changes from .NET 5 to .NET 6 on a machine with eight logical processors: Environment .NET 5 .NET 6 Process affinitized to two logical processors (Windows) 8 2 Process affinitized to two logical processors (Unix) 2 2 CPU utilization limited to the equivalent of two logical processors (Windows) 8 2 CPU utilization limited to the equivalent of two logical processors (Unix) 2 2 Version introduced 6.0 Reason for change This property is frequently used to determine the parallelism factor for a process. We've observed that not limiting the property's value based on affinitization and CPU utilization limit can lead to worse performance. Recommended action Review code that uses Environment.ProcessorCount to scale down the parallelism factor based on application or system configuration. Even if the code takes the process's affinity mask or the job object's CPU utilization limit into account, it may end up using lower parallelism than intended. Review code that expects Environment.ProcessorCount to return the total number of logical processors on the machine, for example, to display it to a user. Instead, you can use a PInvoke call to the GetSystemInfo or GetNativeSystemInfo Win32 APIs. If code performs worse as a result of this change, you can use the DOTNET_PROCESSOR_COUNT environment variable to override the number of processors thought to be available by the .NET runtime and reported by the Environment.ProcessorCount property. For example, if you set DOTNET_PROCESSOR_COUNT to 4, Environment.ProcessorCount will disregard any process affinity and CPU utilization limit and return 4. To mimic .NET 5 behavior, set the environment variable to %NUMBER_OF_PROCESSORS% . Affected APIs System.Environment.ProcessorCount EventSource callback behavior Article • 06/16/2023 For an EventCommand.Disable, the EventSource is now marked as disabled before the callback is issued. Previous behavior Previously, the EventSource.OnEventCommand(EventCommandEventArgs) callback was issued for an EventCommand.Disable prior to setting m_eventSourceEnabled=false . This meant that EventSource.IsEnabled() returned true in the OnEventCommand(EventCommandEventArgs) callback for a user EventSource, even if the command led to the EventSource being disabled. The callback happened after the ability to dispatch events was turned off though, so even if an EventSource tried to fire an event, it wasn't written. New behavior Now, the EventSource is marked as disabled before the callback is issued for an EventCommand.Disable. Version introduced .NET 6 servicing .NET 7 servicing Type of breaking change This change is a behavioral change. Reason for change This change was necessary to support multiple EventCounter instances. The ability to have multiple instances has been requested by multiple customers. In addition, EventCommand.Enable has always issued a consistent view: EventSource.IsEnabled() accurately reports the enabled status, and EventSource can write events from the OnEventCommand callback. This change makes the EventCommand.Disable behavior consistent with EventCommand.Enable . Recommended action It's unlikely that there's a scenario where the previous behavior is desired, and there's no way to revert the behavior. Affected APIs System.Diagnostics.Tracing.EventCommand.Disable File.Replace on Unix throws exceptions to match Windows implementation Article • 05/04/2022 The behavior of File.Replace on Unix-based operating systems has changed. The exceptions it throws now match those that are thrown by the Windows implementation. Previous behavior On Unix, with .NET 5, the File.Replace method: Throws IOException with the message Is a directory when sourceFileName is a file and destinationFileName is a directory. Throws IOException with the message Not a directory when sourceFileName is a directory and destinationFileName is a file. Silently succeeds when both sourceFileName and destinationFileName point to the same file or directory. New behavior On Unix, with .NET 6, the File.Replace method: Throws UnauthorizedAccessException with the message The specified path <path> is not a path , when either sourceFileName or destinationFileName exists and is not a file, or when both sourceFileName and destinationFileName point to the same existing directory. Throws IOException with the message The source <sourceFileName> and destination <destinationFileName> are the same file when sourceFileName and destinationFileName point to the same existing file. Version introduced .NET 6 Type of breaking change This change can affect source compatibility. Reason for change This change was made to ensure that File.Replace throws the same exceptions for the same reasons across platforms. Recommended action If you invoke File.Replace on Unix inside a try catch block, make sure to now also catch UnauthorizedAccessException. Also, be aware of the new behaviors that are caught. Affected APIs System.IO.File.Replace FileStream locks files with shared lock on Unix Article • 11/03/2021 On Unix, if you open a file using FileStream with FileAccess.Read permissions only, and then call FileStream.Lock(Int64, Int64) to lock a region of the file, the operation will now succeed. It succeeds because the runtime locks the file with a shared or read lock instead of a write lock. C# using (FileStream fs = File.OpenRead("testfile")) // Opening with FileAccess.Read only { fs.Lock((long) 3, (long) 1); // Attempting to lock a region of the readonly file } There's no change to the behavior on Windows, where the operation always succeeded. Previous behavior On Unix, if you opened a file using a FileStream with read permissions only, and then called FileStream.Lock(Int64, Int64) to lock a region of the file, the runtime attempted to lock the file with a write lock. That resulted in an UnauthorizedAccessException and the message "Access to the path is denied". New behavior Starting in .NET 6, if you open a file using a FileStream with read permissions only on Unix, and then call FileStream.Lock(Int64, Int64) to lock a region of the file, the runtime locks the file with a read lock (also known as a shared lock). Version introduced .NET 6 RC 1 Type of breaking change This change can affect binary compatibility. Reason for change FileStream.Lock(Int64, Int64) is the API that lets users lock a specific region of a file. There's no API that lets you choose the underlying locking method, so FileStream.Lock(Int64, Int64) should correctly determine the appropriate locking method for the file permissions. Recommended action Prior to .NET 6, to be able to lock the file, you had to do one of the following: Check if the code was being executed in Windows or the FileStream was opened with FileAccess.Write permission. Wrap the FileStream.Lock(Int64, Int64) call with a try catch to capture the UnauthorizedAccessException. If you used one of these workarounds, you can now remove them. Affected APIs System.IO.FileStream.Lock(Int64, Int64) FileStream no longer synchronizes file offset with OS Article • 11/04/2022 To improve performance, FileStream no longer synchronizes the file offset with the operating system. Change description In previous .NET versions, FileStream synchronizes the file offset with the Windows operating system (OS) when it reads or writes to a file. It synchronizes the offset by calling SetFilePointer, which is an expensive system call. Starting in .NET 6, FileStream no longer synchronizes the file offset, and instead just keeps the offset in memory. FileStream.Position always returns the current offset, but if you obtain the file handle from FileStream.SafeFileHandle and query the OS for the current file offset using a system call, the offset value will be 0. The following code shows how the file offset differs between previous .NET versions and .NET 6. C# [DllImport("kernel32.dll")] private static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod); byte[] bytes = new byte[10_000]; string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true)) { SafeFileHandle handle = fs.SafeFileHandle; await fs.WriteAsync(bytes, 0, bytes.Length); Console.WriteLine(fs.Position); // 10000 in all versions if (SetFilePointerEx(handle, 0, out long currentOffset, 1 /* get current offset */)) { Console.WriteLine(currentOffset); // 10000 in .NET 5, 0 in .NET 6 } } Version introduced .NET 6 Reason for change This change was introduced to improve the performance of asynchronous reads and writes and to address the following issues: Win32 FileStream will issue a seek on every ReadAsync call FileStream.Windows useAsync WriteAsync calls blocking APIs With this change, ReadAsync operations are up to two times faster, and WriteAsync operations are up to five times faster. Recommended action Modify any code that relied on the offset being synchronized. To enable the .NET 5 behavior in .NET 6, specify an AppContext switch or an environment variable. By setting the switch to true , you opt out of all performance improvements made to FileStream in .NET 6. JSON { "configProperties": { "System.IO.UseNet5CompatFileStream": true } } Windows Command Prompt set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1 7 Note This switch is only available in .NET 6. It was removed in .NET 7. Affected APIs None. See also SetFilePointer function SetFilePointerEx function FileStream.Position updates after ReadAsync or WriteAsync completes Article • 11/04/2022 FileStream.Position is now updated after ReadAsync or WriteAsync completes. Change description In previous .NET versions on Windows, FileStream.Position is updated after the asynchronous read or write operation starts. Starting in .NET 6, FileStream.Position is updated after those operations complete. The following code shows how the value of FileStream.Position differs between previous .NET versions and .NET 6. C# byte[] bytes = new byte[10_000]; string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true)) { Task[] writes = new Task[3]; writes[0] = fs.WriteAsync(bytes, 0, bytes.Length); Console.WriteLine(fs.Position); // 10000 in .NET 5, 0 in .NET 6 writes[1] = fs.WriteAsync(bytes, 0, bytes.Length); Console.WriteLine(fs.Position); // 20000 in .NET 5, 0 in .NET 6 writes[2] = fs.WriteAsync(bytes, 0, bytes.Length); Console.WriteLine(fs.Position); // 30000 in .NET 5, 0 in .NET 6 await Task.WhenAll(writes); Console.WriteLine(fs.Position); } Version introduced .NET 6 Reason for change // 30000 in all versions FileStream has never been thread-safe, but until .NET 6, .NET has tried to support multiple concurrent calls to its asynchronous methods (ReadAsync and WriteAsync) on Windows. This change was introduced to allow for 100% asynchronous file I/O with FileStream and to fix the following issues: FileStream.FlushAsync ends up doing synchronous writes Win32 FileStream turns async reads into sync reads Now, when buffering is enabled (that is, the bufferSize argument that's passed to the FileStream constructor is greater than 1), every ReadAsync and WriteAsync operation is serialized. Recommended action Modify any code that relied on the position being set before operations completed. To enable the .NET 5 behavior in .NET 6, specify an AppContext switch or an environment variable. By setting the switch to true , you opt out of all performance improvements made to FileStream in .NET 6. JSON { "configProperties": { "System.IO.UseNet5CompatFileStream": true } } Windows Command Prompt set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1 7 Note This switch is only available in .NET 6. It was removed in .NET 7. Affected APIs System.IO.FileStream.Position New diagnostic IDs for obsoleted APIs Article • 12/02/2021 Previously, a few APIs were obsoleted without using custom diagnostic IDs. Starting in .NET 6, those APIs report as obsolete using different, custom diagnostic IDs. If you suppressed warnings for usage of those APIs through CS0618, modify the suppressions to use the new diagnostic IDs, which are SYSLIB0003, SYSLIB0019, and SYSLIB0020. Change description The following table shows the old and new diagnostic IDs for the listed obsolete API. API Previous diagnostic ID New diagnostic ID Thread.GetCompressedStack() CS0618 SYSLIB0003 Thread.SetCompressedStack(CompressedStack) CS0618 SYSLIB0003 RuntimeEnvironment.SystemConfigurationFile CS0618 SYSLIB0019 RuntimeEnvironment.GetRuntimeInterfaceAsIntPtr(Guid, Guid) CS0618 SYSLIB0019 RuntimeEnvironment.GetRuntimeInterfaceAsObject(Guid, Guid) CS0618 SYSLIB0019 JsonSerializerOptions.IgnoreNullValues CS0618 SYSLIB0020 Version introduced .NET 6 Reason for change Starting in .NET 5, obsoletions are intended to use custom diagnostic ID values to allow fine-grained suppression of the warnings. This yields a better experience when the obsolete APIs need to remain referenced. The obsoletions affected here should have had custom diagnostic ID values applied when the APIs were originally marked as [Obsolete] . Recommended action If the SYSLIB0003, SYSLIB0019, or SYSLIB0020 diagnostic IDs are produced from your build, review the usage of the affected APIs. If possible, avoid using those APIs and refer to the messages and documentation for alternatives. If you need to retain the references to the obsolete APIs and suppress the diagnostics, suppress the warnings using the new diagnostic IDs instead of CS0618. Affected APIs System.Threading.Thread.GetCompressedStack() System.Threading.Thread.SetCompressedStack(CompressedStack) System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeInterfaceAsIntPtr( Guid, Guid) System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeInterfaceAsObjec t(Guid, Guid) System.Text.Json.JsonSerializerOptions.IgnoreNullValues See also SYSLIB0003: Code access security is not supported SYSLIB0019: Some RuntimeEnvironment APIs are obsolete SYSLIB0020: IgnoreNullValues is obsolete CS0618 New nullable annotation in AssociatedMetadataTypeTypeDescriptionProvider Article • 09/23/2021 In .NET 6, a nullability annotation has been added to AssociatedMetadataTypeTypeDescriptionProvider.GetTypeDescriptor(Type, Object). This method was previously unannotated for nullable reference types. Previous behavior The affected method was treated as "oblivious" with regard to reference type nullability. New behavior The parameters of the affected method are now annotated with accurate nullability conditions. Version introduced 6.0 RC 2 Type of breaking change This change can affect source compatibility. Reason for change This method had dependencies on other APIs that were previously unannotated. The dependencies have since been annotated, allowing this API to also be annotated. This change completes our nullable reference type annotations for the shared framework libraries. Recommended action Update code that calls this method to reflect the revised nullability contract. Affected APIs API What changed System.ComponentModel.DataAnnotations.AssociatedMetadataTypeTypeDescriptionProvider.GetTypeDescriptor(Type, Object) instance parameter type is nullable New System.Linq.Queryable method overloads Article • 12/02/2021 Additional public method overloads have been added to System.Linq.Queryable as part of the new features implemented in https://github.com/dotnet/runtime/pull/47231 . If your reflection code isn't sufficiently robust when looking up methods, these additions can break your query provider implementations. Change description In .NET 6, new overloads were added to the methods listed in the Affected APIs section. Reflection code, such as that shown in the following example, may break as a result of these additions: C# typeof(System.Linq.Queryable) .GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.Name == "ElementAt") .Single(); This reflection code will now throw an InvalidOperationException with a message similar to: Sequence contains more than one element. Version introduced .NET 6 Reason for change The new overloads were added to extend the LINQ Queryable API. Recommended action If you're a query-provider library author, ensure that your reflection code is tolerant of method overload additions. For example, use a Type.GetMethod overload that explicitly accepts the method's parameter types. Affected APIs New overloads were added for the following Queryable extension methods: System.Linq.Queryable.ElementAt System.Linq.Queryable.ElementAtOrDefault System.Linq.Queryable.Take System.Linq.Queryable.Min System.Linq.Queryable.Max System.Linq.Queryable.FirstOrDefault System.Linq.Queryable.LastOrDefault System.Linq.Queryable.SingleOrDefault System.Linq.Queryable.Zip Changes to nullable reference type annotations Article • 12/02/2021 In .NET 6, some nullability annotations in the .NET libraries have changed. Change description In previous .NET versions, some nullable reference type annotations are incorrect, and build warnings are either absent or incorrect. Starting in .NET 6, some annotations that were previously applied have been updated. New build warnings will be produced and incorrect build warnings will no longer be produced for the affected APIs. Some of these changes are considered to be breaking because they can lead to new build-time warnings. When you migrate to .NET 6, code that references these APIs will need to be updated. Other changes that aren't considered to be breaking are also documented on this page. Any code that references the updated APIs may benefit from removing operators or pragmas that are no longer necessary. Version introduced 6.0 Type of breaking change This change can affect source compatibility. Reason for change Starting in .NET Core 3.0, nullability annotations were applied to the .NET libraries. From the outset of the effort, mistakes in these annotations were anticipated. Through feedback and further testing, the nullable annotations for the affected APIs were determined to be inaccurate. The updated annotations correctly represent the nullability contracts for the APIs. Recommended action Update code that calls these APIs to reflect the revised nullability contracts. Affected APIs The following table lists the affected APIs: API What changed Breaking or nonbreaking ISite.Container Property type is nullable Breaking XContainer.Add(Object[]) Parameter type is Nonbreaking nullable XContainer.AddFirst(Object[]) Parameter type is Nonbreaking nullable XContainer.ReplaceNodes(Object[]) Parameter type is Nonbreaking nullable XDocument(Object[]) Parameter type is Nonbreaking nullable XDocument(XDeclaration, Object[]) Parameter type is nullable Nonbreaking XElement(XName, Object[]) Second parameter type is nullable Nonbreaking XElement.ReplaceAll(Object[]) Parameter type is nullable Nonbreaking XElement.ReplaceAttributes(Object[]) Parameter type is nullable Nonbreaking XNode.AddAfterSelf(Object[]) Parameter type is nullable Nonbreaking XNode.AddBeforeSelf(Object[]) Parameter type is nullable Nonbreaking XNode.ReplaceWith(Object[]) Parameter type is nullable Nonbreaking XStreamingElement(XName, Object) Second parameter type is nullable Nonbreaking API What changed Breaking or nonbreaking XStreamingElement(XName, Object[]) Second parameter Nonbreaking type is nullable XStreamingElement.Add(Object[]) Parameter type is Nonbreaking nullable HttpClient.PatchAsync content parameter Nonbreaking type is nullable HttpClient.PostAsync content parameter Nonbreaking type is nullable HttpClient.PutAsync content parameter Nonbreaking type is nullable MethodCallExpression.Update(Expression, First parameter type is IEnumerable<Expression>) nullable Expression<TDelegate>.Update(Expression, Return type is not IEnumerable<ParameterExpression>) nullable IDataRecord.GetBytes(Int32, Int64, Byte[], Int32, Int32) buffer parameter type Nonbreaking Nonbreaking Breaking is nullable IDataRecord.GetChars(Int32, Int64, Char[], Int32, Int32) buffer parameter type Breaking is nullable DbDataRecord.GetBytes(Int32, Int64, Byte[], Int32, Int32) buffer parameter type Breaking is nullable DbDataRecord.GetChars(Int32, Int64, Char[], Int32, buffer parameter type Int32) is nullable System.Net.HttpListenerContext.AcceptWebSocketAsync subProtocol Breaking Nonbreaking parameter type is nullable Methods that override Object.Equals(Object) and many others that return bool ImmutableArray<T>.Equals(Object) [NotNullWhen(true)] Breaking added to first nullable parameter NotNullWhen(true) was Breaking added to the obj parameter BitVector32.Equals(Object) NotNullWhen(true) was added to the o parameter Breaking API What changed Breaking or nonbreaking BitVector32.Section.Equals(Object) NotNullWhen(true) was Breaking added to the o parameter BlobContentId.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter BlobHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter CustomDebugInformationHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter DocumentNameBlobHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter EntityHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter GuidHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter Handle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter ImportScopeHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter LocalConstantHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter NamespaceDefinitionHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter SequencePoint.Equals(Object) NotNullWhen(true) was added to the obj parameter Breaking API What changed Breaking or nonbreaking SignatureHeader.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter EditAndContinueLogEntry.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter LabelHandle.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter Label.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter OpCode.Equals(Object) NotNullWhen(true) was Breaking added to the obj parameter DateOnly.Equals(System.Object) NotNullWhen(true) was Breaking added to the value parameter TimeOnly.Equals(System.Object) NotNullWhen(true) was Breaking added to the value parameter Pointer.Equals(Object) NotNullWhen(true) was added to the obj parameter See also Attributes for null-state static analysis Nullable reference type annotation changes in ASP.NET Core Breaking Older framework versions dropped from package Article • 09/16/2022 Starting with .NET 6, the core libraries packages can no longer be installed into projects whose target framework is older than: .NET Framework 4.6.1 .NET Core 3.1 .NET Standard 2.0 Change description Previously, you were able to upgrade the packages to the latest version, even if you were using them from a framework older than .NET Framework 4.6.1, .NET Core 3.1, or .NET Standard 2.0. Starting in .NET 6, if you're referencing an impacted package from an earlier framework, you can no longer update the referenced package to the latest version. Version introduced .NET 6 Reason for change Continuing to build for all frameworks increases the complexity and size of a package. In the past, .NET solved this issue by building only for current frameworks and harvesting binaries for older frameworks. Harvesting means that during build, the earlier version of the package is downloaded and the binaries are extracted. While consuming a harvested binary means that you can always update without worrying that a framework is dropped, it also means that you don't get any bug fixes or new features. In other words, harvested assets can't be serviced. That's hidden from you because you're able to keep updating the package to a later version even though you're consuming the same old binary that's no longer updated. Starting with .NET 6, .NET no longer performs any form of harvesting to ensure that all shipped assets can be serviced. Recommended action If your project is maintained but not evolving, simply don't upgrade the impacted packages. This is generally not a huge take back because you're already consuming a frozen binary. If your project is evolving, upgrade it to a later framework version, such as: .NET Framework 4.6.1 .NET Core 3.1 .NET Standard 2.0 Affected APIs The following packages no longer ship old frameworks: Microsoft.Extensions.DependencyModel Microsoft.Win32.Registry.AccessControl Microsoft.Win32.SystemEvents System.Collections.Immutable System.ComponentModel.Annotations System.ComponentModel.Composition System.ComponentModel.Composition.Registration System.Composition.AttributedModel System.Composition.Convention System.Composition.Hosting System.Composition.Runtime System.Composition.TypedParts System.Data.Odbc System.Data.OleDb System.Diagnostics.DiagnosticSource System.Diagnostics.EventLog System.Diagnostics.PerformanceCounter System.DirectoryServices System.DirectoryServices.AccountManagement System.DirectoryServices.Protocols System.Drawing.Common System.IO.Packaging System.IO.Pipelines System.Management System.Net.Http.WinHttpHandler System.Net.WebSockets.WebSocketProtocol System.Numerics.Tensors System.Reflection.Context System.Reflection.Metadata System.Reflection.MetadataLoadContext System.Runtime.Caching System.Runtime.CompilerServices.Unsafe System.Security.Cryptography.Cng System.Security.Cryptography.OpenSsl System.Security.Cryptography.Pkcs System.Security.Cryptography.ProtectedData System.Security.Permissions System.ServiceProcess.ServiceController System.Speech System.Text.Encoding.CodePages System.Text.Encodings.Web System.Threading.AccessControl System.Threading.Channels System.Threading.Tasks.Dataflow System.Windows.Extensions The following packages will no longer be updated because their implementation is now part of the .NET 6 platform: Microsoft.Win32.Registry System.ComponentModel.Annotations System.IO.FileSystem.AccessControl System.IO.Pipes.AccessControl System.Security.AccessControl System.Security.Cryptography.Cng System.Security.Cryptography.OpenSsl System.Security.Principal.Windows Parameter names changed in .NET 6 Article • 12/02/2021 Some parameter names have changed to be consistent between reference and implementation assemblies. Most of the changes are in the reference assemblies, but a handful are in the implementation assemblies. Previous behavior Some reference assembly parameter names were different to their corresponding parameters in the implementation assembly. This can cause problems while using named arguments and reflection. New behavior In .NET 6, these mismatched parameter names were updated to be consistent across the reference and implementation assemblies. The following table shows the APIs and parameter names that changed. API Old parameter name New parameter name Where changed Attribute.GetCustomAttributes(MemberInfo, Type) type attributeType Reference and implementation assembly Attribute.GetCustomAttributes(MemberInfo, Type, Boolean) type attributeType Reference and implementation assembly Strings.InStr(Int32, String, String, CompareMethod) StartPos Start Reference assembly SortedList<TKey,TValue>.ICollection.CopyTo(Array, Int32) arrayIndex index Reference assembly Vector.Narrow source1 , low , high Reference assembly source2 Vector.Widen dest1 , dest2 low , high Reference assembly StreamWriter.WriteLine(ReadOnlySpan<Char>) value buffer Implementation assembly FileStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) array , buffer , count Implementation assembly buffer , count Implementation assembly numBytes FileStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) array , numBytes MemoryStream.Read(Span<Byte>) destination buffer Reference assembly MemoryStream.ReadAsync(Memory<Byte>, CancellationToken) destination buffer Reference assembly MemoryStream.Write(ReadOnlySpan<Byte>) source buffer Reference assembly API Old parameter name New parameter name Where changed MemoryStream.WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) source buffer Reference assembly UnmanagedMemoryStream.Read(Span<Byte>) destination buffer Reference assembly UnmanagedMemoryStream.Write(ReadOnlySpan<Byte>) source buffer Reference assembly SignerInfo.AddUnsignedAttribute(AsnEncodedData) asnEncodedData unsignedAttribute Reference assembly SignerInfo.RemoveUnsignedAttribute(AsnEncodedData) asnEncodedData unsignedAttribute Reference assembly Rfc3161TimestampRequest.ProcessResponse(ReadOnlyMemory<Byte>, source responseBytes Implementation Int32) assembly Rfc3161TimestampToken.TryDecode(ReadOnlyMemory<Byte>, Rfc3161TimestampToken, Int32) source encodedBytes Implementation assembly Rfc3161TimestampTokenInfo.Rfc3161TimestampTokenInfo(Oid, Oid, ReadOnlyMemory<Byte>, ReadOnlyMemory<Byte>, DateTimeOffset, Nullable<Int64>, Boolean, Nullable<ReadOnlyMemory<Byte>>, Nullable<ReadOnlyMemory<Byte>>, X509ExtensionCollection) tsaName timestampAuthorityName Implementation assembly Rfc3161TimestampTokenInfo.TryDecode(ReadOnlyMemory<Byte>, Rfc3161TimestampTokenInfo, Int32) | PrincipalPermission.Equals(Object) o obj Reference assembly UrlMembershipCondition.Equals(Object) o obj Reference assembly DBDataPermission(DBDataPermission) dataPermission permission Implementation assembly DBDataPermission(DBDataPermissionAttribute) attribute permissionAttribute Implementation assembly DBDataPermission(PermissionState, Boolean) blankPassword allowBlankPassword Implementation assembly DBDataPermission.FromXml(SecurityElement) elem securityElement Implementation assembly DBDataPermission.Union(IPermission) other target Implementation assembly Reason for change In cases where the reference assembly parameter names were changed, the new names were deemed more appropriate or readable and minimally breaking. In cases where the names of runtime parameters were changed to gain consistency across platforms or with reference assemblies, the runtime implementation now matches the public API and documentation for the method. Version introduced .NET 6 Recommended action If you encounter a compiler error due to a parameter name change, update the parameter name accordingly. If you use run-time reflection to inspect methods and took a dependency on the parameter names, update the code to use the new parameter names. Affected APIs Microsoft.VisualBasic.Strings.InStr(Int32, String, String, CompareMethod) System.Attribute.GetCustomAttributes(MemberInfo, Type) System.Attribute.GetCustomAttributes(MemberInfo, Type, Boolean) System.Collections.Generic.SortedList<TKey,TValue>.System.Collections.ICollection.CopyTo(Array, Int32) System.IO.StreamWriter.WriteLine(ReadOnlySpan<Char>) System.IO.FileStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.FileStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.MemoryStream.Read(Span<Byte>) System.IO.MemoryStream.ReadAsync(Memory<Byte>, CancellationToken) System.IO.MemoryStream.Write(ReadOnlySpan<Byte>) System.IO.MemoryStream.WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) System.IO.UnmanagedMemoryStream.Read(Span<Byte>) System.IO.UnmanagedMemoryStream.Write(ReadOnlySpan<Byte>) System.Numerics.Vector.Narrow System.Numerics.Vector.Widen System.Security.Cryptography.Pkcs.Rfc3161TimestampRequest.ProcessResponse(ReadOnlyMemory<Byte>, Int32) System.Security.Cryptography.Pkcs.Rfc3161TimestampToken.TryDecode(ReadOnlyMemory<Byte>, Rfc3161TimestampToken, Int32) System.Security.Cryptography.Pkcs.Rfc3161TimestampTokenInfo.Rfc3161TimestampTokenInfo(Oid, Oid, ReadOnlyMemory<Byte>, ReadOnlyMemory<Byte>, DateTimeOffset, Nullable<Int64>, Boolean, Nullable<ReadOnlyMemory<Byte>>, Nullable<ReadOnlyMemory<Byte>>, X509ExtensionCollection) System.Security.Cryptography.Pkcs.Rfc3161TimestampTokenInfo.TryDecode(ReadOnlyMemory<Byte>, Rfc3161TimestampTokenInfo, Int32) System.Security.Cryptography.Pkcs.SignerInfo.AddUnsignedAttribute(AsnEncodedData) System.Security.Cryptography.Pkcs.SignerInfo.RemoveUnsignedAttribute(AsnEncodedData) System.Security.Permissions.PrincipalPermission.Equals(Object) System.Security.Policy.UrlMembershipCondition.Equals(Object) DBDataPermission(DBDataPermission) DBDataPermission(DBDataPermissionAttribute) DBDataPermission(PermissionState, Boolean) System.Data.Common.DBDataPermission.FromXml(SecurityElement) System.Data.Common.DBDataPermission.Union(IPermission) See also Some parameters in Stream-derived types are renamed Some parameters in Stream-derived types are renamed Article • 10/04/2022 In .NET 6, some parameters of methods on types derived from System.IO.Stream have been renamed to match the base class. Change description In previous .NET versions, several types derived from Stream override methods but use different parameter names than those used by the base type. For example, the byte array parameter of DeflateStream.Read(Byte[], Int32, Int32) is named array while the corresponding argument in the base class method is named buffer . In .NET 6, all types that derive from System.IO.Stream that had mismatched parameter names have been brought into conformance with the base type by using the same parameter names as the base type. Version introduced .NET 6 Reason for change There are several reasons for the change: If an invalid argument was passed and an exception was thrown, that exception might have contained the base parameter's name or the derived parameter's name, depending on the implementation. Since the caller may have been using a reference typed as the base or as the derived type, it's impossible for the argument name in the exception to always be correct. Having different parameter names makes it harder to consistently validate behavior across all Stream implementations. .NET 6 adds a public method on Stream for validating arguments, and that method needs to have a consistent parameter name to use. Recommended action The effect of this breaking change is minimal: For existing binaries, its impact is limited to code that uses reflection to examine the names of parameters on the affected derived types. For source code, its impact is limited to code that uses named parameters to invoke methods on the derived stream type using a variable typed as that derived type. In both cases, the recommended action is to consistently use the base parameter name. Affected APIs System.IO.BufferedStream.Read(Byte[], Int32, Int32) System.IO.BufferedStream.Write(Byte[], Int32, Int32) System.IO.Compression.DeflateStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.Compression.DeflateStream.Read(Byte[], Int32, Int32) System.IO.Compression.DeflateStream.ReadAsync(Byte[], Int32, Int32, CancellationToken) System.IO.Compression.DeflateStream.Write(Byte[], Int32, Int32) System.IO.Compression.DeflateStream.WriteAsync(Byte[], Int32, Int32, CancellationToken) System.IO.Compression.GZipStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.Compression.GZipStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.Compression.GZipStream.Read(Byte[], Int32, Int32) System.IO.Compression.GZipStream.ReadAsync(Byte[], Int32, Int32, CancellationToken) System.IO.Compression.GZipStream.Write(Byte[], Int32, Int32) System.IO.Compression.GZipStream.WriteAsync(Byte[], Int32, Int32, CancellationToken) System.IO.FileStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.FileStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.FileStream.Read(Byte[], Int32, Int32) System.IO.FileStream.Write(Byte[], Int32, Int32) System.Net.Sockets.NetworkStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.Net.Sockets.NetworkStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32) System.Net.Sockets.NetworkStream.ReadAsync(Byte[], Int32, Int32, CancellationToken) System.Net.Sockets.NetworkStream.Write(Byte[], Int32, Int32) System.Net.Sockets.NetworkStream.WriteAsync(Byte[], Int32, Int32, CancellationToken) See also Parameter names changed in .NET 6 Partial and zero-byte reads in DeflateStream, GZipStream, and CryptoStream Article • 11/08/2021 DeflateStream, GZipStream, and CryptoStream diverged from typical Stream.Read and Stream.ReadAsync behavior in two ways: They didn't complete the read operation until either the buffer passed to the read operation was completely filled or the end of the stream was reached. As wrapper streams, they didn't delegate zero-length buffer functionality to the stream they wrap. This change addresses both of these issues. Old behavior When Stream.Read or Stream.ReadAsync was called on one of the affected stream types with a buffer of length N , the operation would not complete until: N bytes had been read from the stream, or The underlying stream they wrap returned 0 from a call to its read, indicating no more data is available. Also, when Stream.Read or Stream.ReadAsync was called with a buffer of length 0, the operation would succeed immediately, sometimes without doing a zero-length read on the stream it wraps. New behavior Starting in .NET 6, when Stream.Read or Stream.ReadAsync is called on one of the affected stream types with a buffer of length N , the operation completes when: At least one byte has been read from the stream, or The underlying stream they wrap returns 0 from a call to its read, indicating no more data is available. Also, when Stream.Read or Stream.ReadAsync is called with a buffer of length 0, the operation succeeds once a call with a non-zero buffer would succeed. Version introduced 6.0 Reason for change The streams might not have returned from a read operation even if data had been successfully read. This meant they couldn't readily be used in any bidirectional communication situation where messages smaller than the buffer size were being used. This could lead to deadlocks: the application is unable to read the data from the stream that's necessary to continue the operation. It could also lead to arbitrary slowdowns, with the consumer unable to process available data while waiting for additional data to arrive. Also, in highly scalable applications, it's common to use zero-byte reads as a way of delaying buffer allocation until a buffer is needed. An application can issue a read with an empty buffer, and when that read completes, data should soon be available to consume. The application can then issue the read again, this time with a buffer to receive the data. By delegating to the wrapped stream if no already decompressed or transformed data is available, these streams now inherit any such behavior of the streams they wrap. Recommended action In general, code should: Not make any assumptions about a stream Read or ReadAsync operation reading as much as was requested. The call returns the number of bytes read, which may be less than what was requested. If an application depends on the buffer being completely filled before progressing, it can perform the read in a loop to regain the behavior. C# int totalRead = 0; while (totalRead < buffer.Length) { int bytesRead = stream.Read(buffer.Slice(totalRead)); if (bytesRead == 0) break; totalRead += bytesRead; } Expect that a stream Read or ReadAsync call may not complete until at least a byte of data is available for consumption (or the stream reaches its end), regardless of how many bytes were requested. If an application depends on a zero-byte read completing immediately without waiting, it can check the buffer length itself and skip the call entirely: C# int bytesRead = 0; if (!buffer.IsEmpty) { bytesRead = stream.Read(buffer); } Affected APIs System.IO.Compression.DeflateStream.Read System.IO.Compression.DeflateStream.ReadAsync System.IO.Compression.DeflateStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.Compression.GZipStream.Read System.IO.Compression.GZipStream.ReadAsync System.IO.Compression.GZipStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.Security.Cryptography.CryptoStream.Read System.Security.Cryptography.CryptoStream.ReadAsync System.Security.Cryptography.CryptoStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) Set timestamp on read-only file on Windows Article • 01/12/2022 Setting the timestamp on a file with the read-only attribute now succeeds on Windows and no longer throws an exception. Old behavior Prior to .NET 6 servicing releases, setting the timestamp on a read-only file on Windows resulted in an UnauthorizedAccessException. New behavior Starting in .NET 6.0.2, setting the timestamp on a read-only file on Windows succeeds. Version introduced .NET 6.0.2 (servicing release) Type of breaking change This change can affect binary compatibility. Reason for change Customers gave feedback that they expected setting the timestamp on a read-only file to succeed. This change also makes the Windows behavior consistent with Linux. Finally, the behavior was unintentional, caused by a bug. Recommended action It is unlikely that existing code expects setting the timestamp on a read-only file to fail. However, if your code expects it to fail, add a check for the read-only attribute using File.GetAttributes(String) before attempting to set the timestamp. Affected APIs System.IO.File.SetCreationTime(String, DateTime) System.IO.File.SetCreationTimeUtc(String, DateTime) System.IO.File.SetLastAccessTime(String, DateTime) System.IO.File.SetLastAccessTimeUtc(String, DateTime) System.IO.File.SetLastWriteTime(String, DateTime) System.IO.File.SetLastWriteTimeUtc(String, DateTime) Standard numeric format parsing precision Article • 09/08/2022 .NET now supports greater precision values when formatting numbers as strings using ToString and TryFormat . 7 Note The maximum precision was changed again in .NET 7. For more information, see Maximum precision for numeric format strings. Change description When formatting numbers as strings, the precision specifier in the format string represents the number of digits in the resulting string. Depending on the format specifier, which is the character at the beginning of the string, the precision can represent the total number of digits, the number of significant digits, or the number of decimal digits. In previous .NET versions, the standard numeric format parsing logic is limited to a precision of 99 or less. Some numeric types have more precision, but ToString(string format) does not expose it correctly. If you specify a precision greater than 99, for example, 32.ToString("C100") , the format string is interpreted as a custom numeric format string instead of "currency with precision 100". In custom numeric format strings, characters are interpreted as character literals. In addition, a format string that contains an invalid format specifier is interpreted differently depending on the precision value. H99 throws a FormatException for the invalid format specifier, while H100 is interpreted as a custom numeric format string. Starting in .NET 6, .NET supports precision up to Int32.MaxValue. A format string that consists of a format specifier with any number of digits is interpreted as a standard numeric format string with precision. A FormatException is thrown for either or both of the following conditions: The format specifier character is not a standard format specifier. The precision is greater than Int32.MaxValue. This change was implemented in the parsing logic that affects all numeric types. The following table shows the behavior changes for various format strings. Format string Previous behavior .NET 6+ behavior C2 Denotes currency with two decimal digits Denotes currency with two decimal digits (no change) C100 Denotes custom numeric format string that prints "C100" Denotes currency with 100 decimal digits H99 Throws FormatException due to invalid standard format specifier "H" Throws FormatException due to invalid standard format specifier "H" (no change) H100 Denotes custom numeric format string Throws FormatException due to invalid standard format specifier "H" Version introduced .NET 6 Reason for change This change corrects unexpected behavior when using higher precision for numeric format parsing. Recommended action In most cases, no action is necessary and the correct precision will be shown in the resulting strings. However, if you want to revert to the previous behavior where the format specifier is interpreted as a literal character when the precision is greater than 99, you can wrap that character in single quotes or escape it with a backslash. For example, in previous .NET versions, 42.ToString("G999") returns G999 . To maintain that behavior, change the format string to "'G'999" or "\\G999" . This will work on .NET Framework, .NET Core, and .NET 5+. The following format strings will continue to be interpreted as custom numeric format strings: Start with any character that is not an ASCII alphabetical character, for example, $ or è . Start with an ASCII alphabetical character that's not followed by an ASCII digit, for example, A$ . Start with an ASCII alphabetical character, followed by an ASCII digit sequence, and then any character that is not an ASCII digit character, for example, A12A . Affected APIs This change was implemented in the parsing logic that affects all numeric types. System.Numerics.BigInteger.ToString(String) System.Numerics.BigInteger.ToString(String, IFormatProvider) System.Numerics.BigInteger.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Int32.ToString(String) System.Int32.ToString(String, IFormatProvider) System.Int32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt32.ToString(String) System.UInt32.ToString(String, IFormatProvider) System.UInt32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Byte.ToString(String) System.Byte.ToString(String, IFormatProvider) System.Byte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.SByte.ToString(String) System.SByte.ToString(String, IFormatProvider) System.SByte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Int16.ToString(String) System.Int16.ToString(String, IFormatProvider) System.Int16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt16.ToString(String) System.UInt16.ToString(String, IFormatProvider) System.UInt16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Int64.ToString(String) System.Int64.ToString(String, IFormatProvider) System.Int64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.UInt64.ToString(String) System.UInt64.ToString(String, IFormatProvider) System.UInt64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Half.ToString(String) System.Half.ToString(String, IFormatProvider) System.Half.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Single.ToString(String) System.Single.ToString(String, IFormatProvider) System.Single.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Double.ToString(String) System.Double.ToString(String, IFormatProvider) System.Double.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) System.Decimal.ToString(String) System.Decimal.ToString(String, IFormatProvider) System.Decimal.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) See also Standard numeric format strings Character literals in custom format strings Maximum precision for numeric format strings (.NET 7) Static abstract members declared in interfaces Article • 09/29/2022 .NET 6 previews a new feature where static interface members can be marked as abstract . This feature involves several changes to the ECMA 335 spec to allow intermediate language (IL) metadata patterns that were previously considered illegal. For more information, see dotnet/runtime#49558 . Old behavior If a static interface was marked as abstract : The C# compiler generated error CS0112. Tools and other compilers generated illegal IL metadata. New behavior Starting in .NET 6, static interface members can be marked as abstract and will compile successfully. In addition, the IL metadata patterns that are generated are now considered legal due to changes in the ECMA 335 spec. The implementation of static abstract interface members is provided by types that implement the interface. 7 Note For .NET 6, you must enable preview features in your project to be able to mark an interface member as static abstract . Since this is a newly legal IL pattern, existing tooling may incorrectly process the associated metadata and have unexpected behavior. It's likely that tooling will encounter the new metadata pattern, because interfaces with static abstract members now appear on the primitive types, for example, System.Int32. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced because there was no way to abstract over static members and write generalized code that applies across types that define those static members. This was particularly problematic for member kinds that only exist in a static form, for example, operators. Recommended action Update any tooling that consumes .NET binaries or C# source code to account for the new concept of static abstract interface members, including those that now exist on the .NET primitive types. Affected APIs N/A See also Tutorial: Explore static virtual members in interfaces StringBuilder.Append overloads and evaluation order Article • 10/15/2021 C# 10 adds support for better string interpolation , including the ability to target custom "handlers" in addition to strings. StringBuilder takes advantage of this with new overloads of Append and AppendLine that accept a custom interpolated string handler. Existing calls to these methods may now start binding to the new overloads. In general, behavior is identical but with improved performance. For example, rather than a string first being created and then that string appended, the individual components of the interpolated string are appended directly to the builder. However, this can change the evaluation order of objects used as format items, which can manifest as a difference in behavior. Previous behavior In previous versions, a call to: C# stringBuilder.Append($"{a} {b}"); compiled to the equivalent of: C# stringBuilder.Append(string.Format("{0} {1}", a, b)); This means a is evaluated, then b is evaluated, then a string is created from the results of those evaluations, and then that string is appended to the builder. New behavior Starting in .NET 6, a call to: C# stringBuilder.Append($"{a} {b}"); compiles to the equivalent of: C# var handler = new StringBuilder.AppendInterpolatedStringHandler(1, 2, stringBuilder); handler.AppendFormatted(a); handler.AppendLiteral(" "); handler.AppendFormatted(b); stringBuilder.Append(ref handler); This means a is evaluated and appended to the builder, and then b is evaluated and appended to the builder. If, for example, either a or b is itself the builder, as shown in the following code, the new evaluation order can result in different behavior at run time. C# stringBuilder.Append($"{a} {stringBuilder}"); Version introduced 6.0 RC 1 Type of breaking change This change can affect source compatibility. Reason for change It's common for developers to pass interpolated strings to StringBuilder, as it's more convenient than manually splitting the string up and calling StringBuilder.Append for each part. These new overloads enable the concise syntax and most of the performance of doing the individual calls. Recommended action In most cases where StringBuilder.Append and StringBuilder.AppendLine are used, you won't notice a functional difference. If you find a difference that proves to be problematic, you can restore the previous behavior by adding a cast to (string) prior to the interpolated string. For example: C# stringBuilder.Append((string)$"{a} {b}") This is not recommended, however, unless it's actually required for compatibility. Affected APIs System.Text.StringBuilder.Append System.Text.StringBuilder.AppendLine See also String Interpolation in C# 10 and .NET 6 Strong-name APIs throw PlatformNotSupportedException Article • 07/22/2022 A few APIs that aren't supported in .NET/.NET Core but didn't do anything when accessed have been changed to now throw a PlatformNotSupportedException at run time. Previously, using these APIs would eventually result in a run-time exception further along; the exception is now thrown when the type is instantiated or first accessed. Previous behavior In previous versions, calling AssemblyName.KeyPair or StrongNameKeyPair(Byte[]) was a no-op. Calling StrongNameKeyPair(FileStream) read the stream but otherwise did nothing. New behavior Starting in .NET 6, each of the three affected APIs throws a PlatformNotSupportedException at run time. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change Previously, an application that called the API compiled and ran, but as soon as the instance was used in any code path, it threw a run-time exception. To make it more explicit that this scenario is unsupported, the exception-throwing logic was moved into the instance constructor. In case no instances are created, the exception is also thrown in public entry points that return this type, that is, AssemblyName.KeyPair. Recommended action Strong-name signing is not supported in .NET/.NET Core, and there is no workaround. 7 Note .NET Core/5+ never checks signatures in its runtime. However, if you're targeting cross-platform libraries (for example, a basic auth package that targets .NET Standard 2.0, so it runs on .NET Framework too), then strong-naming is a good idea for cross-runtime compatibility. .NET Framework continues to enforce strong naming if the calling app is strong-named. You can strong-name assemblies in all versions of .NET using the Sn.exe tool. For more information, see Strong name signing . Affected APIs StrongNameKeyPair(FileStream) StrongNameKeyPair(Byte[]) System.Reflection.AssemblyName.KeyPair See also How to: Sign an assembly with a strong name System.Drawing.Common only supported on Windows Article • 07/21/2023 The System.Drawing.Common NuGet package is now attributed as a Windows- specific library. The platform analyzer emits warning at compile time when compiling for non-Windows operating systems. On non-Windows operating systems, unless you set a runtime configuration switch, a TypeInitializationException exception is thrown with PlatformNotSupportedException as the inner exception. Old behavior Prior to .NET 6, using the System.Drawing.Common package did not produce any compile-time warnings, and no run-time exceptions were thrown. New behavior Starting in .NET 6, the platform analyzer emits compile-time warnings when referencing code is compiled for non-Windows operating systems. In addition, the following runtime exception is thrown unless you set a configuration option: System.TypeInitializationException : The type initializer for 'Gdip' threw an exception. ---- System.PlatformNotSupportedException : System.Drawing.Common is not supported on non-Windows platforms. See https://aka.ms/systemdrawingnonwindows for more information. Stack Trace: at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromFile(String filename, IntPtr& bitmap) /_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(42,0): at System.Drawing.Bitmap..ctor(String filename, Boolean useIcm) /_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(25,0): at System.Drawing.Bitmap..ctor(String filename) /_/src/libraries/System.Resources.ResourceManager/tests/ResourceManagerTests .cs(270,0): at System.Resources.Tests.ResourceManagerTests.EnglishImageResourceData()+MoveN ext() /_/src/libraries/System.Linq/src/System/Linq/Select.cs(136,0): at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext() ----- Inner Stack Trace ----/_/src/libraries/System.Drawing.Common/src/System/Drawing/LibraryResolver.cs (31,0): at System.Drawing.LibraryResolver.EnsureRegistered() /_/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix .cs(65,0): at System.Drawing.SafeNativeMethods.Gdip.PlatformInitialize() /_/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs(27,0): at System.Drawing.SafeNativeMethods.Gdip..cctor() Version introduced .NET 6 Type of breaking change This change can affect source compatibility and binary compatibility. Reason for change Because System.Drawing.Common was designed to be a thin wrapper over Windows technologies, its cross-platform implementation is subpar. libgdiplus is the main provider of the cross-platform implementation of System.Drawing.Common on the native side. libgdiplus is effectively a reimplementation of the parts of Windows that System.Drawing.Common depends on. That implementation makes libgdiplus a non-trivial component. It's around 30,000 lines of C code that's largely untested, and it lacks a lot of functionality. libgdiplus also has numerous external dependencies for image processing and text rendering, such as cairo , pango , and other native libraries. Those dependencies make maintaining and shipping the component even more challenging. Since the inclusion of the Mono cross-platform implementation, we have redirected numerous issues to libgdiplus that never got fixed. In comparison, other external dependencies we have taken, such as icu or openssl , are high-quality libraries. It's not viable to get libgdiplus to the point where its feature set and quality is on par with the rest of the .NET stack. From analysis of NuGet packages, we've observed that System.Drawing.Common is used cross-platform mostly for image manipulation, such as QR code generators and text rendering. We haven't noticed heavy graphics usage, as our cross-platform graphics support is incomplete. The usages we see of System.Drawing.Common in non-Windows environments are typically well supported with SkiaSharp and ImageSharp. System.Drawing.Common will continue to evolve only in the context of Windows Forms and GDI+. Recommended action To use these APIs for cross-platform apps, migrate to one of the following libraries: SkiaSharp ImageSharp (tiered license) Microsoft.Maui.Graphics Alternatively, you can enable support for non-Windows platforms in .NET 6 by setting the System.Drawing.EnableUnixSupport runtime configuration switch to true in the runtimeconfig.json file. runtimeconfig.template.json template file: JSON { "configProperties": { "System.Drawing.EnableUnixSupport": true } } [appname].runtimeconfig.json output file: JSON { "runtimeOptions": { "configProperties": { "System.Drawing.EnableUnixSupport": true } } } 7 Note This configuration switch was added to give cross-platform apps that depend heavily on this package time to migrate to more modern libraries. However, non-Windows bugs will not be fixed. This switch is only available in .NET 6 and was removed in .NET 7. For more information, see System.Drawing.Common config switch removed. Affected APIs System.Drawing namespace: Bitmap Brush Brushes BufferedGraphics BufferedGraphicsContext Font FontFamily FontConverter Graphics Icon IconConverter Image ImageAnimator Pen Pens Region SolidBrush StringFormat SystemBrushes SystemFonts SystemIcons SystemPens TextureBrush System.Drawing.Drawing2D namespace: AdjustableArrowCap CustomLineCap GraphicsPath GraphicsPathIterator GraphicsState HatchBrush LinearGradientBrush Matrix PathGradientBrush System.Drawing.Imaging namespace: Encoder EncoderParameter EncoderParameters ImageAttributes ImageCodecInfo ImageFormat Metafile MetafileHeader PlayRecordCallback System.Drawing.Printing namespace: PageSettings PreviewPageInfo PrintController PrintDocument PrinterSettings PrintEventArgs PrintEventHandler PrintPageEventArgs PrintPageEventHandler System.Drawing.Text namespace: FontCollection InstalledFontCollection PrivateFontCollection See also System.Drawing.Common only supported on Windows - dotnet/designs System.Security.SecurityContext is marked obsolete Article • 10/12/2021 SecurityContext is marked obsolete with a custom diagnostic ID. Using any SecurityContext APIs generates warning SYSLIB0003 at compile time. 7 Note Suppressing the default obsoletion diagnostic ID, which is CS0618 for the C# compiler, does not suppress the warnings that the compiler generates when these APIs are used. Old behavior Prior to .NET 6, the SecurityContext type was not marked obsolete, however, all of its public members throw a PlatformNotSupportedException at run time. New behavior Starting in .NET 6, the SecurityContext is marked obsolete. Version introduced .NET 6 RC 1 Type of breaking change This change can affect source compatibility. Reason for change All of the public members of SecurityContext throw a PlatformNotSupportedException at run time. The SecurityContext is part of Code access security (CAS), which is an unsupported legacy technology. Recommended action Remove any use of these APIs from your code. Affected APIs System.Security.SecurityContext See also Most code access security APIs are obsolete Task.FromResult may return singleton Article • 12/02/2021 Task.FromResult<TResult>(TResult) may now return a cached Task<TResult> instance rather than always creating a new instance. Old behavior In previous versions, Task.FromResult<TResult>(TResult) would always allocate a new Task<TResult>, regardless of the type of T or the result value. New behavior For some T types and some result values, Task.FromResult<TResult>(TResult) may return a cached singleton object rather than allocating a new object. For example, it is likely that every call to Task.FromResult(true) will return the same already-completed Task<bool> object. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change Many developers expected Task.FromResult<TResult>(TResult) to behave similarly to asynchronous methods, which already performed such caching. Developers that knew about the allocation behavior often maintained their own cache to avoid the performance cost of always allocating for these commonly used values. For example: C# private static readonly Task<bool> s_trueTask = Task.FromResult(true); Now, such custom caches are no longer required for values such as Boolean and small Int32 values. Recommended action Unless you're using reference equality to check whether one Task instance is the same as another Task instance, you should not be impacted by this change. If you are using such reference equality and need to continue this checking, use the following code to be guaranteed to always get back a unique Task<TResult> instance: C# private static Task<T> NewInstanceFromResult<T>(T result) { var tcs = new TaskCompletionSource<T>(); tcs.TrySetResult(result); return tcs.Task; } 7 Note This pattern is much less efficient than just using Task.FromResult(result) , and should be avoided unless you really need it. Affected APIs System.Threading.Tasks.Task.FromResult<TResult>(TResult) Unhandled exceptions from a BackgroundService Article • 05/12/2022 In previous versions, when a BackgroundService throws an unhandled exception, the exception is lost and the service appears unresponsive. .NET 6 fixes this behavior by logging the exception and stopping the host. Change description In previous .NET versions, when an exception is thrown from a BackgroundService.ExecuteAsync(CancellationToken) override, the host continues to run, and no message is logged. Starting in .NET 6, when an exception is thrown from a BackgroundService.ExecuteAsync(CancellationToken) override, the exception is logged to the current ILogger. By default, the host is stopped when an unhandled exception is encountered. Version introduced .NET 6 Reason for change The new behavior is consistent with the way other app models behave when unhandled exceptions are encountered. It's also confusing to developers when their BackgroundService encounters an error, but nothing is logged. The best default behavior is to stop the host, because unhandled exceptions shouldn't be ignored. They indicate a problem that needs attention. Recommended action If you prefer to keep the previous behavior of allowing an unhandled exception in a BackgroundService to not stop the Host, you can set HostOptions.BackgroundServiceExceptionBehavior to BackgroundServiceExceptionBehavior.Ignore. C# Host.CreateBuilder(args) .ConfigureServices(services => { services.Configure<HostOptions>(hostOptions => { hostOptions.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore; }); }); Affected APIs Microsoft.Extensions.Hosting.IHost.StartAsync(CancellationToken) Microsoft.Extensions.Hosting.BackgroundService.ExecuteAsync(CancellationToken) CreateEncryptor methods throw exception for incorrect feedback size Article • 12/02/2021 The CreateEncryptor and CreateDecryptor methods for AesCng and TripleDESCng now throw a CryptographicException when the object instance is being used with a CNG persisted (or named) key for Cipher Feedback (CFB) mode, with a feedback size other than eight (CFB8). Previous behavior Previously, these classes allowed CFB128 ( AesCng ) or CFB64 ( TripleDESCng ) to be selected. However, if the key was a persisted key, then the computation was always done as if CFB8 was selected. New behavior The CreateEncryptor and CreateDecryptor methods throw a CryptographicException when both of the following conditions are met: CFB128 or CFB64 mode is selected (that is, SymmetricAlgorithm.FeedbackSize is set to 128 or 64). The instance is backed by a persisted key. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced to indicate that the requested work cannot be performed correctly. Recommended action If you encounter this exception, consider switching from CFB128 or CFB64 to CFB8. Making that switch will produce results compatible with the behavior in previous releases. Affected APIs System.Security.Cryptography.AesCng.CreateEncryptor() System.Security.Cryptography.AesCng.CreateDecryptor() System.Security.Cryptography.TripleDESCng.CreateEncryptor() System.Security.Cryptography.TripleDESCng.CreateDecryptor() x86 host path on 64-bit Windows Article • 06/13/2023 The x86 versions of .NET installers for Windows have been modified to no longer add the x86 host location (Program Files (x86)\dotnet) to the PATH environment variable on 64-bit Windows systems. With this change, if the x86 host location was added to PATH by a prior version of .NET, the x86 versions of .NET installers and .NET updates will remove it on upgrade. This change affects .NET Core 3.1, .NET 6, .NET 7, and future versions. This change only affects the dotnet host. It doesn't affect 32-bit/x86 application hosts, like myapp.exe. Those hosts will continue to find the x86 runtime correctly (assuming it's installed). Previous behavior The x86 host location was added to PATH , even on x64/Arm64 systems. Depending on which .NET architecture installer was run first, a user's machine could have either the native (x64/Arm64) or x86 host listed first in PATH . New behavior Going forward, the x86 host location is only added to the PATH environment variable on x86 systems and will be removed on upgrade of .NET or Visual Studio on any x64 and arm64 systems. Version introduced .NET 7 Reason for change Currently, the x86 host location is added to PATH , even on x64/Arm64 systems. Depending on which .NET architecture installer is run first, a user's machine could have either the native (x64/Arm64) or the x86 host as the first location in the PATH list. This ambiguity causes problems with the initial .NET installation and during .NET servicing events. Any of these installation scenarios can modify the order of .NET hosts in PATH , making it non-deterministic. There's a high chance of behavior regression of the .NET runtime. This change streamlines the dotnet host experience on Windows 64-bit systems. Only 64-bit hosts will be available in the system's PATH environment variable: the x64 host on x64 systems and the Arm64 host on Arm64 systems. We removed the ambiguity in the order of dotnet hosts in PATH , and only one host will be present. Recommended action If you need the x86 host in the PATH environment variable on x64/Arm64 systems, add the host location to PATH manually. Affected APIs None. Breaking changes in EF Core 6.0 Article • 01/30/2023 The following API and behavior changes have the potential to break existing applications updating to EF Core 6.0. Target Framework EF Core 6.0 targets .NET 6. Applications targeting older .NET, .NET Core, and .NET Framework versions will need to target .NET 6 to use EF Core 6.0. Summary Breaking change Impact Nested optional dependents sharing a table and with no required properties cannot be saved High Changing the owner of an owned entity now throws an exception Medium Azure Cosmos DB: Related entity types are discovered as owned Medium SQLite: Connections are pooled Medium Many-to-many relationships without mapped join entities are now scaffolded Medium Cleaned up mapping between DeleteBehavior and ON DELETE values Low In-memory database validates required properties do not contain nulls Low Removed last ORDER BY when joining for collections Low DbSet no longer implements IAsyncEnumerable Low TVF return entity type is also mapped to a table by default Low Check constraint name uniqueness is now validated Low Added IReadOnly Metadata interfaces and removed extension methods Low IExecutionStrategy is now a singleton service Low SQL Server: More errors are considered transient Low Azure Cosmos DB: More characters are escaped in 'id' values Low Some Singleton services are now Scoped Low* Breaking change Impact New caching API for extensions that add or replace services Low* New snapshot and design-time model initialization procedure Low OwnedNavigationBuilder.HasIndex returns a different type now Low DbFunctionBuilder.HasSchema(null) overrides [DbFunction(Schema = "schema")] Low Pre-initialized navigations are overridden by values from database queries Low Unknown enum string values in the database are not converted to the enum default when queried Low DbFunctionBuilder.HasTranslation now provides the function arguments as Low IReadOnlyList rather than IReadOnlyCollection Default table mapping is not removed when the entity is mapped to a table-valued Low function dotnet-ef targets .NET 6 Low IModelCacheKeyFactory implementations may need to be updated to handle design- Low time caching * These changes are of particular interest to authors of database providers and extensions. High-impact changes Nested optional dependents sharing a table and with no required properties are disallowed Tracking Issue #24558 Old behavior Models with nested optional dependents sharing a table and with no required properties were allowed, but could result in data loss when querying for the data and then saving again. For example, consider the following model: C# public class Customer { public int Id { get; set; } public string Name { get; set; } public ContactInfo ContactInfo { get; set; } } [Owned] public class ContactInfo { public string Phone { get; set; } public Address Address { get; set; } } [Owned] public class Address { public string House { get; set; } public string Street { get; set; } public string City { get; set; } public string Postcode { get; set; } } None of the properties in ContactInfo or Address are required, and all these entity types are mapped to the same table. The rules for optional dependents (as opposed to required dependents) say that if all of the columns for ContactInfo are null, then no instance of ContactInfo will be created when querying for the owner Customer . However, this also means that no instance of Address will be created, even if the Address columns are non-null. New behavior Attempting to use this model will now throw the following exception: System.InvalidOperationException: Entity type 'ContactInfo' is an optional dependent using table sharing and containing other dependents without any required non shared property to identify whether the entity exists. If all nullable properties contain a null value in database then an object instance won't be created in the query causing nested dependent's values to be lost. Add a required property to create instances with null values for other properties or mark the incoming navigation as required to always create an instance. This prevents data loss when querying and saving data. Why Using models with nested optional dependents sharing a table and with no required properties often resulted in silent data loss. Mitigations Avoid using optional dependents sharing a table and with no required properties. There are three easy ways to do this: 1. Make the dependents required. This means that the dependent entity will always have a value after it is queried, even if all its properties are null. For example: C# public class Customer { public int Id { get; set; } public string Name { get; set; } [Required] public Address Address { get; set; } } Or: C# modelBuilder.Entity<Customer>( b => { b.OwnsOne(e => e.Address); b.Navigation(e => e.Address).IsRequired(); }); 2. Make sure that the dependent contains at least one required property. 3. Map optional dependents to their own table, instead of sharing a table with the principal. For example: C# modelBuilder.Entity<Customer>( b => { b.ToTable("Customers"); b.OwnsOne(e => e.Address, b => b.ToTable("CustomerAddresses")); }); The problems with optional dependents and examples of these mitigations are included in the documentation for What's new in EF Core 6.0. Medium-impact changes Changing the owner of an owned entity now throws an exception Tracking Issue #4073 Old behavior It was possible to reassign an owned entity to a different owner entity. New behavior This action will now throw an exception: The property '{entityType}.{property}' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key, first delete the dependent and invoke 'SaveChanges', and then associate the dependent with the new principal. Why Even though we don't require key properties to exist on an owned type, EF will still create shadow properties to be used as the primary key and the foreign key pointing to the owner. When the owner entity is changed it causes the values of the foreign key on the owned entity to change, and since they are also used as the primary key this results in the entity identity to change. This isn't yet fully supported in EF Core and was only conditionally allowed for owned entities, sometimes resulting in the internal state becoming inconsistent. Mitigations Instead of assigning the same owned instance to a new owner you can assign a copy and delete the old one. Azure Cosmos DB: Related entity types are discovered as owned Tracking Issue #24803 What's new: Default to implicit ownership Old behavior As in other providers, related entity types were discovered as normal (non-owned) types. New behavior Related entity types will now be owned by the entity type on which they were discovered. Only the entity types that correspond to a DbSet<TEntity> property will be discovered as non-owned. Why This behavior follows the common pattern of modeling data in Azure Cosmos DB of embedding related data into a single document. Azure Cosmos DB does not natively support joining different documents, so modeling related entities as non-owned has limited usefulness. Mitigations To configure an entity type to be non-owned call modelBuilder.Entity<MyEntity>(); SQLite: Connections are pooled Tracking Issue #13837 What's new: Default to implicit ownership Old behavior Previously, connections in Microsoft.Data.Sqlite were not pooled. New behavior Starting in 6.0, connections are now pooled by default. This results in database files being kept open by the process even after the ADO.NET connection object is closed. Why Pooling the underlying connections greatly improves the performance of opening and closing ADO.NET connection objects. This is especially noticeable for scenarios where opening the underlying connection is expensive as in the case of encryption, or in scenarios where there are a lot of short-lived connection to the database. Mitigations Connection pooling can be disabled by adding Pooling=False to a connection string. Some scenarios (like deleting the database file) may now encounter errors stating that the file is still in use. You can manually clear the connection pool before performing operations of the file using SqliteConnection.ClearPool() . C# SqliteConnection.ClearPool(connection); File.Delete(databaseFile); Many-to-many relationships without mapped join entities are now scaffolded Tracking Issue #22475 Old behavior Scaffolding (reverse engineering) a DbContext and entity types from an existing database always explicitly mapped join tables to join entity types for many-to-many relationships. New behavior Simple join tables containing only two foreign key properties to other tables are no longer mapped to explicit entity types, but are instead mapped as a many-to-many relationship between the two joined tables. Why Many-to-many relationships without explicit join types were introduced in EF Core 5.0 and are a cleaner, more natural way to represent simple join tables. Mitigations There are two mitigations. The preferred approach is to update code to use the manyto-many relationships directly. It is very rare that the join entity type needs to be used directly when it contains only two foreign keys for the many-to-many relationships. Alternately, the explicit join entity can be added back to the EF model. For example, assuming a many-to-many relationship between Post and Tag , add back the join type and navigations using partial classes: C# public partial class PostTag { public int PostsId { get; set; } public int TagsId { get; set; } public virtual Post Posts { get; set; } public virtual Tag Tags { get; set; } } public partial class Post { public virtual ICollection<PostTag> PostTags { get; set; } } public partial class Tag { public virtual ICollection<PostTag> PostTags { get; set; } } Then add configuration for the join type and navigations to a partial class for the DbContext: C# public partial class DailyContext { partial void OnModelCreatingPartial(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>(entity => { entity.HasMany(d => d.Tags) .WithMany(p => p.Posts) .UsingEntity<PostTag>( l => l.HasOne<Tag>(e => e.Tags).WithMany(e => e.PostTags).HasForeignKey(e => e.TagsId), r => r.HasOne<Post>(e => e.Posts).WithMany(e => e.PostTags).HasForeignKey(e => e.PostsId), j => { j.HasKey("PostsId", "TagsId"); j.ToTable("PostTag"); }); }); } } Finally, remove the generated configuration for the many-to-many relationship from the scaffolded context. This is needed because the scaffolded join entity type must be removed from the model before the explicit type can be used. This code will need to be removed each time the context is scaffolded, but because the code above is in partial classes it will persist. Note that with this configuration, the join entity can be used explicitly, just like in previous versions of EF Core. However, the relationship can also be used as a many-tomany relationship. This means that updating the code like this can be a temporary solution while the rest of the code is updated to use the relationship as a many-to-many in the natural way. Low-impact changes Cleaned up mapping between DeleteBehavior and ON DELETE values Tracking Issue #21252 Old behavior Some of the mappings between a relationship's OnDelete() behavior and the foreign keys' ON DELETE behavior in the database were inconsistent in both Migrations and Scaffolding. New behavior The following table illustrates the changes for Migrations. OnDelete() ON DELETE NoAction NO ACTION ClientNoAction NO ACTION OnDelete() ON DELETE Restrict RESTRICT Cascasde CASCADE ClientCascade RESTRICT NO ACTION SetNull SET NULL ClientSetNull RESTRICT NO ACTION The changes for Scaffolding are as follows. ON DELETE OnDelete() NO ACTION ClientSetNull RESTRICT ClientSetNull Restrict CASCADE Cascade SET NULL SetNull Why The new mappings are more consistent. The default database behavior of NO ACTION is now preferred over the more restrictive and less performant RESTRICT behavior. Mitigations The default OnDelete() behavior of optional relationships is ClientSetNull. Its mapping has changed from RESTRICT to NO ACTION. This may cause a lot of operations to be generated in your first migration added after upgrading to EF Core 6.0. You can choose to either apply these operations or manually remove them from the migration since they have no functional impact on EF Core. SQL Server doesn't support RESTRICT, so these foreign keys were already created using NO ACTION. The migration operations will have no affect on SQL Server and are safe to remove. In-memory database validates required properties do not contain nulls Tracking Issue #10613 Old behavior The in-memory database allowed saving null values even when the property was configured as required. New behavior The in-memory database throws a Microsoft.EntityFrameworkCore.DbUpdateException when SaveChanges or SaveChangesAsync is called and a required property is set to null. Why The in-memory database behavior now matches the behavior of other databases. Mitigations The previous behavior (i.e. not checking null values) can be restored when configuring the in-memory provider. For example: C# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseInMemoryDatabase("MyDatabase", b => b.EnableNullChecks(false)); } Removed last ORDER BY when joining for collections Tracking Issue #19828 Old behavior When performing SQL JOINs on collections (one-to-many relationships), EF Core used to add an ORDER BY for each key column of the joined table. For example, loading all Blogs with their related Posts was done via the following SQL: SQL SELECT [b].[BlogId], [b].[Name], [p].[PostId], [p].[BlogId], [p].[Title] FROM [Blogs] AS [b] LEFT JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId] ORDER BY [b].[BlogId], [p].[PostId] These orderings are necessary for proper materialization of the entities. New behavior The very last ORDER BY for a collection join is now omitted: SQL SELECT [b].[BlogId], [b].[Name], [p].[PostId], [p].[BlogId], [p].[Title] FROM [Blogs] AS [b] LEFT JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId] ORDER BY [b].[BlogId] An ORDER BY for the Post's ID column is no longer generated. Why Every ORDER BY imposes additional work at the database side, and the last ordering isn't necessary for EF Core's materialization needs. Data shows that removing this last ordering can produce a significant performance improvement in some scenarios. Mitigations If your application expects joined entities to be returned in a particular order, make that explicit by adding a LINQ OrderBy operator to your query. DbSet no longer implements IAsyncEnumerable Tracking Issue #24041 Old behavior DbSet<TEntity>, which is used to execute queries on DbContext, used to implement IAsyncEnumerable<T>. New behavior DbSet<TEntity> no longer directly implements IAsyncEnumerable<T>. Why DbSet<TEntity> was originally made to implement IAsyncEnumerable<T> mainly in order to allow direct enumeration on it via the foreach construct. Unfortunately, when a project also references System.Linq.Async in order to compose async LINQ operators client-side, this resulted in an ambiguous invocation error between the operators defined over IQueryable<T> and those defined over IAsyncEnumerable<T> . C# 9 added extension GetEnumerator support for foreach loops, removing the original main reason to reference IAsyncEnumerable . The vast majority of DbSet usages will continue to work as-is, since they compose LINQ operators over DbSet , enumerate it, etc. The only usages broken are those which attempt to cast DbSet directly to IAsyncEnumerable . Mitigations If you need to refer to a DbSet<TEntity> as an IAsyncEnumerable<T>, call DbSet<TEntity>.AsAsyncEnumerable to explicitly cast it. TVF return entity type is also mapped to a table by default Tracking Issue #23408 Old behavior An entity type was not mapped to a table by default when used as a return type of a TVF configured with HasDbFunction. New behavior An entity type used as a return type of a TVF retains the default table mapping. Why It isn't intuitive that configuring a TVF removes the default table mapping for the return entity type. Mitigations To remove the default table mapping, call ToTable(EntityTypeBuilder, String): C# modelBuilder.Entity<MyEntity>().ToTable((string?)null)); Check constraint name uniqueness is now validated Tracking Issue #25061 Old behavior Check constraints with the same name were allowed to be declared and used on the same table. New behavior Explicitly configuring two check constraints with the same name on the same table will now result in an exception. Check constraints created by a convention will be assigned a unique name. Why Most databases don't allow two check constraints with the same name to be created on the same table, and some require them to be unique even across tables. This would result in exception being thrown when applying a migration. Mitigations In some cases, valid check constraint names might be different due to this change. To specify the desired name explicitly, call HasName: C# modelBuilder.Entity<MyEntity>().HasCheckConstraint("CK_Id", "Id > 0", c => c.HasName("CK_MyEntity_Id")); Added IReadOnly Metadata interfaces and removed extension methods Tracking Issue #19213 Old behavior There were three sets of metadata interfaces: IModel, IMutableModel and IConventionModel as well as extension methods. New behavior A new set of IReadOnly interfaces has been added, e.g. IReadOnlyModel. Extension methods that were previously defined for the metadata interfaces have been converted to default interface methods. Why Default interface methods allow the implementation to be overridden, this is leveraged by the new run-time model implementation to offer better performance. Mitigations These changes shouldn't affect most code. However, if you were using the extension methods via the static invocation syntax, it would need to be converted to instance invocation syntax. IExecutionStrategy is now a singleton service Tracking Issue #21350 New behavior IExecutionStrategy is now a singleton service. This means that any added state in custom implementations will remain between executions and the delegate passed to ExecutionStrategy will only be executed once. Why This reduced allocations on two hot paths in EF. Mitigations Implementations deriving from ExecutionStrategy should clear any state in OnFirstExecution(). Conditional logic in the delegate passed to ExecutionStrategy should be moved to a custom implementation of IExecutionStrategy. SQL Server: More errors are considered transient Tracking Issue #25050 New behavior The errors listed in the issue above are now considered transient. When using the default (non-retrying) execution strategy, these errors will now be wrapped in an addition exception instance. Why We continue to gather feedback from both users and SQL Server team on which errors should be considered transient. Mitigations To change the set of errors that are considered transient, use a custom execution strategy that could be derived from SqlServerRetryingExecutionStrategy - Connection Resiliency - EF Core. Azure Cosmos DB: More characters are escaped in 'id' values Tracking Issue #25100 Old behavior In EF Core 5, only '|' was escaped in id values. New behavior In EF Core 6, '/' , '\' , '?' and '#' are also escaped in id values. Why These characters are invalid, as documented in Resource.Id. Using them in id will cause queries to fail. Mitigations You can override the generated value by setting it before the entity is marked as Added : C# var entry = context.Attach(entity); entry.Property("__id").CurrentValue = "MyEntity|/\\?#"; entry.State = EntityState.Added; Some Singleton services are now Scoped Tracking Issue #25084 New behavior Many query services and some design-time services that were registered as Singleton are now registered as Scoped . Why The lifetime had to be changed to allow a new feature - DefaultTypeMapping - to affect queries. The design-time services lifetimes have been adjusted to match the run-time services lifetimes to avoid errors when using both. Mitigations Use TryAdd to register EF Core services using the default lifetime. Only use TryAddProviderSpecificServices for services that are not added by EF. New caching API for extensions that add or replace services Tracking Issue #19152 Old behavior In EF Core 5, GetServiceProviderHashCode returned long and was used directly as part of the cache key for the service provider. New behavior GetServiceProviderHashCode now returns int and is only used to calculate the hash code of the cache key for the service provider. Also, ShouldUseSameServiceProvider needs to be implemented to indicate whether the current object represents the same service configuration and thus can use the same service provider. Why Just using a hash code as part of the cache key resulted in occasional collisions that were hard to diagnose and fix. The additional method ensures that the same service provider is used only when appropriate. Mitigations Many extensions don't expose any options that affect registered services and can use the following implementation of ShouldUseSameServiceProvider: C# private sealed class ExtensionInfo : DbContextOptionsExtensionInfo { public ExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { } ... public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => other is ExtensionInfo; } Otherwise, additional predicates should be added to compare all relevant options. New snapshot and design-time model initialization procedure Tracking Issue #22031 Old behavior In EF Core 5, specific conventions needed to be invoked before the snapshot model was ready to be used. New behavior IModelRuntimeInitializer was introduced to hide some of the required steps, and a runtime model was introduced that doesn't have all the migrations metadata, so the design-time model should be used for model diffing. Why IModelRuntimeInitializer abstracts away the model finalization steps, so these can now be changed without further breaking changes for the users. The optimized run-time model was introduced to improve run-time performance. It has several optimizations, one of which is removing metadata that is not used at run-time. Mitigations The following snippet illustrates how to check whether the current model is different from the snapshot model: C# var snapshotModel = migrationsAssembly.ModelSnapshot?.Model; if (snapshotModel is IMutableModel mutableModel) { snapshotModel = mutableModel.FinalizeModel(); } if (snapshotModel != null) { snapshotModel = context.GetService<IModelRuntimeInitializer> ().Initialize(snapshotModel); } var hasDifferences = context.GetService<IMigrationsModelDiffer> ().HasDifferences( snapshotModel?.GetRelationalModel(), context.GetService<IDesignTimeModel>().Model.GetRelationalModel()); This snippet shows how to implement IDesignTimeDbContextFactory<TContext> by creating a model externally and calling UseModel: C# internal class MyDesignContext : IDesignTimeDbContextFactory<MyContext> { public TestContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DB")); var modelBuilder = SqlServerConventionSetBuilder.CreateModelBuilder(); CustomizeModel(modelBuilder); var model = modelBuilder.Model.FinalizeModel(); var serviceContext = new MyContext(optionsBuilder.Options); model = serviceContext.GetService<IModelRuntimeInitializer> ().Initialize(model); return new MyContext(optionsBuilder.Options); } } OwnedNavigationBuilder.HasIndex returns a different type now Tracking Issue #24005 Old behavior In EF Core 5, HasIndex returned IndexBuilder<TEntity> where TEntity is the owner type. New behavior HasIndex now returns IndexBuilder<TDependentEntity> , where TDependentEntity is the owned type. Why The returned builder object wasn't typed correctly. Mitigations Recompiling your assembly against the latest version of EF Core will be enough to fix any issues caused by this change. DbFunctionBuilder.HasSchema(null) overrides [DbFunction(Schema = "schema")] Tracking Issue #24228 Old behavior In EF Core 5, calling HasSchema with null value didn't store the configuration source, thus DbFunctionAttribute was able to override it. New behavior Calling HasSchema with null value now stores the configuration source and prevents the attribute from overriding it. Why Configuration specified with the ModelBuilder API should not be overridable by data annotations. Mitigations Remove the HasSchema call to let the attribute configure the schema. Pre-initialized navigations are overridden by values from database queries Tracking Issue #23851 Old behavior Navigation properties set to an empty object were left unchanged for tracking queries, but were overwritten for non-tracking queries. For example, consider the following entity types: C# public class Foo { public int Id { get; set; } public Bar Bar { get; set; } = new(); // Don't do this. } public class Bar { public int Id { get; set; } } A no-tracking query for Foo including Bar set Foo.Bar to the entity queried from the database. For example, this code: C# var foo = context.Foos.AsNoTracking().Include(e => e.Bar).Single(); Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}"); Printed Foo.Bar.Id = 1 . However, the same query run for tracking didn't overwrite Foo.Bar with the entity queried from the database. For example, this code: C# var foo = context.Foos.Include(e => e.Bar).Single(); Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}"); Printed Foo.Bar.Id = 0 . New behavior In EF Core 6.0, the behavior of tracking queries now matches that of no-tracking queries. This means that both this code: C# var foo = context.Foos.AsNoTracking().Include(e => e.Bar).Single(); Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}"); And this code: C# var foo = context.Foos.Include(e => e.Bar).Single(); Console.WriteLine($"Foo.Bar.Id = {foo.Bar.Id}"); Print Foo.Bar.Id = 1 . Why There are two reasons for making this change: 1. To ensure that tracking and no-tracking queries have consistent behavior. 2. When a database is queried it is reasonable to assume that the application code wants to get back the values that are stored in the database. Mitigations There are two mitigations: 1. Do not query for objects from the database that should not be included in the results. For example, in the code snippets above, do not Include Foo.Bar if the Bar instance should not be returned from the database and included in the results. 2. Set the value of the navigation after querying from the database. For example, in the code snippets above, call foo.Bar = new() after running the query. Also, consider not initializing related entity instances to default objects. This implies that the related instance is a new entity, not saved to the database, with no key value set. If instead the related entity does exist in the database, then the data in code is fundamentally at odds with the data stored in the database. Unknown enum string values in the database are not converted to the enum default when queried Tracking Issue #24084 Old behavior Enum properties can be mapped to string columns in the database using HasConversion<string>() or EnumToStringConverter . This results in EF Core converting string values in the column to matching members of the .NET enum type. However, if the string value did not match and enum member, then the property was set to the default value for the enum. New behavior EF Core 6.0 now throws an InvalidOperationException with the message "Cannot convert string value ' {value} ' from the database to any value in the mapped ' {enumType} ' enum." Why Converting to the default value can result in database corruption if the entity is later saved back to the database. Mitigations Ideally, ensure that the database column only contains valid values. Alternately, implement a ValueConverter with the old behavior. DbFunctionBuilder.HasTranslation now provides the function arguments as IReadOnlyList rather than IReadOnlyCollection Tracking Issue #23565 Old behavior When configuring translation for a user-defined function using HasTranslation method, the arguments to the function were provided as IReadOnlyCollection<SqlExpression> . New behavior In EF Core 6.0, the arguments are now provided as IReadOnlyList<SqlExpression> . Why IReadOnlyList allows to use indexers, so the arguments are now easier to access. Mitigations None. IReadOnlyList implements IReadOnlyCollection interface, so the transition should be straightforward. Default table mapping is not removed when the entity is mapped to a table-valued function Tracking Issue #23408 Old behavior When an entity was mapped to a table-valued function, its default mapping to a table was removed. New behavior In EF Core 6.0, the entity is still mapped to a table using default mapping, even if it's also mapped to table-valued function. Why Table-valued functions which return entities are often used either as a helper or to encapsulate an operation returning a collection of entities, rather than as a strict replacement of the entire table. This change aims to be more in line with the likely user intention. Mitigations Mapping to a table can be explicitly disabled in the model configuration: C# modelBuilder.Entity<MyEntity>().ToTable((string)null); dotnet-ef targets .NET 6 Tracking Issue #27787 Old behavior The dotnet-ef command has targeted .NET Core 3.1 for a while now. This allowed you to use newer version of the tool without installing newer versions of the .NET runtime. New behavior In EF Core 6.0.6, the dotnet-ef tool now targets .NET 6. You can still use the tool on projects targeting older versions of .NET and .NET Core, but you'll need to install the .NET 6 runtime in order to run the tool. Why The .NET 6.0.200 SDK updated the behavior of dotnet tool install on osx-arm64 to create an osx-x64 shim for tools targeting .NET Core 3.1. In order to maintain a working default experience for dotnet-ef, we had to update it to target .NET 6. Mitigations To run dotnet-ef without installing the .NET 6 runtime, you can install an older version of the tool: .NET CLI dotnet tool install dotnet-ef --version 3.1.* IModelCacheKeyFactory implementations may need to be updated to handle design-time caching Tracking Issue #25154 Old behavior IModelCacheKeyFactory did not have an option to cache the design-time model separately from the runtime model. New behavior IModelCacheKeyFactory has a new overload that allows the design-time model to be cached separately from the runtime model. Not implementing this method may result in an exception similar to: System.InvalidOperationException: 'The requested configuration is not stored in the read-optimized model, please use 'DbContext.GetService<IDesignTimeModel> ().Model'.' Why Implementation of compiled models required separation of the design-time (used when building the model) and runtime (used when executing queries, etc.) models. If the runtime code needs access to design-time information, then the design-time model must be cached. Mitigations Implement the new overload. For example: C# public object Create(DbContext context, bool designTime) => context is DynamicContext dynamicContext ? (context.GetType(), dynamicContext.UseIntProperty, designTime) : (object)context.GetType(); AddProvider checks for non-null provider Article • 11/08/2021 Microsoft.Extensions.Logging.LoggerFactory implements ILoggerFactory with an AddProvider(ILoggerProvider) method. null providers aren't accepted and will cause an ArgumentNullException to be thrown. Version introduced 6.0 RC 1 Previous behavior Previously, AddProvider(ILoggerProvider) did not perform any validation of the provider argument. As such, the method considered null to be a "valid" provider and added it to the collection of providers. New behavior Starting in .NET 6, null providers aren't accepted, and AddProvider(ILoggerProvider) throws an ArgumentNullException if the logging provider argument is null . For example, the following code throws an ArgumentNullException: C# var factory = new LoggerFactory(); ((ILoggerFactory)factory).AddProvider(null)); Type of breaking change This change can affect source compatibility. Reason for change The previous behavior caused some operations inside the class to unnecessarily throw NullReferenceException exceptions. For example, the LoggerFactory.Dispose() method will capture the exception and do nothing. Recommended action Ensure you're not passing a null provider to AddProvider(ILoggerProvider). Affected APIs Microsoft.Extensions.Logging.LoggerFactory.AddProvider(ILoggerProvider) FileConfigurationProvider.Load throws InvalidDataException Article • 11/08/2021 When Load() fails to load a file, it throws an InvalidDataException. If the file or directory doesn't exist, it throws a DirectoryNotFoundException or FileNotFoundException. Version introduced 6.0 RC 1 Previous behavior When loading failed, Load() did not throw an InvalidDataException. New behavior Starting in .NET 6, Load() throws an InvalidDataException if a file fails to load. In addition, the exception message includes the file path that failed to load. Type of breaking change This change can affect source compatibility. Reason for change This change improves the debugging experience. When a file fails to load, it's helpful to know which file failed to load. Recommended action If you are catching specific exceptions when calling Load(), make sure to also catch InvalidDataException. Affected APIs Microsoft.Extensions.Configuration.FileConfigurationProvider.Load() Repeated XML elements include index Article • 10/05/2022 When Microsoft.Extensions.Configuration.Xml is used to read an XML document that has repeated XML elements without a Name attribute, the Configuration entries created with these repeated elements now have an index appended to their configuration path. Version introduced .NET 6 Previous behavior Consider the following XML snippets that show repeated elements without a distinguishing Name attribute. XML <settings> <Data ConnectionString="TestConnectionString" /> <Data Provider="MySql" /> </settings> XML <configuration> <Level1> <Level2 Key1="Value1" /> <Level2 Key2="Value2" /> </Level1> </configuration> The configurations created from these XML files were: txt Data:ConnectionString = TestConnectionString Data:Provider = MySql and txt Level1:Level2:Key1 = Value1 Level1:Level2:Key2 = Value2 respectively. New behavior The configurations created from the XML files in the Previous behavior section are now: txt Data:0:ConnectionString = TestConnectionString Data:1:Provider = MySql and txt Level1:Level2:0:Key1 = Value1 Level1:Level2:1:Key2 = Value2 respectively. Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced to fully support repeated XML elements that don't have a Name attribute. The previous behavior only allowed for repeated elements to set unique values (using attributes or subelements). If repeated XML elements had the same attribute, an exception was thrown. Recommended action To get the original behavior, you can update your XML to collapse the two attributes into the same element. For example: XML <configuration> <Level1> <Level2 Key1="Value1" Key2="Value2" /> </Level1> </configuration> Alternatively, you can update your code to expect indices (such as 0, 1, 2) in the IConfiguration keys: C# configRoot.GetSection("Level1:Level2") becomes C# configRoot.GetSection("Level1:Level2:0") Affected APIs Microsoft.Extensions.Configuration.XmlConfigurationExtensions Microsoft.Extensions.Configuration.Xml.XmlStreamConfigurationProvider Microsoft.Extensions.Configuration.Xml.XmlConfigurationSource See also XML configuration provider Resolving disposed ServiceProvider throws exception Article • 11/10/2021 When a service is resolved after the service provider has been disposed, the affected methods now throw an ObjectDisposedException instead of causing a deadlock. Version introduced 6.0 RC 1 Previous behavior Previously, in the rare case that an application resolved a service after the service provider was disposed, it led to a deadlock. New behavior Starting in .NET 6, an ObjectDisposedException is thrown when a service is resolved after the service provider has been disposed, and there's no deadlock. Type of breaking change This change can affect source compatibility. Reason for change This change was introduced to fix the deadlock scenario. Recommended action Catch ObjectDisposedException when calling any of the affected APIs. Affected APIs System.IServiceProvider.GetService(Type) Microsoft.Extensions.DependencyInjection.ISupportRequiredService.GetRequiredSe rvice(Type) Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRe quiredService(IServiceProvider, Type) Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRe quiredService<T>(IServiceProvider) Culture creation and case mapping in globalization-invariant mode Article • 01/27/2022 This breaking change affects globalization-invariant mode in two ways: Previously, .NET allowed any culture to be created in globalization-invariant mode, as long as the culture name conformed to BCP-47 . However, the invariant culture data was used instead of the real culture data. Starting in .NET 6, an exception is thrown if you create any culture other than the invariant culture in globalization-invariant mode. Previously, globalization-invariant mode only supported case mapping for ASCII characters. Starting in .NET 6, globalization-invariant mode provides full casemapping support for all Unicode-defined characters. Case mapping is used in operations such as string comparisons, string searches, and upper or lower casing strings. Globalization-invariant mode is used for apps that don't required any globalization support. That is, the app runs without access to culture-specific data and behavior. Globalization-invariant mode is enabled by default on some Docker containers, for example, Alpine containers. Old behavior In previous .NET versions when globalization-invariant mode is enabled: If an app creates a culture that's not the invariant culture, the operation succeeds but the returned culture always use the invariant culture data instead of the real culture data. Case mapping was performed only for ASCII characters. For example: C# if ("Á".Equals("á", StringComparison.CurrentCultureIgnoreCase)) // Evaluates to false. New behavior Starting in .NET 6 when globalization-invariant mode is enabled: If an app attempts to create a culture that's not the invariant culture, a CultureNotFoundException exception is thrown. Case mapping is performed for all Unicode-defined characters. For example: C# if ("Á".Equals("á", StringComparison.CurrentCultureIgnoreCase)) // Evaluates to true. Version introduced .NET 6 Reason for change The culture-creation change was introduced to more easily diagnose culture-related problems. Some users are unaware that their apps are running in an environment where globalization-invariant mode is enabled. They may experience unexpected behavior and don't make the association with globalization-invariant mode, so it's hard to diagnose the issue. The full case-mapping support was introduced for better usability and experience in globalization-invariant mode. Recommended action In most cases, no action is needed. However, if you desire the previous culture-creation behavior, you can set a runtime configuration option to allow creation of any culture in globalization-invariant mode. For more information, see Predefined cultures. Affected APIs CultureInfo System.Globalization.CultureInfo.CreateSpecificCulture(String) System.Globalization.CultureInfo.GetCultureInfo RegionInfo Any APIs that perform string casing, comparison, or searching See also .NET globalization invariant mode Invariant, neutral, and specific cultures Static abstract members declared in interfaces Article • 09/29/2022 .NET 6 previews a new feature where static interface members can be marked as abstract . This feature involves several changes to the ECMA 335 spec to allow intermediate language (IL) metadata patterns that were previously considered illegal. For more information, see dotnet/runtime#49558 . Old behavior If a static interface was marked as abstract : The C# compiler generated error CS0112. Tools and other compilers generated illegal IL metadata. New behavior Starting in .NET 6, static interface members can be marked as abstract and will compile successfully. In addition, the IL metadata patterns that are generated are now considered legal due to changes in the ECMA 335 spec. The implementation of static abstract interface members is provided by types that implement the interface. 7 Note For .NET 6, you must enable preview features in your project to be able to mark an interface member as static abstract . Since this is a newly legal IL pattern, existing tooling may incorrectly process the associated metadata and have unexpected behavior. It's likely that tooling will encounter the new metadata pattern, because interfaces with static abstract members now appear on the primitive types, for example, System.Int32. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced because there was no way to abstract over static members and write generalized code that applies across types that define those static members. This was particularly problematic for member kinds that only exist in a static form, for example, operators. Recommended action Update any tooling that consumes .NET binaries or C# source code to account for the new concept of static abstract interface members, including those that now exist on the .NET primitive types. Affected APIs N/A See also Tutorial: Explore static virtual members in interfaces Coerce call arguments according to ECMA-335 Article • 07/12/2022 ECMA-335 (Table III.9: Signature Matching) describes which implicit conversions are supported for call arguments. This change adds checking for the supported conversions. Version introduced 6.0 Change description In previous .NET versions, the just-in-time (JIT) compiler does not coerce call arguments according to ECMA-335. This leads to undefined behavior on some platforms. For example, on x86, passing a long value as an int register leaves the register undefined. Starting in .NET 6, if implicit conversion is not allowed, then the JIT compiler throws an InvalidProgramException. There are two conversion cases that are still allowed: int8 -> nint on 64-bit platform (because it's used often and doesn't lead to bad code) byref -> nint Reason for change The previous behavior caused silent, bad code generation on some platforms, including Arm64 Apple. Recommended action If you updated to .NET 6 and your app throws InvalidProgramException exceptions because of this change, use an explicit conversion for the affected argument or fix the callee declaration. Affected APIs None. Port removed from SPN for Kerberos and Negotiate Article • 11/08/2021 When using HttpClient with Kerberos or Negotiate authentication, non-default ports are no longer included in service principal names (SPN) to look up services. This new .NET 6 behavior is consistent with .NET Core 3.1 and earlier versions. Previous behavior If you connected to a service on a non-default port, .NET 5 included a port component when constructing the SPN to look up the service. New behavior Starting in .NET 6, by default, the SPN is not constructed with a port component, even for non-default ports. Version introduced 6.0 RC 1 Type of breaking change This change can affect binary compatibility. Reason for change We want to bring back the behavior from .NET Core 1.0 - 3.1 that customers had started to depend on. Recommended action If you need to preserve .NET 5 behavior, you can set the app context switch System.Net.Http.UsePortInSpn or the environment variable DOTNET_SYSTEM_NET_HTTP_USEPORTINSPN to true . Affected APIs System.Net.Http.HttpClient behavior WebRequest, WebClient, and ServicePoint are obsolete Article • 11/17/2021 WebRequest, WebClient, and ServicePoint classes are marked as obsolete and generate a SYSLIB0014 warning at compile time. Version introduced 6.0 Change description WebRequest, WebClient, and ServicePoint classes were added to .NET Core in version 2.0 for backward compatibility. However, they introduced several runtime breaking changes, for example, WebRequest.GetRequestStream allocates memory for the whole response, and WebClient.CancelAsync doesn't always cancel immediately. Starting in .NET 6, the WebRequest, WebClient, and ServicePoint classes are deprecated. The classes are still available, but they're not recommended for new development. To reduce the number of analyzer warnings, only construction methods are decorated with the ObsoleteAttribute attribute. Recommended action Use the System.Net.Http.HttpClient class instead. For FTP, since HttpClient doesn't support it, we recommend using a third-party library. Affected APIs WebRequest HttpWebRequest FtpWebRequest WebClient ServicePoint -p option for dotnet run is deprecated Article • 12/02/2021 -p is deprecated as an abbreviation for --project , and using -p generates a warning. This warning comes from the CLI parser, so it won't generally cause failures when warnings are treated as errors. However, if your process wraps MSBuild or CI and checks for the text "Warning", the warning will appear in that check. Version introduced .NET SDK 6.0.100 Old behavior In previous .NET versions, -p indicated --project . New behavior Starting in .NET 6, passing -p to dotnet run results in a warning that it is deprecated and to use the full --project option instead. Despite the warning, -p is still a valid abbreviation for --project . Reason for change We are deprecating -p because of the close relationship dotnet run has with dotnet build and dotnet publish . This breaking change is the first step in aligning abbreviations for these commands. For more information, see Spec for resolving '-p' in 'dotnet run' . Recommended action If you encounter the new warning, use --project . If you have a project argument that includes an = and you use the -p abbreviation, the option will be interpreted as -property . Review any scripts that use dotnet run where you might overlook the warning if -p is used. If you have any scripts that are using dotnet run and process the output, you could encounter a break. dotnet run typically doesn't output anything of its own if there are no errors, so you only get the output of the program that's being run. If you have a script or other program that wraps dotnet run and parses the output, the warning would be unexpected text and may cause a failure. Affected APIs N/A See also Spec for resolving '-p' in 'dotnet run' C# code in templates not supported by earlier versions Article • 11/29/2022 Starting in .NET 6, the project templates that ship with the .NET SDK use the latest C# language features. The following language features are used in template-generated code or enabled by default in the project: Top-level statements Global using directives File-scoped namespaces Target-typed new expressions Nullable reference types Async Main return values Some of the latest C# language features are not supported by previous target frameworks, so you might experience issues in the following scenarios: When you use a .NET 6 template and then change the target framework to a previous version. When you use a .NET 6 template and then multi-target by adding a previous target framework version. Version introduced .NET SDK 6.0.100 Old behavior In previous .NET versions, you can change the target framework to a previous version or add an additional version without having to change the C# code created by the project template. New behavior Starting in .NET 6, when you change or add a target framework, you may need to change the C# code generated by the template to avoid using unsupported language features. The project won't build without these changes. The compiler errors and warnings usually guide you on how to change the generated code to make it compatible with new target framework. Change category This change affects source compatibility. Reason for change We want the project templates to be synchronized with the latest language features. The main usage scenario of targeting the latest framework uses the latest C# language features. Recommended action If you encounter compile-time errors and warnings when you retarget to an earlier framework version, use that information to guide you in changing the generated code to make it compatible with the target framework you selected. To avoid compile-time errors when targeting an older framework, follow these suggestions: Avoid changing the target framework to a previous version. Instead, select the target framework you want during project creation in Visual Studio or at the command line by using dotnet new <templateName> --framework <targetFramework> . When creating a multi-target project, select the lowest target-framework version when you create the project. Add the additional target frameworks after the project is created. Affected APIs N/A EditorConfig files implicitly included Article • 01/24/2022 Roslyn analyzers added support for parsing and respecting .editorconfig file options before the compiler added support for these files. To work around this limitation, .editorconfig files had to be included as AdditionalFiles project items. Now that the compiler implicitly includes .editorconfig files in a project, you'll get an error if you include them as AdditionalFiles project items. Version introduced .NET 6 Previous behavior .editorconfig files could be included as AdditionalFiles project items. New behavior Starting with the .NET 6 SDK, you'll get the following error at compile time if you include an .editorconfig file as an AdditionalFiles project item: error AD0001: Analyzer [...] threw an exception of type 'System.InvalidOperationException' with message 'Passing '.editorconfig' files as additional files is no longer needed. It will be implicitly discovered (if the file is in the project's directory or any ancestor directory), or it should be converted into a 'globalconfig'. 7 Note This warning only appears in .NET 6. It was removed in .NET 7. Change category This change may affect source compatibility. Reason for change The compiler now supports .editorconfig files, and they're implicitly included in a project if the file is in the project directory or an ancestor directory. Recommended action If the .editorconfig file is in the project directory or an ancestor directory, remove the <AdditionalFiles> item for the .editorconfig file from your project file. Otherwise, convert the .editorconfig file to a Global AnalyzerConfig file, and change the AdditionalFiles item to a GlobalAnalyzerConfigFiles item in your project file. Affected APIs N/A Generate apphost for macOS Article • 12/11/2021 When building on macOS, the .NET SDK now produces an executable for app projects. Since .NET Core 3.0, the .NET SDK has created an executable for app projects when building on non-macOS operating systems. However, it did not create an executable on macOS since we weren't signing this binary. That resulted in an app that was recognized as dangerous by the OS, which made it hard for the user to run it. The .NET 6 SDK can sign the app executable, so it now produces the executable by default. Version introduced .NET SDK 6.0.100 Old behavior The apphost executable was not generated by default. You could explicitly ask the SDK to generate an executable by setting the UseAppHost property to true . New behavior When you run dotnet build or dotnet publish , the apphost is now generated by default and is signed using the native command-line codesign, making it easier for users to execute the binary. Reason for change We implemented the necessary changes in the HostModel to be able to code-sign executables. Recommended action If your app targets macOS and you don't want the apphost to be generated, set the UseAppHost property to false to prevent the SDK from generating this file. This setting does not affect dotnet tool install , which always generates an executable. Affected APIs N/A Generate error for duplicate files in publish output Article • 12/02/2021 The .NET SDK generates a new error ( NETSDK1152 ) in cases where files from different source paths would be copied to the same file path in the publish output. This can happen when a project and its project references include a file with the same name that's included in the publish output. Version introduced .NET SDK 6.0.100 Old behavior Both files were copied to the same destination. The second file to be copied overwrote the first file, and which file "won" was mostly arbitrary. In some cases, the build failed. For example, when trying to create a single-file app, the bundler failed with an ArgumentException, as shown in the following build output: shell C:\Program Files\dotnet\sdk\5.0.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publis h.targets(962,5): error MSB4018: The "GenerateBundle" task failed unexpectedly. [C:\repro\repro.csproj] C:\Program Files\dotnet\sdk\5.0.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publis h.targets(962,5): error MSB4018: System.ArgumentException: Invalid input specification: Found multiple entries with the same BundleRelativePath [C:\repro\repro.csproj] C:\Program Files\dotnet\sdk\5.0.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publis h.targets(962,5): error MSB4018: at Microsoft.NET.HostModel.Bundle.Bundler.GenerateBundle(IReadOnlyList`1 fileSpecs) [C:\repro\repro.csproj] New behavior Starting in .NET 6, MSBuild removes duplicate files that are copied to the publish folder if both the source and destination are the same. If there are any remaining duplicates, a NETSDK1152 error is generated and lists the files that are duplicated. Reason for change Duplicate files in the publish output sometimes caused build breaks or unpredictable behavior. Recommended action Ideally, you should update your project to avoid situations where multiple files with the same name are copied to the publish output. The error message includes the name of the duplicate file. Some causes for duplicate files include: An ASP.NET Core project that references an ASP.NET Core web service, and each has its own appsettings.json file. A project item where CopyToOutputDirectory is unnecessarily set to Always . Binary log files can be useful for finding the cause of the duplicated files. Alternatively, you can set the ErrorOnDuplicatePublishOutputFiles property to false . Affected APIs N/A GetTargetFrameworkProperties and GetNearestTargetFramework removed from ProjectReference protocol Article • 12/02/2021 The GetTargetFrameworkProperties target and GetNearestTargetFramework task have been removed from the .NET SDK. Version introduced .NET SDK 6.0.100 Old behavior The GetTargetFrameworkProperties target and the GetNearestTargetFramework task were available but not used. However, custom MSBuild logic could take a dependency on them. New behavior The GetTargetFrameworkProperties target and the GetNearestTargetFramework task no longer exist. Reason for change The GetTargetFrameworkProperties target and the GetNearestTargetFramework task were deprecated in MSBuild 15.5, and .NET 6 removes them completely. Recommended action Use GetTargetFrameworks instead. For more information, see Targets required to be referenceable . Affected APIs N/A Install location for x64 emulated on Arm64 Article • 07/15/2022 We've moved the install location of the x64 version of the .NET SDK and runtime on Arm64 hardware. Previously, the x64 and Arm64 versions installed to the same location, leading to a broken state. In addition, the PATH environment variable value was being set for both installations, so depending on install order, you might have an unexpected version of the dotnet command used by default. Version introduced .NET 6 RC 2 Previous behavior In previous versions, both the Arm64 and x64 versions of .NET SDK and runtime installed to the same location on Arm64 hardware: macOS: /usr/local/share/dotnet Windows: %ProgramFiles%\dotnet This worked if only one version was installed, but was completely broken if both were installed. New behavior In .NET 6, the x64 version of .NET installs to a subfolder named x64 on Arm64 hardware: macOS: /usr/local/share/dotnet/x64 Windows: %ProgramFiles%\dotnet\x64 For more information, see Install location . Change category This change may affect source compatibility. Reason for change Without this change, the x64 and Arm64 versions of the .NET SDK and .NET runtime install to the same location on Arm64 hardware. This leads to being in a completely broken state. This change allows customers to develop for both x64 and Arm64 at the same time. Recommended action If you need to use the x64 version of the dotnet command, manually add that file path to the PATH environment variable. Affected APIs N/A See also x64 emulation model MSBuild no longer supports calling GetType() Article • 09/29/2021 MSBuild 17 no longer supports calling the GetType() instance method within property functions. This method allowed unpredictable code execution during evaluation and could cause Visual Studio hangs. Version introduced .NET SDK 6.0.100-rc1 Previous behavior GetType() calls in MSBuild property functions would execute and sometimes caused unpredictable behavior in Visual Studio. New behavior Starting with the .NET 6 SDK, if you call GetType() in an MSBuild property function, you'll see the following compile-time error during project evaluation: The function "GetType" on type "System.String" is not available for execution as an MSBuild property function. Change category This change affects source compatibility. Reason for change This functionality was not documented or commonly used. It caused performance and reliability issues with project loading, especially in Visual Studio. The only known common use of this pattern was in the CBT system deprecated. , which has been Recommended action Replace any calls to GetType() with alternative MSBuild logic. Affected APIs N/A .NET can't be installed to custom location Article • 08/08/2023 You can no longer change the installation path of .NET with the Windows Installer package. To install .NET to a different path, use the dotnet-install scripts. Version introduced .NET 6 Old behavior Previously, you could set DOTNET_HOME prior to running the Windows MSI installer to install to a location other than Program Files\dotnet. New behavior Starting in .NET 6, DOTNET_HOME is ignored and the SDK and runtime will always install under Program Files\dotnet on Windows. This impacts all .NET installers, including all three runtimes, the hosting bundle, and the SDK installer. It also impacts all architectures, even though the driver of the change was ARM64 support. Reason for change To support SxS architecture installs on ARM64, the x64 version of dotnet must be installed to a location known to the ARM64 dotnet. This means that the native architecture version of dotnet goes in Program Files\dotnet. And on ARM64, the x64 version is installed to Program Files\dotnet\x64, so it can be found when multiple platforms are targeted. Recommended action To install to a custom location, use install scripts instead. Affected APIs N/A OutputType not changed from Exe to WinExe for Windows Forms and WPF projects Article • 09/15/2021 In .NET 5, a change was made to automatically change OutputType from Exe to WinExe for WPF and Windows Forms apps. In .NET 6, we are reverting that change and OutputType will no longer be changed by the SDK. Version introduced .NET 6 RC 1 Previous behavior If a project targeted .NET 5 or higher, OutputType was set to Exe , and UseWindowsForms or UseWPF was set to true , then the .NET SDK would change OutputType to WinExe . New behavior OutputType is no longer changed from what's in the project file. XML <PropertyGroup> <OutputType>Exe</OutputType> </PropertyGroup> Change category This change may affect source compatibility. Reason for change The .NET 5 change was intended to simplify .NET MAUI apps, so that OutputType wouldn't need to be conditioned on the target framework. However: Automatically inferring OutputType broke user expectations and frustrated developers. For more information, see dotnet/sdk#16563 and its linked issues. .NET MAUI apps will use WinUI by default, not Windows Forms or WPF, so the automatic inference doesn't even apply to .NET MAUI apps. Recommended action If you relied on the fact that OutputType was changed from Exe to WinExe , you should explicitly set it to WinExe in the project file. If you were impacted by the previous breaking change and had to set DisableWinExeOutputInference in order to disable the logic that was added in .NET 5, you can remove that property now. Affected APIs N/A See also OutputType set to WinExe for WPF and WinForms apps Publishing a ReadyToRun project with -no-restore requires changes to the restore Article • 05/17/2022 If you publish a project with -p:PublishReadyToRun=true in addition to --no-restore , the project will only build with packages that were restored in a prior dotnet restore operation. In .NET 5, this process worked and resulted in a crossgen'd binary. In .NET 6, this same process will fail with the NETSDK1095 error. Version introduced .NET 6 Previous behavior In previous versions, the crossgen application was packaged with the runtime. As a result, the crossgen process was able to run on your application regardless of if the project had been restored or not. It was a common practice to separate dotnet restore from dotnet publish , adding --no-restore to the publish command to ensure that no additional network accesses occurred. New behavior In .NET 6, dotnet restore followed by dotnet publish -p:PublishReadyToRun=true --norestore will fail with the NETSDK1095 error. This is because the crossgen binary is now shipped as a separate NuGet package, and so needs to be part of the restore operation for publishing to succeed. Reason for change The crossgen binary is not required for many workloads, so it was split out from the main SDK. It is typically acquired on-demand, and the publishing MSBuild targets now handle this acquisition by adding the package to the list of packages to be restored. Recommended action If you want to maintain an isolated publish experience, tell the restore step that you'll be publishing ReadyToRun. Add -p:PublishReadyToRun=true to your restore command line as well. Or, remove --no-restore from your publish command line to allow the publish command to restore crossgen as well. runtimeconfig.dev.json file not generated Article • 10/13/2022 The .NET SDK no longer generates the runtimeconfig.dev.json file by default. This file was not used in most scenarios, and finding and loading the file added small amounts of performance overhead. Previous behavior An [Appname].runtimeconfig.dev.json file was automatically generated at compile time. New behavior The [Appname].runtimeconfig.dev.json file is no longer generated by default. Version introduced .NET SDK 6.0.100 Change category This change may affect binary compatibility. Reason for change Not generating the file provides a small but measurable performance improvement. Recommended action This change should not affect most customers. However, if you still require this file, add <GenerateRuntimeConfigDevFile>true</GenerateRuntimeConfigDevFile> to your project. For more information, see GenerateRuntimeConfigDevFile. Affected APIs N/A RuntimeIdentifier warning if selfcontained is unspecified Article • 06/02/2022 If you specify a RuntimeIdentifier in your project file or use the -r option with dotnet , the .NET SDK defaults the build, publish, and run outputs to be self-contained applications. The default without specifying a RuntimeIdentifier is to have a framework-dependent application. This change introduces a new warning (NETSDK1179) if you specify a RuntimeIdentifier without specifying whether the application is selfcontained. Version introduced .NET 6 RC 1 Previous behavior In previous versions, specifying a RuntimeIdentifier would silently change the application from a framework-dependent application to a self-contained application. New behavior In .NET 6, if you specify a RuntimeIdentifier without specifying whether the application is self-contained, you'll get the following warning: warning NETSDK1179: One of '--self-contained' or '--no-self-contained' options are required when '--runtime' is used. For example, the following command will generate the warning: .NET CLI dotnet publish -r win-x86 Change category This change may affect source compatibility. Reason for change The default without specifying a RuntimeIdentifier is to generate a frameworkdependent application. This default caused confusion for many customers. The purpose of adding the warning is to: Warn customers of the behavior change to default to a framework-dependent app. Encourage customers to specifically choose the type of application they want to build. Prepare customers for possibly changing the behavior in .NET 7 to default to framework-dependent. Recommended action Specify a Boolean value in your project file for SelfContained . Or, add --self-contained with a value to your build or publish command. Affected APIs N/A See also dotnet build command dotnet publish command Tool manifests in root folder Article • 08/01/2023 .NET no longer looks for local tool manifest files in the root folder on Windows, unless overridden via the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable. This change does not impact Linux or macOS. Previous behavior Previously, .NET SDK local tools checked the root folder on all platforms when searching for a tool manifest. The search continued from the current directory up the directory tree to the root folder until it found a manifest. At each level, .NET searches for the tool manifest, named dotnet-tools.json, in a .config subfolder. On a Windows system, if no other tool manifest was found, the SDK ultimately looked for a tool manifest in C:\.config\dotnet-tools.json. New behavior .NET no longer searches in the root folder of the current directory tree by default on Windows, unless overridden via the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable. DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT is set to false by default. Version introduced .NET SDK 7.0.3xx .NET SDK 7.0.1xx .NET SDK 6.0.4xx .NET SDK 6.0.3xx .NET SDK 6.0.1xx .NET SDK 3.1.4xx Type of breaking change This change is a behavioral change. Reason for change This change was made to address a security concern. Since all users can create files and folders in the C:\ directory on Windows, low-privilege attackers can hijack the C:\.config\dotnet-tools.json file. When an administrator runs a dotnet tool command, the tool could potentially read malicious configuration information from the file and download and run malicious tools. Recommended action To disable the new behavior, set the DOTNET_TOOLS_ALLOW_MANIFEST_IN_ROOT environment variable to true or 1 . See also Tutorial: Install and use a .NET local tool using the .NET CLI Version requirements for .NET 6 SDK Article • 05/03/2022 Starting with the .NET SDK 6.0.300, the .NET SDK no longer loads in version 16.11 or earlier of Visual Studio or MSBuild. Version introduced .NET SDK 6.0.300 Old behavior The .NET SDK would load in the 16.10 and 16.11 versions of Visual Studio and MSBuild. New behavior The .NET SDK can only be used with version 17.0 or later of Visual Studio and MSBuild. In addition, any scenarios that use a source generator could fail when using a Visual Studio or MSBuild version earlier than version 17.2. Reason for change Changes were made to features within the SDK that aren't compatible with Visual Studio version 16.11. Recommended action Upgrade to Visual Studio 2022 version 17.0 or later. It's recommended that you use version 17.2 preview builds. Affected APIs N/A .version file includes build version Article • 09/20/2022 The .NET SDK installation folder (under dotnet/sdk/<version>) contains a .version file. This file includes the following data: The hash for the commit for that version of the .NET SDK. The stable version. The runtime identifier (RID) of the .NET SDK. This change adds the specific build number from the product's build system. For example, the file now includes information similar to the following: txt baae4cac8b288405720786a3bcd35ee5a6086f1b 6.0.401 win-x64 6.0.401-servicing.22414.4 Previous behavior The dotnet/sdk/<version>.version file contained three values: Git commit hash Simplified version RID New behavior The dotnet/sdk/<version>.version file contains four values: Git commit hash Simplified Version RID Precise build version Version introduced .NET SDK 6.0.401 Reason for change This change was made to enable internal testing of the dotnet-install script. The simpler, short build version cannot be used by the dotnet-install script prior to release. Recommended action No action is necessary unless you have tooling that parses the .version file. If you do, you'll need to account for a fourth entry in the file. Write reference assemblies to intermediate output Article • 05/21/2022 The .NET SDK now writes reference assemblies to the IntermediateOutputPath instead of the OutDir by default. This change removes these build-time-only artifacts from outputs that you require at run time. Version introduced .NET SDK 6.0.200 Old behavior Since reference assemblies were added, the .NET SDK has written reference assemblies to the ref directory in the OutDir directory of the compilation. In .NET 5, the ProduceReferenceAssembly property was introduced and defaulted to true for net5.0 and later applications. With this change, many applications began implicitly generating reference assemblies in the OutDir directory. New behavior Now, reference assemblies are written to the refint directory of the IntermediateOutputPath directory by default, like many other intermediate artifacts. Reason for change Reference assemblies are generally not run-time assets, and so don't belong in the OutDir directory by default. Recommended action If you have custom build logic and you need to manipulate the reference assemblies, use the TargetRefPath property to get the correct path. If an external system requires the reference assembly in OutDir , set the MSBuild property ProduceReferenceAssemblyInOutDir to true in your project file. DataContractSerializer retains sign when deserializing -0 Article • 11/08/2022 DataContractSerializer and DataContractJsonSerializer previously discarded the sign when deserializing the input "-0" as a float or double. Both serializers have always done the right thing when given "-0.0" as an input, but with an input of "-0", the sign was lost. This behavior is both inconsistent and results in data loss. In addition, these serializers write a value of negative zero out as "-0" during serialization. Previous behavior Previously, the negative sign was lost when deserializing "-0" (but not "-0.0") as a float or double using DataContractSerializer. New behavior The negative sign is now preserved when deserializing "-0" as a float or double. Version introduced .NET 6.0.11 (servicing release) .NET 7 Type of breaking change This change can affect binary compatibility. Reason for change The previous behavior was inconsistent and resulted in data loss. Recommended action In most cases, no action is needed. If your code was affected by the bug, then this is a good change. Or, you've already worked around the bug in a way that's unlikely to be broken by this change. Affected APIs System.Runtime.Serialization.DataContractSerializer.ReadObject System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject Default serialization format for TimeSpan Article • 09/22/2022 System.Text.Json added support for TimeSpan in .NET 6 GA, however this change did not include support for source generators. In .NET 6 servicing release 6.0.2, System.Text.Json includes support for source-generator serialization of TimeSpan values. This support changes the default serialization format for TimeSpan values in source generators. Previous behavior In .NET 6 GA, source generators serialize TimeSpan values by outputting all public properties of the type, which is the default serialization behavior for objects: JSON {"days":0,"hours":0,"milliseconds":0,"minutes":0,"seconds":1,"ticks":1000000 0,"totalDays":1.1574074074074073E05,"totalHours":0.0002777777777777778,"totalMilliseconds":1000,"totalMinutes ":0.016666666666666666,"totalSeconds":1} New behavior In servicing release .NET 6.0.2, source generators serialize TimeSpan values in the following format, which is consistent with the reflection-based serializer format: JSON "00:00:01" Version introduced .NET 6.0.2 (servicing release) Type of breaking change This change may affect binary compatibility. Reason for change System.Text.Json source generation is a new feature, and its serialization behavior should be as consistent as possible with the reflection-based serializer. This change simplifies migration to source generators. Recommended action It's unlikely for users to depend on the current TimeSpan serialization format, as it redundantly outputs all public properties of the type (which is the default serialization behavior for objects), and it doesn't roundtrip. If you do depend on the existing behavior, the recommended course of action is to author a custom converter that outputs the needed properties from TimeSpan: C# public class TimeSpanConverter : JsonConverter<TimeSpan> { public void WriteValue(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteNumber("days", value.Days); writer.WriteNumber("hours", value.Hours); /* insert any needed properties here */ writer.WriteEndObject(); } } Affected APIs System.Text.Json.JsonSerializer.Serialize See also How to use source generation in System.Text.Json System.Text.Json IAsyncEnumerable serialization Article • 09/22/2022 System.Text.Json now supports serializing and deserializing of IAsyncEnumerable<T> instances. Previous behavior In previous versions, System.Text.Json serialized IAsyncEnumerable<T> instances as empty JSON objects ( {} ). Deserialization failed with a JsonException. New behavior Asynchronous serialization methods now enumerate any IAsyncEnumerable<T> instances in an object graph and then serialize them as JSON arrays. Synchronous serializations methods do not support IAsyncEnumerable<T> serialization and throw a NotSupportedException. Version introduced .NET 6 Type of breaking change This change can affect source compatibility. If you retarget to .NET 6, you won't get any compile-time errors, but you may encounter run-time serialization behavior differences. Reason for change This change was introduced to add support for streaming IAsyncEnumerable<T> responses in ASP.NET Core MVC. Recommended action Check if your serialization models contain types that implement IAsyncEnumerable<T> and determine if emitting the enumeration in the JSON output is desirable. You can disable IAsyncEnumerable<T> serialization in one of the following ways: Attach a JsonIgnoreAttribute to the property containing the IAsyncEnumerable<T>. Define a custom converter factory that serializes IAsyncEnumerable<T> instances as empty JSON objects. Affected APIs System.Text.Json.JsonSerializer.SerializeAsync System.Text.Json.JsonSerializer.Serialize See also System.Text.Json support for IAsyncEnumerable JSON source-generation API refactoring Article • 09/22/2022 The APIs that the output of the JSON source generator calls have been refactored. The refactoring makes them easier to extend with new features in the future. Projects that explicitly use the JSON source generator and were compiled with .NET 6 RC 1 or earlier will fail with run-time exceptions when run on the .NET 6 RC 2 runtime. Previous behavior Projects that were compiled using the .NET 6 RC 1 or earlier version of the System.Text.Json source generator and library run as expected. New behavior Projects that were compiled using the .NET 6 RC 1 version of the System.Text.Json source generator and library fail when run against the .NET 6 RC 2 runtime. Projects that are recompiled with the RC 2 SDK work as expected. Version introduced 6.0 RC 2 Type of breaking change This change can affect binary compatibility. Reason for change This change was introduced to make it easier to extend the source-generator implementation with features in the future. For more information, see dotnet/runtime#59243 . Recommended action Recompile your app using the RC 2 SDK. Affected APIs System.Text.Json.Serialization.JsonSerializerContext System.Text.Json.Serialization.JsonSerializableAttribute System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute System.Text.Json.Serialization.Metadata (not intended for direct use) See also How to use source generation in System.Text.Json JsonNumberHandlingAttribute on collection properties Article • 12/02/2021 A minor breaking change was introduced in .NET 6 with regard to the JsonNumberHandlingAttribute attribute. If you apply the attribute to a property that's a collection of non-number values and attempt to serialize or deserialize the property, an InvalidOperationException is thrown. The attribute is only valid for properties that are collections of number types, for example: C# [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public List<int> MyList { get; set; } Previous behavior Although it was ignored during serialization, JsonNumberHandlingAttribute could be applied to properties that were collections of non-number types. For example: C# [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public List<MyClass> MyList { get; set; } New behavior Starting in .NET 6, if you apply JsonNumberHandlingAttribute to a property that's a collection of non-number values and attempt to serialize or deserialize the property, an InvalidOperationException is thrown. Version introduced .NET 6 Type of breaking change This change can affect binary compatibility. Reason for change This change was a side effect of a performance optimization for the number handling feature. Recommended action Remove the JsonNumberHandlingAttribute attribute from incompatible collection properties. Affected APIs All of the System.Text.Json.JsonSerializer serialization and deserialization methods. New JsonSerializer source generator overloads Article • 12/02/2021 The System.Text.Json source generator feature added new overloads to JsonSerializer that accept pre-generated type information via JsonTypeInfo<T> or JsonSerializerContext. These overloads provide a performance optimization over preexisting overloads that take JsonSerializerOptions instances and perform run-time reflection. All of these parameter types are reference types for which you can pass null . The following example shows the method-signature patterns for both approaches: Pre-existing reflection/ JsonSerializerOptions -based overloads: C# public static string JsonSerializer.Serialize<T>(T value, JsonSerializerOptions? options = null); public static string JsonSerializer.Serialize(object value, Type type, JsonSerializerOptions? options = null); public static T JsonSerializer.Deserialize<T>(string json, JsonSerializerOptions? options = null); public static T JsonSerializer.Deserialize(string json, Type type, JsonSerializerOptions? options = null); New source-generator/ JsonTypeInfo / JsonSerializerContext -based overloads: C# public static string JsonSerializer.Serialize<T>(T value, JsonTypeInfo<T> jsonTypeInfo); public static string JsonSerializer.Serialize(object value, Type type, JsonSerializerContext jsonSerializerContext); public static T JsonSerializer.Deserialize<T>(string json, JsonTypeInfo<T> jsonTypeInfo); public static object JsonSerializer.Deserialize(string json, Type type, JsonSerializerContext jsonSerializerContext); Previous behavior You could write code that passed null as the value for the JsonSerializerOptions parameter, and it compiled and ran successfully. C# entity.Property(e => e.Value).HasConversion(v => JsonSerializer.Serialize(v,null), v => JsonSerializer.Deserialize(v, null)); New behavior The new source-generator methods in .NET 6 can introduce compiler ambiguity if you pass null for the JsonSerializerOptions parameter. For example, you might see the following error message: The call is ambiguous between the following methods or properties: 'JsonSerializer.Serialize(TValue, JsonSerializerOptions?)' and 'JsonSerializer.Serialize(TValue, JsonTypeInfo) Version introduced .NET 6 Type of breaking change This change can affect source compatibility. Reason for change New overloads were added to the serializer as a performance optimization. For more information, see Try the new System.Text.Json source generator . Recommended action Update your code in a manner that disambiguates the intended overload, such as performing an explicit cast to the intended target. For example, you can change the example in the Previous behavior section as follows: C# entity.Property(e => e.Value).HasConversion(v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null), v => JsonSerializer.Deserialize(v, (JsonSerializerOptions)null)); Other workarounds include: Omitting the optional parameter JsonSerializerOptions? options = null . Using named arguments. However, you can't omit optional parameters or use named arguments in a lambda expression. Affected APIs All of the System.Text.Json.JsonSerializer methods. Some APIs throw ArgumentNullException Article • 12/02/2021 Some APIs now validate input parameters and throw an ArgumentNullException where previously they threw a NullReferenceException, if invoked with null input arguments. Change description In previous .NET versions, the affected APIs throw a NullReferenceException if invoked with an argument that's null . Starting in .NET 6, the affected APIs throw an ArgumentNullException if invoked with an argument that's null . Change category This change affects binary compatibility. Reason for change Throwing ArgumentNullException conforms to .NET Runtime behavior. It provides a better debug experience by clearly communicating which argument caused the exception. Version introduced .NET 6 Recommended action Review and, if necessary, update your code to prevent passing null input arguments to the affected APIs. If your code handles NullReferenceException, replace or add an additional handler for ArgumentNullException. Affected APIs The following table lists the affected APIs and specific parameters: Method/property Parameter name System.Windows.Forms.TreeNodeCollection.Item[Int32] index DrawTreeNodeEventArgs(Graphics, TreeNode, Rectangle, TreeNodeStates) graphics DataGridViewRowStateChangedEventArgs(DataGridViewRow, dataGridViewRow DataGridViewElementStates) DataGridViewColumnStateChangedEventArgs(DataGridViewColumn, dataGridViewColumn DataGridViewElementStates) See also TreeNodeCollection.Item throws exception if node is assigned elsewhere C# templates use application bootstrap Article • 10/29/2021 In line with related changes in .NET workloads, Windows Forms templates for C# have been updated to support global using directives, file-scoped namespaces, and nullable reference types. Because a typical Windows Forms app consist of multiple types split across multiple files, for example, Form1.cs and Form1.Designer.cs, top-level statements are notably absent from the Windows Forms templates. However, the updated templates do include application bootstrap code. This can cause incompatibility if you target an earlier version of .NET. Version introduced .NET 6 RC 1 Old behavior A Windows Forms application entry point looked like this: C# using using using using using System; System.Collections.Generic; System.Linq; System.Threading.Tasks; System.Windows.Forms; namespace MyApp { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } New behavior The new application entry point for a .NET 6+ application looks like this: C# namespace MyApp; static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { ApplicationConfiguration.Initialize(); Application.Run(new Form1()); } } ApplicationConfiguration.Initialize() is an ephemeral API produced by the Roslyn compiler (via source generators). This method emits the same calls that the original templates had. You can configure the behavior of this API by setting the following MSBuild properties: ApplicationDefaultFont ApplicationHighDpiMode ApplicationUseCompatibleTextRendering ApplicationVisualStyles If you don't explicitly configure any properties, the following code is executed at run time: C# static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { // ApplicationConfiguration.Initialize() will emit the following calls: Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.Run(new Form1()); } } Change category This change affects source compatibility. Reason for change The application bootstrap feature: Allows the Windows Forms designer to render the design surface in the preferred font. Reduces boilerplate code in the templates. Recommended action If the same source is used to build an application that targets multiple TFMs, you can do one of the following: Replace the ApplicationConfiguration.Initialize(); call with the original code (and lose the designer support for Application.SetDefaultFont API). Use #if...#endif directives, for example: C# #if NET6_0_OR_GREATER ApplicationConfiguration.Initialize(); #else Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.SetHighDpiMode(HighDpiMode.SystemAware); #endif Affected APIs N/A DataGridView-related APIs now throw InvalidOperationException Article • 12/02/2021 Some APIs related to DataGridView now throw an InvalidOperationException if the object's DataGridViewCell.DataGridViewCellAccessibleObject.Owner value is null . Change description In previous .NET versions, the affected APIs throw a NullReferenceException when they are invoked and the Owner property value is null . Starting in .NET 6, these APIs throw an InvalidOperationException instead of a NullReferenceException if the Owner property value is null when they're invoked. Change category This change affects binary compatibility. Reason for change Throwing an InvalidOperationException conforms to the behavior of the .NET runtime. It also improves the debugging experience by clearly communicating the invalid property. Version introduced .NET 6 Recommended action Review your code and, if necessary, update it to prevent constructing the affected types with the Owner property as null . Affected APIs The following table lists the affected properties and methods: System.Windows.Forms.DataGridViewTopLeftHeaderCell.DataGridViewTopLeftHead erCellAccessibleObject.Bounds System.Windows.Forms.DataGridViewTopLeftHeaderCell.DataGridViewTopLeftHead erCellAccessibleObject.DefaultAction System.Windows.Forms.DataGridViewTopLeftHeaderCell.DataGridViewTopLeftHead erCellAccessibleObject.Name System.Windows.Forms.DataGridViewTopLeftHeaderCell.DataGridViewTopLeftHead erCellAccessibleObject.Navigate(AccessibleNavigation) System.Windows.Forms.DataGridViewTopLeftHeaderCell.DataGridViewTopLeftHead erCellAccessibleObject.State See also DataGridView-related APIs throw InvalidOperationException (.NET 5) ListViewGroupCollection methods throw new InvalidOperationException Article • 11/13/2021 Previously, an InvalidOperationException was thrown if ListViewGroupCollection methods were invoked on a ListView in virtual mode and the Handle had already been created. Starting in .NET 6, these ListViewGroupCollection methods now only check if the ListView is in virtual mode. If it is, they throw an InvalidOperationException with a more descriptive message. Previous behavior Consider the following code that adds a ListViewGroup to a ListView: C# ListViewGroup group1 = new ListViewGroup { Header = "CollapsibleGroup1", CollapsedState = ListViewGroupCollapsedState.Expanded }; listView.Groups.Add(group1); This code produced an InvalidOperationException with the following message: When the ListView is in virtual mode, you cannot enumerate through the ListView items collection using an enumerator or call GetEnumerator. Use the ListView items indexer instead and access an item by index value. New behavior The same code from the Previous behavior section produces an InvalidOperationException with the following message: You cannot add groups to the ListView groups collection when the ListView is in virtual mode. Change category This change affects binary compatibility. Reason for change The new InvalidOperationException message is more understandable. In addition, it closes a workaround where the developer could add a ListViewGroup to the ListView before the Handle was created. Version introduced .NET 6 RC 2 Recommended action Review and, if necessary, update your code so that it doesn't add a ListViewGroup to a ListView in virtual mode. If your code handles InvalidOperationException exceptions, you may need to update the message to reflect that the ListView is in virtual mode. Affected APIs System.Windows.Forms.ListViewGroupCollection.Add System.Windows.Forms.ListViewGroupCollection.AddRange System.Windows.Forms.ListViewGroupCollection.Insert(Int32, ListViewGroup) NotifyIcon.Text maximum text length increased Article • 12/02/2021 The maximum text length allowed for the NotifyIcon.Text property increased from 63 to 127. Change description In previous .NET versions, the maximum text length allowed for the NotifyIcon.Text property is 63 characters. Starting in .NET 6, the maximum allowed text length is 127 characters. In any version, an ArgumentException is thrown when you attempt to set a value that's longer than the limit. Change category This change affects binary compatibility. Reason for change The maximum allowed text length was increased to be in line with the underlying Windows API. The Windows API was updated in Windows 2000, but due to compatibility reasons, the size limit for this property wasn't updated in .NET Framework. Version introduced .NET 6 Recommended action Review your code and relax any existing guard conditions, if necessary. Affected APIs System.Windows.Forms.NotifyIcon.Text ScaleControl called only when needed Article • 02/16/2022 Scaling is usually needed only when an application is running in SystemAware or PerMonitorV2 mode and the monitor has custom DPI settings that differ from the machine where the app was designed. In these scenarios, the Windows Forms runtime calculates the scale factor, based on custom DPI settings of the monitor, and calls ScaleControl(SizeF, BoundsSpecified) with the new scale factor. To improve performance, ScaleControl is now called only when the calculated scale factor is something other than 1.0F (that is, scaling is needed). This change can break your app if it overrides ScaleControl and performs any custom actions in the override. Version introduced .NET 6 servicing 6.0.101 Old behavior In .NET 6 GA release and earlier versions, the virtual, public API ScaleControl(SizeF, BoundsSpecified) was called every time PerformAutoScale() was called on the container control of the application. That is, the method was called every time there is a layout or font change, regardless of whether scaling was needed. New behavior Starting in .NET 6 servicing releases, ScaleControl(SizeF, BoundsSpecified) is called only when there's a need to scale the form or control. The Windows Forms runtime calculates the scale factor based on the custom DPI settings of the monitor and the DPI settings of the monitor on which the application was designed. ScaleControl(SizeF, BoundsSpecified) is called only if the scale factor indicates that scaling is required. Change category This change affects source compatibility. Reason for change This change was made to improve performance and avoid unnecessary layouts. Recommended action Check if your code performs any custom, non-scaling actions in these overridable methods. Affected APIs System.Windows.Forms.Form.ScaleControl(SizeF, BoundsSpecified) Selected TableLayoutSettings properties throw InvalidEnumArgumentException Article • 12/02/2021 Selected TableLayoutSettings properties now throw an InvalidEnumArgumentException if you attempt to assign an incorrect value. Change description In previous .NET versions, these properties throw an ArgumentOutOfRangeException if you attempt to assign an incorrect value. Starting in .NET 6, these properties throw an InvalidEnumArgumentException in such cases. Change category This change affects binary compatibility. Reason for change Throwing InvalidEnumArgumentException is in line with the existing Windows Forms API in similar situations. Throwing this exception also provides developers with a better debug experience. Version introduced .NET 6 Recommended action Update the code to prevent assigning incorrect values. If necessary, handle an InvalidEnumArgumentException when accessing these APIs. Affected APIs System.Windows.Forms.TableLayoutPanel.CellBorderStyle System.Windows.Forms.TableLayoutPanel.GrowStyle TreeNodeCollection.Item throws exception if node is assigned elsewhere Article • 12/02/2021 TreeNodeCollection.Item[Int32] throws an ArgumentException if the node being assigned is already bound to another TreeView or to this TreeView at a different index. Change description In previous .NET versions, you can assign a tree node to a collection even if it's already bound to a TreeView. This can lead to duplicated nodes. Starting in .NET 6, TreeNodeCollection.Item[Int32] throws an ArgumentException if the node being assigned is already bound to another TreeView or to this TreeView at a different index. Change category This change affects binary compatibility. Reason for change Validating the input parameter is consistent with the behavior of other TreeNodeCollection APIs. Version introduced .NET 6 Recommended action Make sure to unbind a TreeNode before assigning it to the collection. Affected APIs System.Windows.Forms.TreeNodeCollection.Item[Int32] XmlDocument.XmlResolver nullability change Article • 11/08/2021 The nullability for XmlDocument.XmlResolver has changed in .NET 6. The property setter now accepts a nullable reference. Previous behavior The setter for XmlDocument.XmlResolver was annotated as not accepting null : C# public virtual System.Xml.XmlResolver XmlResolver { set { } } New behavior The setter for XmlDocument.XmlResolver is annotated as accepting null : C# public virtual System.Xml.XmlResolver? XmlResolver { set { } } Version introduced 6.0 RC 1 Type of breaking change This change can affect binary compatibility if you've overridden this property in a derived type. Reason for change The non-nullable annotation was incorrect. Recommended action If you have overridden this property in a derived type, you'll need to update your code to handle null when setting the property value. Affected APIs System.Xml.XmlDocument.XmlResolver XNodeReader.GetAttribute behavior for invalid index Article • 12/02/2021 XNodeReader is an internal class, but it's accessible through the XmlReader class if you call XNode.CreateReader. All XmlReader implementations except XNodeReader threw an ArgumentOutOfRangeException for an invalid index in the GetAttribute(Int32) method. With this change, XNodeReader.GetAttribute(int) now also throws an ArgumentOutOfRangeException for an invalid index. Old behavior XNodeReader.GetAttribute(int) returned null if the index was invalid. New behavior XNodeReader.GetAttribute(int) throws an ArgumentOutOfRangeException if the index is invalid. Version introduced .NET 6 Type of breaking change This change can affect source compatibility. Reason for change XmlReader.GetAttribute(int) is well documented, and XNodeReader was not behaving as documented. It's behavior for invalid indices was also inconsistent with other XmlReader implementations. Recommended action To avoid an invalid index: Call XmlReader.AttributeCount to retrieve the number of attributes in the current node. Then, pass a value of range 0..XmlReader.AttributeCount-1 to XmlReader.GetAttribute(Int32). Affected APIs System.Xml.XmlReader.GetAttribute(Int32) Breaking changes in .NET 5 Article • 03/18/2023 If you're migrating an app to .NET 5, the breaking changes listed here might affect you. Changes are grouped by technology area, such as ASP.NET Core or cryptography. This article indicates whether each breaking change is binary compatible or source compatible: Binary compatible - Existing binaries will load and execute successfully without recompilation, and the run-time behavior won't change. Source compatible - Source code will compile successfully without changes when targeting the new runtime or using the new SDK or component. ASP.NET Core Title Binary compatible Source compatible ASP.NET Core apps deserialize quoted numbers ✔️ ❌ AzureAD.UI and AzureADB2C.UI APIs obsolete ✔️ ❌ BinaryFormatter serialization methods are obsolete ✔️ ❌ Resource in endpoint routing is HttpContext ✔️ ❌ Microsoft-prefixed Azure integration packages removed ❌ ✔️ Blazor: Route precedence logic changed in Blazor apps ✔️ ❌ Blazor: Updated browser support ✔️ ✔️ Blazor: Insignificant whitespace trimmed by compiler ✔️ ❌ Blazor: JSObjectReference and JSInProcessObjectReference types are internal ✔️ ❌ Blazor: Target framework of NuGet packages changed ❌ ✔️ Blazor: ProtectedBrowserStorage feature moved to shared framework ✔️ ❌ Blazor: RenderTreeFrame readonly public fields are now properties ❌ ✔️ Blazor: Updated validation logic for static web assets ❌ ✔️ Title Binary compatible Source compatible Cryptography APIs not supported on browser ❌ ✔️ Extensions: Package reference changes ❌ ✔️ Kestrel and IIS BadHttpRequestException types are obsolete ✔️ ❌ HttpClient instances created by IHttpClientFactory log integer ✔️ ❌ HttpSys: Client certificate renegotiation disabled by default ✔️ ❌ IIS: UrlRewrite middleware query strings are preserved ✔️ ❌ Kestrel: Configuration changes detected by default ✔️ ❌ Kestrel: Default supported TLS protocol versions changed ✔️ ❌ Kestrel: HTTP/2 disabled over TLS on incompatible Windows ✔️ ✔️ Kestrel: Libuv transport marked as obsolete ✔️ ❌ Obsolete properties on ConsoleLoggerOptions ✔️ ❌ ResourceManagerWithCultureStringLocalizer class and ✔️ ❌ Pubternal APIs removed ✔️ ❌ Obsolete constructor removed in request localization middleware ✔️ ❌ Middleware: Database error page marked as obsolete ✔️ ❌ Exception handler middleware throws original exception ✔️ ✔️ ObjectModelValidator calls a new overload of Validate ✔️ ❌ Cookie name encoding removed ✔️ ❌ IdentityModel NuGet package versions updated ❌ ✔️ SignalR: MessagePack Hub Protocol options type changed ✔️ ❌ SignalR: MessagePack Hub Protocol moved ✔️ ❌ UseSignalR and UseConnections methods removed ✔️ ❌ CSV content type changed to standards-compliant ✔️ ❌ status codes versions WithCulture interface member removed Code analysis Title Binary compatible Source compatible CA1416 warning ✔️ ❌ CA1417 warning ✔️ ❌ CA1831 warning ✔️ ❌ CA2013 warning ✔️ ❌ CA2014 warning ✔️ ❌ CA2015 warning ✔️ ❌ CA2200 warning ✔️ ❌ CA2247 warning ✔️ ❌ Core .NET libraries Title Binary Source compatible compatible Assembly-related API changes for single-file publishing ❌ ✔️ BinaryFormatter serialization methods are obsolete ✔️ ❌ Code access security APIs are obsolete ✔️ ❌ CreateCounterSetInstance throws ✔️ ❌ Default ActivityIdFormat is W3C ❌ ✔️ Environment.OSVersion returns the correct version ❌ ✔️ FrameworkDescription's value is .NET not .NET Core ✔️ ❌ GAC APIs are obsolete ✔️ ❌ Hardware intrinsic IsSupported checks ❌ ✔️ IntPtr and UIntPtr implement IFormattable ✔️ ❌ LastIndexOf handles empty search strings ❌ ✔️ URI paths with non-ASCII characters on Unix ❌ ✔️ InvalidOperationException Title Binary compatible Source compatible API obsoletions with non-default diagnostic IDs ✔️ ❌ Obsolete properties on ConsoleLoggerOptions ✔️ ❌ Complexity of LINQ OrderBy.First ❌ ✔️ OSPlatform attributes renamed or removed ✔️ ❌ Microsoft.DotNet.PlatformAbstractions package removed ❌ ✔️ PrincipalPermissionAttribute is obsolete ✔️ ❌ Parameter name changes from preview versions ✔️ ❌ Parameter name changes in reference assemblies ✔️ ❌ Remoting APIs are obsolete ❌ ✔️ Order of Activity.Tags list is reversed ✔️ ❌ SSE and SSE2 comparison methods handle NaN ✔️ ❌ Thread.Abort is obsolete ✔️ ❌ Uri recognition of UNC paths on Unix ❌ ✔️ UTF-7 code paths are obsolete ✔️ ❌ Behavior change for Vector2.Lerp and Vector4.Lerp ✔️ ❌ Vector<T> throws NotSupportedException ❌ ✔️ Binary Source compatible compatible Cryptography APIs not supported on browser ❌ ✔️ Cryptography.Oid is init-only ✔️ ❌ Default TLS cipher suites on Linux ❌ ✔️ Create() overloads on cryptographic abstractions are ✔️ ❌ ✔️ ❌ Cryptography Title obsolete Default FeedbackSize value changed Entity Framework Core Breaking changes in EF Core 5.0 Globalization Title Binary Source compatible compatible Use ICU libraries on Windows ❌ ✔️ StringInfo and TextElementEnumerator are UAX29compliant ❌ ✔️ Unicode category changed for Latin-1 characters ✔️ ❌ TextInfo.ListSeparator values changed ✔️ ❌ Interop Title Binary Source compatible compatible Support for WinRT is removed ❌ ✔️ Casting RCW to InterfaceIsIInspectable throws exception ❌ ✔️ No A/W suffix probing on non-Windows platforms ❌ ✔️ Networking Title Binary compatible Source compatible Cookie path handling conforms to RFC 6265 ✔️ ❌ LocalEndPoint is updated after calling SendToAsync ✔️ ❌ MulticastOption.Group doesn't accept null ✔️ ❌ Streams allow successive Begin operations ❌ ✔️ WinHttpHandler removed from .NET runtime ❌ ✔️ SDK Title Binary compatible Source compatible Directory.Packages.props files imported by default ❌ ✔️ ✔️ Error generated when executable project references mismatched executable ✔️ ❌ NETCOREAPP3_1 preprocessor symbol not defined ✔️ ❌ OutputType set to WinExe ❌ ✔️ PublishDepsFilePath behavior change ❌ ✔️ TargetFramework change from netcoreapp to net ❌ ✔️ WinForms and WPF apps use Microsoft.NET.Sdk ❌ ✔️ FrameworkReference replaced with WindowsSdkPackageVersion for Windows SDK Security Title Binary compatible Source compatible Code access security APIs are obsolete ✔️ ❌ PrincipalPermissionAttribute is obsolete ✔️ ❌ UTF-7 code paths are obsolete ✔️ ❌ Serialization Title Binary compatible Source compatible BinaryFormatter.Deserialize rewraps exceptions ✔️ ❌ JsonSerializer.Deserialize requires single-character string ✔️ ❌ ASP.NET Core apps deserialize quoted numbers ✔️ ❌ JsonSerializer.Serialize throws ArgumentNullException ✔️ ❌ Title Binary Source compatible compatible Non-public, parameterless constructors not used for deserialization ✔️ ❌ Options are honored when serializing key-value pairs ✔️ ❌ Windows Forms Title Binary compatible Source compatible Native code can't access Windows Forms objects ✔️ ❌ OutputType set to WinExe ❌ ✔️ DataGridView doesn't reset custom fonts ✔️ ❌ Methods throw ArgumentException ✔️ ❌ Methods throw ArgumentNullException ✔️ ❌ Properties throw ArgumentOutOfRangeException ✔️ ❌ TextFormatFlags.ModifyString is obsolete ✔️ ❌ DataGridView APIs throw InvalidOperationException ✔️ ❌ WinForms apps use Microsoft.NET.Sdk ❌ ✔️ Removed status bar controls ✔️ ❌ WPF Title Binary compatible Source compatible OutputType set to WinExe ❌ ✔️ WPF apps use Microsoft.NET.Sdk ❌ ✔️ See also What's new in .NET 5 ASP.NET Core apps allow deserializing quoted numbers Article • 09/15/2021 Starting in .NET 5, ASP.NET Core apps use the default deserialization options as specified by JsonSerializerDefaults.Web. The Web set of options includes setting NumberHandling to JsonNumberHandling.AllowReadingFromString. This change means that ASP.NET Core apps will successfully deserialize numbers that are represented as JSON strings instead of throwing an exception. Change description In .NET Core 3.0 - 3.1, JsonSerializer throws a JsonException during deserialization if it encounters a quoted number in a JSON payload. The quoted numbers are used to map with number properties in object graphs. In .NET Core 3.0 - 3.1, numbers are only read from JsonTokenType.Number tokens. Starting in .NET 5, quoted numbers in JSON payloads are considered valid, by default, for ASP.NET Core apps. No exception is thrown during deserialization of quoted numbers. Tip There is no behavior change for the default, standalone JsonSerializer or JsonSerializerOptions. This is technically not a breaking change, since it makes a scenario more permissive instead of more restrictive (that is, it succeeds in coercing a number from a JSON string instead of throwing an exception). However, since this is a significant behavioral change that affects many ASP.NET Core apps, it is documented here. The HttpClientJsonExtensions.GetFromJsonAsync and HttpContentJsonExtensions.ReadFromJsonAsync extension methods also use the Web set of serialization options. Version introduced 5.0 Reason for change Multiple users have requested an option for more permissive number handling in JsonSerializer. This feedback indicates that many JSON producers (for example, services across the web) emit quoted numbers. By allowing quoted numbers to be read (deserialized), .NET apps can successfully parse these payloads, by default, in web contexts. The configuration is exposed via JsonSerializerDefaults.Web so that you can specify the same options across different application layers, for example, client, server, and shared. Recommended action If this change is disruptive, for example, if you depend on the strict number handling for validation, you can re-enable the previous behavior. Set the JsonSerializerOptions.NumberHandling option to JsonNumberHandling.Strict. For ASP.NET Core MVC and web API apps, you can configure the option in Startup by using the following code: C# services.AddControllers() .AddJsonOptions(options => options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict); Affected APIs System.Text.Json.JsonSerializer.Deserialize System.Text.Json.JsonSerializer.DeserializeAsync Authentication: AzureAD.UI and AzureADB2C.UI APIs and packages marked obsolete Article • 09/15/2021 In ASP.NET Core 2.1, integration with Azure Active Directory (Azure AD) and Azure Active Directory B2C (Azure AD B2C) authentication is provided by the Microsoft.AspNetCore.Authentication.AzureAD.UI and Microsoft.AspNetCore.Authentication.AzureADB2C.UI packages. The functionality provided by these packages is based on the Azure AD v1.0 endpoint. In ASP.NET Core 5.0 and later, integration with Azure AD and Azure AD B2C authentication is provided by the Microsoft.Identity.Web package. This package is based on the Microsoft Identity Platform, which is formerly known as the Azure AD v2.0 endpoint. Consequently, the old APIs in the Microsoft.AspNetCore.Authentication.AzureAD.UI and Microsoft.AspNetCore.Authentication.AzureADB2C.UI packages were deprecated. For discussion, see GitHub issue dotnet/aspnetcore#25807 . Version introduced 5.0 Preview 8 Old behavior The APIs weren't marked as obsolete. New behavior The APIs are marked as obsolete. Reason for change The Azure AD and Azure AD B2C authentication functionality was migrated to Microsoft Authentication Library (MSAL) APIs that are provided by Microsoft.Identity.Web . Recommended action Follow the Microsoft.Identity.Web API guidance for web apps and web APIs . Affected APIs Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureADDefaults Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureADOptions Microsoft.AspNetCore.Authentication.AzureADB2CAuthenticationBuilderExtensions Microsoft.AspNetCore.Authentication.AzureADB2C.UI.AzureADB2CDefaults Microsoft.AspNetCore.Authentication.AzureADB2C.UI.AzureADB2COptions BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps Article • 05/17/2023 Serialize and Deserialize methods on BinaryFormatter, Formatter, and IFormatter are now obsolete as warning. Additionally, BinaryFormatter serialization is prohibited by default for ASP.NET apps. 7 Note In .NET 7, the affected APIs are obsolete as error. For more information, see BinaryFormatter serialization APIs produce compiler errors. Change description Due to security vulnerabilities in BinaryFormatter, the following methods are now obsolete and produce a compile-time warning with ID SYSLIB0011 . Additionally, in ASP.NET Core 5.0 and later apps, they will throw a NotSupportedException, unless the web app has re-enabled BinaryFormatter functionality. BinaryFormatter.Serialize BinaryFormatter.Deserialize The following serialization methods are also obsolete and produce warning SYSLIB0011 , but have no behavioral changes: Formatter.Serialize(Stream, Object) Formatter.Deserialize(Stream) IFormatter.Serialize(Stream, Object) IFormatter.Deserialize(Stream) Version introduced 5.0 Reason for change These methods are marked obsolete as part of an effort to wind down usage of BinaryFormatter within the .NET ecosystem. Recommended action Stop using BinaryFormatter in your code. Instead, consider using JsonSerializer or XmlSerializer. For more information, see BinaryFormatter security guide. You can temporarily suppress the BinaryFormatter compile-time warning, which is SYSLIB0011 . We recommend that you thoroughly assess your code for risks before choosing this option. The easiest way to suppress the warnings is to surround the individual call site with #pragma directives. C# // Now read the purchase order back from disk using (var readStream = new FileStream("myfile.bin", FileMode.Open)) { var formatter = new BinaryFormatter(); #pragma warning disable SYSLIB0011 return (PurchaseOrder)formatter.Deserialize(readStream); #pragma warning restore SYSLIB0011 } You can also suppress the warning in the project file. XML <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <!-- Disable "BinaryFormatter is obsolete" warnings for entire project --> <NoWarn>$(NoWarn);SYSLIB0011</NoWarn> </PropertyGroup> If you suppress the warning in the project file, the warning is suppressed for all code files in the project. Suppressing SYSLIB0011 does not suppress warnings caused by using other obsolete APIs. To continue using BinaryFormatter in ASP.NET apps, you can re-enable it in the project file. However, it's strongly recommended not to do this. For more information, see BinaryFormatter security guide. XML <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- Warning: Setting the following switch is *NOT* recommended in web apps. --> <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryForma tterSerialization> </PropertyGroup> For more information about recommended actions, see Resolving BinaryFormatter obsoletion and disablement errors. Affected APIs System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize System.Runtime.Serialization.Formatter.Serialize(Stream, Object) System.Runtime.Serialization.Formatter.Deserialize(Stream) System.Runtime.Serialization.IFormatter.Serialize(Stream, Object) System.Runtime.Serialization.IFormatter.Deserialize(Stream) See also SerializationFormat.Binary is obsolete (.NET 7) BinaryFormatter serialization APIs produce compiler errors (.NET 7) BinaryFormatter disabled across most project types (.NET 8) Authorization: Resource in endpoint routing is HttpContext Article • 12/04/2021 When using endpoint routing in ASP.NET Core 3.1, the resource used for authorization is the endpoint. This approach was insufficient for gaining access to the route data (RouteData). Previously in MVC, an HttpContext resource was passed in, which allows access to both the endpoint (Endpoint) and the route data. This change ensures that the resource passed to authorization is always the HttpContext . Version introduced ASP.NET Core 5.0 Old behavior When using endpoint routing and the authorization middleware (AuthorizationMiddleware) or [Authorize] attributes, the resource passed to authorization is the matching endpoint. New behavior Endpoint routing passes the HttpContext to authorization. Reason for change You can get to the endpoint from the HttpContext . However, there was no way to get from the endpoint to things like the route data. There was a loss in functionality from non-endpoint routing. Recommended action If your app uses the endpoint resource, call GetEndpoint on the HttpContext to continue accessing the endpoint. You can revert to the old behavior with SetSwitch. For example: C# AppContext.SetSwitch( "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationRes ource", isEnabled: true); Affected APIs None Azure: Microsoft-prefixed Azure integration packages removed Article • 09/15/2021 The following Microsoft.* packages that provide integration between ASP.NET Core and Azure SDKs aren't included in ASP.NET Core 5.0: Microsoft.Extensions.Configuration.AzureKeyVault , which integrates Azure Key Vault into the Configuration system. Microsoft.AspNetCore.DataProtection.AzureKeyVault , which integrates Azure Key Vault into the ASP.NET Core Data Protection system. Microsoft.AspNetCore.DataProtection.AzureStorage , which integrates Azure Blob Storage into the ASP.NET Core Data Protection system. For discussion on this issue, see dotnet/aspnetcore#19570 . Version introduced 5.0 Preview 1 Old behavior The Microsoft.* packages integrated Azure services with the Configuration and Data Protection APIs. New behavior New Azure.* packages integrate Azure services with the Configuration and Data Protection APIs. Reason for change The change was made because the Microsoft.* packages were: Using outdated versions of the Azure SDK. Simple updates weren't possible because the new versions of the Azure SDK included breaking changes. Tied to the .NET Core release schedule. Transferring ownership of the packages to the Azure SDK team enables package updates as the Azure SDK is updated. Recommended action In ASP.NET Core 2.1 or later projects, replace the old Microsoft.* with the new Azure.* packages. Old New Microsoft.AspNetCore.DataProtection.AzureKeyVault Azure.Extensions.AspNetCore.DataProtection.Keys Microsoft.AspNetCore.DataProtection.AzureStorage Azure.Extensions.AspNetCore.DataProtection.Blobs Microsoft.Extensions.Configuration.AzureKeyVault Azure.Extensions.AspNetCore.Configuration.Secrets The new packages use a new version of the Azure SDK that includes breaking changes. The general usage patterns are unchanged. Some overloads and options may differ to adapt to changes in the underlying Azure SDK APIs. The old packages will: Be supported by the ASP.NET Core team for the lifetime of .NET Core 2.1 and 3.1. Not be included in .NET 5. When upgrading your project to .NET 5, transition to the Azure.* packages to maintain support. Affected APIs AzureKeyVaultConfigurationExtensions.AddAzureKeyVault AzureDataProtectionBuilderExtensions.ProtectKeysWithAzureKeyVault AzureDataProtectionBuilderExtensions.PersistKeysToAzureBlobStorage Blazor: Route precedence logic changed in Blazor apps Article • 09/15/2021 A bug in the Blazor routing implementation affected how the precedence of routes was determined. This bug affects catch-all routes or routes with optional parameters within your Blazor app. Version introduced 5.0.1 Old behavior With the erroneous behavior, routes with lower precedence are considered and matched over routes with higher precedence. For example, the {*slug} route is matched before /customer/{id} . New behavior The current behavior more closely matches the routing behavior defined in ASP.NET Core apps. The framework determines the route precedence for each segment first. The route's length is used only as a second criteria to break ties. Reason for change The original behavior is considered a bug in the implementation. As a goal, the routing system in Blazor apps should behave the same way as the routing system in the rest of ASP.NET Core. Recommended action If upgrading from previous versions of Blazor to 5.x, use the PreferExactMatches attribute on the Router component. This attribute can be used to opt into the correct behavior. For example: razor <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="true"> When PreferExactMatches is set to true , route matching prefers exact matches over wildcards. Affected APIs None Blazor: Updated browser support Article • 09/15/2021 ASP.NET Core 5.0 introduces new Blazor features , some of which are incompatible with older browsers. The list of browsers supported by Blazor in ASP.NET Core 5.0 has been updated accordingly. For discussion, see GitHub issue dotnet/aspnetcore#26475 . Version introduced 5.0 Old behavior Blazor Server supports Microsoft Internet Explorer 11 with sufficient polyfills. Blazor Server and Blazor WebAssembly are also functional in Microsoft Edge Legacy . New behavior Blazor Server in ASP.NET Core 5.0 isn't supported with Microsoft Internet Explorer 11. Blazor Server and Blazor WebAssembly aren't fully functional in Microsoft Edge Legacy. Reason for change New Blazor features in ASP.NET Core 5.0 are incompatible with these older browsers, and use of these older browsers is diminishing. For more information, see the following resources: Windows support for Microsoft Edge Legacy is also ending on March 9, 2021 Microsoft 365 apps and services will end support for Microsoft Internet Explorer 11 by August 17, 2021 Recommended action Upgrade from these older browsers to the new, Chromium-based Microsoft Edge Blazor apps that need to support these older browsers, use ASP.NET Core 3.1. The supported browsers list for Blazor in ASP.NET Core 3.1 hasn't changed and is documented at Supported platforms. . For Affected APIs None Blazor: Insignificant whitespace trimmed from components at compile time Article • 02/25/2022 Starting with ASP.NET Core 5.0, the Razor compiler omits insignificant whitespace in Razor components (.razor files) at compile time. For discussion, see issue dotnet/aspnetcore#23568 . Version introduced 5.0 Old behavior In 3.x versions of Blazor Server and Blazor WebAssembly, whitespace is honored in a component's source code. Whitespace-only text nodes render in the browser's Document Object Model (DOM) even when there's no visual effect. Consider the following Razor component code: razor <ul> @foreach (var item in Items) { <li> @item.Text </li> } </ul> The preceding example renders two whitespace nodes: Outside of the @foreach code block. Around the <li> element. Around the @item.Text output. A list containing 100 items results in 402 whitespace nodes. That's over half of all nodes rendered, even though none of the whitespace nodes visually affect the rendered output. When rendering static HTML for components, whitespace inside a tag wasn't preserved. For example, view the source of the following component: razor <foo bar="baz" /> Whitespace isn't preserved. The pre-rendered output is: razor <foo bar="baz" /> New behavior Unless the @preservewhitespace directive is used with value true , whitespace nodes are removed if they: Are leading or trailing within an element. Are leading or trailing within a RenderFragment parameter. For example, child content being passed to another component. Precede or follow a C# code block such as @if and @foreach . Reason for change A goal for Blazor in ASP.NET Core 5.0 is to improve the performance of rendering and diffing. Insignificant whitespace tree nodes consumed up to 40 percent of the rendering time in benchmarks. Recommended action In most cases, the visual layout of the rendered component is unaffected. However, the whitespace removal might affect the rendered output when using a CSS rule like whitespace: pre . To disable this performance optimization and preserve the whitespace, take one of the following actions: Add the @preservewhitespace true directive at the top of the .razor file to apply the preference to a specific component. Add the @preservewhitespace true directive inside an _Imports.razor file to apply the preference to an entire subdirectory or the entire project. In most cases, no action is required, as applications will typically continue to behave normally (but faster). If the whitespace stripping causes any problems for a particular component, use @preservewhitespace true in that component to disable this optimization. Affected APIs None Blazor: JSObjectReference and JSInProcessObjectReference types changed to internal Article • 09/15/2021 The new Microsoft.JSInterop.JSObjectReference and Microsoft.JSInterop.JSInProcessObjectReference types introduced in ASP.NET Core 5.0 RC1 have been marked as internal . Version introduced 5.0 RC2 Old behavior A JSObjectReference can be obtained from a JavaScript interop call via IJSRuntime . For example: C# var jsObjectReference = await JSRuntime.InvokeAsync<JSObjectReference>(...); New behavior JSObjectReference uses the internal access modifier. The public IJSObjectReference interface must be used instead. For example: C# var jsObjectReference = await JSRuntime.InvokeAsync<IJSObjectReference> (...); JSInProcessObjectReference was also marked as internal and was replaced by IJSInProcessObjectReference . Reason for change The change makes the JavaScript interop feature more consistent with other patterns within Blazor. IJSObjectReference is analogous to IJSRuntime in that it serves a similar purpose and has similar methods and extensions. Recommended action Replace occurrences of JSObjectReference and JSInProcessObjectReference with IJSObjectReference and IJSInProcessObjectReference , respectively. Affected APIs Microsoft.JSInterop.JSObjectReference Microsoft.JSInterop.JSInProcessObjectReference Blazor: Target framework of NuGet packages changed Article • 11/08/2021 Blazor 3.2 WebAssembly projects were compiled to target .NET Standard 2.1 ( <TargetFramework>netstandard2.1</TargetFramework> ). In ASP.NET Core 5.0, both Blazor Server and Blazor WebAssembly projects target .NET 5 ( <TargetFramework>net5.0</TargetFramework> ). To better align with the target framework change, the following Blazor packages no longer target .NET Standard 2.1: Microsoft.AspNetCore.Components Microsoft.AspNetCore.Components.Authorization Microsoft.AspNetCore.Components.Forms Microsoft.AspNetCore.Components.Web Microsoft.AspNetCore.Components.WebAssembly Microsoft.AspNetCore.Components.WebAssembly.Authentication Microsoft.JSInterop Microsoft.JSInterop.WebAssembly Microsoft.Authentication.WebAssembly.Msal For discussion, see GitHub issue dotnet/aspnetcore#23424 . Version introduced 5.0 Preview 7 Old behavior In Blazor 3.1 and 3.2, packages target .NET Standard 2.1 and .NET Core 3.1. New behavior In ASP.NET Core 5.0, packages target .NET 5.0. Reason for change The change was made to better align with .NET target framework requirements. Recommended action Blazor 3.2 WebAssembly projects should target .NET 5 as part of updating their package references to 5.x.x. Libraries that reference one of these packages can either target .NET 5 or multi-target depending on their requirements. Affected APIs None Blazor: ProtectedBrowserStorage feature moved to shared framework Article • 09/15/2021 As part of the ASP.NET Core 5.0 RC2 release, the ProtectedBrowserStorage feature moved to the ASP.NET Core shared framework. Version introduced 5.0 RC2 Old behavior In ASP.NET Core 5.0 Preview 8, the feature is available as a part of the Microsoft.AspNetCore.Components.Web.Extensions package but was only usable in Blazor WebAssembly. In ASP.NET Core 5.0 RC1, the feature is available as part of the Microsoft.AspNetCore.Components.ProtectedBrowserStorage package, which references the Microsoft.AspNetCore.App shared framework. New behavior In ASP.NET Core 5.0 RC2, a NuGet package reference is no longer needed to reference and use the feature. Reason for change The move to the shared framework is a better fit for the user experience customers expect. Recommended action If upgrading from ASP.NET Core 5.0 RC1, complete the following steps: 1. Remove the Microsoft.AspNetCore.Components.ProtectedBrowserStorage package reference from the project. 2. Replace using Microsoft.AspNetCore.Components.ProtectedBrowserStorage; with using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; . 3. Remove the call to AddProtectedBrowserStorage from your Startup class. If upgrading from ASP.NET Core 5.0 Preview 8, complete the following steps: 1. Remove the Microsoft.AspNetCore.Components.Web.Extensions package reference from the project. 2. Replace using Microsoft.AspNetCore.Components.Web.Extensions; with using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; . 3. Remove the call to AddProtectedBrowserStorage from your Startup class. Affected APIs None Blazor: RenderTreeFrame readonly public fields have become properties Article • 02/25/2022 In ASP.NET Core 3.0 and 3.1, the RenderTreeFrame struct exposed various readonly public fields, including FrameType, Sequence, and others. In ASP.NET Core 5.0 RC1 and later versions, all the readonly public fields changed to readonly public properties. This change won't affect many developers because: Any app or library that simply uses .razor files (or even manual RenderTreeBuilder calls) to define its components wouldn't be referencing this type directly. The RenderTreeFrame type itself is regarded as an implementation detail, not intended for use outside of the framework. ASP.NET Core 3.0 and later includes an analyzer that issues compiler warnings if the type is being used directly. Even if you reference RenderTreeFrame directly, this change is binary-breaking but not source-breaking. That is, your existing source code will compile and behave properly. You'll only encounter an issue if compiling against a .NET Core 3.x framework and then running those binaries against the .NET 5 or a later framework. For discussion, see GitHub issue dotnet/aspnetcore#25727 . Version introduced 5.0 RC1 Old behavior Public members on RenderTreeFrame are defined as fields. For example, renderTreeFrame.Sequence and renderTreeFrame.ElementName . New behavior Public members on RenderTreeFrame are defined as properties with the same names as before. For example, renderTreeFrame.Sequence and renderTreeFrame.ElementName . If older precompiled code hasn't been recompiled since this change, it may throw an exception similar to MissingFieldException: Field not found: 'Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame.FrameType'. Reason for change This change was necessary to implement high-impact performance improvements in Razor component rendering in ASP.NET Core 5.0. The same levels of safety and encapsulation are maintained. Recommended action Most Blazor developers are unaffected by this change. The change is more likely to affect library and package authors, but only in rare cases. Specifically, if you're developing: An app and using ASP.NET Core 3.x or upgrading to 5.0 RC1 or later, you don't need to change your own code. However, if you depend on a library that upgraded to account for this change, then you need to update to a newer version of that library. A library and want to support only ASP.NET Core 5.0 RC1 or later, no action is needed. Just ensure that your project file declares a <TargetFramework> value of net5.0 or a later version. A library and want to support both ASP.NET Core 3.x and 5.0, determine whether your code reads any RenderTreeFrame members. For example, evaluating someRenderTreeFrame.FrameType . Most libraries won't read RenderTreeFrame members, including libraries that contain .razor components. In this case, no action is needed. However, if your library does that, you'll need to multi-target to support both netstandard2.1 and net5.0 . Apply the following changes in your project file: Replace the existing <TargetFramework> element with <TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks> . Use a conditional Microsoft.AspNetCore.Components package reference to account for both versions you wish to support. For example: XML <PackageReference Include="Microsoft.AspNetCore.Components" Version="3.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" /> <PackageReference Include="Microsoft.AspNetCore.Components" Version="5.0.0-rc.1.*" Condition="'$(TargetFramework)' != 'netstandard2.0'" /> For further clarification, see this diff showing how @jsakamoto already upgraded the Toolbelt.Blazor.HeadElement library . Affected APIs Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame Blazor: Updated validation logic for static web assets Article • 09/15/2021 There was an issue in conflict validation for static web assets in ASP.NET Core 3.1 and Blazor WebAssembly 3.2. The issue: Prevented proper conflict detection between the host assets and assets from Razor Class Libraries (RCLs) and Blazor WebAssembly apps. Mostly affects Blazor WebAssembly apps, since by default, static web assets in RCLs are served under the _content/$(PackageId) prefix. Version introduced 5.0 Old behavior During development, an RCL's static web assets could be silently overridden with host project assets on the same host path. Consider an RCL that has defined a static web asset to be served at /folder/file.txt. If the host placed a file at wwwroot/folder/file.txt, the file on the server silently overrode the file on the RCL or Blazor WebAssembly app. New behavior ASP.NET Core correctly detects when this issue happens. It informs you, the user, of the conflict so that you can take the appropriate action. Reason for change Static web assets weren't intended to be overridable by files on the wwwroot host of the project. Allowing for the overriding of those files could lead to errors that are difficult to diagnose. The result could be undefined behavior changes in published apps. Recommended action By default, there's no reason for an RCL file to conflict with a file on the host. RCL files are prefixed with _content/${PackageId} . Blazor WebAssembly files are placed at the root of the host URL space, which makes conflicts easier. For example, Blazor WebAssembly apps contain a favicon.ico file that the host might also include in its wwwroot folder. If the conflict's source is an RCL file, it often means code is copying assets from the library into the project's wwwroot folder. Writing code to copy files defeats a primary goal of static web assets. This goal is fundamental to get updates on the browser when the contents are updated without having to trigger a new compilation. You may choose to preserve this behavior and maintain the file on the host. To do so, remove the file from the list of static web assets with a custom MSBuild target. To use the RCL's file or the Blazor WebAssembly app's file instead of the host project's file, remove the file from the host project. Affected APIs None System.Security.Cryptography APIs not supported on Blazor WebAssembly Article • 09/15/2021 System.Security.Cryptography APIs throw a PlatformNotSupportedException at run time when run on a browser. Change description In previous .NET versions, most of the System.Security.Cryptography APIs aren't available to Blazor WebAssembly apps. Starting in .NET 5, Blazor WebAssembly apps target the full .NET 5 API surface area, however, not all .NET 5 APIs are supported due to browser sandbox constraints. In .NET 5 and later versions, the unsupported System.Security.Cryptography APIs throw a PlatformNotSupportedException when running on WebAssembly. Tip The Platform compatibility analyzer will flag any calls to the affected APIs when you build a project that supports the browser platform. This analyzer runs by default in .NET 5 and later apps. Reason for change Microsoft is unable to ship OpenSSL as a dependency in the Blazor WebAssembly configuration. We attempted to work around this by trying to integrate with the browser's SubtleCrypto API. Unfortunately, it required significant API changes that made it too hard to integrate. Version introduced 5.0 Recommended action There are no good workarounds to suggest at this time. Affected APIs All System.Security.Cryptography APIs except the following: System.Security.Cryptography.RandomNumberGenerator System.Security.Cryptography.IncrementalHash System.Security.Cryptography.SHA1 System.Security.Cryptography.SHA256 System.Security.Cryptography.SHA384 System.Security.Cryptography.SHA512 System.Security.Cryptography.SHA1Managed System.Security.Cryptography.SHA256Managed System.Security.Cryptography.SHA384Managed System.Security.Cryptography.SHA512Managed Extensions: Package reference changes affecting some NuGet packages Article • 09/15/2021 With the migration of some Microsoft.Extensions.* NuGet packages from the dotnet/extensions repository to dotnet/runtime , as described in aspnet/Announcements#411 , packaging changes are being applied to some of the migrated packages. For discussion on this issue, see dotnet/aspnetcore#21033 . Version introduced 5.0 Preview 4 Old behavior Some Microsoft.Extensions.* packages included package references for APIs on which your app relied. New behavior Your app may have to add Microsoft.Extensions.* package dependencies. Reason for change Packaging policies were updated to better align with the dotnet/runtime repository. Under the new policy, unused package references are removed from .nupkg files during packaging. Recommended action Consumers of the affected packages should add a direct dependency on the removed package dependency in their project if APIs from removed package dependency are used. The following table lists the affected packages and the corresponding changes. Package name Change description Package name Change description Microsoft.Extensions.Configuration.Binder Removed reference to Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.Json Removed reference to System.Threading.Tasks.Extensions Microsoft.Extensions.Hosting.Abstractions Removed reference to Microsoft.Extensions.Logging.Abstractions Microsoft.Extensions.Logging Removed reference to Microsoft.Extensions.Configuration.Binder Microsoft.Extensions.Logging.Console Removed reference to Microsoft.Extensions.Configuration.Abstractions Microsoft.Extensions.Logging.EventLog Removed reference to System.Diagnostics.EventLog for the .NET Framework 4.6.1 target framework moniker Microsoft.Extensions.Logging.EventSource Removed reference to System.Threading.Tasks.Extensions Microsoft.Extensions.Options Removed reference to System.ComponentModel.Annotations For example, the package reference to Microsoft.Extensions.Configuration was removed from Microsoft.Extensions.Configuration.Binder . No API from the dependency was used in the package. Users of Microsoft.Extensions.Configuration.Binder who depend on APIs from Microsoft.Extensions.Configuration should add a direct reference to it in their project. Affected APIs None HTTP: Kestrel and IIS BadHttpRequestException types marked obsolete and replaced Article • 09/15/2021 Microsoft.AspNetCore.Server.Kestrel.BadHttpRequestException and Microsoft.AspNetCore.Server.IIS.BadHttpRequestException have been marked obsolete and changed to derive from Microsoft.AspNetCore.Http.BadHttpRequestException . The Kestrel and IIS servers still throw their old exception types for backwards compatibility. The obsolete types will be removed in a future release. For discussion, see dotnet/aspnetcore#20614 . Version introduced 5.0 Preview 4 Old behavior Microsoft.AspNetCore.Server.Kestrel.BadHttpRequestException and Microsoft.AspNetCore.Server.IIS.BadHttpRequestException derived from System.IO.IOException. New behavior Microsoft.AspNetCore.Server.Kestrel.BadHttpRequestException and Microsoft.AspNetCore.Server.IIS.BadHttpRequestException are obsolete. The types also derive from Microsoft.AspNetCore.Http.BadHttpRequestException , which derives from System.IO.IOException . Reason for change The change was made to: Consolidate duplicate types. Unify behavior across server implementations. An app can now catch the base exception Microsoft.AspNetCore.Http.BadHttpRequestException when using either Kestrel or IIS. Recommended action Replace usages of Microsoft.AspNetCore.Server.Kestrel.BadHttpRequestException and Microsoft.AspNetCore.Server.IIS.BadHttpRequestException with Microsoft.AspNetCore.Http.BadHttpRequestException . Affected APIs Microsoft.AspNetCore.Server.IIS.BadHttpRequestException Microsoft.AspNetCore.Server.Kestrel.BadHttpRequestException HTTP: HttpClient instances created by IHttpClientFactory log integer status codes Article • 09/15/2021 HttpClient instances created by IHttpClientFactory log HTTP status codes as integers instead of with status code names. Version introduced 5.0 Preview 1 Old behavior Logging uses the textual descriptions of HTTP status codes. Consider the following log messages: Output Received HTTP response after 56.0044ms - OK End processing HTTP request after 70.0862ms - OK New behavior Logging uses the integer values of HTTP status codes. Consider the following log messages: Output Received HTTP response after 56.0044ms - 200 End processing HTTP request after 70.0862ms - 200 Reason for change The original behavior of this logging is inconsistent with other parts of ASP.NET Core that have always used integer values. The inconsistency makes logs difficult to query via structured logging systems such as Elasticsearch . For more context, see dotnet/extensions#1549 . Using integer values is more flexible than text because it allows queries on ranges of values. Adding another log value to capture the integer status code was considered. Unfortunately, doing so would introduce another inconsistency with the rest of ASP.NET Core. HttpClient logging and HTTP server/hosting logging use the same StatusCode key name already. Recommended action The best option is to update logging queries to use the integer values of status codes. This option may cause some difficulty writing queries across multiple ASP.NET Core versions. However, using integers for this purpose is much more flexible for querying logs. If you need to force compatibility with the old behavior and use textual status codes, replace the IHttpClientFactory logging with your own: 1. Copy the .NET Core 3.1 versions of the following classes into your project: LoggingHttpMessageHandlerBuilderFilter LoggingHttpMessageHandler LoggingScopeHttpMessageHandler HttpHeadersLogValue 2. Rename the classes to avoid conflicts with public types in the Microsoft.Extensions.Http NuGet package. 3. Replace the built-in implementation of LoggingHttpMessageHandlerBuilderFilter with your own in the project's Startup.ConfigureServices method. For example: C# public void ConfigureServices(IServiceCollection services) { // Other service registrations go first. Code omitted for brevity. // Place the following after all AddHttpClient registrations. services.RemoveAll<IHttpMessageHandlerBuilderFilter>(); services.AddSingleton<IHttpMessageHandlerBuilderFilter, MyLoggingHttpMessageHandlerBuilderFilter>(); } Affected APIs System.Net.Http.HttpClient HttpSys: Client certificate renegotiation disabled by default Article • 09/15/2021 The option to renegotiate a connection and request a client certificate has been disabled by default. For discussion, see issue dotnet/aspnetcore#23181 . Version introduced ASP.NET Core 5.0 Old behavior The connection can be renegotiated to request a client certificate. New behavior Client certificates can only be requested during the initial connection handshake. For more information, see pull request dotnet/aspnetcore#23162 . Reason for change Renegotiation caused a number of performance and deadlock issues. It's also not supported in HTTP/2. For additional context from when the option to control this behavior was introduced in ASP.NET Core 3.1, see issue dotnet/aspnetcore#14806 . Recommended action Apps that require client certificates should use netsh.exe to set the clientcertnegotiation option to enabled . For more information, see netsh http commands. If you want client certificates enabled for only some parts of your app, see the guidance at Optional client certificates. If you need the old renegotiate behavior, set HttpSysOptions.ClientCertificateMethod to the old value ClientCertificateMethod.AllowRenegotiate . This isn't recommended for the reasons outlined above and in the linked guidance. Affected APIs ConnectionInfo.ClientCertificate ConnectionInfo.GetClientCertificateAsync HttpSysOptions.ClientCertificateMethod IIS: UrlRewrite middleware query strings are preserved Article • 12/04/2021 An IIS UrlRewrite middleware defect prevented the query string from being preserved in rewrite rules. That defect has been fixed to maintain consistency with the IIS UrlRewrite Module's behavior. For discussion, see issue dotnet/aspnetcore#22972 . Version introduced ASP.NET Core 5.0 Old behavior Consider the following rewrite rule: XML <rule name="MyRule" stopProcessing="true"> <match url="^about" /> <action type="Redirect" url="/contact" redirectType="Temporary" appendQueryString="true" /> </rule> The preceding rule doesn't append the query string. A URI like /about?id=1 redirects to /contact instead of /contact?id=1 . The appendQueryString attribute defaults to true as well. New behavior The query string is preserved. The URI from the example in Old behavior would be /contact?id=1 . Reason for change The old behavior didn't match the IIS UrlRewrite Module's behavior. To support porting between the middleware and module, the goal is to maintain consistent behaviors. Recommended action If the behavior of removing the query string is preferred, set the action element to appendQueryString="false" . Affected APIs IISUrlRewriteOptionsExtensions.AddIISUrlRewrite Kestrel: Configuration changes at run time detected by default Article • 09/15/2021 Kestrel now reacts to changes made to the Kestrel section of the project's IConfiguration instance (for example, appsettings.json) at run time. To learn more about how to configure Kestrel using appsettings.json, see the appsettings.json example in Endpoint configuration. Kestrel will bind, unbind, and rebind endpoints as necessary to react to these configuration changes. For discussion, see issue dotnet/aspnetcore#22807 . Version introduced 5.0 Preview 7 Old behavior Before ASP.NET Core 5.0 Preview 6, Kestrel didn't support changing configuration at run time. In ASP.NET Core 5.0 Preview 6, you could opt into the now-default behavior of reacting to configuration changes at run time. Opting in required binding Kestrel's configuration manually: C# using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; public class Program { public static void Main(string[] args) => CreateHostBuilder(args).Build().Run(); public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel((builderContext, kestrelOptions) => { kestrelOptions.Configure( builderContext.Configuration.GetSection("Kestrel"), reloadOnChange: true); }); webBuilder.UseStartup<Startup>(); }); } New behavior Kestrel reacts to configuration changes at run time by default. To support that change, ConfigureWebHostDefaults calls KestrelServerOptions.Configure(IConfiguration, bool) with reloadOnChange: true by default. Reason for change The change was made to support endpoint reconfiguration at run time without completely restarting the server. Unlike with a full server restart, unchanged endpoints aren't unbound even temporarily. Recommended action For most scenarios in which Kestrel's default configuration section doesn't change at run time, this change has no impact and no action is needed. For scenarios in which Kestrel's default configuration section does change at run time and Kestrel should react to it, this is now the default behavior. For scenarios in which Kestrel's default configuration section changes at run time and Kestrel shouldn't react to it, you can opt out as follows: C# using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; public class Program { public static void Main(string[] args) => CreateHostBuilder(args).Build().Run(); public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel((builderContext, kestrelOptions) => { kestrelOptions.Configure( builderContext.Configuration.GetSection("Kestrel"), reloadOnChange: false); }); webBuilder.UseStartup<Startup>(); }); } Notes: This change doesn't modify the behavior of the KestrelServerOptions.Configure(IConfiguration) overload, which still defaults to the reloadOnChange: false behavior. It's also important to make sure the configuration source supports reloading. For JSON sources, reloading is configured by calling AddJsonFile(path, reloadOnChange: true) . Reloading is already configured by default for appsettings.json and appsettings. {Environment}.json. Affected APIs GenericHostBuilderExtensions.ConfigureWebHostDefaults Kestrel: Default supported TLS protocol versions changed Article • 09/15/2021 Kestrel now uses the system default TLS protocol versions rather than restricting connections to the TLS 1.1 and TLS 1.2 protocols like it did previously. This change allows: TLS 1.3 to be used by default in environments that support it. TLS 1.0 to be used in some environments (such as Windows Server 2016 by default), which is usually not desirable. For discussion, see issue dotnet/aspnetcore#22563 . Version introduced 5.0 Preview 6 Old behavior Kestrel required that connections use TLS 1.1 or TLS 1.2 by default. New behavior Kestrel allows the operating system to choose the best protocol to use and to block insecure protocols. HttpsConnectionAdapterOptions.SslProtocols now defaults to SslProtocols.None instead of SslProtocols.Tls12 | SslProtocols.Tls11 . Reason for change The change was made to support TLS 1.3 and future TLS versions by default as they become available. Recommended action Unless your app has a specific reason not to, you should use the new defaults. Verify your system is configured to allow only secure protocols. To disable older protocols, take one of the following actions: Disable older protocols, such as TLS 1.0, system-wide with the Windows instructions. It's currently enabled by default on all Windows versions. Manually select which protocols you want to support in code as follows: C# using System.Security.Authentication; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; public class Program { public static void Main(string[] args) => CreateHostBuilder(args).Build().Run(); public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel(kestrelOptions => { kestrelOptions.ConfigureHttpsDefaults(httpsOptions => { httpsOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13; }); }); webBuilder.UseStartup<Startup>(); }); } Unfortunately, there's no API to exclude specific protocols. Affected APIs HttpsConnectionAdapterOptions.SslProtocols Kestrel: HTTP/2 disabled over TLS on incompatible Windows versions Article • 12/04/2021 To enable HTTP/2 over Transport Layer Security (TLS) on Windows, two requirements need to be met: Application-Layer Protocol Negotiation (ALPN) support, which is available starting with Windows 8.1 and Windows Server 2012 R2. A set of ciphers compatible with HTTP/2, which is available starting with Windows 10 and Windows Server 2016. As such, Kestrel's behavior when HTTP/2 over TLS is configured has changed to: Downgrade to Http1 and log a message at the Information level when ListenOptions.HttpProtocols is set to Http1AndHttp2 . Http1AndHttp2 is the default value for ListenOptions.HttpProtocols . Throw a NotSupportedException when ListenOptions.HttpProtocols is set to Http2 . For discussion, see issue dotnet/aspnetcore#23068 . Version introduced ASP.NET Core 5.0 Old behavior The following table outlines the behavior when HTTP/2 over TLS is configured. Protocols Http2 Http1AndHttp2 Windows 7, Windows 8, Windows 8.1, Windows 10, Windows Server 2008 R2, or earlier Windows Server 2012 Windows Server 2012 R2 Windows Server 2016, or newer Throw Error during TLS handshake * No error NotSupportedException Error during TLS handshake Downgrade to Http1 Downgrade to Error during TLS handshake * No error Http1 * Configure compatible cipher suites to enable these scenarios. New behavior The following table outlines the behavior when HTTP/2 over TLS is configured. Protocols Windows 7, Windows Server Windows 8, Windows Server Windows 8.1, Windows Server Windows 10, 2008 R2, or earlier 2012 2012 R2 Windows Server 2016, or newer Http2 Throw Throw Throw NotSupportedException NotSupportedException NotSupportedException No error ** Http1AndHttp2 Downgrade to Http1 Downgrade to Http1 Downgrade to Http1 No error ** ** Configure compatible cipher suites and set the app context switch Microsoft.AspNetCore.Server.Kestrel.EnableWindows81Http2 to true to enable these scenarios. Reason for change This change ensures compatibility errors for HTTP/2 over TLS on older Windows versions are surfaced as early and as clearly as possible. Recommended action Ensure HTTP/2 over TLS is disabled on incompatible Windows versions. Windows 8.1 and Windows Server 2012 R2 are incompatible since they lack the necessary ciphers by default. However, it's possible to update the Computer Configuration settings to use HTTP/2 compatible ciphers. For more information, see TLS cipher suites in Windows 8.1. Once configured, HTTP/2 over TLS on Kestrel must be enabled by setting the app context switch Microsoft.AspNetCore.Server.Kestrel.EnableWindows81Http2 . For example: C# AppContext.SetSwitch("Microsoft.AspNetCore.Server.Kestrel.EnableWindows81Htt p2", true); No underlying support has changed. For example, HTTP/2 over TLS has never worked on Windows 8 or Windows Server 2012. This change modifies how errors in these unsupported scenarios are presented. Affected APIs None Kestrel: Libuv transport marked as obsolete Article • 06/29/2022 Earlier versions of ASP.NET Core used Libuv as an implementation detail of how asynchronous input and output was performed. In ASP.NET Core 2.0, an alternative, Socket-based transport was developed. In ASP.NET Core 2.1, Kestrel switched to using the Socket -based transport by default. Libuv support was maintained for compatibility reasons. At this point, use of the Socket -based transport is far more common than the Libuv transport. Consequently, Libuv support is marked as obsolete in .NET 5 and will be removed entirely in .NET 6.0. As part of this change, Libuv support for new operating system platforms (like Windows Arm64) won't be added in the .NET 5 timeframe. For discussion on blocking issues that require the use of the Libuv transport, see the GitHub issue at dotnet/aspnetcore#23409 . Version introduced 5.0 Preview 8 Old behavior The Libuv APIs aren't marked as obsolete. New behavior The Libuv APIs are marked as obsolete. Reason for change The Socket -based transport is the default. There aren't any compelling reasons to continue using the Libuv transport. Recommended action Discontinue use of the Libuv package and extension methods. Affected APIs WebHostBuilderLibuvExtensions WebHostBuilderLibuvExtensions.UseLibuv Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions.Thread Count Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions.NoDela y Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions.MaxWr iteBufferSize Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions.MaxRe adBufferSize Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.LibuvTransportOptions.Bac klog Obsolete properties on ConsoleLoggerOptions Article • 09/15/2021 The Microsoft.Extensions.Logging.Console.ConsoleLoggerFormat type and some properties on ConsoleLoggerOptions are now obsolete. Change description Starting in .NET 5, the Microsoft.Extensions.Logging.Console.ConsoleLoggerFormat type and several properties on ConsoleLoggerOptions are obsolete. The obsolete properties are: ConsoleLoggerOptions.DisableColors ConsoleLoggerOptions.IncludeScopes ConsoleLoggerOptions.TimestampFormat ConsoleLoggerOptions.UseUtcTimestamp ConsoleLoggerOptions.Format With the introduction of new formatters, these properties are now available on the individual formatters. Reason for change The Format property is an enumeration type, which cannot represent a custom formatter. The remaining properties were set on ConsoleLoggerOptions and applied to both of the built-in formats for console logs. However, with the introduction of a new formatter API, it makes more sense for formatting to be represented on the formatter-specific options. This change provides better separation between the logger and logger formatters. Version introduced 5.0 Recommended action Use the new ConsoleLoggerOptions.FormatterName property in place of the ConsoleLoggerOptions.Format property. For example: C# loggingBuilder.AddConsole(options => { options.FormatterName = ConsoleFormatterNames.Systemd; }); There are several differences between FormatterName and Format: Format has only two possible options: Default and Systemd . FormatterName is case insensitive and can be any string. The reserved, built-in names are Simple , Systemd , and Json (.NET 5 and later). "Format": "Systemd" maps to "FormatterName": "Systemd" . "Format": "Default" maps to "FormatterName": "Simple" . For the DisableColors, IncludeScopes, TimestampFormat, and UseUtcTimestamp properties, use the corresponding property on the new ConsoleFormatterOptions, JsonConsoleFormatterOptions, or SimpleConsoleFormatterOptions types instead. For example, the corresponding setting for ConsoleLoggerOptions.DisableColors is SimpleConsoleFormatterOptions.ColorBehavior. Previous code: C# loggingBuilder.AddConsole(options => { options.DisableColors = true; }); New code: C# loggingBuilder.AddSimpleConsole(options => { options.ColorBehavior = LoggerColorBehavior.Disabled; }); The following two JSON snippets show how the configuration file changes. Old configuration file: JSON { "Logging": { "LogLevel": { "Default": "None", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information" }, "Format": "Systemd", "IncludeScopes": true, "TimestampFormat": "HH:mm:ss", "UseUtcTimestamp": true } }, "AllowedHosts": "*" } New configuration file: JSON { "Logging": { "LogLevel": { "Default": "None", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information" }, "FormatterName": "Systemd", "FormatterOptions": { "IncludeScopes": true, "TimestampFormat": "HH:mm:ss", "UseUtcTimestamp": true } } }, "AllowedHosts": "*" } Affected APIs Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.DisableColors Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.IncludeScopes Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.TimestampFormat Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.UseUtcTimestamp Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.Format Localization: ResourceManagerWithCultureStringLoc alizer class and WithCulture interface member removed Article • 12/04/2021 The ResourceManagerWithCultureStringLocalizer class and WithCulture method were removed in .NET 5. For context, see aspnet/Announcements#346 and dotnet/aspnetcore#3324 discussion on this change, see dotnet/aspnetcore#7756 . For . Version introduced 5.0 Old behavior The ResourceManagerWithCultureStringLocalizer class and the ResourceManagerStringLocalizer.WithCulture method are obsolete in .NET Core 3.0 and later. New behavior The ResourceManagerWithCultureStringLocalizer class and the ResourceManagerStringLocalizer.WithCulture method have been removed in .NET 5. For an inventory of the changes made, see the pull request at dotnet/extensions#2562 . Reason for change The ResourceManagerWithCultureStringLocalizer class and ResourceManagerStringLocalizer.WithCulture method were often sources of confusion for users of localization. The confusion was especially high when creating a custom IStringLocalizer implementation. This class and method give consumers the impression that an IStringLocalizer instance is expected to be "per-language, per-resource". In reality, the instance should only be "per-resource". At run time, the CultureInfo.CurrentUICulture property determines the language to be used. Recommended action Stop using the ResourceManagerWithCultureStringLocalizer class and the ResourceManagerStringLocalizer.WithCulture method. Affected APIs ResourceManagerWithCultureStringLocalizer ResourceManagerStringLocalizer.WithCulture Localization: "Pubternal" APIs removed Article • 09/15/2021 To better maintain the public API surface of ASP.NET Core, some "pubternal" localization APIs were removed. A "pubternal" API has a public access modifier and is defined in a namespace that implies an internal intent. For discussion, see dotnet/aspnetcore#22291 . Version introduced 5.0 Preview 6 Old behavior The following APIs were public : Microsoft.Extensions.Localization.Internal.AssemblyWrapper Microsoft.Extensions.Localization.Internal.IResourceStringProvider Microsoft.Extensions.Localization.ResourceManagerStringLocalizer constructor overloads accepting either of the following parameter types: AssemblyWrapper IResourceStringProvider New behavior The following list outlines the changes: Microsoft.Extensions.Localization.Internal.AssemblyWrapper became Microsoft.Extensions.Localization.AssemblyWrapper and is now internal . Microsoft.Extensions.Localization.Internal.IResourceStringProvider became Microsoft.Extensions.Localization.Internal.IResourceStringProvider and is now internal . Microsoft.Extensions.Localization.ResourceManagerStringLocalizer constructor overloads accepting either of the following parameter types are now internal : AssemblyWrapper IResourceStringProvider Reason for change Explained more thoroughly at aspnet/Announcements#377 , "pubternal" types were removed from the public API surface. These changes adapt more classes to that design decision. The classes in question were intended as extension points for the team's internal testing. Recommended action Although it's unlikely, some apps may intentionally or accidentally depend upon the "pubternal" types. See the New behavior sections to determine how to migrate away from the types. If you've identified a scenario which the public API allowed before this change but doesn't now, file an issue at dotnet/aspnetcore . Affected APIs Microsoft.Extensions.Localization.Internal.AssemblyWrapper Microsoft.Extensions.Localization.Internal.IResourceStringProvider ResourceManagerStringLocalizer.ResourceManagerStringLocalizer Localization: Obsolete constructor removed in request localization middleware Article • 09/15/2021 The RequestLocalizationMiddleware constructor that lacks an ILoggerFactory parameter was marked as obsolete in this commit . In ASP.NET Core 5.0, the obsolete constructor was removed. For discussion, see dotnet/aspnetcore#23785 . Version introduced 5.0 Preview 8 Old behavior The obsolete RequestLocalizationMiddleware.ctor(RequestDelegate, IOptions<RequestLocalizationOptions>) constructor exists. New behavior The obsolete RequestLocalizationMiddleware.ctor(RequestDelegate, IOptions<RequestLocalizationOptions>) constructor doesn't exist. Reason for change This change ensures that the request localization middleware always has access to a logger. Recommended action When manually constructing an instance of RequestLocalizationMiddleware , pass an ILoggerFactory instance in the constructor. If a valid ILoggerFactory instance isn't available in that context, consider passing the middleware constructor a NullLoggerFactory instance. Affected APIs RequestLocalizationMiddleware.ctor(RequestDelegate, IOptions<RequestLocalizationOptions>) Middleware: Database error page marked as obsolete Article • 09/15/2021 The DatabaseErrorPageMiddleware and its associated extension methods were marked as obsolete in ASP.NET Core 5.0. The middleware and extension methods will be removed in ASP.NET Core 6.0. The functionality will instead be provided by DatabaseDeveloperPageExceptionFilter and its extension methods. For discussion, see the GitHub issue at dotnet/aspnetcore#24987 . Version introduced 5.0 RC 1 Old behavior DatabaseErrorPageMiddleware and its associated extension methods weren't obsolete. New behavior DatabaseErrorPageMiddleware and its associated extension methods are obsolete. Reason for change DatabaseErrorPageMiddleware was migrated to an extensible API for the developer exception page. For more information on the extensible API, see GitHub issue dotnet/aspnetcore#8536 . Recommended action Complete the following steps: 1. Stop using DatabaseErrorPageMiddleware in your project. For example, remove the UseDatabaseErrorPage method call from Startup.Configure : C# public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDatabaseErrorPage(); } } 2. Add the developer exception page to your project. For example, call the UseDeveloperExceptionPage method in Startup.Configure : C# public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } } 3. Add the Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet package to the project file. 4. Add the database developer page exception filter to the services collection. For example, call the AddDatabaseDeveloperPageExceptionFilter method in Startup.ConfigureServices : C# public void ConfigureServices(IServiceCollection services) { services.AddDatabaseDeveloperPageExceptionFilter(); } Affected APIs Microsoft.AspNetCore.Builder.DatabaseErrorPageExtensions.UseDatabaseErrorPage Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddle ware Middleware: Exception Handler Middleware throws original exception if handler not found Article • 09/15/2021 Before ASP.NET Core 5.0, the Exception Handler Middleware executes the configured exception handler when an exception has occurred. If the exception handler, configured via ExceptionHandlingPath, can't be found, an HTTP 404 response is produced. The response is misleading in that it: Seems to be a user error. Obscures the fact that an exception occurred on the server. To address the misleading error in ASP.NET Core 5.0, the ExceptionHandlerMiddleware throws the original exception if the exception handler can't be found. As a result, an HTTP 500 response is produced by the server. The response will be easier to examine in the server logs when debugging the error that occurred. For discussion, see GitHub issue dotnet/aspnetcore#25288 . Version introduced 5.0 RC 1 Old behavior The Exception Handler Middleware produces an HTTP 404 response if the configured exception handler can't be found. New behavior The Exception Handler Middleware throws the original exception if the configured exception handler can't be found. Reason for change The HTTP 404 error doesn't make it obvious that an exception occurred on the server. This change produces an HTTP 500 error to make it obvious that: The problem isn't caused by a user error. An exception was encountered on the server. Recommended action There are no API changes. All existing apps will continue to compile and run. The exception thrown is handled by the server. For example, the exception is converted to an HTTP 500 error response by Kestrel or HTTP.sys. Affected APIs None MVC: ObjectModelValidator calls a new overload of ValidationVisitor.Validate Article • 11/08/2021 In ASP.NET Core 5.0, an overload of the ValidationVisitor.Validate was added. The new overload accepts the top-level model instance that contains properties: diff bool Validate(ModelMetadata metadata, string key, object model, bool alwaysValidateAtTopLevel); + bool Validate(ModelMetadata metadata, string key, object model, bool alwaysValidateAtTopLevel, object container); ObjectModelValidator invokes this new overload of ValidationVisitor to perform validation. This new overload is pertinent if your validation library integrates with ASP.NET Core MVC's model validation system. For discussion, see GitHub issue dotnet/aspnetcore#26020 . Version introduced 5.0 Old behavior ObjectModelValidator invokes the following overload during model validation: C# ValidationVisitor.Validate(ModelMetadata metadata, string key, object model, bool alwaysValidateAtTopLevel) New behavior ObjectModelValidator invokes the following overload during model validation: C# ValidationVisitor.Validate(ModelMetadata metadata, string key, object model, bool alwaysValidateAtTopLevel, object container) Reason for change This change was introduced to support validators, such as CompareAttribute, that rely on inspection of other properties. Recommended action Validation frameworks that rely on ObjectModelValidator to invoke the existing overload of ValidationVisitor must override the new method when targeting .NET 5 or later: C# public class MyCustomValidationVisitor : ValidationVisitor { + public override bool Validate(ModelMetadata metadata, string key, object model, bool alwaysValidateAtTopLevel, object container) + { + ... } Affected APIs ValidationVisitor.Validate Security: Cookie name encoding removed Article • 09/15/2021 The HTTP cookie standard allows only specific characters in cookie names and values. To support disallowed characters, ASP.NET Core: Encodes when creating a response cookie. Decodes when reading a request cookie. In ASP.NET Core 5.0, this encoding behavior changed in response to a security concern. For discussion, see GitHub issue dotnet/aspnetcore#23578 . Version introduced 5.0 Preview 8 Old behavior Response cookie names are encoded. Request cookie names are decoded. New behavior Encoding and decoding of cookie names was removed. For prior supported versions of ASP.NET Core, the team plans to mitigate the decoding issue in-place. Additionally, calling IResponseCookies.Append with an invalid cookie name throws an exception of type ArgumentException. Encoding and decoding of cookie values remains unchanged. Reason for change An issue was discovered in multiple web frameworks . The encoding and decoding could allow an attacker to bypass a security feature called cookie prefixes by spoofing reserved prefixes like __Host- with encoded values like __%48ost- . The attack requires a secondary exploit to inject the spoofed cookies, such as a cross-site scripting (XSS) vulnerability, in the website. These prefixes aren't used by default in ASP.NET Core or Microsoft.Owin libraries or templates. Recommended action If you're moving projects to ASP.NET Core 5.0 or later, ensure that their cookie names conform to the token specification requirements : ASCII characters excluding controls and separators "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | " [" | "]" | "?" | "=" | "{" | "}" | SP | HT . The use of non-ASCII characters in cookie names or other HTTP headers may cause an exception from the server or be improperly round-tripped by the client. Affected APIs HttpRequest.Cookies HttpResponse.Cookies Microsoft.Owin.IOwinRequest.Cookies Microsoft.Owin.IOwinResponse.Cookies Security: IdentityModel NuGet package versions updated Article • 09/15/2021 The following packages were updated to version 6.6.0: Microsoft.IdentityModel.Logging Microsoft.IdentityModel.Protocols.OpenIdConnect Microsoft.IdentityModel.Protocols.WsFederation System.IdentityModel.Tokens.Jwt Version introduced 5.0 Preview 7 Old behavior The package version used is 5.5.0. New behavior For details about changes between package versions, see the 6.6.0 release notes . Reason for change The packages were updated to take advantage of improvements in the underlying libraries. Recommended action The package updates don't introduce public API changes to ASP.NET Core. However, it's possible there are breaking changes in the packages themselves. Affected APIs None SignalR: MessagePack Hub Protocol options type changed Article • 09/15/2021 The ASP.NET Core SignalR MessagePack Hub Protocol options type has changed from IList<MessagePack.IFormatterResolver> to the MessagePack library's MessagePackSerializerOptions type. For discussion on this change, see dotnet/aspnetcore#20506 . Version introduced 5.0 Preview 4 Old behavior You can add to the options as shown in the following example: C# services.AddSignalR() .AddMessagePackProtocol(options => { options.FormatterResolvers.Add(MessagePack.Resolvers.StandardResolver.Instan ce); }); And replace the options as follows: C# services.AddSignalR() .AddMessagePackProtocol(options => { options.FormatterResolvers = new List<MessagePack.IFormatterResolver>() { MessagePack.Resolvers.StandardResolver.Instance }; }); New behavior You can add to the options as shown in the following example: C# services.AddSignalR() .AddMessagePackProtocol(options => { options.SerializerOptions = options.SerializeOptions.WithResolver(MessagePack.Resolvers.StandardResolver .Instance); }); And replace the options as follows: C# services.AddSignalR() .AddMessagePackProtocol(options => { options.SerializerOptions = MessagePackSerializerOptions .Standard .WithResolver(MessagePack.Resolvers.StandardResolver.Instance) .WithSecurity(MessagePackSecurity.UntrustedData); }); Reason for change This change is part of moving to MessagePack v2.x, which was announced in aspnet/Announcements#404 . The v2.x library has added an options API that's easier to use and provides more features than the list of MessagePack.IFormatterResolver that was exposed before. Recommended action This breaking change affects anyone who is configuring values on MessagePackHubProtocolOptions. If you're using the ASP.NET Core SignalR MessagePack Hub Protocol and modifying the options, update your usage to use the new options API as shown above. Affected APIs Microsoft.AspNetCore.SignalR.MessagePackHubProtocolOptions SignalR: MessagePack Hub Protocol moved to MessagePack 2.x package Article • 09/15/2021 The ASP.NET Core SignalR MessagePack Hub Protocol uses the MessagePack NuGet package for MessagePack serialization. ASP.NET Core 5.0 upgrades the package from 1.x to the latest 2.x package version. For discussion on this issue, see dotnet/aspnetcore#18692 . Version introduced 5.0 Preview 1 Old behavior ASP.NET Core SignalR used the MessagePack 1.x package to serialize and deserialize MessagePack messages. New behavior ASP.NET Core SignalR uses the MessagePack 2.x package to serialize and deserialize MessagePack messages. Reason for change The latest improvements in the MessagePack 2.x package add useful functionality. Recommended action This breaking change applies when: Setting or configuring values on MessagePackHubProtocolOptions. Using the MessagePack APIs directly and using the ASP.NET Core SignalR MessagePack Hub Protocol in the same project. The newer version will be loaded instead of the previous version. For migration guidance from the package authors, see Migrating from MessagePack v1.x to MessagePack v2.x . Some aspects of message serialization and deserialization are affected. Specifically, there are behavioral changes to how DateTime values are serialized . Affected APIs Microsoft.AspNetCore.SignalR.MessagePackHubProtocolOptions SignalR: UseSignalR and UseConnections methods removed Article • 09/15/2021 In ASP.NET Core 3.0, SignalR adopted endpoint routing. As part of that change, the UseSignalR, UseConnections, and some related methods were marked as obsolete. In ASP.NET Core 5.0, those obsolete methods were removed. For the full list of methods, see Affected APIs. For discussion on this issue, see dotnet/aspnetcore#20082 . Version introduced 5.0 Preview 3 Old behavior SignalR hubs and connection handlers could be registered in the middleware pipeline using the UseSignalR or UseConnections methods. New behavior SignalR hubs and connection handlers should be registered within UseEndpoints using the MapHub and MapConnectionHandler extension methods on IEndpointRouteBuilder. Reason for change The old methods had custom routing logic that didn't interact with other routing components in ASP.NET Core. In ASP.NET Core 3.0, a new general-purpose routing system, called endpoint routing, was introduced. Endpoint routing enabled SignalR to interact with other routing components. Switching to this model allows users to realize the full benefits of endpoint routing. Consequently, the old methods have been removed. Recommended action Remove code that calls UseSignalR or UseConnections from your project's Startup.Configure method. Replace it with calls to MapHub or MapConnectionHandler , respectively, within the body of a call to UseEndpoints . For example: Old code: C# app.UseSignalR(routes => { routes.MapHub<SomeHub>("/path"); }); New code: C# app.UseEndpoints(endpoints => { endpoints.MapHub<SomeHub>("/path"); }); In general, your previous MapHub and MapConnectionHandler calls can be transferred directly from the body of UseSignalR and UseConnections to UseEndpoints with little-tono change needed. Affected APIs ConnectionsAppBuilderExtensions.UseConnections SignalRAppBuilderExtensions.UseSignalR ConnectionsRouteBuilder.MapConnections ConnectionsRouteBuilder.MapConnectionHandler HubRouteBuilder.MapHub Static files: CSV content type changed to standards-compliant Article • 09/15/2021 In ASP.NET Core 5.0, the default Content-Type response header value that the Static File Middleware uses for .csv files has changed to the standards-compliant value text/csv . For discussion on this issue, see dotnet/aspnetcore#17385 . Version introduced 5.0 Preview 1 Old behavior The Content-Type header value application/octet-stream was used. New behavior The Content-Type header value text/csv is used. Reason for change Compliance with the RFC 7111 standard. Recommended action If this change impacts your app, you can customize the file extension-to-MIME type mapping. To revert to the application/octet-stream MIME type, modify the UseStaticFiles method call in Startup.Configure . For example: C# var provider = new FileExtensionContentTypeProvider(); provider.Mappings[".csv"] = MediaTypeNames.Application.Octet; app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider }); For more information on customizing the mapping, see FileExtensionContentTypeProvider. Affected APIs Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider Warning CA1416: Platform compatibility Article • 05/13/2022 .NET code analyzer rule CA1416 is enabled, by default, starting in .NET 5. It produces a build warning for calls to platform-specific APIs from call sites that don't verify the operating system. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA1416. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA1416 informs you when you're using platform-specific APIs from places where the platform context isn't verified. Rule CA1416, the platform compatibility analyzer, works hand-in-hand with some other features that are new in .NET 5. .NET 5 introduces the SupportedOSPlatformAttribute and UnsupportedOSPlatformAttribute, which let you specify the platforms that an API is or isn't supported on. In the absence of these attributes, an API is assumed to be supported on all platforms. These attributes have been applied to platform-specific APIs in the core .NET libraries. In projects that target platforms for which APIs that they use aren't available, rule CA1416 flags any platform-specific API call where the platform context isn't verified. Most of the APIs that are now decorated with the SupportedOSPlatformAttribute and UnsupportedOSPlatformAttribute attributes throw PlatformNotSupportedException exceptions when they're invoked on an unsupported operating system. Now that these APIs are marked as platform-specific, rule CA1416 helps you prevent run-time PlatformNotSupportedException exceptions by adding OS checks to your call sites. Examples The Console.Beep(Int32, Int32) method is only supported on Windows and is decorated with [SupportedOSPlatform("windows")] . The following code will produce a CA1416 warning at build time if the project targets net5.0 (cross platform). But this code won't warn if the project targets Windows ( net5.0windows ) and the GenerateAssemblyInfo is enabled for the project. For actions you can take to avoid the warning, see Recommended action. C# public void PlayCMajor() { Console.Beep(261, 1000); } The Image.FromFile(String) method is not supported in the browser and is decorated with [UnsupportedOSPlatform("browser")] . The following code will produce a CA1416 warning at build time if the project supports the browser platform. C# public void CreateImage() { Image newImage = Image.FromFile("SampImag.jpg"); } Tip Blazor WebAssembly projects and Razor class library projects include browser support automatically. To manually add the browser as a supported platform for your project, add the following entry to your project file: XML <ItemGroup> <SupportedPlatform Include="browser" /> </ItemGroup> Version introduced 5.0 Recommended action Ensure that platform-specific APIs are only called when the code is running on an appropriate platform. You can check the current operating system using one of the Is<Platform> methods in the System.OperatingSystem class, for example, OperatingSystem.IsWindows(), before calling a platform-specific API. You can use one of the Is<Platform> methods in the condition of an if statement: C# public void PlayCMajor() { if (OperatingSystem.IsWindows()) { Console.Beep(261, 1000); } } Or, if you don't want the overhead of an additional if statement at run time, call Debug.Assert(Boolean) instead: C# public void PlayCMajor() { Debug.Assert(OperatingSystem.IsWindows()); Console.Beep(261, 1000); } If you're authoring a library, you can mark your API as platform-specific. In this case, the burden of checking requirements falls on your callers. You can mark specific methods or types or an entire assembly. C# [SupportedOSPlatform("windows")] public void PlayCMajor() { Console.Beep(261, 1000); } If you don't want to fix all your call sites, you can choose one of the following options to suppress the warning: To suppress rule CA1416, you can do so using #pragma or the NoWarn compiler flag, or by setting the rule's severity to none in an .editorconfig file. C# public void PlayCMajor() { #pragma warning disable CA1416 Console.Beep(261, 1000); #pragma warning restore CA1416 } To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs For Windows platform: All APIs listed at https://github.com/dotnet/designs/blob/main/accepted/2020/windows-specificapis/windows-specific-apis.md . System.Security.Cryptography.DSAOpenSsl System.Security.Cryptography.ECDiffieHellmanOpenSsl System.Security.Cryptography.ECDsaOpenSsl System.Security.Cryptography.RSAOpenSsl For Blazor WebAssembly platform: All APIs listed at https://github.com/dotnet/runtime/issues/41087 See also CA1416: Validate platform compatibility Platform compatibility analyzer . Warning CA1417: OutAttribute on string parameter for P/Invoke Article • 11/08/2021 .NET code analyzer rule CA1417 is enabled, by default, starting in .NET 5. It produces a build warning for any Platform Invoke (P/Invoke) method definitions where a String parameter is passed by value and marked with OutAttribute. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA1417. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA1417 flags P/Invoke method definitions where a String parameter is marked with the OutAttribute attribute and is passed by value. For example: C# [DllImport("MyLibrary")] private static extern void PIMethod([Out] string s); The .NET runtime maintains a table, called the intern pool, that contains a single reference to each unique literal string in a program. If an interned string marked with OutAttribute is passed by value to a P/Invoke method, the runtime can be destabilized. For more information about string interning, see the remarks for String.Intern(String). Version introduced 5.0 Recommended action If you need to marshal modified string data back to the caller, pass the string by reference instead. C# [DllImport("MyLibrary")] private static extern void PIMethod(out string s); If you don't need to marshal modified string data back to the caller, simply remove the OutAttribute. C# [DllImport("MyLibrary")] private static extern void PIMethod(string s); For more information, see CA1417. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs Not detectable via API analysis. Warning CA1831: Use AsSpan instead of Range-based indexers for string Article • 11/08/2021 .NET code analyzer rule CA1831 is enabled, by default, starting in .NET 5. It produces a build warning for any code where a Range-based indexer is used on a string, but no copy was intended. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA1831. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA1831 finds instances where a Range-based indexer is used on a string, but no copy was intended. If the Range-based indexer is used directly on a string to produce an implicit cast, then an unnecessary copy of the requested portion of the string is created. For example: C# ReadOnlySpan<char> slice = str[1..3]; CA1831 suggests using the Range-based indexer on a span of the string, instead. For example: C# ReadOnlySpan<char> slice = str.AsSpan()[1..3]; Version introduced 5.0 Recommended action To correct your code and avoid unnecessary allocations, call AsSpan(String) or AsMemory(String) before using the Range-based indexer. For example: C# ReadOnlySpan<char> slice = str.AsSpan()[1..3]; If you don't want to change your code, you can disable the rule by setting its severity to suggestion or none . For more information, see Configure code analysis rules. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs System.Range Warning CA2013: Do not use ReferenceEquals with value types Article • 11/08/2021 .NET code analyzer rule CA2013 is enabled, by default, starting in .NET 5. It produces a build warning for any code where ReferenceEquals(Object, Object) is used to compare one or more value types for equality. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA2013. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA2013 finds instances where ReferenceEquals(Object, Object) is used to compare one or more value types for equality. Comparing value types for equality in this way can lead to incorrect results, because the values are boxed before they're compared. ReferenceEquals(Object, Object) will return false even if the compared values represent the same instance of a value type. Version introduced 5.0 Recommended action Change the code to use an appropriate equality operator, such as == . You should not suppress this warning. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs System.Object.ReferenceEquals(Object, Object) Warning CA2014: Do not use stackalloc in loops Article • 11/08/2021 .NET code analyzer rule CA2014 is enabled, by default, starting in .NET 5. It produces a build warning for any C# code where a stackalloc expression is used inside a loop. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA2014. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA2014 looks for C# code where a stackalloc expression is used inside a loop. stackalloc allocates memory from the current stack frame. The memory isn't released until the current method call returns, which can lead to stack overflows. Because you can't catch stack overflow exceptions, the app will terminate in case of stack overflow. Version introduced 5.0 Recommended action Avoid using stackalloc inside loops. Allocate the memory block outside the loop and reuse it inside the loop. For more information, see CA2014. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs Not detectable via API analysis. Warning CA2015: Do not define finalizers for types derived from MemoryManager<T> Article • 11/08/2021 .NET code analyzer rule CA2015 is enabled, by default, starting in .NET 5. It produces a build warning for any types that derive from MemoryManager<T> that define a finalizer. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA2015. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA2015 flags types that derive from MemoryManager<T> that define a finalizer. Adding a finalizer to a type that derives from MemoryManager<T> is likely an indication of a bug. It suggests that a native resource that could have been obtained in a Span<T> is getting cleaned up, potentially while it's still in use by the Span<T>. Version introduced 5.0 Recommended action Remove the finalizer definition. For more information, see CA2015. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs Not detectable via API analysis. Warning CA2200: Rethrow to preserve stack details Article • 11/08/2021 .NET code analyzer rule CA2200 is enabled, by default, starting in .NET 5. It produces a build warning for any catch blocks that rethrow an exception and the exception is explicitly specified in the throw statement. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA2200. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA2200 flags code where exceptions are rethrown and the exception variable is specified in the throw statement. When an exception is thrown, part of the information it carries is the stack trace. The stack trace is a list of the method call hierarchy that starts with the method that throws the exception and ends with the method that catches the exception. If an exception is rethrown by specifying the exception in the throw statement, the stack trace restarts at the current method and the list of method calls between the original method that threw the exception and the current method is lost. To keep the original stack trace information with the exception, use the throw statement without specifying the exception. The following code snippet does not produce a warning for rule CA2200. The commented line would trigger a violation, however. C# catch (ArithmeticException e) { // throw e; throw; } Version introduced 5.0 Recommended action Rethrow exceptions without specifying the exception explicitly. For more information, see CA2200. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs Not detectable via API analysis. Warning CA2247: Argument to TaskCompletionSource constructor should be TaskCreationOptions value Article • 11/08/2021 .NET code analyzer rule CA2247 is enabled, by default, starting in .NET 5. It produces a build warning for calls to the TaskCompletionSource<TResult> constructor that pass an argument of type TaskContinuationOptions. Change description Starting in .NET 5, the .NET SDK includes .NET source code analyzers. Several of these rules are enabled, by default, including CA2247. If your project contains code that violates this rule and is configured to treat warnings as errors, this change could break your build. Rule CA2247 finds calls to the TaskCompletionSource<TResult> constructor that pass an argument of type TaskContinuationOptions. The TaskCompletionSource<TResult> type has a constructor that accepts a TaskCreationOptions value, and another constructor that accepts an Object. If you accidentally pass a TaskContinuationOptions value instead of a TaskCreationOptions value, the constructor with the Object parameter is called at run time. Your code will compile and run but won't have the intended behavior. Version introduced 5.0 Recommended action Replace the TaskContinuationOptions argument with the corresponding TaskCreationOptions value. Do not suppress this warning, since it almost always highlights a bug in your code. For more information, see CA2247. To disable code analysis completely, set EnableNETAnalyzers to false in your project file. For more information, see EnableNETAnalyzers. Affected APIs TaskCompletionSource<TResult>(Object) Assembly-related API behavior changes for single-file publishing format Article • 09/15/2021 Multiple APIs related to an assembly's file location have behavior changes when they're invoked in a single-file publishing format. Change description In single-file publishing for .NET 5 and later versions, bundled assemblies are loaded from memory instead of extracted to disk. For single-file published apps, this means that certain location-related APIs return different values on .NET 5 and later than on previous versions of .NET. The changes are as follows: API Previous versions .NET 5 and later Assembly.Location Returns extracted DLL file path Returns empty string for bundled assemblies Assembly.CodeBase Returns extracted DLL file path Throws exception for bundled assemblies Assembly.GetFile(String) Returns null for bundled assemblies Throws exception for bundled assemblies Environment.GetCommandLineArgs() Value is the name of the Value is the name of the host [0] entry point DLL executable AppContext.BaseDirectory Value is the temporary extraction directory Value is the containing directory of the host executable Version introduced 5.0 Recommended action Avoid dependencies on the file location of assemblies when publishing as a single file. Affected APIs Assembly.Location Assembly.CodeBase Assembly.GetFile(String) Environment.GetCommandLineArgs() AppContext.BaseDirectory Most code access security APIs are obsolete Article • 11/08/2021 Most code access security (CAS)-related types in .NET are now obsolete as warning. This includes CAS attributes, such as SecurityPermissionAttribute, CAS permission objects, such as SocketPermission, EvidenceBase-derived types, and other supporting APIs. Change description In .NET Framework 2.x - 4.x, CAS attributes and APIs can influence the course of code execution, including ensuring that CAS-demand stack walks succeed or fail. C# // In .NET Framework, the attribute causes CAS stack walks // to terminate successfully when this permission is demanded. [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] public void DoSomething() { // open a socket to contoso.com:443 } In .NET Core 2.x - 3.x, the runtime does not honor CAS attributes or CAS APIs. The runtime ignores attributes on method entry, and most programmatic APIs have no effect. C# // The .NET Core runtime ignores the following attribute. [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] public void DoSomething() { // open a socket to contoso.com:443 } Additionally, programmatic calls to expansive APIs ( Assert ) always succeed, while programmatic calls to restrictive APIs ( Deny , PermitOnly ) always throw an exception at run time. (PrincipalPermission is an exception to this rule. See the Recommended action section below.) C# public void DoAssert() { // The line below has no effect at run time. new SocketPermission(PermissionState.Unrestricted).Assert(); } public void DoDeny() { // The line below throws PlatformNotSupportedException at run time. new SocketPermission(PermissionState.Unrestricted).Deny(); } In .NET 5 and later versions, most CAS-related APIs are obsolete and produce compiletime warning SYSLIB0003 . C# [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] // warning SYSLIB0003 public void DoSomething() { new SocketPermission(PermissionState.Unrestricted).Assert(); // warning SYSLIB0003 new SocketPermission(PermissionState.Unrestricted).Deny(); // warning SYSLIB0003 } This is a compile-time only change. There is no run-time change from previous versions of .NET Core. Methods that perform no operation in .NET Core 2.x - 3.x will continue to perform no operation at run time in .NET 5 and later. Methods that throw PlatformNotSupportedException in .NET Core 2.x - 3.x will continue to throw a PlatformNotSupportedException at run time in .NET 5 and later. Reason for change Code access security (CAS) is an unsupported legacy technology. The infrastructure to enable CAS exists only in .NET Framework 2.x - 4.x, but is deprecated and not receiving servicing or security fixes. Due to CAS's deprecation, the supporting infrastructure was not brought forward to .NET Core or .NET 5+. However, the APIs were brought forward so that apps could cross-compile against .NET Framework and .NET Core. This led to "fail open" scenarios, where some CAS-related APIs exist and are callable but perform no action at run time. This can lead to security issues for components that expect the runtime to honor CAS- related attributes or programmatic API calls. To better communicate that the runtime doesn't respect these attributes or APIs, we have obsoleted the majority of them in .NET 5.0. Version introduced 5.0 Recommended action If you're asserting any security permission, remove the attribute or call that asserts the permission. C# // REMOVE the attribute below. [SecurityPermission(SecurityAction.Assert, ControlThread = true)] public void DoSomething() { } public void DoAssert() { // REMOVE the line below. new SecurityPermission(SecurityPermissionFlag.ControlThread).Assert(); } If you're denying or restricting (via PermitOnly ) any permission, contact your security advisor. Because CAS attributes are not honored by the .NET 5+ runtime, your application could have a security hole if it incorrectly relies on the CAS infrastructure to restrict access to these methods. C# // REVIEW the attribute below; could indicate security vulnerability. [SecurityPermission(SecurityAction.Deny, ControlThread = true)] public void DoSomething() { } public void DoPermitOnly() { // REVIEW the line below; could indicate security vulnerability. new SecurityPermission(SecurityPermissionFlag.ControlThread).PermitOnly(); } If you're demanding any permission (except PrincipalPermission), remove the demand. All demands will succeed at run time. C# // REMOVE the attribute below; it will always succeed. [SecurityPermission(SecurityAction.Demand, ControlThread = true)] public void DoSomething() { } public void DoDemand() { // REMOVE the line below; it will always succeed. new SecurityPermission(SecurityPermissionFlag.ControlThread).Demand(); } If you're demanding PrincipalPermission, consult the guidance for PrincipalPermissionAttribute is obsolete as error. That guidance applies for both PrincipalPermission and PrincipalPermissionAttribute. If you absolutely must disable these warnings (which is not recommended), you can suppress the SYSLIB0003 warning in code. C# #pragma warning disable SYSLIB0003 // disable the warning [SecurityPermission(SecurityAction.Demand, ControlThread = true)] #pragma warning restore SYSLIB0003 // re-enable the warning public void DoSomething() { } public void DoDemand() { #pragma warning disable SYSLIB0003 // disable the warning new SecurityPermission(SecurityPermissionFlag.ControlThread).Demand(); #pragma warning restore SYSLIB0003 // re-enable the warning } You can also suppress the warning in your project file. Doing so disables the warning for all source files within the project. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below suppresses SYSLIB0003 project-wide --> <NoWarn>$(NoWarn);SYSLIB0003</NoWarn> </PropertyGroup> </Project> 7 Note Suppressing SYSLIB0003 disables only the CAS-related obsoletion warnings. It does not disable any other warnings or change the behavior of the .NET 5+ runtime. Security Affected APIs System.AppDomain.PermissionSet System.Configuration.ConfigurationPermission System.Configuration.ConfigurationPermissionAttribute System.Data.Common.DBDataPermission System.Data.Common.DBDataPermissionAttribute System.Data.Odbc.OdbcPermission System.Data.Odbc.OdbcPermissionAttribute System.Data.OleDb.OleDbPermission System.Data.OleDb.OleDbPermissionAttribute System.Data.OracleClient.OraclePermission System.Data.OracleClient.OraclePermissionAttribute System.Data.SqlClient.SqlClientPermission System.Data.SqlClient.SqlClientPermissionAttribute System.Diagnostics.EventLogPermission System.Diagnostics.EventLogPermissionAttribute System.Diagnostics.PerformanceCounterPermission System.Diagnostics.PerformanceCounterPermissionAttribute System.DirectoryServices.DirectoryServicesPermission System.DirectoryServices.DirectoryServicesPermissionAttribute System.Drawing.Printing.PrintingPermission System.Drawing.Printing.PrintingPermissionAttribute System.Net.DnsPermission System.Net.DnsPermissionAttribute System.Net.Mail.SmtpPermission System.Net.Mail.SmtpPermissionAttribute System.Net.NetworkInformation.NetworkInformationPermission System.Net.NetworkInformation.NetworkInformationPermissionAttribute System.Net.PeerToPeer.Collaboration.PeerCollaborationPermission System.Net.PeerToPeer.Collaboration.PeerCollaborationPermissionAttribute System.Net.PeerToPeer.PnrpPermission System.Net.PeerToPeer.PnrpPermissionAttribute System.Net.SocketPermission System.Net.SocketPermissionAttribute System.Net.WebPermission System.Net.WebPermissionAttribute System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute System.Security.CodeAccessPermission System.Security.HostProtectionException System.Security.IPermission System.Security.IStackWalk System.Security.NamedPermissionSet System.Security.PermissionSet System.Security.Permissions.CodeAccessSecurityAttribute System.Security.Permissions.DataProtectionPermission System.Security.Permissions.DataProtectionPermissionAttribute System.Security.Permissions.DataProtectionPermissionFlags System.Security.Permissions.EnvironmentPermission System.Security.Permissions.EnvironmentPermissionAccess System.Security.Permissions.EnvironmentPermissionAttribute System.Security.Permissions.FileDialogPermission System.Security.Permissions.FileDialogPermissionAccess System.Security.Permissions.FileDialogPermissionAttribute System.Security.Permissions.FileIOPermission System.Security.Permissions.FileIOPermissionAccess System.Security.Permissions.FileIOPermissionAttribute System.Security.Permissions.GacIdentityPermission System.Security.Permissions.GacIdentityPermissionAttribute System.Security.Permissions.HostProtectionAttribute System.Security.Permissions.HostProtectionResource System.Security.Permissions.IUnrestrictedPermission System.Security.Permissions.IsolatedStorageContainment System.Security.Permissions.IsolatedStorageFilePermission System.Security.Permissions.IsolatedStorageFilePermissionAttribute System.Security.Permissions.IsolatedStoragePermission System.Security.Permissions.IsolatedStoragePermissionAttribute System.Security.Permissions.KeyContainerPermission System.Security.Permissions.KeyContainerPermissionAccessEntry System.Security.Permissions.KeyContainerPermissionAccessEntryCollection System.Security.Permissions.KeyContainerPermissionAccessEntryEnumerator System.Security.Permissions.KeyContainerPermissionAttribute System.Security.Permissions.KeyContainerPermissionFlags System.Security.Permissions.MediaPermission System.Security.Permissions.MediaPermissionAttribute System.Security.Permissions.MediaPermissionAudio System.Security.Permissions.MediaPermissionImage System.Security.Permissions.MediaPermissionVideo System.Security.Permissions.PermissionSetAttribute System.Security.Permissions.PermissionState System.Security.Permissions.PrincipalPermission System.Security.Permissions.PrincipalPermissionAttribute System.Security.Permissions.PublisherIdentityPermission System.Security.Permissions.PublisherIdentityPermissionAttribute System.Security.Permissions.ReflectionPermission System.Security.Permissions.ReflectionPermissionAttribute System.Security.Permissions.ReflectionPermissionFlag System.Security.Permissions.RegistryPermission System.Security.Permissions.RegistryPermissionAccess System.Security.Permissions.RegistryPermissionAttribute System.Security.Permissions.ResourcePermissionBase System.Security.Permissions.ResourcePermissionBaseEntry System.Security.Permissions.SecurityAction System.Security.Permissions.SecurityAttribute System.Security.Permissions.SecurityPermission System.Security.Permissions.SecurityPermissionAttribute System.Security.Permissions.SecurityPermissionFlag System.Security.Permissions.SiteIdentityPermission System.Security.Permissions.SiteIdentityPermissionAttribute System.Security.Permissions.StorePermission System.Security.Permissions.StorePermissionAttribute System.Security.Permissions.StorePermissionFlags System.Security.Permissions.StrongNameIdentityPermission System.Security.Permissions.StrongNameIdentityPermissionAttribute System.Security.Permissions.StrongNamePublicKeyBlob System.Security.Permissions.TypeDescriptorPermission System.Security.Permissions.TypeDescriptorPermissionAttribute System.Security.Permissions.TypeDescriptorPermissionFlags System.Security.Permissions.UIPermission System.Security.Permissions.UIPermissionAttribute System.Security.Permissions.UIPermissionClipboard System.Security.Permissions.UIPermissionWindow System.Security.Permissions.UrlIdentityPermission System.Security.Permissions.UrlIdentityPermissionAttribute System.Security.Permissions.WebBrowserPermission System.Security.Permissions.WebBrowserPermissionAttribute System.Security.Permissions.WebBrowserPermissionLevel System.Security.Permissions.ZoneIdentityPermission System.Security.Permissions.ZoneIdentityPermissionAttribute System.Security.Policy.ApplicationTrust.ApplicationTrust(PermissionSet, IEnumerable<StrongName>) System.Security.Policy.ApplicationTrust.FullTrustAssemblies System.Security.Policy.FileCodeGroup System.Security.Policy.GacInstalled System.Security.Policy.IIdentityPermissionFactory System.Security.Policy.PolicyLevel.AddNamedPermissionSet(NamedPermissionSet) System.Security.Policy.PolicyLevel.ChangeNamedPermissionSet(String, PermissionSet) System.Security.Policy.PolicyLevel.GetNamedPermissionSet(String) System.Security.Policy.PolicyLevel.RemoveNamedPermissionSet System.Security.Policy.PolicyStatement.PermissionSet System.Security.Policy.PolicyStatement.PolicyStatement System.Security.Policy.Publisher System.Security.Policy.Site System.Security.Policy.StrongName System.Security.Policy.StrongNameMembershipCondition System.Security.Policy.Url System.Security.Policy.Zone System.Security.SecurityManager System.ServiceProcess.ServiceControllerPermission System.ServiceProcess.ServiceControllerPermissionAttribute System.Transactions.DistributedTransactionPermission System.Transactions.DistributedTransactionPermissionAttribute System.Web.AspNetHostingPermission System.Web.AspNetHostingPermissionAttribute System.Xaml.Permissions.XamlLoadPermission CounterSet.CreateCounterSetInstance now throws InvalidOperationException if instance already exists Article • 09/15/2021 Starting in .NET 5, CounterSet.CreateCounterSetInstance(String) throws an InvalidOperationException instead of an ArgumentException if the counter set already exists. Change description In .NET Framework and .NET Core 1.0 to 3.1, you can create an instance of the counter set by calling CreateCounterSetInstance. However, if the counter set already exists, the method throws an ArgumentException exception. In .NET 5 and later versions, when you call CreateCounterSetInstance and the counter set exists, an InvalidOperationException exception is thrown. Version introduced 5.0 Recommended action If you catch ArgumentException exceptions in your app when calling CreateCounterSetInstance, consider also catching InvalidOperationException exceptions. 7 Note Catching ArgumentException exceptions is not recommended. Affected APIs System.Diagnostics.PerformanceData.CounterSet.CreateCounterSetInstance Default ActivityIdFormat is W3C Article • 11/08/2021 The default identifier format for activity (Activity.DefaultIdFormat) is now ActivityIdFormat.W3C. Change description The W3C activity ID format was introduced in .NET Core 3.0 as an alternative to the hierarchical ID format. However, to preserve compatibility, the W3C format wasn't made the default until .NET 5. The default was changed in .NET 5 because the W3C format has been ratified and gained traction across multiple language implementations. If your app targets a platform other than .NET 5 or later, it will experience the old behavior, where Hierarchical is the default format. This default applies to platforms net45+, netstandard1.1+, and netcoreapp (1.x, 2.x, and 3.x). In .NET 5 and later, Activity.DefaultIdFormat is set to ActivityIdFormat.W3C. Version introduced 5.0 Recommended action If your application is agnostic to the identifier that's used for distributed tracing, no action is needed. Libraries such as ASP.NET Core and HttpClient can consume or propagate both versions of the ActivityIdFormat. If you require interoperability with existing systems, or current systems rely on the format of the identifier, you can preserve the old behavior by setting DefaultIdFormat to ActivityIdFormat.Hierarchical. Alternatively, you can set an AppContext switch in one of three ways: In the project file. XML <ItemGroup> <RuntimeHostConfigurationOption Include="System.Diagnostics.DefaultActivityIdFormatIsHierarchial" Value="true" /> </ItemGroup> In the runtimeconfig.json file. JSON { "runtimeOptions": { "configProperties": { "System.Diagnostics.DefaultActivityIdFormatIsHierarchial": true } } } Through an environment variable. Set DOTNET_SYSTEM_DIAGNOSTICS_DEFAULTACTIVITYIDFORMATISHIERARCHIAL to true or 1. Affected APIs System.Diagnostics.Activity.DefaultIdFormat Environment.OSVersion returns the correct operating system version Article • 09/15/2021 Environment.OSVersion returns the actual version of the operating system (OS) instead of, for example, the OS that's selected for application compatibility. Change description In previous .NET versions, Environment.OSVersion returns an OS version that may be incorrect when an application runs under Windows compatibility mode. For more information, see GetVersionExA function remarks. On macOS, Environment.OSVersion returns the underlying Darwin kernel version. Starting in .NET 5, Environment.OSVersion returns the actual version of the operating system for Windows and macOS. The following table shows the difference in behavior. Previous .NET versions .NET 5+ Windows 6.2.9200.0 10.0.19042.0 macOS 19.6.0.0 10.15.7 Reason for change Users of this property expect it to return the actual version of the operating system. Most .NET apps don't specify their supported version in their application manifest, and thus get the default supported version from the dotnet host. As a result, the compatibility shim is rarely meaningful for the app that's running. When Windows releases a new version and an older dotnet host is still in use, these apps may get an incorrect OS version. Returning the actual version is more inline with developers' expectations of this API. With the introduction of OperatingSystem.IsWindowsVersionAtLeast, OperatingSystem.IsMacOSVersionAtLeast, and System.Runtime.Versioning.SupportedOSPlatformAttribute in .NET 5, Environment.OSVersion was changed to be consistent for Windows and macOS. Version introduced 5.0 Recommended action Review and test any code that uses Environment.OSVersion to ensure it behaves as desired. Affected APIs System.Environment.OSVersion FrameworkDescription's value is .NET instead of .NET Core Article • 09/15/2021 RuntimeInformation.FrameworkDescription now returns ".NET" instead of ".NET Core". Change description In previous .NET versions, RuntimeInformation.FrameworkDescription returns ".NET Core" as part of the description string, for example, .NET Core 3.1.1 . Starting in .NET 5, RuntimeInformation.FrameworkDescription returns ".NET" as part of the description string, for example, .NET 5.0.0 . Reason for change With .NET 5, netcoreapp is replaced by net as the short target-framework moniker. For consistency, the framework's description has also been updated. The change is cosmetic, as the FrameworkName isn't encoded anywhere else than in the RuntimeInformation.FrameworkDescription property. Version introduced 5.0 Recommended action Update any code that searches for ".NET Core" in the string returned by FrameworkDescription. Affected APIs System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription Global assembly cache APIs are obsolete Article • 11/08/2021 .NET Core and .NET 5 and later versions eliminate the concept of the global assembly cache (GAC) that was present in .NET Framework. As such, all .NET Core and .NET 5+ APIs that deal with the GAC either fail or perform no operation. To help steer developers away from these APIs, some GAC-related APIs are marked as obsolete, and generate a SYSLIB0005 warning at compile time. These APIs may be removed in a future version of .NET. Change description The following APIs are marked obsolete. API Marked obsolete in... Assembly.GlobalAssemblyCache 5.0 RC1 In .NET Framework 2.x - 4.x, the GlobalAssemblyCache property returns true if the queried assembly was loaded from the GAC, and false if it was loaded from a different location on disk. In .NET Core 2.x - 3.x, the GlobalAssemblyCache always returns false , reflecting that the GAC does not exist in .NET Core. C# Assembly asm = typeof(object).Assembly; // Prints 'True' on .NET Framework, 'False' on .NET Core. Console.WriteLine(asm.GlobalAssemblyCache); In .NET 5 and later versions, the GlobalAssemblyCache property continues to always return false . However, the property getter is also marked as obsolete to indicate to callers that they should stop accessing the property. Libraries and apps should not use the GlobalAssemblyCache API to make determinations about run-time behavior, as it always returns false in .NET Core and .NET 5 and later versions. C# Assembly asm = typeof(object).Assembly; // Prints 'False' on .NET 5+; also produces warning SYSLIB0005 at compile time. Console.WriteLine(asm.GlobalAssemblyCache); This is a compile-time only change. There is no run-time change from previous versions of .NET Core. Reason for change The global assembly cache (GAC) does not exist as a concept in .NET Core and .NET 5 and later versions. Version introduced .NET 5.0 Recommended action If your application queries the GlobalAssemblyCache property, consider removing the call. If you use the GlobalAssemblyCache value to choose between an "assembly in the GAC"-flow vs. an "assembly not in the GAC"-flow at run time, reconsider whether the flow still makes sense for a .NET Core or .NET 5+ application. If you must continue to use the obsolete APIs, you can suppress the SYSLIB0005 warning in code. C# Assembly asm = typeof(object).Assembly; #pragma warning disable SYSLIB0005 // Disable the warning. // Prints 'False' on .NET 5+. Console.WriteLine(asm.GlobalAssemblyCache); #pragma warning restore SYSLIB0005 // Re-enable the warning. You can also suppress the warning in your project file, which disables the warning for all source files in the project. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below will suppress SYSLIB0005 project-wide --> <NoWarn>$(NoWarn);SYSLIB0005</NoWarn> </PropertyGroup> </Project> Suppressing SYSLIB0005 disables only the GlobalAssemblyCache obsoletion warning. It does not disable any other warnings. Affected APIs System.Reflection.Assembly.GlobalAssemblyCache Hardware intrinsic IsSupported checks may differ for nested types Article • 09/15/2021 Checking <Isa>.X64.IsSupported , where <Isa> refers to the classes in the System.Runtime.Intrinsics.X86 namespace, may now produce a different result to previous versions of .NET. Tip ISA stands for industry standard architecture. Version introduced 5.0 Change description In previous versions of .NET, some of the System.Runtime.Intrinsics.X86 hardwareintrinsic types, for example, System.Runtime.Intrinsics.X86.Aes, didn't expose a nested X64 class. For these types, calling <Isa>.X64.IsSupported resolved to an IsSupported property on a nested X64 class of a parent class of <Isa> . This meant that the property could return true even when <Isa>.IsSupported returns false . In .NET 5 and later versions, all of the System.Runtime.Intrinsics.X86 types expose a nested X64 class that appropriately reports support. This ensures that the general hierarchy remains correct, and that if <Isa>.X64.IsSupported is true , then <Isa>.IsSupported can also be assumed to be true . Reason for change It was intended that if <Isa>.X64.IsSupported is true , <Isa>.IsSupported is also implied to be true . However, due to how member resolution works in C#, classes that didn't have a nested X64 class exposed a situation where this wasn't always the case and led to bugs in user code. Recommended action If necessary, adjust code that checks IsSupported to check for the appropriate ISA. Affected APIs System.Runtime.Intrinsics.X86.Aes.X64.IsSupported System.Runtime.Intrinsics.X86.Avx.X64.IsSupported System.Runtime.Intrinsics.X86.Avx2.X64.IsSupported System.Runtime.Intrinsics.X86.Fma.X64.IsSupported System.Runtime.Intrinsics.X86.Pclmulqdq.X64.IsSupported System.Runtime.Intrinsics.X86.Sse3.X64.IsSupported System.Runtime.Intrinsics.X86.Ssse3.X64.IsSupported IntPtr and UIntPtr implement IFormattable Article • 09/15/2021 IntPtr and UIntPtr now implement IFormattable. Functions that check for IFormattable support may now return different results for these types, because they may pass in a format specifier and a culture. Change description In previous versions of .NET, IntPtr and UIntPtr do not implement IFormattable. Functions that check for IFormattable may fall back to just calling IntPtr.ToString or UIntPtr.ToString, which means that format specifiers and cultures are not respected. In .NET 5 and later versions, IntPtr and UIntPtr implement IFormattable. Functions that check for IFormattable support may now return different results for these types, because they may pass in a format specifier and a culture. This change impacts scenarios like interpolated strings and Console.WriteLine, among others. Reason for change IntPtr and UIntPtr now have language support in C# through the nint and nuint keywords. The backing types were updated to provide near parity (where possible) with functionality exposed by other primitive types, such as System.Int32. Version introduced 5.0 Recommended action If you don't want a format specifier or custom culture to be used when displaying values of these types, you can call the IntPtr.ToString() and UIntPtr.ToString() overloads of ToString() . Affected APIs Not detectable via API analysis. LastIndexOf has improved handling of empty search strings Article • 09/15/2021 String.LastIndexOf and related APIs now return correct values when searching for a zerolength (or zero-length equivalent) substring within a larger string. Change description In .NET Framework and .NET Core 1.0 - 3.1, String.LastIndexOf and related APIs might return an incorrect value when the caller searches for a zero-length substring. C# Console.WriteLine("Hello".LastIndexOf("")); // prints '4' (incorrect) ReadOnlySpan<char> span = "Hello"; Console.WriteLine(span.LastIndexOf("")); // prints '0' (incorrect) Starting with .NET 5, these APIs return the correct value for LastIndexOf . C# Console.WriteLine("Hello".LastIndexOf("")); // prints '5' (correct) ReadOnlySpan<char> span = "Hello"; Console.WriteLine(span.LastIndexOf("")); // prints '5' (correct) In these examples, 5 is the correct answer because "Hello".Substring(5) and "Hello".AsSpan().Slice(5) both produce an empty string, which is trivially equal to the empty substring that is sought. Reason for change This change was part of an overall bug fixing effort around string handling for .NET 5. It also helps unify our behavior between Windows and non-Windows platforms. For more information, see dotnet/runtime#13383 Version introduced and dotnet/runtime##13382 . 5.0 Recommended action You don't need to take any action. The .NET 5 runtime provides the new behaviors automatically. There is no compatibility switch to restore the old behavior. Affected APIs System.String.LastIndexOf System.Globalization.CompareInfo.LastIndexOf System.MemoryExtensions.LastIndexOf URI paths with non-ASCII characters parse correctly on Unix Article • 11/08/2021 A bug was fixed in the System.Uri class such that absolute URI paths that contain nonASCII characters now parse correctly on Unix platforms. Change description In previous versions of .NET, absolute URI paths that contain non-ASCII characters are parsed incorrectly on Unix platforms, and segments of the path are duplicated. (Absolute paths are those that start with "/".) The parsing issue has been fixed for .NET 5. If you move from a previous version of .NET to .NET 5 or later, you'll get different values produced by Uri.AbsoluteUri, Uri.ToString(), and other Uri members. Consider the output of the following code when run on Unix. C# var myUri = new Uri("/üri"); Console.WriteLine($"AbsoluteUri: {myUri.AbsoluteUri}"); Console.WriteLine($"ToString: {myUri.ToString()}"); Output on previous .NET version: text AbsoluteUri: /%C3%BCri/%C3%BCri ToString: /üri/üri Output on .NET 5 or later version: text AbsoluteUri: /%C3%BCri ToString: /üri Version introduced 5.0 Recommended action If you have code that expects and accounts for the duplicated path segments, you can remove that code. Affected APIs System.Uri API obsoletions with non-default diagnostic IDs Article • 06/07/2022 Some APIs have been marked as obsolete, starting in .NET 5. This breaking change is specific to APIs that have been marked as obsolete with a custom diagnostic ID. Suppressing the default obsoletion diagnostic ID, which is CS0618 for the C# compiler, does not suppress the warnings that the compiler generates when these APIs are used. Change description In previous .NET versions, these APIs can be used without any build warning. In .NET 5 and later versions, use of these APIs produces a compile-time warning or error with a custom diagnostic ID. The use of custom diagnostic IDs allows you to suppress the obsoletion warnings individually instead of blanket-suppressing all obsoletion warnings. The following table lists the custom diagnostic IDs and their corresponding warning messages for obsoleted APIs. Diagnostic ID Description Severity SYSLIB0001 The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead. Warning SYSLIB0002 PrincipalPermissionAttribute is not honored by the runtime and must not be used. Error SYSLIB0003 Code access security (CAS) is not supported or honored by the runtime. Warning SYSLIB0004 The constrained execution region (CER) feature is not supported. Warning SYSLIB0005 The global assembly cache (GAC) is not supported. Warning SYSLIB0006 Thread.Abort() is not supported and throws PlatformNotSupportedException. Warning SYSLIB0007 The default implementation of this cryptography algorithm is not supported. Warning SYSLIB0008 The CreatePdbGenerator() API is not supported and throws PlatformNotSupportedException. Warning Diagnostic ID Description Severity SYSLIB0009 The AuthenticationManager.Authenticate and AuthenticationManager.PreAuthenticate methods are not supported Warning and throw PlatformNotSupportedException. SYSLIB0010 Some remoting APIs are not supported and throw Warning PlatformNotSupportedException. SYSLIB0011 BinaryFormatter serialization is obsolete and should not be used. Warning SYSLIB0012 Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead. Warning Version introduced .NET 5.0 Recommended action Follow the specific guidance provided for the each diagnostic ID using the URL link provided on the warning. Warnings or errors for these obsoletions can't be suppressed using the standard diagnostic ID for obsolete types or members; use the custom SYSLIBxxxx diagnostic ID value instead. Affected APIs SYSLIB0001 Encoding.UTF7 UTF7Encoding SYSLIB0002 PrincipalPermissionAttribute(SecurityAction) SYSLIB0003 Classes in the System.Security.Permissions namespace: System.Security.Permissions.CodeAccessSecurityAttribute System.Security.Permissions.DataProtectionPermission System.Security.Permissions.DataProtectionPermissionAttribute System.Security.Permissions.EnvironmentPermission System.Security.Permissions.EnvironmentPermissionAttribute System.Security.Permissions.FileDialogPermission System.Security.Permissions.FileDialogPermissionAttribute System.Security.Permissions.FileIOPermission System.Security.Permissions.FileIOPermissionAttribute System.Security.Permissions.GacIdentityPermission System.Security.Permissions.GacIdentityPermissionAttribute System.Security.Permissions.HostProtectionAttribute System.Security.Permissions.IsolatedStorageFilePermission System.Security.Permissions.IsolatedStorageFilePermissionAttribute System.Security.Permissions.IsolatedStoragePermission System.Security.Permissions.IsolatedStoragePermissionAttribute System.Security.Permissions.KeyContainerPermission System.Security.Permissions.KeyContainerPermissionAccessEntry System.Security.Permissions.KeyContainerPermissionAccessEntryCollection System.Security.Permissions.KeyContainerPermissionAccessEntryEnumerator System.Security.Permissions.KeyContainerPermissionAttribute System.Security.Permissions.MediaPermission System.Security.Permissions.MediaPermissionAttribute System.Security.Permissions.PermissionSetAttribute System.Security.Permissions.PrincipalPermission System.Security.Permissions.PrincipalPermissionAttribute System.Security.Permissions.PublisherIdentityPermission System.Security.Permissions.PublisherIdentityPermissionAttribute System.Security.Permissions.ReflectionPermission System.Security.Permissions.ReflectionPermissionAttribute System.Security.Permissions.RegistryPermission System.Security.Permissions.RegistryPermissionAttribute System.Security.Permissions.ResourcePermissionBase System.Security.Permissions.ResourcePermissionBaseEntry System.Security.Permissions.SecurityAttribute System.Security.Permissions.SecurityPermission System.Security.Permissions.SecurityPermissionAttribute System.Security.Permissions.SiteIdentityPermission System.Security.Permissions.SiteIdentityPermissionAttribute System.Security.Permissions.StorePermission System.Security.Permissions.StorePermissionAttribute System.Security.Permissions.StrongNameIdentityPermission System.Security.Permissions.StrongNameIdentityPermissionAttribute System.Security.Permissions.StrongNamePublicKeyBlob System.Security.Permissions.TypeDescriptorPermission System.Security.Permissions.TypeDescriptorPermissionAttribute System.Security.Permissions.UIPermission System.Security.Permissions.UIPermissionAttribute System.Security.Permissions.UrlIdentityPermission System.Security.Permissions.UrlIdentityPermissionAttribute System.Security.Permissions.WebBrowserPermission System.Security.Permissions.WebBrowserPermissionAttribute System.Security.Permissions.ZoneIdentityPermission System.Security.Permissions.ZoneIdentityPermissionAttribute Classes that derive from CodeAccessSecurityAttribute : System.Configuration.ConfigurationPermissionAttribute System.Data.Common.DBDataPermissionAttribute System.Data.Odbc.OdbcPermissionAttribute System.Data.OleDb.OleDbPermissionAttribute System.Data.OracleClient.OraclePermissionAttribute System.Data.SqlClient.SqlClientPermissionAttribute System.Diagnostics.EventLogPermissionAttribute System.Diagnostics.PerformanceCounterPermissionAttribute System.DirectoryServices.DirectoryServicesPermissionAttribute System.Drawing.Printing.PrintingPermissionAttribute System.Net.DnsPermissionAttribute System.Net.SocketPermissionAttribute System.Net.WebPermissionAttribute System.Net.Mail.SmtpPermissionAttribute System.Net.NetworkInformation.NetworkInformationPermissionAttribute System.Net.PeerToPeer.PnrpPermissionAttribute System.Net.PeerToPeer.Collaboration.PeerCollaborationPermissionAttribute System.ServiceProcess.ServiceControllerPermissionAttribute System.Transactions.DistributedTransactionPermissionAttribute System.Web.AspNetHostingPermissionAttribute Interfaces: System.Security.Permissions.IUnrestrictedPermission System.Security.IPermission System.Security.IStackWalk System.Security.Policy.IIdentityPermissionFactory Classes that implement IStackWalk : System.Security.NamedPermissionSet System.Security.PermissionSet Classes that implement IPermission : System.Security.CodeAccessPermission Classes that derive from CodeAccessPermission : System.Configuration.ConfigurationPermission System.Data.Common.DBDataPermission System.Data.Odbc.OdbcPermission System.Data.OleDb.OleDbPermission System.Data.SqlClient.SqlClientPermission System.Data.OracleClient.OraclePermission System.Drawing.Printing.PrintingPermission System.Net.DnsPermission System.Net.SocketPermission System.Net.WebPermission System.Net.Mail.SmtpPermission System.Net.NetworkInformation.NetworkInformationPermission System.Net.PeerToPeer.PnrpPermission System.Net.PeerToPeer.Collaboration.PeerCollaborationPermission System.Transactions.DistributedTransactionPermission System.Web.AspNetHostingPermission System.Xaml.Permissions.XamlLoadPermission Classes that derive from ResourcePermissionBase : System.Diagnostics.EventLogPermission System.Diagnostics.PerformanceCounterPermission System.DirectoryServices.DirectoryServicesPermission System.ServiceProcess.ServiceControllerPermission Enums in the System.Security.Permissions namespace: System.Security.Permissions.DataProtectionPermissionFlags System.Security.Permissions.EnvironmentPermissionAccess System.Security.Permissions.FileDialogPermissionAccess System.Security.Permissions.FileIOPermissionAccess System.Security.Permissions.HostProtectionResource System.Security.Permissions.IsolatedStorageContainment System.Security.Permissions.KeyContainerPermissionFlags System.Security.Permissions.MediaPermissionAudio System.Security.Permissions.MediaPermissionImage System.Security.Permissions.MediaPermissionVideo System.Security.Permissions.PermissionState System.Security.Permissions.ReflectionPermissionFlag System.Security.Permissions.RegistryPermissionAccess System.Security.Permissions.SecurityAction System.Security.Permissions.SecurityPermissionFlag System.Security.Permissions.StorePermissionFlags System.Security.Permissions.TypeDescriptorPermissionFlags System.Security.Permissions.UIPermissionClipboard System.Security.Permissions.UIPermissionWindow System.Security.Permissions.WebBrowserPermissionLevel Classes and members that depend on code access security types: System.AppDomain.ExecuteAssembly(String, String[], Byte[], AssemblyHashAlgorithm) System.AppDomain.PermissionSet System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute System.Security.HostProtectionException System.Security.Policy.FileCodeGroup System.Security.Policy.StrongName System.Security.Policy.StrongNameMembershipCondition System.Security.Policy.ApplicationTrust.ApplicationTrust(PermissionSet, IEnumerable<StrongName>) System.Security.Policy.ApplicationTrust.FullTrustAssemblies System.Security.Policy.GacInstalled System.Security.Policy.PolicyStatement.PolicyStatement System.Security.Policy.PolicyLevel.AddNamedPermissionSet(NamedPermissionSet) System.Security.Policy.PolicyLevel.ChangeNamedPermissionSet(String, PermissionSet) System.Security.Policy.PolicyLevel.GetNamedPermissionSet(String) System.Security.Policy.PolicyLevel.RemoveNamedPermissionSet(String) PolicyLevel.RemoveNamedPermissionSet(NamedPermissionSet) System.Security.Policy.PolicyStatement.PermissionSet System.Security.Policy.Publisher System.Security.Policy.Site System.Security.Policy.Url System.Security.Policy.Zone System.Security.SecurityManager SYSLIB0004 RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(RuntimeHelpers+TryCode, RuntimeHelpers+CleanupCode, Object) RuntimeHelpers.PrepareConstrainedRegions() RuntimeHelpers.PrepareConstrainedRegionsNoOP() RuntimeHelpers.PrepareContractedDelegate(Delegate) RuntimeHelpers.ProbeForSufficientStack() System.Runtime.ConstrainedExecution.Cer System.Runtime.ConstrainedExecution.Consistency System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute System.Runtime.ConstrainedExecution.ReliabilityContractAttribute SYSLIB0005 Assembly.GlobalAssemblyCache SYSLIB0006 Thread.Abort() Thread.Abort(Object) SYSLIB0007 System.Security.Cryptography.AsymmetricAlgorithm.Create() System.Security.Cryptography.HashAlgorithm.Create() System.Security.Cryptography.HMAC.Create() System.Security.Cryptography.KeyedHashAlgorithm.Create() System.Security.Cryptography.SymmetricAlgorithm.Create() SYSLIB0008 DebugInfoGenerator.CreatePdbGenerator() SYSLIB0009 AuthenticationManager.Authenticate AuthenticationManager.PreAuthenticate SYSLIB0010 MarshalByRefObject.GetLifetimeService() MarshalByRefObject.InitializeLifetimeService() SYSLIB0011 System.Exception.SerializeObjectState BinaryFormatter.Serialize BinaryFormatter.Deserialize Formatter.Serialize(Stream, Object) Formatter.Deserialize(Stream) IFormatter.Serialize(Stream, Object) IFormatter.Deserialize(Stream) SYSLIB0012 Assembly.CodeBase Assembly.EscapedCodeBase See also API obsoletions with non-default diagnostic IDs (.NET 6) API obsoletions with non-default diagnostic IDs (.NET 7) Obsolete features in .NET 5+ Obsolete properties on ConsoleLoggerOptions Article • 09/15/2021 The Microsoft.Extensions.Logging.Console.ConsoleLoggerFormat type and some properties on ConsoleLoggerOptions are now obsolete. Change description Starting in .NET 5, the Microsoft.Extensions.Logging.Console.ConsoleLoggerFormat type and several properties on ConsoleLoggerOptions are obsolete. The obsolete properties are: ConsoleLoggerOptions.DisableColors ConsoleLoggerOptions.IncludeScopes ConsoleLoggerOptions.TimestampFormat ConsoleLoggerOptions.UseUtcTimestamp ConsoleLoggerOptions.Format With the introduction of new formatters, these properties are now available on the individual formatters. Reason for change The Format property is an enumeration type, which cannot represent a custom formatter. The remaining properties were set on ConsoleLoggerOptions and applied to both of the built-in formats for console logs. However, with the introduction of a new formatter API, it makes more sense for formatting to be represented on the formatter-specific options. This change provides better separation between the logger and logger formatters. Version introduced 5.0 Recommended action Use the new ConsoleLoggerOptions.FormatterName property in place of the ConsoleLoggerOptions.Format property. For example: C# loggingBuilder.AddConsole(options => { options.FormatterName = ConsoleFormatterNames.Systemd; }); There are several differences between FormatterName and Format: Format has only two possible options: Default and Systemd . FormatterName is case insensitive and can be any string. The reserved, built-in names are Simple , Systemd , and Json (.NET 5 and later). "Format": "Systemd" maps to "FormatterName": "Systemd" . "Format": "Default" maps to "FormatterName": "Simple" . For the DisableColors, IncludeScopes, TimestampFormat, and UseUtcTimestamp properties, use the corresponding property on the new ConsoleFormatterOptions, JsonConsoleFormatterOptions, or SimpleConsoleFormatterOptions types instead. For example, the corresponding setting for ConsoleLoggerOptions.DisableColors is SimpleConsoleFormatterOptions.ColorBehavior. Previous code: C# loggingBuilder.AddConsole(options => { options.DisableColors = true; }); New code: C# loggingBuilder.AddSimpleConsole(options => { options.ColorBehavior = LoggerColorBehavior.Disabled; }); The following two JSON snippets show how the configuration file changes. Old configuration file: JSON { "Logging": { "LogLevel": { "Default": "None", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information" }, "Format": "Systemd", "IncludeScopes": true, "TimestampFormat": "HH:mm:ss", "UseUtcTimestamp": true } }, "AllowedHosts": "*" } New configuration file: JSON { "Logging": { "LogLevel": { "Default": "None", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { "LogLevel": { "Default": "Information" }, "FormatterName": "Systemd", "FormatterOptions": { "IncludeScopes": true, "TimestampFormat": "HH:mm:ss", "UseUtcTimestamp": true } } }, "AllowedHosts": "*" } Affected APIs Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.DisableColors Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.IncludeScopes Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.TimestampFormat Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.UseUtcTimestamp Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions.Format Complexity of LINQ OrderBy.First{OrDefault} increased Article • 09/15/2021 The implementation of OrderBy . First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) and OrderBy . FirstOrDefault<TSource> (IEnumerable<TSource>, Func<TSource,Boolean>) has changed, resulting in increased complexity for the operation. Change description In .NET Core 1.x - 3.x, calling OrderBy or OrderByDescending followed by First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) or FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) operates with O(N) complexity. Since only the first (or default) element is required, only one enumeration is required to find it. However, the predicate that's supplied to First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) or FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) is invoked exactly N times, where N is the length of the sequence. In .NET 5 and later versions, a change was made such that calling OrderBy or OrderByDescending followed by First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) or FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) operates with O(N log N) complexity instead of O(N) complexity. However, the predicate that's supplied to First<TSource> (IEnumerable<TSource>, Func<TSource,Boolean>) or FirstOrDefault<TSource> (IEnumerable<TSource>, Func<TSource,Boolean>) may be invoked less than N times, which is more important for overall performance. 7 Note This change matches the implementation and complexity of the operation in .NET Framework. Reason for change The benefit of invoking the predicate fewer times outweighs a lower overall complexity, so the implementation that was introduced in .NET Core 1.0 was reverted. For more information, see this dotnet/runtime issue . Version introduced 5.0 Recommended action No action is required on the developer's part. Affected APIs System.Linq.Enumerable.OrderBy System.Linq.Enumerable.OrderByDescending System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) OSPlatform attributes renamed or removed Article • 09/15/2021 The following attributes that were introduced in .NET 5 Preview 8 have been removed or renamed: MinimumOSPlatformAttribute , RemovedInOSPlatformAttribute , and ObsoletedInOSPlatformAttribute . Change description .NET 5 Preview 8 introduced the following attributes in the System.Runtime.Versioning namespace: MinimumOSPlatformAttribute RemovedInOSPlatformAttribute ObsoletedInOSPlatformAttribute In .NET 5 Preview 8, when a project targets an OS-specific flavor of .NET 5 by using a target framework moniker such as net5.0-windows , the build adds an assembly-level System.Runtime.Versioning.MinimumOSPlatformAttribute attribute. In .NET 5 RC1, the ObsoletedInOSPlatformAttribute has been removed, and MinimumOSPlatformAttribute and RemovedInOSPlatformAttribute have been renamed as follows: Preview 8 name RC1 and later name MinimumOSPlatformAttribute SupportedOSPlatformAttribute RemovedInOSPlatformAttribute UnsupportedOSPlatformAttribute In .NET 5 RC1 and later, when a project targets an OS-specific flavor of .NET 5 by using a target framework moniker such as net5.0-windows , the build adds an assembly-level SupportedOSPlatformAttribute attribute. Reason for change .NET 5 Preview 8 introduced attributes in System.Runtime.Versioning to specify supported platforms for APIs. The attributes are consumed by the Platform compatibility analyzer to produce build warnings when platform-specific APIs are consumed on platforms that don't support those APIs. For .NET 5 RC1, an additional feature was added to the platform compatibility analyzer for platform exclusion. The feature allows APIs to be marked as entirely unsupported on OS platforms. That feature prompted changes to the attributes, including using more suitable names. The ObsoletedInOSPlatformAttribute was removed because it was no longer needed. Version introduced 5.0 RC1 Recommended action When you retarget your project from .NET 5 Preview 8 to .NET 5 RC1, you might encounter build or run-time errors due to these changes. For example, the renaming of MinimumOSPlatformAttribute is likely to produce errors, because the attribute is applied to platform-specific assemblies at build time, and old build artifacts will still reference the old API name. Example build-time errors: error CS0246: The type or namespace name 'MinimumOSPlatformAttribute' could not be found (are you missing a using directive or an assembly reference?) error CS0246: The type or namespace name 'RemovedInOSPlatformAttribute' could not be found (are you missing a using directive or an assembly reference?) error CS0246: The type or namespace name 'ObsoletedInOSPlatformAttribute' could not be found (are you missing a using directive or an assembly reference?) Example run-time error: Unhandled exception. System.TypeLoadException: Could not load type 'System.Runtime.Versioning.MinimumOSPlatformAttribute' from assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. To resolve these errors: Update any references of MinimumOSPlatformAttribute to SupportedOSPlatformAttribute. Update any references of RemovedInOSPlatformAttribute to UnsupportedOSPlatformAttribute. Remove any references to ObsoletedInOSPlatformAttribute . Rebuild your project (or perform clean + build) to delete old build artifacts. Affected APIs System.Runtime.Versioning.MinimumOSPlatformAttribute System.Runtime.Versioning.ObsoletedInOSPlatformAttribute System.Runtime.Versioning.RemovedInOSPlatformAttribute Microsoft.DotNet.PlatformAbstractions package removed Article • 09/15/2021 No new versions of the Microsoft.DotNet.PlatformAbstractions NuGet package will be produced. Change description Previously, new versions of the Microsoft.DotNet.PlatformAbstractions library were produced alongside new versions of .NET Core. Going forward, no new functionality will be added to the library, and no new major versions will be released. However, existing versions of the library will continue to work and be serviced. The Microsoft.DotNet.PlatformAbstractions library overlaps with APIs that are already established in the System.* namespaces. Also, some Microsoft.DotNet.PlatformAbstractions APIs weren't designed with the same level of scrutiny and long-term supportability as the rest of the System.* APIs. For example, Microsoft.DotNet.PlatformAbstractions uses the Platform enumeration to describe the current operating system platform. This enumeration design was explicitly rejected when the RuntimeInformation.IsOSPlatform(OSPlatform) API was designed, to allow for new platforms and future flexibility. The scenarios enabled by the Microsoft.DotNet.PlatformAbstractions library are now possible without it. Existing versions will continue to work, even in .NET 5 and later, and will be serviced along with previous versions of .NET Core. However, new functionality won't be added to the library. Instead, new functionality will be added to other libraries and APIs. Version introduced 5.0 Recommended action You can continue to use older versions of the library if they meet your requirements. If the older versions don't meet your requirements, replace usages of the PlatformAbstractions APIs with the recommended replacements. PlatformAbstractions API Recommended replacement ApplicationEnvironment.ApplicationBasePath AppContext.BaseDirectory HashCodeCombiner System.HashCode RuntimeEnvironment.GetRuntimeIdentifier() RuntimeInformation.RuntimeIdentifier RuntimeEnvironment.OperatingSystemPlatform RuntimeInformation.IsOSPlatform(OSPlatform) RuntimeEnvironment.RuntimeArchitecture RuntimeInformation.ProcessArchitecture RuntimeEnvironment.OperatingSystem RuntimeInformation.OSDescription RuntimeEnvironment.OperatingSystemVersion RuntimeInformation.OSDescription and Environment.OSVersion 7 Note Most use cases for RuntimeEnvironment.OperatingSystem and RuntimeEnvironment.OperatingSystemVersion are for display purposes, for example, displaying to a user, logging, and telemetry. It's not recommended to make run-time decisions based on an operating system (OS) version. Environment.OSVersion now returns the correct version for Windows and macOS operating systems. However, for most Unix distributions, what is considered to be the "OS version" is not as straightforward. For example, it could be the Linux kernel version, or it could be the distro version. For most Unix platforms, Environment.OSVersion and RuntimeInformation.OSDescription return the version that's returned by uname . To get the Linux distro name and version information, the recommended approach is to read the /etc/os-release file. Affected APIs Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBaseP ath Microsoft.DotNet.PlatformAbstractions.HashCodeCombiner Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier () Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystem Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemPlatf orm Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersi on Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.RuntimeArchitecture PrincipalPermissionAttribute is obsolete as error Article • 09/15/2021 The PrincipalPermissionAttribute constructor is obsolete and produces a compile-time error. You cannot instantiate this attribute or apply it to a method. Change description On .NET Framework and .NET Core, you can annotate methods with the PrincipalPermissionAttribute attribute. For example: C# [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] public void MyMethod() { // Code that should only run when the current user is an administrator. } Starting in .NET 5, you cannot apply the PrincipalPermissionAttribute attribute to a method. The constructor for the attribute is obsolete and produces a compile-time error. Unlike other obsoletion warnings, you can't suppress the error. Reason for change The PrincipalPermissionAttribute type, like other types that subclass SecurityAttribute, is part of .NET's Code Access Security (CAS) infrastructure. In .NET Framework 2.x - 4.x, the runtime enforces PrincipalPermissionAttribute annotations on method entry, even if the application is running under a full-trust scenario. .NET Core and .NET 5 and later don't support CAS attributes, and the runtime ignores them. This difference in behavior from .NET Framework to .NET Core and .NET 5 can result in a "fail open" scenario, where access should have been blocked but instead has been allowed. To prevent the "fail open" scenario, you can no longer apply the attribute in code that targets .NET 5 or later. Version introduced 5.0 Recommended action If you encounter the obsoletion error, you must take action. If you're applying the attribute to an ASP.NET MVC action method: Consider using ASP.NET's built-in authorization infrastructure. The following code demonstrates how to annotate a controller with an AuthorizeAttribute attribute. The ASP.NET runtime will authorize the user before performing the action. C# using Microsoft.AspNetCore.Authorization; namespace MySampleApp { [Authorize(Roles = "Administrator")] public class AdministrationController : Controller { public ActionResult MyAction() { // This code won't run unless the current user // is in the 'Administrator' role. } } } For more information, see Role-based authorization in ASP.NET Core and Introduction to authorization in ASP.NET Core. If you're applying the attribute to library code outside the context of a web app: Perform the checks manually at the beginning of your method. This can be done by using the IPrincipal.IsInRole(String) method. C# using System.Threading; void DoSomething() { if (Thread.CurrentPrincipal == null || !Thread.CurrentPrincipal.IsInRole("Administrators")) { throw new Exception("User is anonymous or isn't an admin."); } // Code that should run only when user is an administrator. } Affected APIs System.Security.Permissions.PrincipalPermissionAttribute Parameter names changed in RC2 Article • 09/15/2021 Some reference assembly parameter names have changed to match parameter names in the implementation assemblies. Change description In previous .NET 5 preview and RC versions, some reference assembly parameter names are different to their corresponding parameters in the implementation assembly. This can cause problems while using named arguments and reflection. In .NET 5 RC2, these mismatched parameter names were updated in the reference assemblies to exactly match the corresponding parameter names in the implementation assemblies. The following table shows the APIs and parameter names that changed. API Old parameter name New parameter name ActivityContext(ActivityTraceId, ActivitySpanId, ActivityTraceFlags, String, Boolean) traceOptions traceFlags CompareInfo.IsPrefix(ReadOnlySpan<Char>, ReadOnlySpan<Char>, CompareOptions, Int32) suffix prefix Reason for change The parameter names were changed for consistency and to avoid failures when using named arguments and reflection. Version introduced 5.0 RC2 Recommended action If you encounter a compiler error due to a parameter name change, update the parameter name accordingly. Affected APIs ActivityContext(ActivityTraceId, ActivitySpanId, ActivityTraceFlags, String, Boolean) System.Globalization.CompareInfo.IsPrefix(ReadOnlySpan<Char>, ReadOnlySpan<Char>, CompareOptions, Int32) Parameter names changed in reference assemblies Article • 09/15/2021 Some reference assembly parameter names have changed to match parameter names in the implementation assemblies. Change description In previous .NET versions, some reference assembly parameter names are different to their corresponding parameters in the implementation assembly. This can cause problems while using named arguments and reflection. In .NET 5, these mismatched parameter names were updated in the reference assemblies to exactly match the corresponding parameter names in the implementation assemblies. The following table shows the APIs and parameter names that changed. API Old parameter name New parameter name CodeGenerator.GenerateStatements(CodeStatementCollection) stms stmts Icon.ISerializable.GetObjectData(SerializationInfo, StreamingContext) info si Image.ISerializable.GetObjectData(SerializationInfo, info si IPAddress.Parse(ReadOnlySpan<Char>) ipString ipSpan IPAddress.TryParse(ReadOnlySpan<Char>, IPAddress) ipString ipSpan IsolatedStorageFileStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) buffer array IsolatedStorageFileStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) buffer array NetworkCredential.GetCredential(String, Int32, String) authType authenticationType ParenthesizePropertyNameAttribute.Equals(Object) o obj RefreshPropertiesAttribute.Equals(Object) value obj StreamingContext) API Old parameter New parameter name name StackFrame(Boolean) fNeedFileInfo needFileInfo StackFrame(Int32, Boolean) fNeedFileInfo needFileInfo StringNormalizationExtensions.IsNormalized(String, NormalizationForm) value strInput StringNormalizationExtensions.IsNormalized(String) value strInput StringNormalizationExtensions.Normalize(String, NormalizationForm) value strInput StringNormalizationExtensions.Normalize(String) value strInput Reason for change The parameter names were changed for consistency and to avoid failures when using named arguments and reflection. Version introduced 5.0 Recommended action If you encounter a compiler error due to a parameter name change, update the parameter name accordingly. Affected APIs System.CodeDom.Compiler.CodeGenerator.GenerateStatements(CodeStatementCo llection) System.ComponentModel.ParenthesizePropertyNameAttribute.Equals(Object) System.ComponentModel.RefreshPropertiesAttribute.Equals(Object) StackFrame(Boolean) StackFrame(Int32, Boolean) System.Drawing.Icon.System.Runtime.Serialization.ISerializable.GetObjectData(Seria lizationInfo, StreamingContext) System.Drawing.Image.System.Runtime.Serialization.ISerializable.GetObjectData(Se rializationInfo, StreamingContext) System.IO.IsolatedStorage.IsolatedStorageFileStream.BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) System.IO.IsolatedStorage.IsolatedStorageFileStream.BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object) System.Net.IPAddress.Parse(ReadOnlySpan<Char>) System.Net.IPAddress.TryParse(ReadOnlySpan<Char>, IPAddress) System.Net.NetworkCredential.GetCredential(String, Int32, String) System.StringNormalizationExtensions.IsNormalized(String, NormalizationForm) System.StringNormalizationExtensions.IsNormalized(String) System.StringNormalizationExtensions.Normalize(String, NormalizationForm) System.StringNormalizationExtensions.Normalize(String) Remoting APIs are obsolete Article • 09/15/2021 Some remoting-related APIs are marked as obsolete and generate a SYSLIB0010 warning at compile time. These APIs may be removed in a future version of .NET. Change description The following remoting APIs are marked obsolete. API Marked obsolete in... MarshalByRefObject.GetLifetimeService() 5.0 RC1 MarshalByRefObject.InitializeLifetimeService() 5.0 RC1 In .NET Framework 2.x - 4.x, the GetLifetimeService() and InitializeLifetimeService() methods control the lifetime of instances involved with .NET remoting. In .NET Core 2.x3.x, these methods always throw a PlatformNotSupportedException at run time. In .NET 5 and later versions, the GetLifetimeService() and InitializeLifetimeService() methods are marked obsolete as warning, but continue to throw a PlatformNotSupportedException at run time. C# // MemoryStream, like all Stream instances, subclasses MarshalByRefObject. MemoryStream stream = new MemoryStream(); // Throws PlatformNotSupportedException; also produces warning SYSLIB0010. obj.InitializeLifetimeService(); This is a compile-time only change. There is no run-time change from previous versions of .NET Core. Reason for change .NET remoting is a legacy technology. It allows instantiating an object in another process (potentially even on a different machine) and interacting with that object as if it were an ordinary, in-process .NET object instance. The .NET remoting infrastructure only exists in .NET Framework 2.x - 4.x. .NET Core and .NET 5 and later versions don't have support for .NET remoting, and the remoting APIs either don't exist or always throw exceptions on these runtimes. To help steer developers away from these APIs, we are obsoleting selected remotingrelated APIs. These APIs may be removed entirely in a future version of .NET. Version introduced .NET 5.0 Recommended action Consider using WCF or HTTP-based REST services to communicate with objects in other applications or across machines. For more information, see .NET Framework technologies unavailable on .NET Core. If you must continue to use the obsolete APIs, you can suppress the SYSLIB0010 warning in code. C# MarshalByRefObject obj = GetMarshalByRefObj(); #pragma warning disable SYSLIB0010 // Disable the warning. obj.InitializeLifetimeService(); // Still throws PNSE. obj.GetLifetimeService(); // Still throws PNSE. #pragma warning restore SYSLIB0010 // Reenable the warning. You can also suppress the warning in your project file, which disables the warning for all source files in the project. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below will suppress SYSLIB0010 project-wide --> <NoWarn>$(NoWarn);SYSLIB0010</NoWarn> </PropertyGroup> </Project> Suppressing SYSLIB0010 disables only the remoting API obsoletion warnings. It does not disable any other warnings. Additionally, it doesn't change the hardcoded run-time behavior of always throwing PlatformNotSupportedException. Affected APIs System.MarshalByRefObject.GetLifetimeService() System.MarshalByRefObject.InitializeLifetimeService() Order of tags in Activity.Tags is reversed Article • 04/16/2022 Activity.Tags now stores items in the list according to the order they're added. That is, the first item that's added is first in the list. This change was made to match the OpenTelemetry Attributes specification . Change description In previous .NET versions, Activity.Tags stores items in the reverse order from which they're added. That is, the first item added is last in the list. Starting in .NET 5, the order of the items is reversed, and the first item added is always first in the list. Version introduced 5.0 Recommended action If your app has a dependency on the Activity.Tags list order and you're upgrading to .NET 5 or later, you'll need to change this part of your code. Affected APIs System.Diagnostics.Activity.Tags SSE and SSE2 CompareGreaterThan methods properly handle NaN inputs Article • 09/15/2021 The following System.Runtime.Intrinsics.X86.Sse and System.Runtime.Intrinsics.X86.Sse2 methods have been fixed to properly handle NaN inputs and match the hardware behavior of the equivalent methods in the System.Runtime.Intrinsics.X86.Avx class: CompareGreaterThan CompareGreaterThanOrEqual CompareNotGreaterThan CompareNotGreaterThanOrEqual CompareScalarGreaterThan CompareScalarGreaterThanOrEqual CompareScalarNotGreaterThan CompareScalarNotGreaterThanOrEqual Change description Previously, NaN inputs to the listed Sse and Sse2 methods returned an incorrect result. The result also differed from the result generated by the corresponding method in the Avx class. Starting in .NET 5, these methods correctly handle NaN inputs and return the same results as the corresponding methods in the Avx class. The Streaming SIMD Extensions (SSE) and Streaming SIMD Extensions 2 (SSE2) industry standard architectures (ISAs) don't provide direct hardware support for these comparison methods, so they're implemented in software. Previously, the methods were improperly implemented, and they incorrectly handled NaN inputs. For code ported from native, the incorrect behavior may introduce bugs. For a 256-bit code path, the methods can also produce different results to the equivalent methods in the Avx class. As an example of how the methods were previously incorrect, you can implement CompareNotGreaterThan(x,y) as CompareLessThanOrEqual(x,y) for regular integers. However, for NaN inputs, that logic computes the wrong result. Instead, using CompareNotLessThan(y,x) compares the numbers correctly and takes NaN inputs into consideration. Version introduced 5.0 Recommended action If the previous behavior was a bug, no change is required. If the previous behavior was desired, you can maintain that behavior by changing the relevant invocation as follows: CompareGreaterThan(x,y) -> CompareNotLessThanOrEqual(x,y) CompareGreaterThanOrEqual(x,y) -> CompareNotLessThan(x,y) CompareNotGreaterThan(x,y) -> CompareLessThanOrEqual(x,y) CompareNotGreaterThanOrEqual(x,y) -> CompareLessThan(x,y) CompareScalarGreaterThan(x,y) -> CompareScalarNotLessThanOrEqual(x,y) CompareScalarGreaterThanOrEqual(x,y) -> CompareScalarNotLessThan(x,y) CompareScalarNotGreaterThan(x,y) -> CompareScalarLessThanOrEqual(x,y) CompareScalarNotGreaterThanOrEqual(x,y) -> CompareScalarLessThan(x,y) Affected APIs System.Runtime.Intrinsics.X86.Sse.CompareGreaterThan(Vector128<Single>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareGreaterThanOrEqual(Vector128<Single >, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareNotGreaterThan(Vector128<Single>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareNotGreaterThanOrEqual(Vector128<Sin gle>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareScalarGreaterThan(Vector128<Single>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareScalarGreaterThanOrEqual(Vector128<S ingle>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareScalarNotGreaterThan(Vector128<Singl e>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse.CompareScalarNotGreaterThanOrEqual(Vector12 8<Single>, Vector128<Single>) System.Runtime.Intrinsics.X86.Sse2.CompareGreaterThan(Vector128<Double>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareGreaterThanOrEqual(Vector128<Doubl e>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareNotGreaterThan(Vector128<Double>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareNotGreaterThanOrEqual(Vector128<D ouble>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareScalarGreaterThan(Vector128<Double >, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareScalarGreaterThanOrEqual(Vector128< Double>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareScalarNotGreaterThan(Vector128<Dou ble>, Vector128<Double>) System.Runtime.Intrinsics.X86.Sse2.CompareScalarNotGreaterThanOrEqual(Vector1 28<Double>, Vector128<Double>) Thread.Abort is obsolete Article • 06/01/2022 The Thread.Abort APIs are obsolete. Projects that target .NET 5 or a later version will encounter compile-time warning SYSLIB0006 if these methods are called. Change description Previously, calls to Thread.Abort did not produce compile-time warnings, however, the method did throw a PlatformNotSupportedException at run time. Starting in .NET 5, Thread.Abort is marked obsolete as warning. Calling this method produces compiler warning SYSLIB0006 . The implementation of the method is unchanged, and it continues to throw a PlatformNotSupportedException. Reason for change Given that Thread.Abort always throws a PlatformNotSupportedException on all .NET implementations except .NET Framework, ObsoleteAttribute was added to the method to draw attention to places where it's called. When you call Thread.Abort to abort a thread other than the current thread, you don't know what code has executed or failed to execute when the ThreadAbortException is thrown. You also cannot be certain of the state of your application or any application and user state that it's responsible for preserving. For example, calling Thread.Abort may prevent the execution of static constructors or the release of managed or unmanaged resources. For this reason, Thread.Abort always throws a PlatformNotSupportedException on .NET Core and .NET 5+. Version introduced 5.0 Recommended action Use a CancellationToken to abort processing of a unit of work instead of calling Thread.Abort. The following example illustrates the use of CancellationToken. C# void ProcessPendingWorkItemsNew(CancellationToken cancellationToken) { if (QueryIsMoreWorkPending()) { // If the CancellationToken is marked as "needs to cancel", // this will throw the appropriate exception. cancellationToken.ThrowIfCancellationRequested(); WorkItem work = DequeueWorkItem(); ProcessWorkItem(work); } } For more information, see Cancellation in managed threads. To suppress the compile-time warning, suppress warning code SYSLIB0006 . The warning code is specific to Thread.Abort and suppressing it doesn't suppress other obsoletion warnings in your code. However, we recommend that you remove calls to Thread.Abort instead of suppressing the warning. C# void MyMethod() { #pragma warning disable SYSLIB0006 Thread.CurrentThread.Abort(); #pragma warning restore SYSLIB0006 } You can also suppress the warning in the project file. XML <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <!-- Disable "Thread.Abort is obsolete" warnings for entire project. --> <NoWarn>$(NoWarn);SYSLIB0006</NoWarn> </PropertyGroup> Affected APIs System.Threading.Thread.Abort Uri recognition of UNC paths on Unix Article • 09/15/2021 The Uri class now recognizes strings that start with two forward slashes ( // ) as universal naming convention (UNC) paths on Unix operating systems. This change makes the behavior for such strings consistent across all platforms. Change description In previous versions of .NET, the Uri class recognizes strings that start with two forward slashes, for example, //contoso , as absolute file paths on Unix operating systems. However, on Windows, such strings are recognized as UNC paths. Starting in .NET 5, the Uri class recognizes strings that start with two forward slashes as UNC paths on all platforms, including Unix. In addition, properties behave according to UNC semantics: Uri.IsUnc returns true . Backslashes in the path are replaced with forward slashes. For example, //first\second becomes //first/second . Uri.LocalPath doesn't percent-encode characters. For example, //first/\uFFF0 is not converted to //first/%EF%BF%B0 . Version introduced 5.0 Recommended action No action is required on the part of the developer. Affected APIs System.Uri UTF-7 code paths are obsolete Article • 01/27/2022 The UTF-7 encoding is no longer in wide use among applications, and many specs now forbid its use in interchange. It's also occasionally used as an attack vector in applications that don't anticipate encountering UTF-7-encoded data. Microsoft warns against use of System.Text.UTF7Encoding because it doesn't provide error detection. Consequently, the Encoding.UTF7 property and UTF7Encoding constructors are now obsolete. Additionally, Encoding.GetEncoding and Encoding.GetEncodings no longer allow you to specify UTF-7 . Change description Previously, you could create an instance of the UTF-7 encoding by using the Encoding.GetEncoding APIs. For example: C# Encoding enc1 = Encoding.GetEncoding("utf-7"); // By name. Encoding enc2 = Encoding.GetEncoding(65000); // By code page. Additionally, an instance that represents the UTF-7 encoding was enumerated by the Encoding.GetEncodings() method, which enumerates all the Encoding instances registered on the system. Starting in .NET 5, the Encoding.UTF7 property and UTF7Encoding constructors are obsolete and produce warning SYSLIB0001 . However, to reduce the number of warnings that callers receive when using the UTF7Encoding class, the UTF7Encoding type itself is not marked obsolete. C# // The next line generates warning SYSLIB0001. UTF7Encoding enc = new UTF7Encoding(); // The next line does not generate a warning. byte[] bytes = enc.GetBytes("Hello world!"); Additionally, the Encoding.GetEncoding methods treat the encoding name utf-7 and the code page 65000 as unknown . Treating the encoding as unknown causes the method to throw an ArgumentException. C# // Throws ArgumentException, same as calling Encoding.GetEncoding("unknown"). Encoding enc = Encoding.GetEncoding("utf-7"); Finally, the Encoding.GetEncodings() method doesn't include the UTF-7 encoding in the EncodingInfo array that it returns. The encoding is excluded because it cannot be instantiated. C# foreach (EncodingInfo encInfo in Encoding.GetEncodings()) { // The next line would throw if GetEncodings included UTF-7. Encoding enc = Encoding.GetEncoding(encInfo.Name); } Reason for change Many applications call Encoding.GetEncoding("encoding-name") with an encoding name value that's provided by an untrusted source. For example, a web client or server might take the charset portion of the Content-Type header and pass the value directly to Encoding.GetEncoding without validating it. This could allow a malicious endpoint to specify Content-Type: ...; charset=utf-7 , which could cause the receiving application to misbehave. Additionally, disabling UTF-7 code paths allows optimizing compilers, such as those used by Blazor, to remove these code paths entirely from the resulting application. As a result, the compiled applications run more efficiently and take less disk space. Version introduced 5.0 Recommended action In most cases, you don't need to take any action. However, for apps that have previously activated UTF-7-related code paths, consider the guidance that follows. If your app calls Encoding.GetEncoding with unknown encoding names provided by an untrusted source: Instead, compare the encoding names against a configurable allow list. The configurable allow list should at minimum include the industry-standard "utf-8". Depending on your clients and regulatory requirements, you may also need to allow region-specific encodings, such as "GB18030". If you don't implement an allow list, Encoding.GetEncoding will return any Encoding that's built into the system or that's registered via a custom EncodingProvider. Audit your service's requirements to validate that this is the desired behavior. UTF-7 continues to be disabled by default unless your application re-enables the compatibility switch mentioned later in this article. If you're using Encoding.UTF7 or UTF7Encoding within your own protocol or file format: Switch to using Encoding.UTF8 or UTF8Encoding. UTF-8 is an industry standard and is widely supported across languages, operating systems, and runtimes. Using UTF-8 eases future maintenance of your code and makes it more interoperable with the rest of the ecosystem. If you're comparing an Encoding instance against Encoding.UTF7: Instead, consider performing a check against the well-known UTF-7 code page, which is 65000 . By comparing against the code page, you avoid the warning and also handle some edge cases, such as if somebody called new UTF7Encoding() or subclassed the type. C# void DoSomething(Encoding enc) { // Don't perform the check this way. // It produces a warning and misses some edge cases. if (enc == Encoding.UTF7) { // Encoding is UTF-7. } // Instead, perform the check this way. if (enc != null && enc.CodePage == 65000) { // Encoding is UTF-7. } } If you must use Encoding.UTF7 or UTF7Encoding: You can suppress the SYSLIB0001 warning in code or within your project's .csproj file. C# #pragma warning disable SYSLIB0001 // Disable the warning. Encoding enc = Encoding.UTF7; #pragma warning restore SYSLIB0001 // Re-enable the warning. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below suppresses SYSLIB0001 project-wide --> <NoWarn>$(NoWarn);SYSLIB0001</NoWarn> </PropertyGroup> </Project> 7 Note Suppressing SYSLIB0001 only disables the Encoding.UTF7 and UTF7Encoding obsoletion warnings. It doesn't disable any other warnings or change the behavior of APIs like Encoding.GetEncoding. If you must support Encoding.GetEncoding("utf-7", ...) : You can re-enable support for this via a compatibility switch. This compatibility switch can be specified in the application's .csproj file or in a runtime configuration file, as shown in the following examples. In the application's .csproj file: XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- Re-enable support for UTF-7 --> <EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding> </PropertyGroup> </Project> In the application's runtimeconfig.template.json file: JSON { "configProperties": { "System.Text.Encoding.EnableUnsafeUTF7Encoding": true } } Tip If you re-enable support for UTF-7, you should perform a security review of code that calls Encoding.GetEncoding. Affected APIs System.Text.Encoding.UTF7 UTF7Encoding() UTF7Encoding(Boolean) System.Text.Encoding.GetEncoding(Int32) System.Text.Encoding.GetEncoding(String) System.Text.Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) System.Text.Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) System.Text.Encoding.GetEncodings() Behavior change for Vector2.Lerp and Vector4.Lerp Article • 09/15/2021 The implementation of Vector2.Lerp(Vector2, Vector2, Single) and Vector4.Lerp(Vector4, Vector4, Single) changed to correctly account for a floating-point rounding error. Change description Previously, Vector2.Lerp(Vector2, Vector2, Single) and Vector4.Lerp(Vector4, Vector4, Single) were implemented as value1 + (value2 - value1) * amount . However, due to a floating-point rounding error, this algorithm doesn't always return value2 when amount is 1.0f . In .NET 5 and later, the implementation uses the same algorithm as Vector3.Lerp(Vector3, Vector3, Single), which is (value1 * (1.0f - amount)) + (value2 * amount) . This algorithm correctly accounts for the rounding error. Now, when amount is 1.0f , the result is precisely value2 . The updated algorithm also allows the algorithm to be freely optimized using MathF.FusedMultiplyAdd when it's available. Version introduced 5.0 Recommended action No action is necessary. However, if you want to maintain the old behavior, you can implement your own Lerp function that uses the previous algorithm of value1 + (value2 - value1) * amount . Affected APIs System.Numerics.Vector2.Lerp(Vector2, Vector2, Single) System.Numerics.Vector4.Lerp(Vector4, Vector4, Single) Vector<T> always throws NotSupportedException for unsupported types Article • 06/29/2022 System.Numerics.Vector<T> now always throws a NotSupportedException for unsupported type parameters. Change description Previously, members of Vector<T> would not always throw a NotSupportedException when T was an unsupported type. The exception wasn't always thrown because of code paths that supported hardware acceleration. For example, Vector<bool> + Vector<bool> returned default instead of throwing an exception on platforms that have no hardware acceleration, such as Arm32. For unsupported types, Vector<T> members exhibited inconsistent behavior across different platforms and hardware configurations. Starting in .NET 5, Vector<T> members always throw a NotSupportedException on all hardware configurations when T is not a supported type. Unsupported types The supported types for the type parameter of Vector<T> are: byte sbyte short ushort int uint long ulong float double The supported types have not changed, however, they may change in the future. Version introduced 5.0 Recommended action Don't use an unsupported type for the type parameter of Vector<T>. Affected APIs System.Numerics.Vector<T> and all its members System.Security.Cryptography APIs not supported on Blazor WebAssembly Article • 09/15/2021 System.Security.Cryptography APIs throw a PlatformNotSupportedException at run time when run on a browser. Change description In previous .NET versions, most of the System.Security.Cryptography APIs aren't available to Blazor WebAssembly apps. Starting in .NET 5, Blazor WebAssembly apps target the full .NET 5 API surface area, however, not all .NET 5 APIs are supported due to browser sandbox constraints. In .NET 5 and later versions, the unsupported System.Security.Cryptography APIs throw a PlatformNotSupportedException when running on WebAssembly. Tip The Platform compatibility analyzer will flag any calls to the affected APIs when you build a project that supports the browser platform. This analyzer runs by default in .NET 5 and later apps. Reason for change Microsoft is unable to ship OpenSSL as a dependency in the Blazor WebAssembly configuration. We attempted to work around this by trying to integrate with the browser's SubtleCrypto API. Unfortunately, it required significant API changes that made it too hard to integrate. Version introduced 5.0 Recommended action There are no good workarounds to suggest at this time. Affected APIs All System.Security.Cryptography APIs except the following: System.Security.Cryptography.RandomNumberGenerator System.Security.Cryptography.IncrementalHash System.Security.Cryptography.SHA1 System.Security.Cryptography.SHA256 System.Security.Cryptography.SHA384 System.Security.Cryptography.SHA512 System.Security.Cryptography.SHA1Managed System.Security.Cryptography.SHA256Managed System.Security.Cryptography.SHA384Managed System.Security.Cryptography.SHA512Managed System.Security.Cryptography.Oid is functionally init-only Article • 09/15/2021 The System.Security.Cryptography.Oid class, which is used to represent ASN.1 Object Identifier values and their "friendly" names, was previously fully mutable. This mutability was often overlooked or came as a surprise. The property setters now throw a PlatformNotSupportedException when you attempt to change the value after it's already been assigned. Change description In previous versions, the property setters on Oid can be used to change the value of the FriendlyName and Value properties. In .NET 5 and later versions, the property setters can only be used to initialize the value. Once the property has a value, either from a constructor or a previous call to the property setter, the property setter always throws a PlatformNotSupportedException. Reason for change This change enables the reuse of Oid objects as part of return values in public APIs to reduce object allocation profiles. It avoids the need to create temporary "defensive" copies when Oid values are used as inputs. Version introduced 5.0 Recommended action Avoid using the Oid property setters other than for object initialization. To represent a new value, use a new instance instead of changing the value on an existing object. Affected APIs System.Security.Cryptography.Oid.FriendlyName System.Security.Cryptography.Oid.Value Default TLS cipher suites for .NET on Linux Article • 12/04/2022 .NET, on Linux, now respects the OpenSSL configuration for default cipher suites when doing TLS/SSL via the SslStream class or higher-level operations, such as HTTPS via the HttpClient class. When default cipher suites aren't explicitly configured, .NET on Linux uses a tightly restricted list of permitted cipher suites. Change description In previous .NET versions, .NET does not respect system configuration for default cipher suites. The default cipher suite list for .NET on Linux is very permissive. Starting in .NET 5, .NET on Linux respects the OpenSSL configuration for default cipher suites when it's specified in openssl.cnf. When cipher suites aren't explicitly configured, the only permitted cipher suites are as follows: TLS 1.3 cipher suites TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 Since this fallback default doesn't include any cipher suites that are compatible with TLS 1.0 or TLS 1.1, these older protocol versions are effectively disabled by default. Supplying a CipherSuitePolicy value to SslStream for a specific session will still replace the configuration file content and/or .NET fallback default. Reason for change Users running .NET on Linux requested that the default configuration for SslStream be changed to one that provided a high security rating from third-party assessment tools. Version introduced 5.0 Recommended action The new defaults are likely to work when communicating with modern clients or servers. If you need to expand the default cipher suite list to accept legacy clients (or to contact legacy servers), use one of the following workarounds: Specify a cryptography policy by configuring the CipherSuitesPolicy type as it pertains to SslServerAuthenticationOptions.CipherSuitesPolicy or SslClientAuthenticationOptions.CipherSuitesPolicy. C# var clientOpts = new SslClientAuthenticationOptions { // ... CipherSuitesPolicy = new CipherSuitesPolicy( new[] { TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }), }; using (SslStream sslStream = new SslStream(networkStream)) { sslStream.AuthenticateAsClient(clientOptions); // ... } Or, for HttpClient: C# var handler = new SocketsHttpHandler { SslOptions = { CipherSuitesPolicy = new CipherSuitesPolicy( new[] { TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }), }, }; using (var httpClient = new HttpClient(handler)) { // ... } Change the OpenSSL configuration file. On many Linux distributions, the OpenSSL configuration file is at /etc/ssl/openssl.cnf. This sample openssl.cnf file is a minimal file that's equivalent to the default cipher suites policy for .NET 5 and later on Linux. Instead of replacing the system file, merge these concepts with the file that's present on your system. ini openssl_conf = default_conf [default_conf] ssl_conf = ssl_sect [ssl_sect] system_default = system_default_sect [system_default_sect] CipherString = ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCMSHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHEECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256SHA384:ECDHE-RSA-AES128-SHA256 On the Red Hat Enterprise Linux, CentOS, and Fedora distributions, .NET applications default to the cipher suites permitted by the system-wide cryptographic policies. On these distributions, use the crypto-policies configuration instead of changing the OpenSSL configuration file. Affected APIs N/A Instantiating default implementations of cryptographic abstractions is not supported Article • 11/08/2021 The parameterless Create() overloads on cryptographic abstractions are obsolete as warning as of .NET 5.0. Change description In .NET Framework 2.0 - 4.8, abstract cryptographic primitive factories such as HashAlgorithm.Create() can be configured to return different algorithms. For example, on a default install of .NET Framework 4.8, the parameterless, static method HashAlgorithm.Create() returns an instance of the SHA1 algorithm, as shown in the following snippet. .NET Framework only C# // Return an instance of the default hash algorithm (SHA1). HashAlgorithm alg = HashAlgorithm.Create(); // Prints 'System.Security.Cryptography.SHA1CryptoServiceProvider'. Console.WriteLine(alg.GetType()); // Change the default algorithm to be SHA256, not SHA1. CryptoConfig.AddAlgorithm(typeof(SHA256CryptoServiceProvider), typeof(HashAlgorithm).FullName); alg = HashAlgorithm.Create(); // Prints 'System.Security.Cryptography.SHA256CryptoServiceProvider'. Console.WriteLine(alg.GetType()); You can also use machine-wide configuration to change the default algorithm without needing to call into CryptoConfig programmatically. In .NET Core 2.0 - 3.1, abstract cryptographic primitive factories such as HashAlgorithm.Create() always throw a PlatformNotSupportedException. C# // Throws PlatformNotSupportedException on .NET Core. HashAlgorithm alg = HashAlgorithm.Create(); In .NET 5 and later versions, abstract cryptographic primitive factories such as HashAlgorithm.Create() are marked obsolete and produce a compile-time warning with ID SYSLIB0007 . At run time, these methods continue to throw a PlatformNotSupportedException. C# // Throws PlatformNotSupportedException. // Also produces compile-time warning SYSLIB0007 on .NET 5+. HashAlgorithm alg = HashAlgorithm.Create(); This is a compile-time only change. There is no run-time change from previous versions of .NET Core. 7 Note Only the parameterless overloads of the Create() methods are obsolete. Parameterized overloads are not obsolete and still function as expected. C# // Call Create(string), providing an explicit algorithm family name. // Works in .NET Framework, .NET Core, and .NET 5+. HashAlgorithm hashAlg = HashAlgorithm.Create("SHA256"); Parameterless overloads of specific algorithm families (not abstractions) are not obsolete, and will continue to function as expected. C# // Call a specific algorithm family's parameterless Create() ctor. // Works in .NET Framework, .NET Core, and .NET 5+. Aes aesAlg = Aes.Create(); Reason for change The cryptographic configuration system present in .NET Framework is no longer present in .NET Core and .NET 5+, since that legacy system doesn't allow for proper cryptographic agility. .NET's backward-compatibility requirements also prohibit the framework from updating certain cryptographic APIs to keep up with advances in cryptography. For example, the HashAlgorithm.Create() method was introduced in .NET Framework 1.0, when the SHA-1 hash algorithm was state-of-the-art. Twenty years have passed, and now SHA-1 is considered broken, but we cannot change HashAlgorithm.Create() to return a different algorithm. Doing so would introduce an unacceptable breaking change in consuming applications. Best practice dictates that libraries that consume cryptographic primitives (such as AES, SHA-*, and RSA) should be in full control over how they consume these primitives. Applications that require future-proofing should utilize higher-level libraries that wrap these primitives and add key management and cryptographic agility capabilities. These libraries are often provided by the hosting environment. One example is ASP.NET's Data Protection library, which handles these concerns on behalf of the calling application. Version introduced 5.0 Recommended action The recommended course of action is to replace calls to the now-obsolete APIs with calls to factory methods for specific algorithms, for example, Aes.Create(). This gives you full control over which algorithms are instantiated. If you need to maintain compatibility with existing payloads generated by .NET Framework apps that use the now-obsolete APIs, use the replacements suggested in the following table. The table provides a mapping from .NET Framework default algorithms to their .NET 5+ equivalents. .NET Framework .NET Core / Remarks .NET 5+ compatible replacement AsymmetricAlgorithm.Create() RSA.Create() HashAlgorithm.Create() SHA1.Create() The SHA-1 algorithm is considered broken. Consider using a stronger algorithm if possible. Consult your security advisor for further guidance. HMAC.Create() HMACSHA1() The HMACSHA1 algorithm is discouraged for most modern applications. Consider using a stronger algorithm if possible. Consult your security advisor for further guidance. .NET Framework .NET Core / .NET 5+ compatible Remarks replacement KeyedHashAlgorithm.Create() HMACSHA1() The HMACSHA1 algorithm is discouraged for most modern applications. Consider using a stronger algorithm if possible. Consult your security advisor for further guidance. SymmetricAlgorithm.Create() Aes.Create() If you must continue to call the obsolete parameterless Create() overloads, you can suppress the SYSLIB0007 warning in code. C# #pragma warning disable SYSLIB0007 // Disable the warning. HashAlgorithm alg = HashAlgorithm.Create(); // Still throws PNSE. #pragma warning restore SYSLIB0007 // Re-enable the warning. You can also suppress the warning in your project file. Doing so disables the warning for all source files within the project. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below suppresses SYSLIB0007 project-wide --> <NoWarn>$(NoWarn);SYSLIB0007</NoWarn> </PropertyGroup> </Project> 7 Note Suppressing SYSLIB0007 disables only the obsoletion warnings for the cryptography APIs listed here. It does not disable any other warnings. Additionally, even if you suppress the warning, these obsoleted APIs will still throw a PlatformNotSupportedException at run time. Affected APIs System.Security.Cryptography.AsymmetricAlgorithm.Create() System.Security.Cryptography.HashAlgorithm.Create() System.Security.Cryptography.HMAC.Create() System.Security.Cryptography.KeyedHashAlgorithm.Create() System.Security.Cryptography.SymmetricAlgorithm.Create() Default FeedbackSize value for instances created by TripleDES.Create changed Article • 10/12/2021 The default value for the SymmetricAlgorithm.FeedbackSize property on the TripleDES instance returned from TripleDES.Create() has changed from 64 to 8 to make migration from .NET Framework easier. This property, unless used directly in caller code, is used only when the Mode property is CipherMode.CFB. Support for the CFB mode was first added to .NET for the 5.0 RC1 release, so only .NET 5 RC1 and .NET 5 RC2 applications should be impacted by this change. Change description In .NET Core and previous pre-release versions of .NET 5, TripleDES.Create().FeedbackSize has a default value of 64. Starting in the RTM version of .NET 5, TripleDES.Create().FeedbackSize has a default value of 8. Reason for change In .NET Framework, the TripleDES base class defaults the value of FeedbackSize to 64, but the TripleDESCryptoServiceProvider class overwrites the default to 8. When the FeedbackSize property was introduced to .NET Core in version 2.0, this same behavior was preserved. However, in .NET Framework, TripleDES.Create() returns an instance of TripleDESCryptoServiceProvider, so the default value from the algorithm factory is 8. For .NET Core and .NET 5+, the algorithm factory returns a non-public implementation, which, until now, had a default value of 64. Changing the TripleDES implementation class' FeedbackSize value to 8 allows for applications written for .NET Framework that specified the cipher mode as CFB but didn't explicitly assign the FeedbackSize property, to continue to function on .NET 5. Version introduced 5.0 Recommended action Applications that encrypt or decrypt data in the RC1 or RC2 versions of .NET 5 do so with CFB64, when the following conditions are met: With a TripleDES instance from TripleDES.Create(). Using the default value for FeedbackSize. With the Mode property set to CipherMode.CFB. To maintain this behavior, assign the FeedbackSize property to 64 . Not all TripleDES implementations use the same default for FeedbackSize. We recommend that if you use the CFB cipher mode on TripleDES instances, you should always explicitly assign the FeedbackSize property value. C# TripleDES cipher = TripleDES.Create(); cipher.Mode = CipherMode.CFB; // Explicitly set the FeedbackSize for CFB to control between CFB8 and CFB64. cipher.FeedbackSize = 8; Affected APIs System.Security.Cryptography.TripleDES.Create() System.Security.Cryptography.SymmetricAlgorithm.FeedbackSize Breaking changes in EF Core 5.0 Article • 02/18/2023 The following API and behavior changes have the potential to break existing applications updating to EF Core 5.0.0. Summary Breaking change Impact EF Core 5.0 does not support .NET Framework Medium IProperty.GetColumnName() is now obsolete Medium Precision and scale are required for decimals Medium Required or non-nullable navigation from principal to dependent has different semantics Medium Defining query is replaced with provider-specific methods Medium Non-null reference navigations are not overwritten by queries Medium ToView() is treated differently by migrations Medium ToTable(null) marks the entity type as not mapped to a table Medium Removed HasGeometricDimension method from SQLite NTS extension Low Azure Cosmos DB: Partition key is now added to the primary key Low Azure Cosmos DB: id property renamed to __id Low Azure Cosmos DB: byte[] is now stored as a base64 string instead of a number array Low Azure Cosmos DB: GetPropertyName and SetPropertyName were renamed Low Value generators are called when the entity state is changed from Detached to Low Unchanged, Updated, or Deleted IMigrationsModelDiffer now uses IRelationalModel Low Discriminators are read-only Low Provider-specific EF.Functions methods throw for in-memory provider Low IndexBuilder.HasName is now obsolete Low A pluralizer is now included for scaffolding reverse engineered models Low Breaking change Impact INavigationBase replaces INavigation in some APIs to support skip navigations Low Some queries with correlated collection that also use Distinct or GroupBy are no longer Low supported Using a collection of Queryable type in projection is not supported Low Medium-impact changes EF Core 5.0 does not support .NET Framework Tracking Issue #15498 Old behavior EF Core 3.1 targets .NET Standard 2.0, which is supported by .NET Framework. New behavior EF Core 5.0 targets .NET Standard 2.1, which is not supported by .NET Framework. This means EF Core 5.0 cannot be used with .NET Framework applications. Why This is part of the wider movement across .NET teams aimed at unification to a single .NET target framework. For more information see the future of .NET Standard . Mitigations .NET Framework applications can continue to use EF Core 3.1, which is a long-term support (LTS) release . Alternately, applications can be updated to use .NET Core 3.1 or .NET 5, both of which support .NET Standard 2.1. IProperty.GetColumnName() is now obsolete Tracking Issue #2266 Old behavior GetColumnName() returned the name of the column that a property is mapped to. New behavior GetColumnName() still returns the name of a column that a property is mapped to, but this behavior is now ambiguous since EF Core 5 supports TPT and simultaneous mapping to a view or a function where these mappings could use different column names for the same property. Why We marked this method as obsolete to guide users to a more accurate overload GetColumnName(IProperty, StoreObjectIdentifier). Mitigations If the entity type is only ever mapped to a single table, and never to views, functions, or multiple tables, the GetColumnBaseName(IReadOnlyProperty) can be used in EF Core 5.0 and 6.0 to obtain the table name. For example: C# var columnName = property.GetColumnBaseName(); In EF Core 7.0, this can again be replaced with the new GetColumnName , which behaves as the original did for simple, single table only mappings. If the entity type may be mapped to views, functions, or multiple tables, then a StoreObjectIdentifier must be obtained to identity the table, view, or function. This can be then be used to get the column name for that store object. For example: C# var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null))); Precision and scale are required for decimals Tracking Issue #19293 Old behavior EF Core did not normally set precision and scale on SqlParameter objects. This means the full precision and scale was sent to SQL Server, at which point SQL Server would round based on the precision and scale of the database column. New behavior EF Core now sets precision and scale on parameters using the values configured for properties in the EF Core model. This means rounding now happens in SqlClient. Consequentially, if the configured precision and scale do not match the database precision and scale, then the rounding seen may change. Why Newer SQL Server features, including Always Encrypted, require that parameter facets are fully specified. In addition, SqlClient made a change to round instead of truncate decimal values, thereby matching the SQL Server behavior. This made it possible for EF Core to set these facets without changing the behavior for correctly configured decimals. Mitigations Map your decimal properties using a type name that includes precision and scale. For example: C# public class Blog { public int Id { get; set; } [Column(TypeName = "decimal(16, 5)")] public decimal Score { get; set; } } Or use HasPrecision in the model building APIs. For example: C# protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>().Property(e => e.Score).HasPrecision(16, 5); } Required or non-nullable navigation from principal to dependent has different semantics Tracking Issue #17286 Old behavior Only the navigations to principal could be configured as required. Therefore, using RequiredAttribute on the navigation to the dependent (the entity containing the foreign key) or marking it as non-nullable would instead create the foreign key on the defining entity type. New behavior With the added support for required dependents, it is now possible to mark any reference navigation as required, meaning that in the case shown above the foreign key will be defined on the other side of the relationship and the properties won't be marked as required. Calling IsRequired before specifying the dependent end is now ambiguous: C# modelBuilder.Entity<Blog>() .HasOne(b => b.BlogImage) .WithOne(i => i.Blog) .IsRequired() .HasForeignKey<BlogImage>(b => b.BlogForeignKey); Why The new behavior is necessary to enable support for required dependents (see #12100 ). Mitigations Remove RequiredAttribute from the navigation to the dependent and place it instead on the navigation to the principal or configure the relationship in OnModelCreating : C# modelBuilder.Entity<Blog>() .HasOne(b => b.BlogImage) .WithOne(i => i.Blog) .HasForeignKey<BlogImage>(b => b.BlogForeignKey) .IsRequired(); Defining query is replaced with provider-specific methods Tracking Issue #18903 Old behavior Entity types were mapped to defining queries at the Core level. Anytime the entity type was used in the query root of the entity type was replaced by the defining query for any provider. New behavior APIs for defining query are deprecated. New provider-specific APIs were introduced. Why While defining queries were implemented as replacement query whenever query root is used in the query, it had a few issues: If defining query is projecting entity type using new { ... } in Select method, then identifying that as an entity required additional work and made it inconsistent with how EF Core treats nominal types in the query. For relational providers FromSql is still needed to pass the SQL string in LINQ expression form. Initially defining queries were introduced as client-side views to be used with InMemory provider for keyless entities (similar to database views in relational databases). Such definition makes it easy to test application against in-memory database. Afterwards they became broadly applicable, which was useful but brought inconsistent and hard to understand behavior. So we decided to simplify the concept. We made LINQ based defining query exclusive to In-Memory provider and treat them differently. For more information, see this issue . Mitigations For relational providers, use ToSqlQuery method in OnModelCreating and pass in a SQL string to use for the entity type. For the In-Memory provider, use ToInMemoryQuery method in OnModelCreating and pass in a LINQ query to use for the entity type. Non-null reference navigations are not overwritten by queries Tracking Issue #2693 Old behavior In EF Core 3.1, reference navigations eagerly initialized to non-null values would sometimes be overwritten by entity instances from the database, regardless of whether or not key values matched. However, in other cases, EF Core 3.1 would do the opposite and leave the existing non-null value. New behavior Starting with EF Core 5.0, non-null reference navigations are never overwritten by instances returned from a query. Note that eager initialization of a collection navigation to an empty collection is still supported. Why Initialization of a reference navigation property to an "empty" entity instance results in an ambiguous state. For example: C# public class Blog { public int Id { get; set; } public Author Author { get; set; ) = new Author(); } Normally a query for Blogs and Authors will first create Blog instances and then set the appropriate Author instances based on the data returned from the database. However, in this case every Blog.Author property is already initialized to an empty Author . Except EF Core has no way to know that this instance is "empty". So overwriting this instance could potentially silently throw away a valid Author . Therefore, EF Core 5.0 now consistently does not overwrite a navigation that is already initialized. This new behavior also aligns with the behavior of EF6 in most cases, although upon investigation we also found some cases of inconsistency in EF6. Mitigations If this break is encountered, then the fix is to stop eagerly initializing reference navigation properties. ToView() is treated differently by migrations Tracking Issue #2725 Old behavior Calling ToView(string) made the migrations ignore the entity type in addition to mapping it to a view. New behavior Now ToView(string) marks the entity type as not mapped to a table in addition to mapping it to a view. This results in the first migration after upgrading to EF Core 5 to try to drop the default table for this entity type as it's not longer ignored. Why EF Core now allows an entity type to be mapped to both a table and a view simultaneously, so ToView is no longer a valid indicator that it should be ignored by migrations. Mitigations Use the following code to mark the mapped table as excluded from migrations: C# protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>().ToTable("UserView", t => t.ExcludeFromMigrations()); } ToTable(null) marks the entity type as not mapped to a table Tracking Issue #21172 Old behavior ToTable(null) would reset the table name to the default. New behavior ToTable(null) now marks the entity type as not mapped to any table. Why EF Core now allows an entity type to be mapped to both a table and a view simultaneously, so ToTable(null) is used to indicate that it isn't mapped to any table. Mitigations Use the following code to reset the table name to the default if it's not mapped to a view or a DbFunction: C# protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User> ().Metadata.RemoveAnnotation(RelationalAnnotationNames.TableName); } Low-impact changes Removed HasGeometricDimension method from SQLite NTS extension Tracking Issue #14257 Old behavior HasGeometricDimension was used to enable additional dimensions (Z and M) on geometry columns. However, it only ever affected database creation. It was unnecessary to specify it to query values with additional dimensions. It also didn't work correctly when inserting or updating values with additional dimensions (see #14257 ). New behavior To enable inserting and updating geometry values with additional dimensions (Z and M), the dimension needs to be specified as part of the column type name. This API matches more closely to the underlying behavior of SpatiaLite's AddGeometryColumn function. Why Using HasGeometricDimension after specifying the dimension in the column type is unnecessary and redundant, so we removed HasGeometricDimension entirely. Mitigations Use HasColumnType to specify the dimension: C# modelBuilder.Entity<GeoEntity>( x => { // Allow any GEOMETRY value with optional Z and M values x.Property(e => e.Geometry).HasColumnType("GEOMETRYZM"); // Allow only POINT values with an optional Z value x.Property(e => e.Point).HasColumnType("POINTZ"); }); Azure Cosmos DB: Partition key is now added to the primary key Tracking Issue #15289 Old behavior The partition key property was only added to the alternate key that includes id . New behavior The partition key property is now also added to the primary key by convention. Why This change makes the model better aligned with Azure Cosmos DB semantics and improves the performance of Find and some queries. Mitigations To prevent the partition key property to be added to the primary key, configure it in OnModelCreating . C# modelBuilder.Entity<Blog>() .HasKey(b => b.Id); Azure Cosmos DB: id property renamed to __id Tracking Issue #17751 Old behavior The shadow property mapped to the id JSON property was also named id . New behavior The shadow property created by convention is now named __id . Why This change makes it less likely that the id property clashes with an existing property on the entity type. Mitigations To go back to the 3.x behavior, configure the id property in OnModelCreating . C# modelBuilder.Entity<Blog>() .Property<string>("id") .ToJsonProperty("id"); Azure Cosmos DB: byte[] is now stored as a base64 string instead of a number array Tracking Issue #17306 Old behavior Properties of type byte[] were stored as a number array. New behavior Properties of type byte[] are now stored as a base64 string. Why This representation of byte[] aligns better with expectations and is the default behavior of the major JSON serialization libraries. Mitigations Existing data stored as number arrays will still be queried correctly, but currently there isn't a supported way to change back the insert behavior. If this limitation is blocking your scenario, comment on this issue Azure Cosmos DB: GetPropertyName and SetPropertyName were renamed Tracking Issue #17874 Old behavior Previously the extension methods were called GetPropertyName and SetPropertyName New behavior The old API was removed and new methods added: GetJsonPropertyName , SetJsonPropertyName Why This change removes the ambiguity around what these methods are configuring. Mitigations Use the new API. Value generators are called when the entity state is changed from Detached to Unchanged, Updated, or Deleted Tracking Issue #15289 Old behavior Value generators were only called when the entity state changed to Added. New behavior Value generators are now called when the entity state is changed from Detached to Unchanged, Updated, or Deleted and the property contains the default values. Why This change was necessary to improve the experience with properties that are not persisted to the data store and have their value generated always on the client. Mitigations To prevent the value generator from being called, assign a non-default value to the property before the state is changed. IMigrationsModelDiffer now uses IRelationalModel Tracking Issue #20305 Old behavior IMigrationsModelDiffer API was defined using IModel . New behavior IMigrationsModelDiffer API now uses IRelationalModel . However the model snapshot still contains only IModel as this code is part of the application and Entity Framework can't change it without making a bigger breaking change. Why IRelationalModel is a newly added representation of the database schema. Using it to find differences is faster and more accurate. Mitigations Use the following code to compare the model from snapshot with the model from context : C# var dependencies = context.GetService<ProviderConventionSetBuilderDependencies>(); var relationalDependencies = context.GetService<RelationalConventionSetBuilderDependencies>(); var typeMappingConvention = new TypeMappingConvention(dependencies); typeMappingConvention.ProcessModelFinalizing(((IConventionModel)modelSnapsho t.Model).Builder, null); var relationalModelConvention = new RelationalModelConvention(dependencies, relationalDependencies); var sourceModel = relationalModelConvention.ProcessModelFinalized(snapshot.Model); var modelDiffer = context.GetService<IMigrationsModelDiffer>(); var hasDifferences = modelDiffer.HasDifferences( ((IMutableModel)sourceModel).FinalizeModel().GetRelationalModel(), context.Model.GetRelationalModel()); We are planning to improve this experience in 6.0 (see #22031 ) Discriminators are read-only Tracking Issue #21154 Old behavior It was possible to change the discriminator value before calling SaveChanges New behavior An exception will be thrown in the above case. Why EF doesn't expect the entity type to change while it is still being tracked, so changing the discriminator value leaves the context in an inconsistent state, which might result in unexpected behavior. Mitigations If changing the discriminator value is necessary and the context will be disposed immediately after calling SaveChanges , the discriminator can be made mutable: C# modelBuilder.Entity<BaseEntity>() .Property<string>("Discriminator") .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save); Provider-specific EF.Functions methods throw for inmemory provider Tracking Issue #20294 Old behavior Provider-specific EF.Functions methods contained implementation for client execution, which allowed them to be executed on the in-memory provider. For example, EF.Functions.DateDiffDay is a Sql Server specific method, which worked on InMemory provider. New behavior Provider-specific methods have been updated to throw an exception in their method body to block evaluating them on client side. Why Provider-specific methods map to a database function. The computation done by the mapped database function can't always be replicated on the client side in LINQ. It may cause the result from the server to differ when executing the same method on client. Since these methods are used in LINQ to translate to specific database functions, they don't need to be evaluated on client side. As the in-memory provider is a different database, these methods aren't available for this provider. Trying to execute them for InMemory provider, or any other provider that doesn't translate these methods, throws an exception. Mitigations Since there's no way to mimic behavior of database functions accurately, you should test the queries containing them against same kind of database as in production. IndexBuilder.HasName is now obsolete Tracking Issue #21089 Old behavior Previously, only one index could be defined over a given set of properties. The database name of an index was configured using IndexBuilder.HasName. New behavior Multiple indexes are now allowed on the same set or properties. These indexes are now distinguished by a name in the model. By convention, the model name is used as the database name; however it can also be configured independently using HasDatabaseName. Why In the future, we'd like to enable both ascending and descending indexes or indexes with different collations on the same set of properties. This change moves us another step in that direction. Mitigations Any code that was previously calling IndexBuilder.HasName should be updated to call HasDatabaseName instead. If your project includes migrations generated prior to EF Core version 2.0.0, you can safely ignore the warning in those files and suppress it by adding #pragma warning disable 612, 618 . A pluralizer is now included for scaffolding reverse engineered models Tracking Issue #11160 Old behavior Previously, you had to install a separate pluralizer package in order to pluralize DbSet and collection navigation names and singularize table names when scaffolding a DbContext and entity types by reverse engineering a database schema. New behavior EF Core now includes a pluralizer that uses the Humanizer library. This is the same library Visual Studio uses to recommend variable names. Why Using plural forms of words for collection properties and singular forms for types and reference properties is idiomatic in .NET. Mitigations To disable the pluralizer, use the --no-pluralize option on dotnet ef dbcontext scaffold or the -NoPluralize switch on Scaffold-DbContext . INavigationBase replaces INavigation in some APIs to support skip navigations Tracking Issue #2568 Old behavior EF Core prior to 5.0 supported only one form of navigation property, represented by the INavigation interface. New behavior EF Core 5.0 introduces many-to-many relationships which use "skip navigations". These are represented by the ISkipNavigation interface, and most of the functionality of INavigation has been pushed down to a common base interface: INavigationBase . Why Most of the functionality between normal and skip navigations is the same. However, skip navigations have a different relationship to foreign keys than normal navigations, since the FKs involved are not directly on either end of the relationship, but rather in the join entity. Mitigations In many cases applications can switch to using the new base interface with no other changes. However, in cases where the navigation is used to access foreign key properties, application code should either be constrained to only normal navigations, or updated to do the appropriate thing for both normal and skip navigations. Some queries with correlated collection that also use Distinct or GroupBy are no longer supported Tracking Issue #15873 Old behavior Previously, queries involving correlated collections followed by GroupBy , as well as some queries using Distinct we allowed to execute. GroupBy example: C# context.Parents .Select(p => p.Children .GroupBy(c => c.School) .Select(g => g.Key)) Distinct example - specifically Distinct queries where inner collection projection doesn't contain the primary key: C# context.Parents .Select(p => p.Children .Select(c => c.School) .Distinct()) These queries could return incorrect results if the inner collection contained any duplicates, but worked correctly if all the elements in the inner collection were unique. New behavior These queries are no longer supported. Exception is thrown indicating that we don't have enough information to correctly build the results. Why For correlated collection scenarios we need to know entity's primary key in order to assign collection entities to the correct parent. When inner collection doesn't use GroupBy or Distinct , the missing primary key can simply be added to the projection. However in case of GroupBy and Distinct it can't be done because it would change the result of GroupBy or Distinct operation. Mitigations Rewrite the query to not use GroupBy or Distinct operations on the inner collection, and perform these operations on the client instead. C# context.Parents .Select(p => p.Children.Select(c => c.School)) .ToList() .Select(x => x.GroupBy(c => c).Select(g => g.Key)) C# context.Parents .Select(p => p.Children.Select(c => c.School)) .ToList() .Select(x => x.Distinct()) Using a collection of Queryable type in projection is not supported Tracking Issue #16314 Old behavior Previously, it was possible to use collection of a Queryable type inside the projection in some cases, for example as an argument to a List<T> constructor: C# context.Blogs .Select(b => new List<Post>(context.Posts.Where(p => p.BlogId == b.Id))) New behavior These queries are no longer supported. Exception is thrown indicating that we can't create an object of Queryable type and suggesting how this could be fixed. Why We can't materialize an object of a Queryable type, so they would automatically be created using List<T> type instead. This would often cause an exception due to type mismatch which was not very clear and could be surprising to some users. We decided to recognize the pattern and throw a more meaningful exception. Mitigations Add ToList() call after the Queryable object in the projection: C# context.Blogs.Select(b => context.Posts.Where(p => p.BlogId == b.Id).ToList()) Globalization APIs use ICU libraries on Windows 10 Article • 12/29/2022 .NET 5 and later versions use International Components for Unicode (ICU) libraries for globalization functionality when running on Windows 10 May 2019 Update or later. Change description In .NET Core 1.0 - 3.1 and .NET Framework 4 and later, .NET libraries use National Language Support (NLS) APIs for globalization functionality on Windows. For example, NLS functions were used to compare strings, get culture information, and perform string casing in the appropriate culture. Starting in .NET 5, if an app is running on Windows 10 May 2019 Update or later, .NET libraries use ICU globalization APIs, by default. 7 Note Windows 10 May 2019 Update and later versions ship with the ICU native library. If the .NET runtime can't load ICU, it uses NLS instead. Behavioral differences You might see changes in your app even if you don't realize you're using globalization facilities. This section lists a couple of the behavioral changes you might see, but there are others too. String.IndexOf Consider the following code that calls String.IndexOf(String) to find the index of the newline character in a string. C# string s = "Hello\r\nworld!"; int idx = s.IndexOf("\n"); Console.WriteLine(idx); In .NET Core 3.1 and earlier versions on Windows, the snippet prints 6 . In .NET 5 and on Windows 10 May 2019 Update and later versions, the snippet prints -1 . In .NET 6 and later versions, the snippet prints 6 , however, ICU libraries are still used. To fix this code by conducting an ordinal search instead of a culture-sensitive search, call the IndexOf(String, StringComparison) overload and pass in StringComparison.Ordinal as an argument. You can run code analysis rules CA1307: Specify StringComparison for clarity and CA1309: Use ordinal StringComparison to find these call sites in your code. For more information, see Behavior changes when comparing strings on .NET 5+. Currency symbol Consider the following code that formats a string using the currency format specifier C . The current thread's culture is set to a culture that includes only the language and not the country or region. C# System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de"); string text = string.Format("{0:C}", 100); In .NET Core 3.1 and earlier versions on Windows, the value of text is "100,00 €" . In .NET 5 and later versions on Windows 19H1 and later versions, the value of text is "100,00 ¤" , which uses the international currency symbol instead of the euro. In ICU, the design is that a currency is a property of a country or region, not a language. Reason for change This change was introduced to unify .NET's globalization behavior across all supported operating systems. It also provides the ability for applications to bundle their own globalization libraries rather than depend on the operating system's built-in libraries. Version introduced .NET 5.0 Recommended action No action is required on the part of the developer. However, if you wish to continue using NLS globalization APIs, you can set a run-time switch to revert to that behavior. For more information about the available switches, see the .NET globalization and ICU article. Affected APIs System.Span<T> System.String Most types in the System.Globalization namespace System.Array.Sort (when sorting an array of strings) System.Collections.Generic.List<T>.Sort() (when the list elements are strings) System.Collections.Generic.SortedDictionary<TKey,TValue> (when the keys are strings) System.Collections.Generic.SortedList<TKey,TValue> (when the keys are strings) System.Collections.Generic.SortedSet<T> (when the set contains strings) See also Globalization APIs use ICU libraries on Windows Server StringInfo and TextElementEnumerator are now UAX29-compliant Article • 09/15/2021 Prior to this change, System.Globalization.StringInfo and System.Globalization.TextElementEnumerator didn't properly handle all grapheme clusters. Some graphemes were split into their constituent components instead of being kept together. Now, StringInfo and TextElementEnumerator process grapheme clusters according to the latest version of the Unicode Standard. In addition, the Microsoft.VisualBasic.Strings.StrReverse method, which reverses the characters in a string in Visual Basic, now also follows the Unicode standard for grapheme clusters. Change description A grapheme or extended grapheme cluster is a single user-perceived character that may be made up of multiple Unicode code points. For example, the string containing the Thai character "kam" (กำ) consists of the following two characters: ก (= '\u0e01') THAI CHARACTER KO KAI ำ (= '\u0e33') THAI CHARACTER SARA AM When displayed to the user, the operating system combines the two characters to form the single display character (or grapheme) "kam" or กำ. Emoji can also consist of multiple characters that are combined for display in a similar way. Tip The .NET documentation sometimes uses the term "text element" when referring to a grapheme. The StringInfo and TextElementEnumerator classes inspect strings and return information about the graphemes they contain. In .NET Framework (all versions) and .NET Core 3.x and earlier, these two classes use custom logic that handles some combining classes but doesn't fully comply with the Unicode Standard . For example, the StringInfo and TextElementEnumerator classes incorrectly split the single Thai character "kam" back into its constituent components instead of keeping them together. These classes also incorrectly split the emoji character "🤷🏽♀️" into four clusters (person shrugging, skin tone modifier, gender modifier, and an invisible combiner) instead of keeping them together as a single grapheme cluster. Starting with .NET 5, the StringInfo and TextElementEnumerator classes implement the Unicode standard as defined by Unicode Standard Annex #29, rev. 35, sec. 3 . In particular, they now return extended grapheme clusters for all combining classes. Consider the following C# code: C# using System.Globalization; static void Main(string[] args) { PrintGraphemes("กำ"); PrintGraphemes("🤷🏽♀️"); } static void PrintGraphemes(string str) { Console.WriteLine($"Printing graphemes of \"{str}\"..."); int i = 0; TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(str); while (enumerator.MoveNext()) { Console.WriteLine($"Grapheme {++i}: \"{enumerator.Current}\""); } Console.WriteLine($"({i} grapheme(s) total.)"); Console.WriteLine(); } In .NET Framework and .NET Core 3.x and earlier versions, the graphemes are split up, and the console output is as follows: txt Printing graphemes of "กำ"... Grapheme 1: "ก" Grapheme 2: "ำ" (2 grapheme(s) total.) Printing graphemes of "🤷🏽♀️"... Grapheme 1: "🤷" Grapheme 2: "🏽" Grapheme 3: " " Grapheme 4: "♀️ " (4 grapheme(s) total.) In .NET 5 and later versions, the graphemes are kept together, and the console output is as follows: txt Printing graphemes of "กำ"... Grapheme 1: "กำ" (1 grapheme(s) total.) Printing graphemes of "🤷🏽♀️"... Grapheme 1: "🤷🏽♀️" (1 grapheme(s) total.) In addition, starting in .NET 5, the Microsoft.VisualBasic.Strings.StrReverse method, which reverses the characters in a string in Visual Basic, now also follows the Unicode standard for grapheme clusters. These changes are part of a wider set of Unicode and UTF-8 improvements in .NET, including an extended grapheme cluster enumeration API to complement the Unicode scalar-value enumeration APIs that were introduced with the System.Text.Rune type in .NET Core 3.0. Version introduced .NET 5.0 Recommended action You don't need to take any action. Your apps will automatically behave in a more standards-compliant manner in a variety of globalization-related scenarios. Affected APIs System.Globalization.StringInfo System.Globalization.TextElementEnumerator Microsoft.VisualBasic.Strings.StrReverse Unicode category changed for some Latin-1 characters Article • 11/08/2021 Char methods now return the correct Unicode category for characters in the Latin-1 range. The category matches that of the Unicode standard. Change description In previous .NET versions, Char methods used a fixed list of Unicode categories for characters in the Latin-1 range. However, the Unicode standard has changed the categories of some of these characters since those APIs were implemented, creating a discrepancy. In addition, there was also a discrepancy between Char and CharUnicodeInfo APIs, which follow the Unicode standard. In .NET 5 and later versions, Char methods use and return the Unicode category that matches the Unicode standard for all characters. The following table shows the characters whose Unicode categories have changed in .NET 5: Character Unicode category in previous .NET versions Unicode category in .NET 5 and later versions § (\u00a7) OtherSymbol OtherPunctuation ª (\u00aa) LowercaseLetter OtherLetter SHY (\u00ad) DashPunctuation Format ¶ (\u00b6) OtherSymbol OtherPunctuation º (\u00ba) LowercaseLetter OtherLetter Version introduced .NET 5.0 Recommended action If you have any code that gets the Unicode character category by using the Char class and assumes the category will never change, you may need to update it. Reason for change This change was made so that the categories returned by the Char type are consistent with both the Unicode standard and the CharUnicodeInfo type. Affected APIs System.Char.GetUnicodeCategory System.Char.IsLetter System.Char.IsPunctuation System.Char.IsSymbol System.Char.IsLower Additionally, any class that depends on Char to obtain the Unicode character category, for example, Regex, is affected by this change. TextInfo.ListSeparator values changed Article • 09/15/2021 The default TextInfo.ListSeparator values for different cultures have changed on all operating systems. Change description In .NET 5.0.0, as part of the switch from NLS to ICU libraries, the default TextInfo.ListSeparator values for different cultures changed on Windows. Decimal separator values, obtained from International Components for Unicode (ICU), were used as the ListSeparator values. On Linux and macOS, there was no change in TextInfo.ListSeparator values; that is, they continued to use decimal separator values. For all operating systems in .NET 5.0.1 and later versions, the values for TextInfo.ListSeparator are equivalent to the values that would be obtained from NLS. For Windows, this means the values are equivalent to what they were in .NET Framework and .NET Core 1.0 - 3.1. For Linux and macOS, the TextInfo.ListSeparator values now match the TextInfo.ListSeparator values for Windows. The following table summarizes the changes for TextInfo.ListSeparator values. .NET Framework .NET Core 1.0 - 3.1 .NET 5 .NET 5.0.1 Windows Obtain from NLS Decimal separator from ICU. Can switch back to NLS. Equivalent to NLS Linux and macOS Decimal separator from ICU Decimal separator from ICU Equivalent to NLS Version introduced 5.0.1 Reason for change Developers reported that they use the TextInfo.ListSeparator property when parsing comma-separated value (CSV) files, and the new TextInfo.ListSeparator values broke that parsing. Recommended action If your code relies on the previous decimal separator values, you can hardcode the desired TextInfo.ListSeparator values. Affected APIs System.Globalization.TextInfo.ListSeparator Built-in support for WinRT is removed from .NET Article • 04/02/2022 Built-in support for consumption of Windows runtime (WinRT) APIs in .NET is removed. Version introduced 5.0 Change description Previously, CoreCLR could consume Windows metadata (WinMD) files to active and consume WinRT types. Starting in .NET 5, CoreCLR can no longer consume WinMD files directly. If you attempt to reference an unsupported assembly, you'll get a FileNotFoundException. If you activate a WinRT class, you'll get a PlatformNotSupportedException. This breaking change was made for the following reasons: So WinRT can be developed and improved separately from the .NET runtime. For symmetry with interop systems provided for other operating systems, such as iOS and Android. To take advantage of other .NET features, such as C# features, intermediate language (IL) trimming, and ahead-of-time (AOT) compilation. To simplify the .NET runtime codebase. Recommended action Remove references to the Microsoft.Windows.SDK.Contracts package specify the version of the Windows APIs that you want to access via the TargetFramework property of the project. For example: XML <TargetFramework>net5.0-windows10.0.19041.0</TargetFramework> . Instead, If you're consuming a third-party runtime component that's defined in a .winmd file, add a reference to the Microsoft.Windows.CsWinRT NuGet package . For information on how to generate the C# projection, see the C#/WinRT documentation. For more information, see Call Windows Runtime APIs in desktop apps. Affected APIs System.IO.WindowsRuntimeStorageExtensions System.IO.WindowsRuntimeStreamExtensions System.Runtime.InteropServices.WindowsRuntime System.WindowsRuntimeSystemExtensions Windows.Foundation.Point Windows.Foundation.Size Windows.UI.Color Casting RCW to an InterfaceIsIInspectable interface throws PlatformNotSupportedException Article • 12/04/2021 Casting a runtime callable wrapper (RCW) to an interface marked as InterfaceIsIInspectable now throws a PlatformNotSupportedException. This change is a follow up to the removal of WinRT support from .NET. Version introduced .NET 5 Change description In previous .NET versions, casting an RCW to an interface marked as InterfaceIsIInspectable worked as expected. Starting in .NET 5, casting an RCW to an interface marked as InterfaceIsIInspectable throws a PlatformNotSupportedException at cast time. Reason for change The support for InterfaceIsIInspectable was removed. Since the underlying support in the runtime no longer exists, throwing a PlatformNotSupportedException enables a graceful failure path. Throwing an exception also makes it more discoverable that this feature is no longer supported. Recommended action If you can define the interface in a Windows runtime metadata (WinMD) file, use the C#/WinRT tool instead. Otherwise, mark the interface as InterfaceIsIUnknown instead of InterfaceIsIInspectable, and add three dummy entries to the start of the interface for the InterfaceIsIInspectable methods. The following code snippet shows an example. C# [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IMine { // Do not call these three methods. // They're exclusively to fill in the slots in the vtable. void GetIIdsSlot(); void GetRuntimeClassNameSlot(); void GetTrustLevelSlot(); // The original members of the IMine interface go here. ... } Affected APIs System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIInspectable No A/W suffix probing on nonWindows platforms Article • 09/15/2021 The .NET runtimes no longer add an A or W suffix to function export names during probing for P/Invokes on non-Windows platforms. Version introduced 5.0 Change description Windows has a convention of adding an A or W suffix to Windows SDK function names, which correspond to the Windows code page and Unicode versions, respectively. In previous versions of .NET, both the CoreCLR and Mono runtimes add an A or W suffix to the export name during export discovery for P/Invokes on all platforms. In .NET 5 and later versions, an A or W suffix is added to the export name during export discovery on Windows only. On Unix platforms, the suffix is not added. The semantics of both runtimes on the Windows platform remain unchanged. Reason for change This change was made to simplify cross-platform probing. It's overhead that shouldn't be incurred, given that non-Windows platforms don't contain this semantic. Recommended action To mitigate the change, you can manually add the desired suffix on non-Windows platforms. For example: C# [DllImport(...)] extern static void SetWindowTextW(); Affected APIs System.Runtime.InteropServices.DllImportAttribute Cookie path handling now conforms to RFC 6265 Article • 09/15/2021 Path-handling algorithms defined in RFC 6265 were implemented for the Cookie and CookieContainer classes. Version introduced 5.0 Change description The Path property is no longer required to be a prefix of the request path. The calculation of the default value of Path and path-matching algorithms were implemented as defined in section 5.1.4 of RFC 6265. Recommended action In most cases, you won't need to take any action. However, if your code was dependent on Path validation, you'll need to implement required validation in your code. If your code was dependent on default value calculation for Path, consider supplying the Path value manually instead of using the default value. Affected APIs System.Net.Cookie System.Net.CookieContainer Socket.LocalEndPoint is updated after calling SendToAsync Article • 09/15/2021 Socket.SendToAsync(SocketAsyncEventArgs) now updates the value of the Socket.LocalEndPoint property to the socket's local address. Version introduced 5.0 Change description In previous .NET versions, Socket.SendToAsync(SocketAsyncEventArgs) does not alter the value of the Socket.LocalEndPoint property on the socket instance. Starting in .NET 5, when SendToAsync(SocketAsyncEventArgs) successfully completes, the value of Socket.LocalEndPoint is the implicitly bound socket's local address. This new behavior is consistent with the behavior of SendTo(Byte[], EndPoint) and BeginSendTo(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback, Object)/EndSendTo(IAsyncResult). Reason for change This change fixes a bug and makes the behavior consistent across SendTo variants. Recommended action Alter any code that assumes that SendToAsync(SocketAsyncEventArgs) won't alter the value of Socket.LocalEndPoint. Affected APIs System.Net.Sockets.Socket.SendToAsync(SocketAsyncEventArgs) MulticastOption.Group doesn't accept a null value Article • 09/15/2021 MulticastOption.Group no longer accepts a value of null . If you set the property to null , an ArgumentNullException is thrown. Version introduced 5.0 Change description In previous versions of .NET, you can set the MulticastOption.Group property to null . If the MulticastOption is later passed to Socket.SetSocketOption, the runtime throws a NullReferenceException. In .NET 5 and later, an ArgumentNullException is thrown if you set the property to null . Reason for change To be consistent with the Framework Design Guidelines, the property has been updated to throw an ArgumentNullException if the value is null . Recommended action Make sure that you don't set MulticastOption.Group to null . Affected APIs System.Net.Sockets.MulticastOption.Group NegotiateStream and SslStream allow successive Begin operations Article • 09/15/2021 Error cases on security streams are handled differently, and successive calls to BeginAuthenticateAsServer or BeginAuthenticateAsClient may no longer fail. Version introduced 5.0 Change description In previous .NET versions, calling BeginAuthenticateAsServer or BeginAuthenticateAsClient successively without first calling EndAuthenticateAsServer or EndAuthenticateAsClient results in a NotSupportedException. Starting in .NET 5, successive calls to BeginAuthenticateAsServer or BeginAuthenticateAsClient no longer result in a NotSupportedException, because these APIs are backed by a Task-based implementation. Reason for change Switching the internal implementation from asynchronous programming model (APM) to Task-based improves performance and decreases code complexity. Recommended action No action is required on the part of the developer. Affected APIs System.Net.Security.SslStream.BeginAuthenticateAsServer System.Net.Security.SslStream.BeginAuthenticateAsClient System.Net.Security.NegotiateStream.BeginAuthenticateAsServer System.Net.Security.NegotiateStream.BeginAuthenticateAsClient WinHttpHandler removed from .NET runtime Article • 09/15/2021 The WinHttpHandler class was removed from the System.Net.Http.dll assembly. It's now available only as an out-of-band (OOB) NuGet package . Version introduced 5.0 Change description In previous .NET versions, the WinHttpHandler class is available as part of the core .NET libraries. Starting in .NET 5, the WinHttpHandler class is only available as a separately installed NuGet package . Recommended action Install the System.Net.Http.WinHttpHandler NuGet package . Or, if you don't require WinHTTP-specific features, use SocketsHttpHandler instead. Affected APIs System.Net.Http.WinHttpHandler Error generated when executable project references mismatched executable Article • 09/15/2021 Generally, an executable project references library projects, not other executable projects. An executable project can also reference another executable project to use APIs that are defined in it. Some developers want to reference an executable project from another executable project so that both apps are placed in and are runnable from the same output folder. However, this scenario does not work if a self-contained executable references a non-self-contained executable, or vice versa. Because of how the application host works, neither app can be launched. To prevent situations where apps aren't runnable, .NET SDK 5+ produces compile-time errors NETSDK1150 and NETSDK1151 when it detects mismatched executable references. Change description In previous .NET SDK versions, you could reference a self-contained executable project from a non-self-contained executable project without a build error. However, both apps would not be runnable. Starting in .NET SDK 5, an error is generated if an executable project references another executable project and the SelfContained values don't match. Version introduced .NET SDK 5.0.300 Reason for change The errors were introduced to prevent situations where you expect to be able to launch both applications but cannot. Recommended action If the referenced project doesn't need to be runnable from the output folder, you can set a property to avoid this error check: XML <ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableRef erencesMatchSelfContained> For more information, see ValidateExecutableReferencesMatchSelfContained. Affected APIs None. OutputType set to WinExe for WPF and WinForms apps Article • 09/15/2021 OutputType is automatically set to WinExe for Windows Presentation Foundation (WPF) and Windows Forms apps. When OutputType is set to WinExe , a console window doesn't open when the app is executed. Change description In previous versions of the .NET SDK, the value that's specified for OutputType in the project file is used. For example: XML <PropertyGroup> <OutputType>Exe</OutputType> </PropertyGroup> Starting in the 5.0.100 version of the .NET SDK, when OutputType is set to Exe , it is automatically changed to WinExe for WPF and Windows Forms apps that target any framework version, including .NET Framework. XML <PropertyGroup> <OutputType>WinExe</OutputType> </PropertyGroup> If OutputType is not specified in the project file, it defaults to Library and that value doesn't change. Reason for change It's assumed that most users don't want a console window to open when a WPF or Windows Forms app is executed. In addition, now that these application types use the .NET SDK instead of the Windows Desktop SDK, the correct default will be set. Further, when support for targeting iOS and Android is added, it will be easier to multi-target between multiple platforms if they all use the same output type. Version introduced .NET SDK 5.0.100 Recommended action No action is required in your part. However, if you want to revert to the old behavior, set the DisableWinExeOutputInference property to true in your project file. XML <DisableWinExeOutputInference>true</DisableWinExeOutputInference> Affected APIs Not detectable via API analysis. WinForms and WPF apps use Microsoft.NET.Sdk Article • 09/15/2021 Windows Forms and Windows Presentation Framework (WPF) apps now use the .NET SDK ( Microsoft.NET.Sdk ) instead of the .NET Core WinForms and WPF SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Change description In previous .NET Core versions, WinForms and WPF apps used a separate project SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Starting in .NET 5, the WinForms and WPF SDK has been unified with the .NET SDK ( Microsoft.NET.Sdk ). In addition, new target framework monikers (TFM) replace netcoreapp and netstandard in .NET 5. The following example shows the changes you'd need to make for a WPF project file when retargeting to .NET 5 or later. In previous .NET Core versions: XML <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> In .NET 5 and later versions: XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net5.0-windows</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> Version introduced .NET SDK 5.0.100 Recommended action In your WPF or Windows Forms project file: Update the Sdk attribute to Microsoft.NET.Sdk . Update the TargetFramework property to net5.0-windows . Affected APIs None. Directory.Packages.props files is imported by default Article • 09/15/2021 NuGet's .props files automatically import a file named Directory.Packages.props if it's found in the project folder or any of its ancestors. Version introduced 5.0 Change description In previous .NET versions, you could have a file named Directory.Packages.props in your project file and it wouldn't be automatically imported by NuGet's .props file at build time. Starting in .NET 5, such a file is automatically imported if it exists in the project folder or any of its ancestors. If you have a file with this name in your project folder, this automatic import could change behavior of the build. For example, the file will be imported but it wasn't before, or the order of when it's imported could change if you specifically import it. Reason for change This change was made in order to support central package versioning for NuGet. Recommended action Rename the existing Directory.Packages.props file if it should not be imported automatically. Affected APIs N/A NETCOREAPP3_1 preprocessor symbol is not defined when targeting .NET 5 Article • 09/15/2021 In .NET 5 RC2 and later versions, projects no longer define preprocessor symbols for earlier versions, but only for the version that they target. This is the same behavior as .NET Core 1.0 - 3.1. Version introduced 5.0 RC2 Change description In .NET 5 preview 7 through RC1, projects that target net5.0 define both NETCOREAPP3_1 and NET5_0 preprocessor symbols. The intent behind this behavior change was that starting with .NET 5, conditional compilation symbols would be cumulative . In .NET 5 RC2 and later, projects only define symbols for the target framework monikers (TFM) that it targets and not for any earlier versions. Reason for change The change from preview 7 was reverted due to customer feedback. Defining symbols for earlier versions surprised and confused customers, and some assumed it was a bug in the C# compiler. Recommended action Make sure that your #if logic doesn't assume that NETCOREAPP3_1 is defined when the project targets net5.0 or higher. Instead, assume that NETCOREAPP3_1 is only defined when the project explicitly targets netcoreapp3.1 . For example, if your project multitargets for .NET Core 2.1 and .NET Core 3.1 and you call APIs that were introduced in .NET Core 3.1, your #if logic should look as follows: C# #if NETCOREAPP2_1 || NETCOREAPP3_0 // Fallback behavior for old versions. #elif NETCOREAPP // Behavior for .NET Core 3.1 and later. #endif Affected APIs N/A PublishDepsFilePath behavior change Article • 09/15/2021 The PublishDepsFilePath MSBuild property is empty for single-file applications. Additionally, for non single-file applications, the deps.json file may not be copied to the output directory until later in the build. Version introduced 5.0 Change description In previous .NET versions, the PublishDepsFilePath MSBuild property is the path to the app's deps.json file in the output directory for non single-file applications, and a path in the intermediate directory for single-file apps. Starting in .NET 5, PublishDepsFilePath is empty for single-file applications and a new IntermediateDepsFilePath property specifies the deps.json location in the intermediate directory. Additionally, for non single-file applications, the deps.json file may not be copied to the output directory (that is, the path specified by PublishDepsFilePath ) until later in the build. Reason for change This change was made for a couple of reasons: Due to a refactoring of the publish logic in order to support improved single-file apps in .NET 5. In single-file apps, to help guard against targets that try to rewrite the deps.json file after deps.json has already been bundled, thus silently not affecting the app. For this reason, PublishDepsFilePath is empty for single-file applications. Recommended action Targets that rewrite the deps.json file should generally do so using the IntermediateDepsFilePath property. Affected APIs N/A TargetFramework change from netcoreapp to net Article • 09/15/2021 The value for the MSBuild TargetFramework property changed from netcoreapp3.1 to net5.0 . This can break code that relies on parsing the value of TargetFramework . Version introduced 5.0 Change description In .NET Core 1.0 - 3.1, the value for the MSBuild TargetFramework property starts with netcoreapp , for example, netcoreapp3.1 for apps that target .NET Core 3.1. Starting in .NET 5, this value is simplified to just start with net , for example, net5.0 for .NET 5.0. For more information, see The future of .NET Standard and Target framework names in .NET 5 . Reason for change Simplifies the TargetFramework value. Enables projects to include a TargetPlatform in the TargetFramework property. Recommended action If you have logic that parses the value of TargetFramework , you'll need to update it. For example, the following MSBuild condition relies on the value of TargetFramework . XML <PropertyGroup Condition="$(TargetFramework.StartsWith('netcoreapp'))"> For this requirement, you can update the code to compare the target framework identifier instead. XML <PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) ' == '.NETCoreApp'"> Affected APIs N/A FrameworkReference replaced with WindowsSdkPackageVersion for Windows SDK Article • 09/15/2021 Starting in .NET 5.0.8 (which includes .NET SDK 5.0.302 and .NET SDK 5.0.205), developers targeting Windows can't use the FrameworkReference item to override their version of the Windows SDK targeting package. The WindowsSdkPackageVersion property replaces this functionality. 7 Note We don't recommend overriding the Windows SDK version, because the Windows SDK targeting packages are included with the .NET 5+ SDK. Instead, to reference the latest Windows SDK package, update your version of the .NET SDK. Version introduced .NET SDK 5.0.302, .NET SDK 5.0.205 Previous behavior Developers could use the FrameworkReference item to override the Windows SDK package version in .NET 5 applications. For example: XML <ItemGroup> <FrameworkReference Update="Microsoft.Windows.SDK.NET.Ref" RuntimeFrameworkVersion="10.0.19041.18" /> <FrameworkReference Update="Microsoft.Windows.SDK.NET.Ref" TargetingPackVersion="10.0.19041.18" /> </ItemGroup> New behavior The WindowsSdkPackageVersion property replaces the behavior of the FrameworkReference override. For example: XML <PropertyGroup> <WindowsSdkPackageVersion>10.0.19041.18</WindowsSdkPackageVersion> </PropertyGroup> Category of change This change might affect source compatibility. Reason for change This change was introduced to simplify the package override behavior for targeting the Windows SDK packages produced by C#/WinRT. Recommended action Remove any use of FrameworkReference in your .NET 5+ app's project file when targeting the Windows SDK. Affected APIs Windows APIs in .NET 5 and later versions that are provided by the Windows SDK targeting package . Most code access security APIs are obsolete Article • 11/08/2021 Most code access security (CAS)-related types in .NET are now obsolete as warning. This includes CAS attributes, such as SecurityPermissionAttribute, CAS permission objects, such as SocketPermission, EvidenceBase-derived types, and other supporting APIs. Change description In .NET Framework 2.x - 4.x, CAS attributes and APIs can influence the course of code execution, including ensuring that CAS-demand stack walks succeed or fail. C# // In .NET Framework, the attribute causes CAS stack walks // to terminate successfully when this permission is demanded. [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] public void DoSomething() { // open a socket to contoso.com:443 } In .NET Core 2.x - 3.x, the runtime does not honor CAS attributes or CAS APIs. The runtime ignores attributes on method entry, and most programmatic APIs have no effect. C# // The .NET Core runtime ignores the following attribute. [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] public void DoSomething() { // open a socket to contoso.com:443 } Additionally, programmatic calls to expansive APIs ( Assert ) always succeed, while programmatic calls to restrictive APIs ( Deny , PermitOnly ) always throw an exception at run time. (PrincipalPermission is an exception to this rule. See the Recommended action section below.) C# public void DoAssert() { // The line below has no effect at run time. new SocketPermission(PermissionState.Unrestricted).Assert(); } public void DoDeny() { // The line below throws PlatformNotSupportedException at run time. new SocketPermission(PermissionState.Unrestricted).Deny(); } In .NET 5 and later versions, most CAS-related APIs are obsolete and produce compiletime warning SYSLIB0003 . C# [SocketPermission(SecurityAction.Assert, Host = "contoso.com", Port = "443")] // warning SYSLIB0003 public void DoSomething() { new SocketPermission(PermissionState.Unrestricted).Assert(); // warning SYSLIB0003 new SocketPermission(PermissionState.Unrestricted).Deny(); // warning SYSLIB0003 } This is a compile-time only change. There is no run-time change from previous versions of .NET Core. Methods that perform no operation in .NET Core 2.x - 3.x will continue to perform no operation at run time in .NET 5 and later. Methods that throw PlatformNotSupportedException in .NET Core 2.x - 3.x will continue to throw a PlatformNotSupportedException at run time in .NET 5 and later. Reason for change Code access security (CAS) is an unsupported legacy technology. The infrastructure to enable CAS exists only in .NET Framework 2.x - 4.x, but is deprecated and not receiving servicing or security fixes. Due to CAS's deprecation, the supporting infrastructure was not brought forward to .NET Core or .NET 5+. However, the APIs were brought forward so that apps could cross-compile against .NET Framework and .NET Core. This led to "fail open" scenarios, where some CAS-related APIs exist and are callable but perform no action at run time. This can lead to security issues for components that expect the runtime to honor CAS- related attributes or programmatic API calls. To better communicate that the runtime doesn't respect these attributes or APIs, we have obsoleted the majority of them in .NET 5.0. Version introduced 5.0 Recommended action If you're asserting any security permission, remove the attribute or call that asserts the permission. C# // REMOVE the attribute below. [SecurityPermission(SecurityAction.Assert, ControlThread = true)] public void DoSomething() { } public void DoAssert() { // REMOVE the line below. new SecurityPermission(SecurityPermissionFlag.ControlThread).Assert(); } If you're denying or restricting (via PermitOnly ) any permission, contact your security advisor. Because CAS attributes are not honored by the .NET 5+ runtime, your application could have a security hole if it incorrectly relies on the CAS infrastructure to restrict access to these methods. C# // REVIEW the attribute below; could indicate security vulnerability. [SecurityPermission(SecurityAction.Deny, ControlThread = true)] public void DoSomething() { } public void DoPermitOnly() { // REVIEW the line below; could indicate security vulnerability. new SecurityPermission(SecurityPermissionFlag.ControlThread).PermitOnly(); } If you're demanding any permission (except PrincipalPermission), remove the demand. All demands will succeed at run time. C# // REMOVE the attribute below; it will always succeed. [SecurityPermission(SecurityAction.Demand, ControlThread = true)] public void DoSomething() { } public void DoDemand() { // REMOVE the line below; it will always succeed. new SecurityPermission(SecurityPermissionFlag.ControlThread).Demand(); } If you're demanding PrincipalPermission, consult the guidance for PrincipalPermissionAttribute is obsolete as error. That guidance applies for both PrincipalPermission and PrincipalPermissionAttribute. If you absolutely must disable these warnings (which is not recommended), you can suppress the SYSLIB0003 warning in code. C# #pragma warning disable SYSLIB0003 // disable the warning [SecurityPermission(SecurityAction.Demand, ControlThread = true)] #pragma warning restore SYSLIB0003 // re-enable the warning public void DoSomething() { } public void DoDemand() { #pragma warning disable SYSLIB0003 // disable the warning new SecurityPermission(SecurityPermissionFlag.ControlThread).Demand(); #pragma warning restore SYSLIB0003 // re-enable the warning } You can also suppress the warning in your project file. Doing so disables the warning for all source files within the project. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below suppresses SYSLIB0003 project-wide --> <NoWarn>$(NoWarn);SYSLIB0003</NoWarn> </PropertyGroup> </Project> 7 Note Suppressing SYSLIB0003 disables only the CAS-related obsoletion warnings. It does not disable any other warnings or change the behavior of the .NET 5+ runtime. Security Affected APIs System.AppDomain.PermissionSet System.Configuration.ConfigurationPermission System.Configuration.ConfigurationPermissionAttribute System.Data.Common.DBDataPermission System.Data.Common.DBDataPermissionAttribute System.Data.Odbc.OdbcPermission System.Data.Odbc.OdbcPermissionAttribute System.Data.OleDb.OleDbPermission System.Data.OleDb.OleDbPermissionAttribute System.Data.OracleClient.OraclePermission System.Data.OracleClient.OraclePermissionAttribute System.Data.SqlClient.SqlClientPermission System.Data.SqlClient.SqlClientPermissionAttribute System.Diagnostics.EventLogPermission System.Diagnostics.EventLogPermissionAttribute System.Diagnostics.PerformanceCounterPermission System.Diagnostics.PerformanceCounterPermissionAttribute System.DirectoryServices.DirectoryServicesPermission System.DirectoryServices.DirectoryServicesPermissionAttribute System.Drawing.Printing.PrintingPermission System.Drawing.Printing.PrintingPermissionAttribute System.Net.DnsPermission System.Net.DnsPermissionAttribute System.Net.Mail.SmtpPermission System.Net.Mail.SmtpPermissionAttribute System.Net.NetworkInformation.NetworkInformationPermission System.Net.NetworkInformation.NetworkInformationPermissionAttribute System.Net.PeerToPeer.Collaboration.PeerCollaborationPermission System.Net.PeerToPeer.Collaboration.PeerCollaborationPermissionAttribute System.Net.PeerToPeer.PnrpPermission System.Net.PeerToPeer.PnrpPermissionAttribute System.Net.SocketPermission System.Net.SocketPermissionAttribute System.Net.WebPermission System.Net.WebPermissionAttribute System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute System.Security.CodeAccessPermission System.Security.HostProtectionException System.Security.IPermission System.Security.IStackWalk System.Security.NamedPermissionSet System.Security.PermissionSet System.Security.Permissions.CodeAccessSecurityAttribute System.Security.Permissions.DataProtectionPermission System.Security.Permissions.DataProtectionPermissionAttribute System.Security.Permissions.DataProtectionPermissionFlags System.Security.Permissions.EnvironmentPermission System.Security.Permissions.EnvironmentPermissionAccess System.Security.Permissions.EnvironmentPermissionAttribute System.Security.Permissions.FileDialogPermission System.Security.Permissions.FileDialogPermissionAccess System.Security.Permissions.FileDialogPermissionAttribute System.Security.Permissions.FileIOPermission System.Security.Permissions.FileIOPermissionAccess System.Security.Permissions.FileIOPermissionAttribute System.Security.Permissions.GacIdentityPermission System.Security.Permissions.GacIdentityPermissionAttribute System.Security.Permissions.HostProtectionAttribute System.Security.Permissions.HostProtectionResource System.Security.Permissions.IUnrestrictedPermission System.Security.Permissions.IsolatedStorageContainment System.Security.Permissions.IsolatedStorageFilePermission System.Security.Permissions.IsolatedStorageFilePermissionAttribute System.Security.Permissions.IsolatedStoragePermission System.Security.Permissions.IsolatedStoragePermissionAttribute System.Security.Permissions.KeyContainerPermission System.Security.Permissions.KeyContainerPermissionAccessEntry System.Security.Permissions.KeyContainerPermissionAccessEntryCollection System.Security.Permissions.KeyContainerPermissionAccessEntryEnumerator System.Security.Permissions.KeyContainerPermissionAttribute System.Security.Permissions.KeyContainerPermissionFlags System.Security.Permissions.MediaPermission System.Security.Permissions.MediaPermissionAttribute System.Security.Permissions.MediaPermissionAudio System.Security.Permissions.MediaPermissionImage System.Security.Permissions.MediaPermissionVideo System.Security.Permissions.PermissionSetAttribute System.Security.Permissions.PermissionState System.Security.Permissions.PrincipalPermission System.Security.Permissions.PrincipalPermissionAttribute System.Security.Permissions.PublisherIdentityPermission System.Security.Permissions.PublisherIdentityPermissionAttribute System.Security.Permissions.ReflectionPermission System.Security.Permissions.ReflectionPermissionAttribute System.Security.Permissions.ReflectionPermissionFlag System.Security.Permissions.RegistryPermission System.Security.Permissions.RegistryPermissionAccess System.Security.Permissions.RegistryPermissionAttribute System.Security.Permissions.ResourcePermissionBase System.Security.Permissions.ResourcePermissionBaseEntry System.Security.Permissions.SecurityAction System.Security.Permissions.SecurityAttribute System.Security.Permissions.SecurityPermission System.Security.Permissions.SecurityPermissionAttribute System.Security.Permissions.SecurityPermissionFlag System.Security.Permissions.SiteIdentityPermission System.Security.Permissions.SiteIdentityPermissionAttribute System.Security.Permissions.StorePermission System.Security.Permissions.StorePermissionAttribute System.Security.Permissions.StorePermissionFlags System.Security.Permissions.StrongNameIdentityPermission System.Security.Permissions.StrongNameIdentityPermissionAttribute System.Security.Permissions.StrongNamePublicKeyBlob System.Security.Permissions.TypeDescriptorPermission System.Security.Permissions.TypeDescriptorPermissionAttribute System.Security.Permissions.TypeDescriptorPermissionFlags System.Security.Permissions.UIPermission System.Security.Permissions.UIPermissionAttribute System.Security.Permissions.UIPermissionClipboard System.Security.Permissions.UIPermissionWindow System.Security.Permissions.UrlIdentityPermission System.Security.Permissions.UrlIdentityPermissionAttribute System.Security.Permissions.WebBrowserPermission System.Security.Permissions.WebBrowserPermissionAttribute System.Security.Permissions.WebBrowserPermissionLevel System.Security.Permissions.ZoneIdentityPermission System.Security.Permissions.ZoneIdentityPermissionAttribute System.Security.Policy.ApplicationTrust.ApplicationTrust(PermissionSet, IEnumerable<StrongName>) System.Security.Policy.ApplicationTrust.FullTrustAssemblies System.Security.Policy.FileCodeGroup System.Security.Policy.GacInstalled System.Security.Policy.IIdentityPermissionFactory System.Security.Policy.PolicyLevel.AddNamedPermissionSet(NamedPermissionSet) System.Security.Policy.PolicyLevel.ChangeNamedPermissionSet(String, PermissionSet) System.Security.Policy.PolicyLevel.GetNamedPermissionSet(String) System.Security.Policy.PolicyLevel.RemoveNamedPermissionSet System.Security.Policy.PolicyStatement.PermissionSet System.Security.Policy.PolicyStatement.PolicyStatement System.Security.Policy.Publisher System.Security.Policy.Site System.Security.Policy.StrongName System.Security.Policy.StrongNameMembershipCondition System.Security.Policy.Url System.Security.Policy.Zone System.Security.SecurityManager System.ServiceProcess.ServiceControllerPermission System.ServiceProcess.ServiceControllerPermissionAttribute System.Transactions.DistributedTransactionPermission System.Transactions.DistributedTransactionPermissionAttribute System.Web.AspNetHostingPermission System.Web.AspNetHostingPermissionAttribute System.Xaml.Permissions.XamlLoadPermission PrincipalPermissionAttribute is obsolete as error Article • 09/15/2021 The PrincipalPermissionAttribute constructor is obsolete and produces a compile-time error. You cannot instantiate this attribute or apply it to a method. Change description On .NET Framework and .NET Core, you can annotate methods with the PrincipalPermissionAttribute attribute. For example: C# [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] public void MyMethod() { // Code that should only run when the current user is an administrator. } Starting in .NET 5, you cannot apply the PrincipalPermissionAttribute attribute to a method. The constructor for the attribute is obsolete and produces a compile-time error. Unlike other obsoletion warnings, you can't suppress the error. Reason for change The PrincipalPermissionAttribute type, like other types that subclass SecurityAttribute, is part of .NET's Code Access Security (CAS) infrastructure. In .NET Framework 2.x - 4.x, the runtime enforces PrincipalPermissionAttribute annotations on method entry, even if the application is running under a full-trust scenario. .NET Core and .NET 5 and later don't support CAS attributes, and the runtime ignores them. This difference in behavior from .NET Framework to .NET Core and .NET 5 can result in a "fail open" scenario, where access should have been blocked but instead has been allowed. To prevent the "fail open" scenario, you can no longer apply the attribute in code that targets .NET 5 or later. Version introduced 5.0 Recommended action If you encounter the obsoletion error, you must take action. If you're applying the attribute to an ASP.NET MVC action method: Consider using ASP.NET's built-in authorization infrastructure. The following code demonstrates how to annotate a controller with an AuthorizeAttribute attribute. The ASP.NET runtime will authorize the user before performing the action. C# using Microsoft.AspNetCore.Authorization; namespace MySampleApp { [Authorize(Roles = "Administrator")] public class AdministrationController : Controller { public ActionResult MyAction() { // This code won't run unless the current user // is in the 'Administrator' role. } } } For more information, see Role-based authorization in ASP.NET Core and Introduction to authorization in ASP.NET Core. If you're applying the attribute to library code outside the context of a web app: Perform the checks manually at the beginning of your method. This can be done by using the IPrincipal.IsInRole(String) method. C# using System.Threading; void DoSomething() { if (Thread.CurrentPrincipal == null || !Thread.CurrentPrincipal.IsInRole("Administrators")) { throw new Exception("User is anonymous or isn't an admin."); } // Code that should run only when user is an administrator. } Affected APIs System.Security.Permissions.PrincipalPermissionAttribute UTF-7 code paths are obsolete Article • 01/27/2022 The UTF-7 encoding is no longer in wide use among applications, and many specs now forbid its use in interchange. It's also occasionally used as an attack vector in applications that don't anticipate encountering UTF-7-encoded data. Microsoft warns against use of System.Text.UTF7Encoding because it doesn't provide error detection. Consequently, the Encoding.UTF7 property and UTF7Encoding constructors are now obsolete. Additionally, Encoding.GetEncoding and Encoding.GetEncodings no longer allow you to specify UTF-7 . Change description Previously, you could create an instance of the UTF-7 encoding by using the Encoding.GetEncoding APIs. For example: C# Encoding enc1 = Encoding.GetEncoding("utf-7"); // By name. Encoding enc2 = Encoding.GetEncoding(65000); // By code page. Additionally, an instance that represents the UTF-7 encoding was enumerated by the Encoding.GetEncodings() method, which enumerates all the Encoding instances registered on the system. Starting in .NET 5, the Encoding.UTF7 property and UTF7Encoding constructors are obsolete and produce warning SYSLIB0001 . However, to reduce the number of warnings that callers receive when using the UTF7Encoding class, the UTF7Encoding type itself is not marked obsolete. C# // The next line generates warning SYSLIB0001. UTF7Encoding enc = new UTF7Encoding(); // The next line does not generate a warning. byte[] bytes = enc.GetBytes("Hello world!"); Additionally, the Encoding.GetEncoding methods treat the encoding name utf-7 and the code page 65000 as unknown . Treating the encoding as unknown causes the method to throw an ArgumentException. C# // Throws ArgumentException, same as calling Encoding.GetEncoding("unknown"). Encoding enc = Encoding.GetEncoding("utf-7"); Finally, the Encoding.GetEncodings() method doesn't include the UTF-7 encoding in the EncodingInfo array that it returns. The encoding is excluded because it cannot be instantiated. C# foreach (EncodingInfo encInfo in Encoding.GetEncodings()) { // The next line would throw if GetEncodings included UTF-7. Encoding enc = Encoding.GetEncoding(encInfo.Name); } Reason for change Many applications call Encoding.GetEncoding("encoding-name") with an encoding name value that's provided by an untrusted source. For example, a web client or server might take the charset portion of the Content-Type header and pass the value directly to Encoding.GetEncoding without validating it. This could allow a malicious endpoint to specify Content-Type: ...; charset=utf-7 , which could cause the receiving application to misbehave. Additionally, disabling UTF-7 code paths allows optimizing compilers, such as those used by Blazor, to remove these code paths entirely from the resulting application. As a result, the compiled applications run more efficiently and take less disk space. Version introduced 5.0 Recommended action In most cases, you don't need to take any action. However, for apps that have previously activated UTF-7-related code paths, consider the guidance that follows. If your app calls Encoding.GetEncoding with unknown encoding names provided by an untrusted source: Instead, compare the encoding names against a configurable allow list. The configurable allow list should at minimum include the industry-standard "utf-8". Depending on your clients and regulatory requirements, you may also need to allow region-specific encodings, such as "GB18030". If you don't implement an allow list, Encoding.GetEncoding will return any Encoding that's built into the system or that's registered via a custom EncodingProvider. Audit your service's requirements to validate that this is the desired behavior. UTF-7 continues to be disabled by default unless your application re-enables the compatibility switch mentioned later in this article. If you're using Encoding.UTF7 or UTF7Encoding within your own protocol or file format: Switch to using Encoding.UTF8 or UTF8Encoding. UTF-8 is an industry standard and is widely supported across languages, operating systems, and runtimes. Using UTF-8 eases future maintenance of your code and makes it more interoperable with the rest of the ecosystem. If you're comparing an Encoding instance against Encoding.UTF7: Instead, consider performing a check against the well-known UTF-7 code page, which is 65000 . By comparing against the code page, you avoid the warning and also handle some edge cases, such as if somebody called new UTF7Encoding() or subclassed the type. C# void DoSomething(Encoding enc) { // Don't perform the check this way. // It produces a warning and misses some edge cases. if (enc == Encoding.UTF7) { // Encoding is UTF-7. } // Instead, perform the check this way. if (enc != null && enc.CodePage == 65000) { // Encoding is UTF-7. } } If you must use Encoding.UTF7 or UTF7Encoding: You can suppress the SYSLIB0001 warning in code or within your project's .csproj file. C# #pragma warning disable SYSLIB0001 // Disable the warning. Encoding enc = Encoding.UTF7; #pragma warning restore SYSLIB0001 // Re-enable the warning. XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- NoWarn below suppresses SYSLIB0001 project-wide --> <NoWarn>$(NoWarn);SYSLIB0001</NoWarn> </PropertyGroup> </Project> 7 Note Suppressing SYSLIB0001 only disables the Encoding.UTF7 and UTF7Encoding obsoletion warnings. It doesn't disable any other warnings or change the behavior of APIs like Encoding.GetEncoding. If you must support Encoding.GetEncoding("utf-7", ...) : You can re-enable support for this via a compatibility switch. This compatibility switch can be specified in the application's .csproj file or in a runtime configuration file, as shown in the following examples. In the application's .csproj file: XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- Re-enable support for UTF-7 --> <EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding> </PropertyGroup> </Project> In the application's runtimeconfig.template.json file: JSON { "configProperties": { "System.Text.Encoding.EnableUnsafeUTF7Encoding": true } } Tip If you re-enable support for UTF-7, you should perform a security review of code that calls Encoding.GetEncoding. Affected APIs System.Text.Encoding.UTF7 UTF7Encoding() UTF7Encoding(Boolean) System.Text.Encoding.GetEncoding(Int32) System.Text.Encoding.GetEncoding(String) System.Text.Encoding.GetEncoding(Int32, EncoderFallback, DecoderFallback) System.Text.Encoding.GetEncoding(String, EncoderFallback, DecoderFallback) System.Text.Encoding.GetEncodings() BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps Article • 05/17/2023 Serialize and Deserialize methods on BinaryFormatter, Formatter, and IFormatter are now obsolete as warning. Additionally, BinaryFormatter serialization is prohibited by default for ASP.NET apps. 7 Note In .NET 7, the affected APIs are obsolete as error. For more information, see BinaryFormatter serialization APIs produce compiler errors. Change description Due to security vulnerabilities in BinaryFormatter, the following methods are now obsolete and produce a compile-time warning with ID SYSLIB0011 . Additionally, in ASP.NET Core 5.0 and later apps, they will throw a NotSupportedException, unless the web app has re-enabled BinaryFormatter functionality. BinaryFormatter.Serialize BinaryFormatter.Deserialize The following serialization methods are also obsolete and produce warning SYSLIB0011 , but have no behavioral changes: Formatter.Serialize(Stream, Object) Formatter.Deserialize(Stream) IFormatter.Serialize(Stream, Object) IFormatter.Deserialize(Stream) Version introduced 5.0 Reason for change These methods are marked obsolete as part of an effort to wind down usage of BinaryFormatter within the .NET ecosystem. Recommended action Stop using BinaryFormatter in your code. Instead, consider using JsonSerializer or XmlSerializer. For more information, see BinaryFormatter security guide. You can temporarily suppress the BinaryFormatter compile-time warning, which is SYSLIB0011 . We recommend that you thoroughly assess your code for risks before choosing this option. The easiest way to suppress the warnings is to surround the individual call site with #pragma directives. C# // Now read the purchase order back from disk using (var readStream = new FileStream("myfile.bin", FileMode.Open)) { var formatter = new BinaryFormatter(); #pragma warning disable SYSLIB0011 return (PurchaseOrder)formatter.Deserialize(readStream); #pragma warning restore SYSLIB0011 } You can also suppress the warning in the project file. XML <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <!-- Disable "BinaryFormatter is obsolete" warnings for entire project --> <NoWarn>$(NoWarn);SYSLIB0011</NoWarn> </PropertyGroup> If you suppress the warning in the project file, the warning is suppressed for all code files in the project. Suppressing SYSLIB0011 does not suppress warnings caused by using other obsolete APIs. To continue using BinaryFormatter in ASP.NET apps, you can re-enable it in the project file. However, it's strongly recommended not to do this. For more information, see BinaryFormatter security guide. XML <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <!-- Warning: Setting the following switch is *NOT* recommended in web apps. --> <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryForma tterSerialization> </PropertyGroup> For more information about recommended actions, see Resolving BinaryFormatter obsoletion and disablement errors. Affected APIs System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize System.Runtime.Serialization.Formatter.Serialize(Stream, Object) System.Runtime.Serialization.Formatter.Deserialize(Stream) System.Runtime.Serialization.IFormatter.Serialize(Stream, Object) System.Runtime.Serialization.IFormatter.Deserialize(Stream) See also SerializationFormat.Binary is obsolete (.NET 7) BinaryFormatter serialization APIs produce compiler errors (.NET 7) BinaryFormatter disabled across most project types (.NET 8) BinaryFormatter.Deserialize rewraps some exceptions in SerializationException Article • 09/15/2021 The BinaryFormatter.Deserialize method now rewraps some exception objects inside a SerializationException before propagating the exception back to the caller. Change description Previously, the BinaryFormatter.Deserialize method allowed some arbitrary exceptions, such as ArgumentNullException, to propagate up the stack to its callers. In .NET 5 and later, the BinaryFormatter.Deserialize method more aggressively catches exceptions that occur due to invalid deserialization operations and wraps them in a SerializationException. Version introduced 5.0 Recommended action In most cases, you don't need to take any action. However, if your call site depends on a particular exception being thrown, you can unwrap the exception from the outer SerializationException, as shown in the following example. C# Stream inputStream = GetInputStream(); var formatter = new BinaryFormatter(); try { object deserialized = formatter.Deserialize(inputStream); } catch (MyException myEx) { // Handle 'myEx' here in case it was thrown directly. } catch (SerializationException serEx) when (serEx.InnerException is MyException myEx) { // Handle 'myEx' here in case it was wrapped in SerializationException. } Affected APIs System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize System.Text.Json requires single-char string to deserialize a char Article • 09/15/2021 To successfully deserialize a Char using System.Text.Json, the JSON string must contain a single character. Change description In previous .NET versions, a multi- char string in the JSON is successfully deserialized to a char property or field. Only the first char of the string is used, as in the following example: C# // .NET Core 3.0 and 3.1: Returns the first char 'a'. // .NET 5 and later: Throws JsonException because payload has more than one char. char deserializedChar = JsonSerializer.Deserialize<char>("\"abc\""); In .NET 5 and later, anything other than a single- char string causes a JsonException to be thrown when the deserialization target is a char . The following example string is successfully deserialized in all .NET versions: C# // Correct usage. char deserializedChar = JsonSerializer.Deserialize<char>("\"a\""); Version introduced 5.0 Reason for change Parsing for deserialization should only succeed when the provided payload is valid for the target type. For a char type, the only valid payload is a single- char string. Recommended action When you deserialize JSON into a char target, make sure the string consists of a single char . Affected APIs System.Text.Json.JsonSerializer.Deserialize ASP.NET Core apps allow deserializing quoted numbers Article • 09/15/2021 Starting in .NET 5, ASP.NET Core apps use the default deserialization options as specified by JsonSerializerDefaults.Web. The Web set of options includes setting NumberHandling to JsonNumberHandling.AllowReadingFromString. This change means that ASP.NET Core apps will successfully deserialize numbers that are represented as JSON strings instead of throwing an exception. Change description In .NET Core 3.0 - 3.1, JsonSerializer throws a JsonException during deserialization if it encounters a quoted number in a JSON payload. The quoted numbers are used to map with number properties in object graphs. In .NET Core 3.0 - 3.1, numbers are only read from JsonTokenType.Number tokens. Starting in .NET 5, quoted numbers in JSON payloads are considered valid, by default, for ASP.NET Core apps. No exception is thrown during deserialization of quoted numbers. Tip There is no behavior change for the default, standalone JsonSerializer or JsonSerializerOptions. This is technically not a breaking change, since it makes a scenario more permissive instead of more restrictive (that is, it succeeds in coercing a number from a JSON string instead of throwing an exception). However, since this is a significant behavioral change that affects many ASP.NET Core apps, it is documented here. The HttpClientJsonExtensions.GetFromJsonAsync and HttpContentJsonExtensions.ReadFromJsonAsync extension methods also use the Web set of serialization options. Version introduced 5.0 Reason for change Multiple users have requested an option for more permissive number handling in JsonSerializer. This feedback indicates that many JSON producers (for example, services across the web) emit quoted numbers. By allowing quoted numbers to be read (deserialized), .NET apps can successfully parse these payloads, by default, in web contexts. The configuration is exposed via JsonSerializerDefaults.Web so that you can specify the same options across different application layers, for example, client, server, and shared. Recommended action If this change is disruptive, for example, if you depend on the strict number handling for validation, you can re-enable the previous behavior. Set the JsonSerializerOptions.NumberHandling option to JsonNumberHandling.Strict. For ASP.NET Core MVC and web API apps, you can configure the option in Startup by using the following code: C# services.AddControllers() .AddJsonOptions(options => options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict); Affected APIs System.Text.Json.JsonSerializer.Deserialize System.Text.Json.JsonSerializer.DeserializeAsync JsonSerializer.Serialize throws ArgumentNullException when type parameter is null Article • 09/15/2021 JsonSerializer.Serialize, JsonSerializer.SerializeAsync, and JsonSerializer.SerializeToUtf8Bytes overloads that have a parameter of type Type now throw an ArgumentNullException whenever null is passed for that parameter. Change description In .NET Core 3.1, the JsonSerializer.Serialize, JsonSerializer.SerializeAsync(Stream, Object, Type, JsonSerializerOptions, CancellationToken), and JsonSerializer.SerializeToUtf8Bytes(Object, Type, JsonSerializerOptions) overloads that have a Type parameter throw an ArgumentNullException when null is passed for the Type inputType parameter, but not if the Object value parameter is also null . Starting in .NET 5, these methods always throw an ArgumentNullException when null is passed for the Type parameter. Behavior in .NET Core 3.1: C# // Returns a string with value "null". JsonSerializer.Serialize(null, null); // Returns a byte array with value "null". JsonSerializer.SerializeToUtf8Bytes(null, null); Behavior in .NET 5 and later: C# // Throws ArgumentNullException: "Value cannot be null. (Parameter 'inputType')". JsonSerializer.Serialize(null, null); // Throws ArgumentNullException: "Value cannot be null. (Parameter 'inputType')". JsonSerializer.SerializeToUtf8Bytes(null, null); Version introduced 5.0 Reason for change Passing in null for the Type inputType parameter is unacceptable and should always throw an ArgumentNullException. Recommended action Make sure that you are not passing null for the Type inputType parameter of these methods. Affected APIs System.Text.Json.JsonSerializer.Serialize(Object, Type, JsonSerializerOptions) System.Text.Json.JsonSerializer.Serialize(Utf8JsonWriter, Object, Type, JsonSerializerOptions) System.Text.Json.JsonSerializer.SerializeAsync(Stream, Object, Type, JsonSerializerOptions, CancellationToken) System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(Object, Type, JsonSerializerOptions) Non-public, parameterless constructors not used for deserialization Article • 09/15/2021 For consistency across all supported target framework monikers (TFMs), non-public, parameterless constructors are no longer used for deserialization with JsonSerializer, by default. Change description The standalone System.Text.Json NuGet packages that support .NET Standard 2.0 and higher, that is, versions 4.6.0-4.7.2, behave inconsistently with the built-in behavior on .NET Core 3.0 and 3.1. On .NET Core 3.x, internal and private constructors can be used for deserialization. In the standalone packages, non-public constructors are not allowed, and a MissingMethodException is thrown if no public, parameterless constructor is defined. Starting with .NET 5 and System.Text.Json NuGet package 5.0.0, the behavior is consistent between the NuGet package and the built-in APIs. Non-public constructors, including parameterless constructors, are ignored by the serializer by default. The serializer uses one of the following constructors for deserialization: Public constructor annotated with JsonConstructorAttribute. Public parameterless constructor. Public parameterized constructor (if it's the only public constructor present). If none of these constructors are available, a NotSupportedException is thrown if you attempt to deserialize the type. Version introduced 5.0 Reason for change To enforce consistent behavior between all target framework monikers (TFMs) that System.Text.Json builds for (.NET Core 3.0 and later versions and .NET Standard 2.0) Because JsonSerializer shouldn't call the non-public surface area of a type, whether that's a constructor, a property, or a field. Recommended action If you own the type and it's feasible, make the parameterless constructor public. Otherwise, implement a JsonConverter<T> for the type and control the deserialization behavior. You can call a non-public constructor from a JsonConverter<T> implementation if C# accessibility rules for that scenario allow it. Affected APIs System.Text.Json.JsonSerializer.Deserialize System.Text.Json.JsonSerializer.DeserializeAsync PropertyNamingPolicy, PropertyNameCaseInsensitive, and Encoder options are honored when serializing and deserializing key-value pairs Article • 10/04/2022 JsonSerializer now honors the PropertyNamingPolicy and Encoder options when serializing the Key and Value property names of a KeyValuePair<TKey,TValue> instance. Additionally, JsonSerializer honors the PropertyNamingPolicy and PropertyNameCaseInsensitive options when deserializing KeyValuePair<TKey,TValue> instances. Change description Serialization In .NET Core 3.x versions and in the 4.6.0-4.7.2 versions of the System.Text.Json NuGet package , the properties of KeyValuePair<TKey,TValue> instances are always serialized as "Key" and "Value" exactly, regardless of any JsonSerializerOptions.PropertyNamingPolicy and JsonSerializerOptions.Encoder options. The following code example shows how the Key and Value properties are not camelcased after serialization, even though the specified property-naming policy dictates so. C# var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; KeyValuePair<int, int> kvp = KeyValuePair.Create(1, 1); Console.WriteLine(JsonSerializer.Serialize(kvp, options)); // Expected: {"key":1,"value":1} // Actual: {"Key":1,"Value":1} Starting in .NET 5, the PropertyNamingPolicy and Encoder options are honored when serializing KeyValuePair<TKey,TValue> instances. The following code example shows how the Key and Value properties are camel-cased after serialization, in accordance with the specified property-naming policy. C# var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; KeyValuePair<int, int> kvp = KeyValuePair.Create(1, 1); Console.WriteLine(JsonSerializer.Serialize(kvp, options)); // {"key":1,"value":1} Deserialization In .NET Core 3.x versions and in the 4.7.x versions of the System.Text.Json NuGet package , a JsonException is thrown when the JSON property names are not precisely Key and Value , for example, if they don't start with an uppercase letter. The exception is thrown even if a specified property-naming policy expressly permits it. C# var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; string json = @"{""key"":1,""value"":1}"; // Throws JsonException. JsonSerializer.Deserialize<KeyValuePair<int, int>>(json, options); Starting in .NET 5, the PropertyNamingPolicy and PropertyNameCaseInsensitive options are honored when deserializing using JsonSerializer. For example, the following code snippet shows successful deserialization of lowercased Key and Value property names because the specified property-naming policy permits it. C# var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; string json = @"{""key"":1,""value"":1}"; KeyValuePair<int, int> kvp = JsonSerializer.Deserialize<KeyValuePair<int, int>>(json); Console.WriteLine(kvp.Key); // 1 Console.WriteLine(kvp.Value); // 1 To accommodate payloads that were serialized with previous versions, "Key" and "Value" are special-cased to match when deserializing. Even though the Key and Value property names aren't camel-cased according to the PropertyNamingPolicy option in the following code example, they deserialize successfully. C# var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; string json = @"{""Key"":1,""Value"":1}"; KeyValuePair<int, int> kvp = JsonSerializer.Deserialize<KeyValuePair<int, int>>(json); Console.WriteLine(kvp.Key); // 1 Console.WriteLine(kvp.Value); // 1 Version introduced 5.0 Reason for change Substantial customer feedback indicated that the PropertyNamingPolicy should be honored. For completeness, the PropertyNameCaseInsensitive and Encoder options are also honored, so that KeyValuePair<TKey,TValue> instances are treated the same as any other plain old CLR object (POCO). Recommended action If this change is disruptive to you, you can use a custom converter that implements the desired semantics. Affected APIs System.Text.Json.JsonSerializer.Serialize System.Text.Json.JsonSerializer.SerializeToUtf8Bytes System.Text.Json.JsonSerializer.SerializeAsync System.Text.Json.JsonSerializer.Deserialize System.Text.Json.JsonSerializer.DeserializeAsync Native code can't access Windows Forms objects Article • 03/11/2022 Starting in .NET 5, you can no longer access Windows Forms objects from native code. Change description In previous .NET versions, some Windows Forms types were decorated as visible to COM interop, and thus were accessible to native code. Starting in .NET 5, no Windows Forms API are visible to COM interop or accessible to native code. The .NET runtime no longer supports creating custom type libraries out of the box. In addition, the .NET runtime can't depend on the type library for .NET Framework (which would require maintaining the shape of classes as they were in .NET Framework). Reason for change Removal of ComVisible(true) from enumerations that were used for type library (TLB file) generation and lookup: Since there is no WinForms TLB provided by .NET Core, there's no value in keeping this attribute. Removal of ComVisible(true) from AccessibleObject classes: The classes are not CoCreateable (they have no parameterless constructor), and exposing an already existing instance to COM does not require that attribute. Removal of ComVisible(true) from Control and Component classes: This was used to allow hosting of WinForms controls via OLE/ActiveX, for example in VB6 or MFC. However, this requires a TLB for WinForms, which is no longer provided, as well as registry-based activation, which also would not work out of the box. Generally, there was no maintenance of COM-based hosting of WinForms controls, so support was removed instead of leaving it in an unsupported state. Removal of ClassInterface attributes from controls: If hosting via OLE/ActiveX is not supported, these attributes aren't needed anymore. They are kept in other places where objects are still exposed to COM and the attribute may be relevant. Removal of ComVisible(true) from EventArgs : They were most likely used with OLE/ActiveX hosting, which is no longer supported. They are not CoCreateable either, so the attribute has no purpose. Also, exposing existing instances without providing a TLB makes no sense. Removal of ComVisible(true) from delegates: Purpose is unknown, but since ActiveX hosting of WinForms Controls is no longer supported, it's unlikely to have any usefulness. Removal of ComVisible(true) from some non-public code: The only potential consumer would be the new Visual Studio designer, but without a GUID specified, it's unlikely that it's still needed. Removal of ComVisible(true) from some arbitrary public designer classes: The old Visual Studio designer may have been using COM interop to talk to these classes. However, the old designer doesn't support .NET Core, so few people would need these as ComVisible . IWin32Window defined the same GUID that was defined in .NET Framework, which has dangerous consequences. If you require interop with .NET Framework, use ComImport . The WinForms managed IDataObject was made ComVisible . This is not required, there is a separate ComImport interface declaration for IDataObject COM interop. It's counterproductive to have the managed IDataObject be ComVisible , since no TLB is provided and marshalling will always fail. Also, the GUID was not specified and differed from .NET Framework, so its unlikely that removing an undocumented IID will affect customers negatively. Removal of ComVisible(false) : Those are placed in seemingly arbitrary places and are redundant when the default is to not expose classes to COM interop. Version introduced .NET 5.0 Recommended action The following example works on .NET Framework and .NET Core 3.1. This example relies on the .NET Framework type library, which allows the JavaScript to call back into the form subclass via reflection. C# [PermissionSet(SecurityAction.Demand, Name="FullTrust")] [System.Runtime.InteropServices.ComVisibleAttribute(true)] public class Form1 : Form { private WebBrowser webBrowser1 = new WebBrowser(); protected override void OnLoad(EventArgs e) { webBrowser1.AllowWebBrowserDrop = false; webBrowser1.IsWebBrowserContextMenuEnabled = false; webBrowser1.WebBrowserShortcutsEnabled = false; webBrowser1.ObjectForScripting = this; webBrowser1.DocumentText = "<html><body><button " + "onclick=\"window.external.Test('called from script code')\">" + "call client code from script code</button>" + "</body></html>"; } public void Test(String message) { MessageBox.Show(message, "client code"); } } There are two possible ways to make the example work on .NET 5 and later versions: Introduce a user-declared ObjectForScripting object that supports IDispatch (which is applied by default, unless changed explicitly at the project level). C# public class MyScriptObject { private Form1 _form; public MyScriptObject(Form1 form) { _form = form; } public void Test(string message) { MessageBox.Show(message, "client code"); } } public partial class Form1 : Form { protected override void OnLoad(EventArgs e) { ... // Works correctly. webBrowser1.ObjectForScripting = new MyScriptObject(this); ... } } Declare an interface with the methods to expose. C# public interface IForm1 { void Test(string message); } [ComDefaultInterface(typeof(IForm1))] public partial class Form1 : Form, IForm1 { protected override void OnLoad(EventArgs e) { ... // Works correctly. webBrowser1.ObjectForScripting = this; ... } } Affected APIs All Windows Forms APIs. OutputType set to WinExe for WPF and WinForms apps Article • 09/15/2021 OutputType is automatically set to WinExe for Windows Presentation Foundation (WPF) and Windows Forms apps. When OutputType is set to WinExe , a console window doesn't open when the app is executed. Change description In previous versions of the .NET SDK, the value that's specified for OutputType in the project file is used. For example: XML <PropertyGroup> <OutputType>Exe</OutputType> </PropertyGroup> Starting in the 5.0.100 version of the .NET SDK, when OutputType is set to Exe , it is automatically changed to WinExe for WPF and Windows Forms apps that target any framework version, including .NET Framework. XML <PropertyGroup> <OutputType>WinExe</OutputType> </PropertyGroup> If OutputType is not specified in the project file, it defaults to Library and that value doesn't change. Reason for change It's assumed that most users don't want a console window to open when a WPF or Windows Forms app is executed. In addition, now that these application types use the .NET SDK instead of the Windows Desktop SDK, the correct default will be set. Further, when support for targeting iOS and Android is added, it will be easier to multi-target between multiple platforms if they all use the same output type. Version introduced .NET SDK 5.0.100 Recommended action No action is required in your part. However, if you want to revert to the old behavior, set the DisableWinExeOutputInference property to true in your project file. XML <DisableWinExeOutputInference>true</DisableWinExeOutputInference> Affected APIs Not detectable via API analysis. DataGridView no longer resets fonts for customized cell styles Article • 09/15/2021 When the ambient font changes, DataGridView no longer resets default cell style fonts to match the ambient font if the cell style font has been customized. Change description In previous .NET versions, if the ambient font changes, DataGridView resets and overrides user-defined fonts in the DefaultCellStyle, ColumnHeadersDefaultCellStyle, and RowHeadersDefaultCellStyle properties. Starting in .NET 5, if you configure font settings in the DefaultCellStyle, ColumnHeadersDefaultCellStyle, or RowHeadersDefaultCellStyle properties, those settings are retained even when the ambient font changes. For any of these properties that you don't customize the font, the font will change to match the ambient font settings. Reason for change With the change of the default font in .NET Core 3.0, the default font settings for the various cell styles also changed. This behavior is undesirable for apps that rely on custom styling in their DataGridView controls, and impeded the migration of these apps from .NET Framework to .NET 5.0. Version introduced .NET 5.0 Recommended action No action is required on your part. However, if you've customized the font in the DefaultCellStyle, ColumnHeadersDefaultCellStyle, or RowHeadersDefaultCellStyle properties and want the font to match the ambient font, set DataGridViewCellStyle.Font to null for each property. Affected APIs System.Windows.Forms.DataGridView.DefaultCellStyle System.Windows.Forms.DataGridView.ColumnHeadersDefaultCellStyle System.Windows.Forms.DataGridView.RowHeadersDefaultCellStyle WinForms methods now throw ArgumentException Article • 09/15/2021 Some Windows Forms methods now throw an ArgumentException for invalid arguments, where previously they did not. Change description Previously, passing arguments of an unexpected or incorrect type to certain Windows Forms methods would result in an indeterminate state. Starting in .NET 5, these methods now throw an ArgumentException when passed invalid arguments. Throwing an ArgumentException conforms to the behavior of the .NET runtime. It also improves the debugging experience by clearly communicating which argument is invalid. Version introduced .NET 5.0 Recommended action Update the code to prevent passing invalid arguments. If necessary, handle an ArgumentException when calling the method. Affected APIs The following table lists the affected methods and parameters: Method Parameter name Condition Version added System.Windows.Forms.TabControl.GetToolTipText(Object) item Argument is not of type Preview 1 TabPage. Method Parameter name Condition Version added System.Windows.Forms.DataFormats.GetFormat(String) format Argument is null , Preview 5 String.Empty, or white space. InputLanguageChangedEventArgs(CultureInfo, Byte) culture Unable to Preview retrieve an 7 InputLanguage for the specified culture. WinForms methods now throw ArgumentNullException Article • 09/15/2021 Some Windows Forms methods now throw an ArgumentNullException for null arguments, where previously they threw a NullReferenceException. Change description Previously, certain Windows Forms methods threw a NullReferenceException if passed an argument that was null. Starting in .NET 5, these methods now throw an ArgumentNullException for null arguments, instead. Throwing an ArgumentNullException conforms to the behavior of the .NET runtime. It also improves the debugging experience by clearly communicating that an argument is null and which argument it is. Version introduced .NET 5.0 Recommended action If you call any of these methods and your code currently catches a NullReferenceException for null arguments, catch an ArgumentNullException instead. In addition, consider updating the code to prevent passing null arguments to the listed methods. Affected APIs The following table lists the affected methods and parameters: Method Parameter Version name added Control.ControlCollection(Control) owner Preview 1 TabControl.GetToolTipText(Object) item Preview 1 Method Parameter name Version added TableLayoutControlCollection(TableLayoutPanel) container Preview 1 ToolStripRenderer.OnRenderArrow(ToolStripArrowRenderEventArg e Preview 1 e Preview 1 e Preview 1 ToolStripRenderer.OnRenderItemText(ToolStripItemTextRenderEven tArgs) e Preview 1 ToolStripRenderer.OnRenderStatusStripSizingGrip(ToolStripRender EventArgs) > e Preview 1 DataGridViewComboBoxEditingControl.ApplyCellStyleToEditingCo ntrol(DataGridViewCellStyle) dataGridViewCe Preview 2 llStyle RichTextBox.LoadFile(Stream, RichTextBoxStreamType) data Preview 2 ListBox.IntegerCollection(ListBox) owner Preview 5 ListBox.IntegerCollection.CopyTo(Array, Int32) destination Preview 5 ListViewGroup.ISerializable.GetObjectData(SerializationInfo, Strea mingContext) info Preview 5 VisualStyleRenderer(String, Int32, Int32) className Preview 5 ListBox.ObjectCollection(ListBox) owner Preview 6 ListBox.ObjectCollection(ListBox, Object[]) owner , value Preview 6 ListBox.ObjectCollection(ListBox, ListBox+ObjectCollection) owner , value Preview 6 ListBox.ObjectCollection.AddRange(Object[]) items Preview 6 ListBox.ObjectCollection.AddRange(ListBox+ObjectCollection) value Preview 6 ListBox.ObjectCollection.CopyTo(Object[], Int32) destination Preview 6 ListBox.ObjectCollection.ICollection.CopyTo(Array, Int32) destination Preview 6 ListView.SelectedIndexCollection(ListView) owner Preview 7 TreeNodeCollection.Find(String, Boolean) key is null or Preview 8 s) ToolStripRenderer.OnRenderItemCheck(ToolStripItemImageRender EventArgs) ToolStripRenderer.OnRenderItemImage(ToolStripItemImageRender EventArgs) empty Method ListView.ListViewItemCollection.Find(String, Boolean) Parameter Version name added key is null or RC1 empty ScrollableControl.OnPaintBackground(PaintEventArgs) e RC1 WinForms properties now throw ArgumentOutOfRangeException Article • 09/15/2021 Some Windows Forms properties now throw an ArgumentOutOfRangeException for invalid arguments, where previously they did not. Change description Previously, these properties threw various exceptions, such as NullReferenceException, IndexOutOfRangeException, or ArgumentException, when passed out-of-range arguments. Starting in .NET 5, these properties now throw an ArgumentOutOfRangeException when passed arguments that are out of range. Throwing an ArgumentOutOfRangeException conforms to the behavior of the .NET runtime. It also improves the debugging experience by clearly communicating which argument is invalid. Version introduced .NET 5.0 Recommended action Update the code to prevent passing invalid arguments. If necessary, handle an ArgumentOutOfRangeException when setting the property. Affected APIs The following table lists the affected properties and parameters: Property Parameter name Version added ListBox.IntegerCollection.Item[Int32] index 5.0 Preview 5 TreeNode.ImageIndex value 5.0 Preview 6 TreeNode.SelectedImageIndex value 5.0 Preview 6 TextFormatFlags.ModifyString is obsolete Article • 09/15/2021 The TextFormatFlags.ModifyString field is obsolete, as a warning, and may be removed in a future .NET version. Change description In previous .NET versions, the TextFormatFlags.ModifyString enumeration field is not marked obsolete. In .NET 5 and later versions, it is marked obsolete as a warning. This field may be removed in a future .NET version. Reason for change Passing a string to TextRenderer.MeasureText with TextFormatFlags.ModifyString alters the string in some situations. This behavior breaks the string immutability promise and may lead to a fatal .NET runtime state corruption. Version introduced .NET 5.0 Recommended action Update any code that relies on TextFormatFlags.ModifyString. Affected APIs System.Windows.Forms.TextFormatFlags.ModifyString DataGridView-related APIs throw InvalidOperationException Article • 09/15/2021 Some APIs related to DataGridView now throw an InvalidOperationException if the object's DataGridViewCell.DataGridViewCellAccessibleObject.Owner value is null . Change description In previous .NET versions, the affected APIs throw a NullReferenceException when they are invoked and the Owner property value is null . Starting in .NET 5, these APIs throw an InvalidOperationException instead of a NullReferenceException if the Owner property value is null when they're invoked. Reason for change Throwing an InvalidOperationException conforms to the behavior of the .NET runtime. It also improves the debugging experience by clearly communicating the invalid property. Version introduced .NET 5.0 Recommended action Review your code and, if necessary, update it to prevent constructing the affected types with the Owner property as null . Affected APIs The following table lists the affected APIs: Affected method or property Validated property Version added DataGridViewButtonCell.DataGridViewButtonCellAccessibleObject.DoDe Owner 5.0 faultAction() Affected method or property Validated property Version added DataGridViewCheckBoxCell.DataGridViewCheckBoxCellAccessibleObject. DefaultAction Owner 5.0 DataGridViewCheckBoxCell.DataGridViewCheckBoxCellAccessibleObject. State Owner 5.0 DataGridViewCheckBoxCell.DataGridViewCheckBoxCellAccessibleObject. DoDefaultAction() Owner 5.0 DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess ibleObject.Bounds Owner 5.0 DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess Owner 5.0 Owner 5.0 Owner 5.0 Owner 5.0 Owner 5.0 Owner 5.0 Owner 5.0 ibleObject.DefaultAction DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess ibleObject.Name DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess ibleObject.Parent DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess ibleObject.DoDefaultAction() DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellAccess ibleObject.Navigate(AccessibleNavigation) DataGridViewImageCell.DataGridViewImageCellAccessibleObject.DoDef aultAction() DataGridViewLinkCell.DataGridViewLinkCellAccessibleObject.DoDefault Action() See also DataGridView-related APIs throw InvalidOperationException (.NET 6) WinForms and WPF apps use Microsoft.NET.Sdk Article • 09/15/2021 Windows Forms and Windows Presentation Framework (WPF) apps now use the .NET SDK ( Microsoft.NET.Sdk ) instead of the .NET Core WinForms and WPF SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Change description In previous .NET Core versions, WinForms and WPF apps used a separate project SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Starting in .NET 5, the WinForms and WPF SDK has been unified with the .NET SDK ( Microsoft.NET.Sdk ). In addition, new target framework monikers (TFM) replace netcoreapp and netstandard in .NET 5. The following example shows the changes you'd need to make for a WPF project file when retargeting to .NET 5 or later. In previous .NET Core versions: XML <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> In .NET 5 and later versions: XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net5.0-windows</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> Version introduced .NET SDK 5.0.100 Recommended action In your WPF or Windows Forms project file: Update the Sdk attribute to Microsoft.NET.Sdk . Update the TargetFramework property to net5.0-windows . Affected APIs None. Removed status bar controls Article • 09/15/2021 Starting in .NET 5, some Windows Forms controls are no longer available. Change description Starting with .NET 5, some of the status bar-related Windows Forms controls are no longer available. Replacement controls that have better design and support were introduced in .NET Framework 2.0. The deprecated controls were previously removed from designer toolboxes but were still available to be used. Now, they have been completely removed. The following types are no longer available: StatusBar StatusBarDrawItemEventArgs StatusBarDrawItemEventHandler StatusBarPanel StatusBarPanelAutoSize StatusBarPanelBorderStyle StatusBarPanelClickEventArgs StatusBarPanelClickEventHandler StatusBarPanelStyle Version introduced 5.0 Recommended action Move to the replacement APIs for these controls and their scenarios: Old Control (API) Recommended Replacement StatusBar StatusStrip StatusBarPanel ToolStripStatusLabel Affected APIs System.Windows.Forms.StatusBar System.Windows.Forms.StatusBarDrawItemEventArgs System.Windows.Forms.StatusBarDrawItemEventHandler System.Windows.Forms.StatusBarPanel System.Windows.Forms.StatusBarPanelAutoSize System.Windows.Forms.StatusBarPanelBorderStyle System.Windows.Forms.StatusBarPanelClickEventArgs System.Windows.Forms.StatusBarPanelClickEventHandler System.Windows.Forms.StatusBarPanelStyle OutputType set to WinExe for WPF and WinForms apps Article • 09/15/2021 OutputType is automatically set to WinExe for Windows Presentation Foundation (WPF) and Windows Forms apps. When OutputType is set to WinExe , a console window doesn't open when the app is executed. Change description In previous versions of the .NET SDK, the value that's specified for OutputType in the project file is used. For example: XML <PropertyGroup> <OutputType>Exe</OutputType> </PropertyGroup> Starting in the 5.0.100 version of the .NET SDK, when OutputType is set to Exe , it is automatically changed to WinExe for WPF and Windows Forms apps that target any framework version, including .NET Framework. XML <PropertyGroup> <OutputType>WinExe</OutputType> </PropertyGroup> If OutputType is not specified in the project file, it defaults to Library and that value doesn't change. Reason for change It's assumed that most users don't want a console window to open when a WPF or Windows Forms app is executed. In addition, now that these application types use the .NET SDK instead of the Windows Desktop SDK, the correct default will be set. Further, when support for targeting iOS and Android is added, it will be easier to multi-target between multiple platforms if they all use the same output type. Version introduced .NET SDK 5.0.100 Recommended action No action is required in your part. However, if you want to revert to the old behavior, set the DisableWinExeOutputInference property to true in your project file. XML <DisableWinExeOutputInference>true</DisableWinExeOutputInference> Affected APIs Not detectable via API analysis. WinForms and WPF apps use Microsoft.NET.Sdk Article • 09/15/2021 Windows Forms and Windows Presentation Framework (WPF) apps now use the .NET SDK ( Microsoft.NET.Sdk ) instead of the .NET Core WinForms and WPF SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Change description In previous .NET Core versions, WinForms and WPF apps used a separate project SDK ( Microsoft.NET.Sdk.WindowsDesktop ). Starting in .NET 5, the WinForms and WPF SDK has been unified with the .NET SDK ( Microsoft.NET.Sdk ). In addition, new target framework monikers (TFM) replace netcoreapp and netstandard in .NET 5. The following example shows the changes you'd need to make for a WPF project file when retargeting to .NET 5 or later. In previous .NET Core versions: XML <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> In .NET 5 and later versions: XML <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net5.0-windows</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project> Version introduced .NET SDK 5.0.100 Recommended action In your WPF or Windows Forms project file: Update the Sdk attribute to Microsoft.NET.Sdk . Update the TargetFramework property to net5.0-windows . Affected APIs None. Breaking changes in .NET Core 3.1 Article • 07/28/2023 If you're migrating to version 3.1 of .NET Core or ASP.NET Core, the breaking changes listed in this article may affect your app. ASP.NET Core HTTP: Browser SameSite changes impact authentication Some browsers, such as Chrome and Firefox, made breaking changes to their implementations of SameSite for cookies. The changes impact remote authentication scenarios, such as OpenID Connect and WS-Federation, which must opt out by sending SameSite=None . However, SameSite=None breaks on iOS 12 and some older versions of other browsers. The app needs to sniff these versions and omit SameSite . For discussion on this issue, see dotnet/aspnetcore#14996 . Version introduced 3.1 Preview 1 Old behavior SameSite is a 2016 draft standard extension to HTTP cookies. It's intended to mitigate Cross-Site Request Forgery (CSRF). This was originally designed as a feature the servers would opt into by adding the new parameters. ASP.NET Core 2.0 added initial support for SameSite . New behavior Google proposed a new draft standard that isn't backwards compatible. The standard changes the default mode to Lax and adds a new entry None to opt out. Lax suffices for most app cookies; however, it breaks cross-site scenarios like OpenID Connect and WSFederation login. Most OAuth logins aren't affected because of differences in how the request flows. The new None parameter causes compatibility problems with clients that implemented the prior draft standard (for example, iOS 12). Chrome 80 will include the changes. See SameSite Updates for the Chrome product launch timeline. ASP.NET Core 3.1 has been updated to implement the new SameSite behavior. The update redefines the behavior of SameSiteMode.None to emit SameSite=None and adds a new value SameSiteMode.Unspecified to omit the SameSite attribute. All cookie APIs now default to Unspecified , though some components that use cookies set values more specific to their scenarios such as the OpenID Connect correlation and nonce cookies. For other recent changes in this area, see HTTP: Some cookie SameSite defaults changed to None. In ASP.NET Core 3.0, most defaults were changed from SameSiteMode.Lax to SameSiteMode.None (but still using the prior standard). Reason for change Browser and specification changes as outlined in the preceding text. Recommended action Apps that interact with remote sites, such as through third-party login, need to: Test those scenarios on multiple browsers. Apply the cookie policy browser sniffing mitigation discussed in Support older browsers. For testing and browser sniffing instructions, see the following section. Determine if you're affected Test your web app using a client version that can opt into the new behavior. Chrome, Firefox, and Microsoft Edge Chromium all have new opt-in feature flags that can be used for testing. Verify that your app is compatible with older client versions after you've applied the patches, especially Safari. For more information, see Support older browsers. Chrome Chrome 78 and later yield misleading test results. Those versions have a temporary mitigation in place and allow cookies less than two minutes old. With the appropriate test flags enabled, Chrome 76 and 77 yield more accurate results. To test the new behavior, toggle chrome://flags/#same-site-by-default-cookies to enabled. Chrome 75 and earlier are reported to fail with the new None setting. For more information, see Support older browsers. Google doesn't make older Chrome versions available. You can, however, download older versions of Chromium, which will suffice for testing. Follow the instructions at Download Chromium . Chromium 76 Win64 Chromium 74 Win64 Safari Safari 12 strictly implemented the prior draft and fails if it sees the new None value in cookies. This must be avoided via the browser sniffing code shown in Support older browsers. Ensure you test Safari 12 and 13 as well as WebKit-based, OS-style logins using Microsoft Authentication Library (MSAL), Active Directory Authentication Library (ADAL), or whichever library you're using. The problem is dependent on the underlying OS version. OSX Mojave 10.14 and iOS 12 are known to have compatibility problems with the new behavior. Upgrading to OSX Catalina 10.15 or iOS 13 fixes the problem. Safari doesn't currently have an opt-in flag for testing the new specification behavior. Firefox Firefox support for the new standard can be tested on version 68 and later by opting in on the about:config page with the feature flag network.cookie.sameSite.laxByDefault . No compatibility issues have been reported on older versions of Firefox. Microsoft Edge While Microsoft Edge supports the old SameSite standard, as of version 44 it didn't have any compatibility problems with the new standard. Microsoft Edge Chromium The feature flag is edge://flags/#same-site-by-default-cookies . No compatibility issues were observed when testing with Microsoft Edge Chromium 78. Electron Versions of Electron include older versions of Chromium. For example, the version of Electron used by Microsoft Teams is Chromium 66, which exhibits the older behavior. Perform your own compatibility testing with the version of Electron your product uses. For more information, see Support older browsers. Support older browsers The 2016 SameSite standard mandated that unknown values be treated as SameSite=Strict values. Consequently, any older browsers that support the original standard may break when they see a SameSite property with a value of None . Web apps must implement browser sniffing if they intend to support these old browsers. ASP.NET Core doesn't implement browser sniffing for you because User-Agent request header values are highly unstable and change on a weekly basis. Instead, an extension point in the cookie policy allows you to add User-Agent -specific logic. In Startup.cs, add the following code: C# private void CheckSameSite(HttpContext httpContext, CookieOptions options) { if (options.SameSite == SameSiteMode.None) { var userAgent = httpContext.Request.Headers["UserAgent"].ToString(); // TODO: Use your User Agent library of choice here. if (/* UserAgent doesn't support new behavior */) { options.SameSite = SameSiteMode.Unspecified; } } } public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = SameSiteMode.Unspecified; options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); }); } public void Configure(IApplicationBuilder app) { // Before UseAuthentication or anything else that writes cookies. app.UseCookiePolicy(); app.UseAuthentication(); // code omitted for brevity } Opt-out switches The Microsoft.AspNetCore.SuppressSameSiteNone compatibility switch enables you to temporarily opt out of the new ASP.NET Core cookie behavior. Add the following JSON to a runtimeconfig.template.json file in your project: JSON { "configProperties": { "Microsoft.AspNetCore.SuppressSameSiteNone": "true" } } Other Versions Related SameSite patches are forthcoming for: ASP.NET Core 2.1, 2.2, and 3.0 Microsoft.Owin 4.1 System.Web (for .NET Framework 4.7.2 and later) Category ASP.NET Affected APIs Microsoft.AspNetCore.Builder.CookiePolicyOptions.MinimumSameSitePolicy Microsoft.AspNetCore.Http.CookieBuilder.SameSite Microsoft.AspNetCore.Http.CookieOptions.SameSite Microsoft.AspNetCore.Http.SameSiteMode Microsoft.Net.Http.Headers.SameSiteMode Microsoft.Net.Http.Headers.SetCookieHeaderValue.SameSite Deployment x86 host path on 64-bit Windows MSBuild Design-time builds only return top-level package references Starting in .NET Core SDK 3.1.400, only top-level package references are returned by the RunResolvePackageDependencies target. Version introduced .NET Core SDK 3.1.400 Change description In previous versions of the .NET Core SDK, the RunResolvePackageDependencies target created the following MSBuild items that contained information from the NuGet assets file: PackageDefinitions PackageDependencies TargetDefinitions FileDefinitions FileDependencies This data is used by Visual Studio to populate the Dependencies node in Solution Explorer. However, it can be a large amount of data, and the data isn't needed unless the Dependencies node is expanded. Starting in the .NET Core SDK version 3.1.400, most of these items aren't generated by default. Only items of type Package are returned. If Visual Studio needs the items to populate the Dependencies node, it reads the information directly from the assets file. Reason for change This changed was introduced to improve solution-load performance inside of Visual Studio. Previously, all package references would be loaded, which involved loading many references that most users would never view. Recommended action If you have MSBuild logic that depends on these items being created, set the EmitLegacyAssetsFileItems property to true in your project file. This setting enables the previous behavior where all the items are created. Category MSBuild Affected APIs N/A SDK Tool manifests in root folder Windows Forms Removed controls Starting in .NET Core 3.1, some Windows Forms controls are no longer available. Change description Starting with .NET Core 3.1, various Windows Forms controls are no longer available. Replacement controls that have better design and support were introduced in .NET Framework 2.0. The deprecated controls were previously removed from designer toolboxes but were still available to be used. The following types are no longer available: ContextMenu DataGrid DataGrid.HitTestType DataGridBoolColumn DataGridCell DataGridColumnStyle DataGridLineStyle DataGridParentRowsLabelStyle DataGridPreferredColumnWidthTypeConverter DataGridTableStyle DataGridTextBox DataGridTextBoxColumn GridColumnStylesCollection GridTablesFactory GridTableStylesCollection IDataGridEditingService IMenuEditorService MainMenu Menu Menu.MenuItemCollection MenuItem ToolBar ToolBarAppearance ToolBarButton ToolBar.ToolBarButtonCollection ToolBarButtonClickEventArgs ToolBarButtonStyle ToolBarTextAlign Version introduced 3.1 Recommended action Each removed control has a recommended replacement control. Refer to the following table: Removed control (API) Recommended replacement ContextMenu ContextMenuStrip DataGrid DataGridView Associated APIs that are removed DataGridCell, DataGridRow, DataGridTableCollection, DataGridColumnCollection, DataGridTableStyle, DataGridColumnStyle, DataGridLineStyle, DataGridParentRowsLabel, DataGridParentRowsLabelStyle, DataGridBoolColumn, DataGridTextBox, GridColumnStylesCollection, GridTableStylesCollection, HitTestType MainMenu MenuStrip Menu ToolStripDropDown, ToolStripDropDownMenu MenuItemCollection Removed control (API) Recommended replacement Associated APIs that are removed MenuItem ToolStripMenuItem ToolBar ToolStrip ToolBarAppearance ToolBarButton ToolStripButton ToolBarButtonClickEventArgs, ToolBarButtonClickEventHandler, ToolBarButtonStyle, ToolBarTextAlign Category Windows Forms Affected APIs System.Windows.Forms.ContextMenu System.Windows.Forms.GridColumnStylesCollection System.Windows.Forms.GridTablesFactory System.Windows.Forms.GridTableStylesCollection System.Windows.Forms.IDataGridEditingService System.Windows.Forms.MainMenu System.Windows.Forms.Menu System.Windows.Forms.Menu.MenuItemCollection System.Windows.Forms.MenuItem System.Windows.Forms.ToolBar System.Windows.Forms.ToolBar.ToolBarButtonCollection System.Windows.Forms.ToolBarAppearance System.Windows.Forms.ToolBarButton System.Windows.Forms.ToolBarButtonClickEventArgs System.Windows.Forms.ToolBarButtonStyle System.Windows.Forms.ToolBarTextAlign System.Windows.Forms.DataGrid System.Windows.Forms.DataGrid.HitTestType System.Windows.Forms.DataGridBoolColumn System.Windows.Forms.DataGridCell System.Windows.Forms.DataGridColumnStyle System.Windows.Forms.DataGridLineStyle System.Windows.Forms.DataGridParentRowsLabelStyle System.Windows.Forms.DataGridPreferredColumnWidthTypeConverter System.Windows.Forms.DataGridTableStyle System.Windows.Forms.DataGridTextBox System.Windows.Forms.DataGridTextBoxColumn System.Windows.Forms.Design.IMenuEditorService CellFormatting event not raised if tooltip is shown A DataGridView now shows a cell's text and error tooltips when hovered by a mouse and when selected via the keyboard. If a tooltip is shown, the DataGridView.CellFormatting event is not raised. Change description Prior to .NET Core 3.1, a DataGridView that had the ShowCellToolTips property set to true showed a tooltip for a cell's text and errors when the cell was hovered by a mouse. Tooltips were not shown when a cell was selected via the keyboard (for example, by using the Tab key, shortcut keys, or arrow navigation). If the user edited a cell, and then, while the DataGridView was still in edit mode, hovered over a cell that did not have the ToolTipText property set, a CellFormatting event was raised to format the cell's text for display in the cell. To meet accessibility standards, starting in .NET Core 3.1, a DataGridView that has the ShowCellToolTips property set to true shows tooltips for a cell's text and errors not only when the cell is hovered, but also when it's selected via the keyboard. As a consequence of this change, the CellFormatting event is not raised when cells that don't have the ToolTipText property set are hovered while the DataGridView is in edit mode. The event is not raised because the content of the hovered cell is shown as a tooltip instead of being displayed in the cell. Version introduced 3.1 Recommended action Refactor any code that depends on the CellFormatting event while the DataGridView is in edit mode. Category Windows Forms Affected APIs None See also What's new in .NET Core 3.1 Breaking changes in .NET Core 3.0 Article • 03/18/2023 If you're migrating to version 3.0 of .NET Core, ASP.NET Core, or EF Core, the breaking changes listed in this article may affect your app. ASP.NET Core Obsolete Antiforgery, CORS, Diagnostics, MVC, and Routing APIs removed "Pubternal" APIs removed Authentication: Google+ deprecation Authentication: HttpContext.Authentication property removed Authentication: Newtonsoft.Json types replaced Authentication: OAuthHandler ExchangeCodeAsync signature changed Authorization: AddAuthorization overload moved to different assembly Authorization: IAllowAnonymous removed from AuthorizationFilterContext.Filters Authorization: IAuthorizationPolicyProvider implementations require new method Caching: CompactOnMemoryPressure property removed Caching: Microsoft.Extensions.Caching.SqlServer uses new SqlClient package Caching: ResponseCaching "pubternal" types changed to internal Data Protection: DataProtection.Blobs uses new Azure Storage APIs Hosting: AspNetCoreModule V1 removed from Windows Hosting Bundle Hosting: Generic host restricts Startup constructor injection Hosting: HTTPS redirection enabled for IIS out-of-process apps Hosting: IHostingEnvironment and IApplicationLifetime types replaced Hosting: ObjectPoolProvider removed from WebHostBuilder dependencies HTTP: DefaultHttpContext extensibility removed HTTP: HeaderNames fields changed to static readonly HTTP: Response body infrastructure changes HTTP: Some cookie SameSite default values changed HTTP: Synchronous IO disabled by default Identity: AddDefaultUI method overload removed Identity: UI Bootstrap version change Identity: SignInAsync throws exception for unauthenticated identity Identity: SignInManager constructor accepts new parameter Identity: UI uses static web assets feature Kestrel: Connection adapters removed Kestrel: Empty HTTPS assembly removed Kestrel: Request trailer headers moved to new collection Kestrel: Transport abstraction layer changes Localization: APIs marked obsolete Logging: DebugLogger class made internal MVC: Controller action Async suffix removed MVC: JsonResult moved to Microsoft.AspNetCore.Mvc.Core MVC: Precompilation tool deprecated MVC: Types changed to internal MVC: Web API compatibility shim removed Razor: RazorTemplateEngine API removed Razor: Runtime compilation moved to a package Session state: Obsolete APIs removed Shared framework: Assembly removal from Microsoft.AspNetCore.App Shared framework: Microsoft.AspNetCore.All removed SignalR: HandshakeProtocol.SuccessHandshakeData replaced SignalR: HubConnection methods removed SignalR: HubConnectionContext constructors changed SignalR: JavaScript client package name change SignalR: Obsolete APIs SPAs: SpaServices and NodeServices marked obsolete SPAs: SpaServices and NodeServices console logger fallback default change Target framework: .NET Framework not supported Obsolete Antiforgery, CORS, Diagnostics, MVC, and Routing APIs removed Obsolete members and compatibility switches in ASP.NET Core 2.2 were removed. Version introduced 3.0 Reason for change Improvement of API surface over time. Recommended action While targeting .NET Core 2.2, follow the guidance in the obsolete build messages to adopt new APIs instead. Category ASP.NET Core Affected APIs The following types and members were marked as obsolete for ASP.NET Core 2.1 and 2.2: Types Microsoft.AspNetCore.Diagnostics.Views.WelcomePage Microsoft.AspNetCore.DiagnosticsViewPage.Views.AttributeValue Microsoft.AspNetCore.DiagnosticsViewPage.Views.BaseView Microsoft.AspNetCore.DiagnosticsViewPage.Views.HelperResult Microsoft.AspNetCore.Mvc.Formatters.Xml.ProblemDetails21Wrapper Microsoft.AspNetCore.Mvc.Formatters.Xml.ValidationProblemDetails21Wrapper Microsoft.AspNetCore.Mvc.Razor.Compilation.ViewsFeatureProvider Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageArgumentBinder Microsoft.AspNetCore.Routing.IRouteValuesAddressMetadata Microsoft.AspNetCore.Routing.RouteValuesAddressMetadata Constructors Microsoft.AspNetCore.Cors.Infrastructure.CorsService(IOptions{CorsOptions}) Microsoft.AspNetCore.Routing.Tree.TreeRouteBuilder(ILoggerFactory,UrlEncoder,O bjectPool{UriBuildingContext},IInlineConstraintResolver) Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterCanWriteContext Microsoft.AspNetCore.Mvc.ApiExplorer.DefaultApiDescriptionProvider(IOptions{Mv cOptions},IInlineConstraintResolver,IModelMetadataProvider) Microsoft.AspNetCore.Mvc.ApiExplorer.DefaultApiDescriptionProvider(IOptions{Mv cOptions},IInlineConstraintResolver,IModelMetadataProvider,IActionResultTypeMa pper) Microsoft.AspNetCore.Mvc.Formatters.FormatFilter(IOptions{MvcOptions}) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ArrayModelBinder`1(IModelBinder ) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ByteArrayModelBinder Microsoft.AspNetCore.Mvc.ModelBinding.Binders.CollectionModelBinder`1(IModel Binder) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder(IDicti onary`2) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DictionaryModelBinder`2(IModelBi nder,IModelBinder) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DoubleModelBinder(System.Globali zation.NumberStyles) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatModelBinder(System.Globaliz ation.NumberStyles) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormCollectionModelBinder Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormFileModelBinder Microsoft.AspNetCore.Mvc.ModelBinding.Binders.HeaderModelBinder Microsoft.AspNetCore.Mvc.ModelBinding.Binders.KeyValuePairModelBinder`2(IModel Binder,IModelBinder) Microsoft.AspNetCore.Mvc.ModelBinding.Binders.SimpleTypeModelBinder(System.Ty pe) Microsoft.AspNetCore.Mvc.ModelBinding.ModelAttributes(IEnumerable{System.Obje ct}) Microsoft.AspNetCore.Mvc.ModelBinding.ModelAttributes(IEnumerable{System.Objec t},IEnumerable{System.Object}) Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory(IModelMetadataProvide r,IOptions{MvcOptions}) Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder(IModelMetadataProvider,I ModelBinderFactory,IObjectModelValidator) Microsoft.AspNetCore.Mvc.Routing.KnownRouteValueConstraint() Microsoft.AspNetCore.Mvc.Formatters.XmlDataContractSerializerInputFormatter Microsoft.AspNetCore.Mvc.Formatters.XmlDataContractSerializerInputFormatter(Sy stem.Boolean) Microsoft.AspNetCore.Mvc.Formatters.XmlDataContractSerializerInputFormatter(Mv cOptions) Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter(System.Boolea n) Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter(MvcOptions) Microsoft.AspNetCore.Mvc.TagHelpers.ImageTagHelper(IHostingEnvironment,IMe moryCache,HtmlEncoder,IUrlHelperFactory) Microsoft.AspNetCore.Mvc.TagHelpers.LinkTagHelper(IHostingEnvironment,IMemoryC ache,HtmlEncoder,JavaScriptEncoder,IUrlHelperFactory) Microsoft.AspNetCore.Mvc.TagHelpers.ScriptTagHelper(IHostingEnvironment,IMemor yCache,HtmlEncoder,JavaScriptEncoder,IUrlHelperFactory) Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAdapter(RazorPage Base) Properties Microsoft.AspNetCore.Antiforgery.AntiforgeryOptions.CookieDomain Microsoft.AspNetCore.Antiforgery.AntiforgeryOptions.CookieName Microsoft.AspNetCore.Antiforgery.AntiforgeryOptions.CookiePath Microsoft.AspNetCore.Antiforgery.AntiforgeryOptions.RequireSsl Microsoft.AspNetCore.Mvc.ApiBehaviorOptions.AllowInferringBindingSourceForColl ectionTypesAsFromQuery Microsoft.AspNetCore.Mvc.ApiBehaviorOptions.SuppressUseValidationProblemDetail sForInvalidModelStateResponses Microsoft.AspNetCore.Mvc.CookieTempDataProviderOptions.CookieName Microsoft.AspNetCore.Mvc.CookieTempDataProviderOptions.Domain Microsoft.AspNetCore.Mvc.CookieTempDataProviderOptions.Path Microsoft.AspNetCore.Mvc.DataAnnotations.MvcDataAnnotationsLocalizationOptions .AllowDataAnnotationsLocalizationForEnumDisplayAttributes Microsoft.AspNetCore.Mvc.Formatters.Xml.MvcXmlOptions.AllowRfc7807CompliantPro blemDetailsFormat Microsoft.AspNetCore.Mvc.MvcOptions.AllowBindingHeaderValuesToNonStringModelT ypes Microsoft.AspNetCore.Mvc.MvcOptions.AllowCombiningAuthorizeFilters Microsoft.AspNetCore.Mvc.MvcOptions.AllowShortCircuitingValidationWhenNoValida torsArePresent Microsoft.AspNetCore.Mvc.MvcOptions.AllowValidatingTopLevelNodes Microsoft.AspNetCore.Mvc.MvcOptions.InputFormatterExceptionPolicy Microsoft.AspNetCore.Mvc.MvcOptions.SuppressBindingUndefinedValueToEnumType Microsoft.AspNetCore.Mvc.MvcViewOptions.AllowRenderingMaxLengthAttribute Microsoft.AspNetCore.Mvc.MvcViewOptions.SuppressTempDataAttributePrefix Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions.AllowAreas Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions.AllowDefaultHandlingForO ptionsRequests Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions.AllowMappingHeadRequests ToGetHandler Methods Microsoft.AspNetCore.Mvc.LocalRedirectResult.ExecuteResult(ActionContext) Microsoft.AspNetCore.Mvc.RedirectResult.ExecuteResult(ActionContext) Microsoft.AspNetCore.Mvc.RedirectToActionResult.ExecuteResult(ActionContext) Microsoft.AspNetCore.Mvc.RedirectToPageResult.ExecuteResult(ActionContext) Microsoft.AspNetCore.Mvc.RedirectToRouteResult.ExecuteResult(ActionContext) Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionCon text,IValueProvider,ParameterDescriptor) Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(Action Context,IValueProvider,ParameterDescriptor,Object) "Pubternal" APIs removed To better maintain the public API surface of ASP.NET Core, most of the types in *.Internal namespaces (referred to as "pubternal" APIs) have become truly internal. Members in these namespaces were never meant to be supported as public-facing APIs. The APIs could break in minor releases and often did. Code that depends on these APIs breaks when updating to ASP.NET Core 3.0. For more information, see dotnet/aspnetcore#4932 and dotnet/aspnetcore#11312 . Version introduced 3.0 Old behavior The affected APIs are marked with the public access modifier and exist in *.Internal namespaces. New behavior The affected APIs are marked with the internal access modifier and can no longer be used by code outside that assembly. Reason for change The guidance for these "pubternal" APIs was that they: Could change without notice. Weren't subject to .NET policies to prevent breaking changes. Leaving the APIs public (even in the *.Internal namespaces) was confusing to customers. Recommended action Stop using these "pubternal" APIs. If you have questions about alternate APIs, open an issue in the dotnet/aspnetcore repository. For example, consider the following HTTP request buffering code in an ASP.NET Core 2.2 project. The EnableRewind extension method exists in the Microsoft.AspNetCore.Http.Internal namespace. C# HttpContext.Request.EnableRewind(); In an ASP.NET Core 3.0 project, replace the EnableRewind call with a call to the EnableBuffering extension method. The request buffering feature works as it did in the past. EnableBuffering calls the now internal API. C# HttpContext.Request.EnableBuffering(); Category ASP.NET Core Affected APIs All APIs in the Microsoft.AspNetCore.* and Microsoft.Extensions.* namespaces that have an Internal segment in the namespace name. For example: Microsoft.AspNetCore.Authentication.Internal Microsoft.AspNetCore.Builder.Internal Microsoft.AspNetCore.DataProtection.Cng.Internal Microsoft.AspNetCore.DataProtection.Internal Microsoft.AspNetCore.Hosting.Internal Microsoft.AspNetCore.Http.Internal Microsoft.AspNetCore.Mvc.Core.Infrastructure Microsoft.AspNetCore.Mvc.Core.Internal Microsoft.AspNetCore.Mvc.Cors.Internal Microsoft.AspNetCore.Mvc.DataAnnotations.Internal Microsoft.AspNetCore.Mvc.Formatters.Internal Microsoft.AspNetCore.Mvc.Formatters.Json.Internal Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal Microsoft.AspNetCore.Mvc.Internal Microsoft.AspNetCore.Mvc.ModelBinding.Internal Microsoft.AspNetCore.Mvc.Razor.Internal Microsoft.AspNetCore.Mvc.RazorPages.Internal Microsoft.AspNetCore.Mvc.TagHelpers.Internal Microsoft.AspNetCore.Mvc.ViewFeatures.Internal Microsoft.AspNetCore.Rewrite.Internal Microsoft.AspNetCore.Routing.Internal Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure Microsoft.AspNetCore.Server.Kestrel.Https.Internal Authentication: Google+ deprecated and replaced Google is starting to shut down Google+ Sign-in for apps as early as January 28, 2019. Change description ASP.NET 4.x and ASP.NET Core have been using the Google+ Sign-in APIs to authenticate Google account users in web apps. The affected NuGet packages are Microsoft.AspNetCore.Authentication.Google Microsoft.Owin.Security.Google for ASP.NET Core and for Microsoft.Owin with ASP.NET Web Forms and MVC. Google's replacement APIs use a different data source and format. The mitigations and solutions provided below account for the structural changes. Apps should verify the data itself still satisfies their requirements. For example, names, email addresses, profile links, and profile photos may provide subtly different values than before. Version introduced All versions. This change is external to ASP.NET Core. Recommended action Owin with ASP.NET Web Forms and MVC For Microsoft.Owin 3.1.0 and later, a temporary mitigation is outlined here . Apps should complete testing with the mitigation to check for changes in the data format. There are plans to release Microsoft.Owin 4.0.1 with a fix. Apps using any prior version should update to version 4.0.1. ASP.NET Core 1.x The mitigation in Owin with ASP.NET Web Forms and MVC can be adapted to ASP.NET Core 1.x. NuGet package patches aren't planned because 1.x has reached end of life status. ASP.NET Core 2.x For Microsoft.AspNetCore.Authentication.Google version 2.x, replace your existing call to AddGoogle in Startup.ConfigureServices with the following code: C# .AddGoogle(o => { o.ClientId = Configuration["Authentication:Google:ClientId"]; o.ClientSecret = Configuration["Authentication:Google:ClientSecret"]; o.UserInformationEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo"; o.ClaimActions.Clear(); o.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); o.ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); o.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name"); o.ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name"); o.ClaimActions.MapJsonKey("urn:google:profile", "link"); o.ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); }); The February 2.1 and 2.2 patches incorporated the preceding reconfiguration as the new default. No patch is planned for ASP.NET Core 2.0 since it has reached end of life . ASP.NET Core 3.0 The mitigation given for ASP.NET Core 2.x can also be used for ASP.NET Core 3.0. In future 3.0 previews, the Microsoft.AspNetCore.Authentication.Google package may be removed. Users would be directed to Microsoft.AspNetCore.Authentication.OpenIdConnect instead. The following code shows how to replace AddGoogle with AddOpenIdConnect in Startup.ConfigureServices . This replacement can be used with ASP.NET Core 2.0 and later and can be adapted for ASP.NET Core 1.x as needed. C# .AddOpenIdConnect("Google", o => { o.ClientId = Configuration["Authentication:Google:ClientId"]; o.ClientSecret = Configuration["Authentication:Google:ClientSecret"]; o.Authority = "https://accounts.google.com"; o.ResponseType = OpenIdConnectResponseType.Code; o.CallbackPath = "/signin-google"; // Or register the default "/signinoidc" o.Scope.Add("email"); }); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Authentication.Google Authentication: HttpContext.Authentication property removed The deprecated Authentication property on HttpContext has been removed. Change description As part of dotnet/aspnetcore#6504 , the deprecated Authentication property on HttpContext has been removed. The Authentication property has been deprecated since 2.0. A migration guide was published to migrate code using this deprecated property to the new replacement APIs. The remaining unused classes / APIs related to the old ASP.NET Core 1.x authentication stack were removed in commit dotnet/aspnetcore@d7a7c65 . For discussion, see dotnet/aspnetcore#6533 . Version introduced 3.0 Reason for change ASP.NET Core 1.0 APIs have been replaced by extension methods in Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions. Recommended action See the migration guide. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Http.Authentication.AuthenticateInfo Microsoft.AspNetCore.Http.Authentication.AuthenticationManager Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext Microsoft.AspNetCore.Http.Features.Authentication.ChallengeBehavior Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext Microsoft.AspNetCore.Http.Features.Authentication.DescribeSchemesContext Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature.Ha ndler Microsoft.AspNetCore.Http.Features.Authentication.SignInContext Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext Microsoft.AspNetCore.Http.HttpContext.Authentication Authentication: Newtonsoft.Json types replaced In ASP.NET Core 3.0, Newtonsoft.Json types used in Authentication APIs have been replaced with System.Text.Json types. Except for the following cases, basic usage of the Authentication packages remains unaffected: Classes derived from the OAuth providers, such as those from aspnet-contrib . Advanced claim manipulation implementations. For more information, see dotnet/aspnetcore#7105 dotnet/aspnetcore#7289 . For discussion, see . Version introduced 3.0 Recommended action For derived OAuth implementations, the most common change is to replace JObject.Parse with JsonDocument.Parse in the CreateTicketAsync override as shown here . JsonDocument implements IDisposable . The following list outlines known changes: ClaimAction.Run(JObject, ClaimsIdentity, String) becomes ClaimAction.Run(JsonElement userData, ClaimsIdentity identity, string issuer) . All derived implementations of ClaimAction are similarly affected. ClaimActionCollectionMapExtensions.MapCustomJson(ClaimActionCollection, String, Func<JObject,String>) becomes MapCustomJson(this ClaimActionCollection collection, string claimType, Func<JsonElement, string> resolver) ClaimActionCollectionMapExtensions.MapCustomJson(ClaimActionCollection, String, String, Func<JObject,String>) becomes MapCustomJson(this ClaimActionCollection collection, string claimType, string valueType, Func<JsonElement, string> resolver) OAuthCreatingTicketContext has had one old constructor removed and the other replaced JObject with JsonElement . The User property and RunClaimActions method have been updated to match. Success(JObject) now accepts a parameter of type JsonDocument instead of JObject . The Response property has been updated to match. OAuthTokenResponse is now disposable and will be disposed by OAuthHandler . Derived OAuth implementations overriding ExchangeCodeAsync don't need to dispose the JsonDocument or OAuthTokenResponse . UserInformationReceivedContext.User changed from JObject to JsonDocument . TwitterCreatingTicketContext.User changed from JObject to JsonElement . The last parameter of TwitterHandler.CreateTicketAsync(ClaimsIdentity,AuthenticationProperties,AccessTo ken,JObject) changed from JObject to JsonElement . The replacement method is TwitterHandler.CreateTicketAsync(ClaimsIdentity, AuthenticationProperties, AccessToken, JsonElement). Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Authentication.Facebook Microsoft.AspNetCore.Authentication.Google Microsoft.AspNetCore.Authentication.MicrosoftAccount Microsoft.AspNetCore.Authentication.OAuth Microsoft.AspNetCore.Authentication.OpenIdConnect Microsoft.AspNetCore.Authentication.Twitter Authentication: OAuthHandler ExchangeCodeAsync signature changed In ASP.NET Core 3.0, the signature of OAuthHandler.ExchangeCodeAsync was changed from: C# protected virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.OAuth.OAuthT okenResponse> ExchangeCodeAsync(string code, string redirectUri) { throw null; } To: C# protected virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.OAuth.OAuthT okenResponse> ExchangeCodeAsync(Microsoft.AspNetCore.Authentication.OAuth.OAuthCodeExchang eContext context) { throw null; } Version introduced 3.0 Old behavior The code and redirectUri strings were passed as separate arguments. New behavior Code and RedirectUri are properties on OAuthCodeExchangeContext that can be set via the OAuthCodeExchangeContext constructor. The new OAuthCodeExchangeContext type is the only argument passed to OAuthHandler.ExchangeCodeAsync . Reason for change This change allows additional parameters to be provided in a non-breaking manner. There's no need to create new ExchangeCodeAsync overloads. Recommended action Construct an OAuthCodeExchangeContext with the appropriate code and redirectUri values. An AuthenticationProperties instance must be provided. This single OAuthCodeExchangeContext instance can be passed to OAuthHandler.ExchangeCodeAsync instead of multiple arguments. Category ASP.NET Core Affected APIs OAuthHandler<TOptions>.ExchangeCodeAsync(String, String) Authorization: AddAuthorization overload moved to different assembly The core AddAuthorization methods that used to reside in Microsoft.AspNetCore.Authorization were renamed to AddAuthorizationCore . The old AddAuthorization methods still exist, but are in the Microsoft.AspNetCore.Authorization.Policy assembly instead. Apps using both methods should see no impact. Note that Microsoft.AspNetCore.Authorization.Policy now ships in the shared framework rather than a standalone package as discussed in Shared framework: Assemblies removed from Microsoft.AspNetCore.App. Version introduced 3.0 Old behavior AddAuthorization methods existed in Microsoft.AspNetCore.Authorization . New behavior AddAuthorization methods exist in Microsoft.AspNetCore.Authorization.Policy . AddAuthorizationCore is the new name for the old methods. Reason for change AddAuthorization is a better method name for adding all common services needed for authorization. Recommended action Either add a reference to Microsoft.AspNetCore.Authorization.Policy or use AddAuthorizationCore instead. Category ASP.NET Core Affected APIs Microsoft.Extensions.DependencyInjection.AuthorizationServiceCollectionExtensions.Add Authorization(IServiceCollection, Action<AuthorizationOptions>) Authorization: IAllowAnonymous removed from AuthorizationFilterContext.Filters As of ASP.NET Core 3.0, MVC doesn't add AllowAnonymousFilters for [AllowAnonymous] attributes that were discovered on controllers and action methods. This change is addressed locally for derivatives of AuthorizeAttribute, but it's a breaking change for IAsyncAuthorizationFilter and IAuthorizationFilter implementations. Such implementations wrapped in a [TypeFilter] attribute are a popular and supported way to achieve strongly-typed, attribute-based authorization when both configuration and dependency injection are required. Version introduced 3.0 Old behavior IAllowAnonymous appeared in the AuthorizationFilterContext.Filters collection. Testing for the interface's presence was a valid approach to override or disable the filter on individual controller methods. New behavior IAllowAnonymous no longer appears in the AuthorizationFilterContext.Filters collection. IAsyncAuthorizationFilter implementations that are dependent on the old behavior typically cause intermittent HTTP 401 Unauthorized or HTTP 403 Forbidden responses. Reason for change A new endpoint routing strategy was introduced in ASP.NET Core 3.0. Recommended action Search the endpoint metadata for IAllowAnonymous . For example: C# var endpoint = context.HttpContext.GetEndpoint(); if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null) { } An example of this technique is seen in this HasAllowAnonymous method . Category ASP.NET Core Affected APIs None Authorization: IAuthorizationPolicyProvider implementations require new method In ASP.NET Core 3.0, a new GetFallbackPolicyAsync method was added to IAuthorizationPolicyProvider . This fallback policy is used by the authorization middleware when no policy is specified. For more information, see dotnet/aspnetcore#9759 . Version introduced 3.0 Old behavior Implementations of IAuthorizationPolicyProvider didn't require a GetFallbackPolicyAsync method. New behavior Implementations of IAuthorizationPolicyProvider require a GetFallbackPolicyAsync method. Reason for change A new method was needed for the new AuthorizationMiddleware to use when no policy is specified. Recommended action Add the GetFallbackPolicyAsync method to your implementations of IAuthorizationPolicyProvider . Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider Caching: CompactOnMemoryPressure property removed The ASP.NET Core 3.0 release removed the obsolete MemoryCacheOptions APIs . Change description This change is a follow-up to aspnet/Caching#221 . For discussion, see dotnet/extensions#1062 . Version introduced 3.0 Old behavior MemoryCacheOptions.CompactOnMemoryPressure property was available. New behavior The MemoryCacheOptions.CompactOnMemoryPressure property has been removed. Reason for change Automatically compacting the cache caused problems. To avoid unexpected behavior, the cache should only be compacted when needed. Recommended action To compact the cache, downcast to MemoryCache and call Compact when needed. Category ASP.NET Core Affected APIs MemoryCacheOptions.CompactOnMemoryPressure Caching: Microsoft.Extensions.Caching.SqlServer uses new SqlClient package The Microsoft.Extensions.Caching.SqlServer package will use the new Microsoft.Data.SqlClient package instead of System.Data.SqlClient package. This change could cause slight behavioral breaking changes. For more information, see Introducing the new Microsoft.Data.SqlClient . Version introduced 3.0 Old behavior The Microsoft.Extensions.Caching.SqlServer package used the System.Data.SqlClient package. New behavior Microsoft.Extensions.Caching.SqlServer is now using the Microsoft.Data.SqlClient package. Reason for change Microsoft.Data.SqlClient is a new package that is built off of System.Data.SqlClient . It's where all new feature work will be done from now on. Recommended action Customers shouldn't need to worry about this breaking change unless they were using types returned by the Microsoft.Extensions.Caching.SqlServer package and casting them to System.Data.SqlClient types. For example, if someone was casting a DbConnection to the old SqlConnection type, they would need to change the cast to the new Microsoft.Data.SqlClient.SqlConnection type. Category ASP.NET Core Affected APIs None Caching: ResponseCaching "pubternal" types changed to internal In ASP.NET Core 3.0, "pubternal" types in ResponseCaching have been changed to internal . In addition, default implementations of IResponseCachingPolicyProvider and IResponseCachingKeyProvider are no longer added to services as part of the AddResponseCaching method. Change description In ASP.NET Core, "pubternal" types are declared as public but reside in a namespace suffixed with .Internal . While these types are public, they have no support policy and are subject to breaking changes. Unfortunately, accidental use of these types has been common, resulting in breaking changes to these projects and limiting the ability to maintain the framework. Version introduced 3.0 Old behavior These types were publicly visible, but unsupported. New behavior These types are now internal . Reason for change The internal scope better reflects the unsupported policy. Recommended action Copy types that are used by your app or library. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.ResponseCaching.Internal.CachedResponse Microsoft.AspNetCore.ResponseCaching.Internal.CachedVaryByRules Microsoft.AspNetCore.ResponseCaching.Internal.IResponseCache Microsoft.AspNetCore.ResponseCaching.Internal.IResponseCacheEntry Microsoft.AspNetCore.ResponseCaching.Internal.IResponseCachingKeyProvider Microsoft.AspNetCore.ResponseCaching.Internal.IResponseCachingPolicyProvider Microsoft.AspNetCore.ResponseCaching.Internal.MemoryResponseCache Microsoft.AspNetCore.ResponseCaching.Internal.ResponseCachingContext Microsoft.AspNetCore.ResponseCaching.Internal.ResponseCachingKeyProvider Microsoft.AspNetCore.ResponseCaching.Internal.ResponseCachingPolicyProvider Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.ResponseCa chingMiddleware(RequestDelegate, IOptions<ResponseCachingOptions>, ILoggerFactory, IResponseCachingPolicyProvider, IResponseCache, IResponseCachingKeyProvider) Data Protection: DataProtection.Blobs uses new Azure Storage APIs Azure.Extensions.AspNetCore.DataProtection.Blobs depends on the Azure Storage libraries . These libraries renamed their assemblies, packages, and namespaces. Starting in ASP.NET Core 3.0, Azure.Extensions.AspNetCore.DataProtection.Blobs uses the new Azure.Storage. -prefixed APIs and packages. For questions about the Azure Storage APIs, use https://github.com/Azure/azurestorage-net . For discussion on this issue, see dotnet/aspnetcore#19570 . Version introduced 3.0 Old behavior The package referenced the WindowsAzure.Storage NuGet package. The package references the Microsoft.Azure.Storage.Blob NuGet package. New behavior The package references the Azure.Storage.Blob NuGet package. Reason for change This change allows Azure.Extensions.AspNetCore.DataProtection.Blobs to migrate to the recommended Azure Storage packages. Recommended action If you still need to use the older Azure Storage APIs with ASP.NET Core 3.0, add a direct dependency to the package WindowsAzure.Storage or Microsoft.Azure.Storage . This package can be installed alongside the new Azure.Storage APIs. In many cases, the upgrade only involves changing the using statements to use the new namespaces: diff + + using using using using using using Microsoft.WindowsAzure.Storage; Microsoft.WindowsAzure.Storage.Blob; Microsoft.Azure.Storage; Microsoft.Azure.Storage.Blob; Azure.Storage; Azure.Storage.Blobs; Category ASP.NET Core Affected APIs None Hosting: AspNetCoreModule V1 removed from Windows Hosting Bundle Starting with ASP.NET Core 3.0, the Windows Hosting Bundle won't contain AspNetCoreModule (ANCM) V1. ANCM V2 is backwards compatible with ANCM OutOfProcess and is recommended for use with ASP.NET Core 3.0 apps. For discussion, see dotnet/aspnetcore#7095 . Version introduced 3.0 Old behavior ANCM V1 is included in the Windows Hosting Bundle. New behavior ANCM V1 isn't included in the Windows Hosting Bundle. Reason for change ANCM V2 is backwards compatible with ANCM OutOfProcess and is recommended for use with ASP.NET Core 3.0 apps. Recommended action Use ANCM V2 with ASP.NET Core 3.0 apps. If ANCM V1 is required, it can be installed using the ASP.NET Core 2.1 or 2.2 Windows Hosting Bundle. This change will break ASP.NET Core 3.0 apps that: Explicitly opted into using ANCM V1 with <AspNetCoreModuleName>AspNetCoreModule</AspNetCoreModuleName> . Have a custom web.config file with <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" /> . Category ASP.NET Core Affected APIs None Hosting: Generic host restricts Startup constructor injection The only types the generic host supports for Startup class constructor injection are IHostEnvironment , IWebHostEnvironment , and IConfiguration . Apps using WebHost are unaffected. Change description Prior to ASP.NET Core 3.0, constructor injection could be used for arbitrary types in the Startup class's constructor. In ASP.NET Core 3.0, the web stack was replatformed onto the generic host library. You can see the change in the Program.cs file of the templates: ASP.NET Core 2.x: https://github.com/dotnet/aspnetcore/blob/5cb615fcbe8559e49042e93394008077e304 54c0/src/Templating/src/Microsoft.DotNet.Web.ProjectTemplates/content/EmptyWebCSharp/Program.cs#L20-L22 ASP.NET Core 3.0: https://github.com/dotnet/aspnetcore/blob/b1ca2c1155da3920f0df5108b9fedbe82efaa 11c/src/ProjectTemplates/Web.ProjectTemplates/content/EmptyWebCSharp/Program.cs#L19-L24 Host uses one dependency injection (DI) container to build the app. WebHost uses two containers: one for the host and one for the app. As a result, the Startup constructor no longer supports custom service injection. Only IHostEnvironment , IWebHostEnvironment , and IConfiguration can be injected. This change prevents DI issues such as the duplicate creation of a singleton service. Version introduced 3.0 Reason for change This change is a consequence of replatforming the web stack onto the generic host library. Recommended action Inject services into the Startup.Configure method signature. For example: C# public void Configure(IApplicationBuilder app, IOptions<MyOptions> options) Category ASP.NET Core Affected APIs None Hosting: HTTPS redirection enabled for IIS out-of-process apps Version 13.0.19218.0 of the ASP.NET Core Module (ANCM) for hosting via IIS out-ofprocess enables an existing HTTPS redirection feature for ASP.NET Core 3.0 and 2.2 apps. For discussion, see dotnet/AspNetCore#15243 . Version introduced 3.0 Old behavior The ASP.NET Core 2.1 project template first introduced support for HTTPS middleware methods like UseHttpsRedirection and UseHsts. Enabling HTTPS redirection required the addition of configuration, since apps in development don't use the default port of 443. HTTP Strict Transport Security (HSTS) is active only if the request is already using HTTPS. Localhost is skipped by default. New behavior In ASP.NET Core 3.0, the IIS HTTPS scenario was enhanced . With the enhancement, an app could discover the server's HTTPS ports and make UseHttpsRedirection work by default. The in-process component accomplished port discovery with the IServerAddresses feature, which only affects ASP.NET Core 3.0 apps because the in- process library is versioned with the framework. The out-of-process component changed to automatically add the ASPNETCORE_HTTPS_PORT environment variable. This change affected both ASP.NET Core 2.2 and 3.0 apps because the out-of-process component is shared globally. ASP.NET Core 2.1 apps aren't affected because they use a prior version of ANCM by default. The preceding behavior was modified in ASP.NET Core 3.0.1 and 3.1.0 Preview 3 to reverse the behavior changes in ASP.NET Core 2.x. These changes only affect IIS out-ofprocess apps. As detailed above, installing ASP.NET Core 3.0.0 had the side effect of also activating the UseHttpsRedirection middleware in ASP.NET Core 2.x apps. A change was made to ANCM in ASP.NET Core 3.0.1 and 3.1.0 Preview 3 such that installing them no longer has this effect on ASP.NET Core 2.x apps. The ASPNETCORE_HTTPS_PORT environment variable that ANCM populated in ASP.NET Core 3.0.0 was changed to ASPNETCORE_ANCM_HTTPS_PORT in ASP.NET Core 3.0.1 and 3.1.0 Preview 3. UseHttpsRedirection was also updated in these releases to understand both the new and old variables. ASP.NET Core 2.x won't be updated. As a result, it reverts to the previous behavior of being disabled by default. Reason for change Improved ASP.NET Core 3.0 functionality. Recommended action No action is required if you want all clients to use HTTPS. To allow some clients to use HTTP, take one of the following steps: Remove the calls to UseHttpsRedirection and UseHsts from your project's Startup.Configure method, and redeploy the app. In your web.config file, set the ASPNETCORE_HTTPS_PORT environment variable to an empty string. This change can occur directly on the server without redeploying the app. For example: XML <aspNetCore processPath="dotnet" arguments=".\WebApplication3.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" > <environmentVariables> <environmentVariable name="ASPNETCORE_HTTPS_PORT" value="" /> </environmentVariables> </aspNetCore> UseHttpsRedirection can still be: Activated manually in ASP.NET Core 2.x by setting the ASPNETCORE_HTTPS_PORT environment variable to the appropriate port number (443 in most production scenarios). Deactivated in ASP.NET Core 3.x by defining ASPNETCORE_ANCM_HTTPS_PORT with an empty string value. This value is set in the same fashion as the preceding ASPNETCORE_HTTPS_PORT example. Machines running ASP.NET Core 3.0.0 apps should install the ASP.NET Core 3.0.1 runtime before installing the ASP.NET Core 3.1.0 Preview 3 ANCM. Doing so ensures that UseHttpsRedirection continues to operate as expected for the ASP.NET Core 3.0 apps. In Azure App Service, ANCM deploys on a separate schedule from the runtime because of its global nature. ANCM was deployed to Azure with these changes after ASP.NET Core 3.0.1 and 3.1.0 were deployed. Category ASP.NET Core Affected APIs HttpsPolicyBuilderExtensions.UseHttpsRedirection(IApplicationBuilder) Hosting: IHostingEnvironment and IApplicationLifetime types marked obsolete and replaced New types have been introduced to replace existing IHostingEnvironment and IApplicationLifetime types. Version introduced 3.0 Old behavior There were two different IHostingEnvironment and IApplicationLifetime types from Microsoft.Extensions.Hosting and Microsoft.AspNetCore.Hosting . New behavior The old types have been marked as obsolete and replaced with new types. Reason for change When Microsoft.Extensions.Hosting was introduced in ASP.NET Core 2.1, some types like IHostingEnvironment and IApplicationLifetime were copied from Microsoft.AspNetCore.Hosting . Some ASP.NET Core 3.0 changes cause apps to include both the Microsoft.Extensions.Hosting and Microsoft.AspNetCore.Hosting namespaces. Any use of those duplicate types causes an "ambiguous reference" compiler error when both namespaces are referenced. Recommended action Replaced any usages of the old types with the newly introduced types as below: Obsolete types (warning): Microsoft.Extensions.Hosting.IHostingEnvironment Microsoft.AspNetCore.Hosting.IHostingEnvironment Microsoft.Extensions.Hosting.IApplicationLifetime Microsoft.AspNetCore.Hosting.IApplicationLifetime Microsoft.Extensions.Hosting.EnvironmentName Microsoft.AspNetCore.Hosting.EnvironmentName New types: Microsoft.Extensions.Hosting.IHostEnvironment Microsoft.AspNetCore.Hosting.IWebHostEnvironment : IHostEnvironment Microsoft.Extensions.Hosting.IHostApplicationLifetime Microsoft.Extensions.Hosting.Environments The new IHostEnvironment IsDevelopment and IsProduction extension methods are in the Microsoft.Extensions.Hosting namespace. That namespace may need to be added to your project. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Hosting.EnvironmentName Microsoft.AspNetCore.Hosting.IApplicationLifetime Microsoft.AspNetCore.Hosting.IHostingEnvironment Microsoft.Extensions.Hosting.EnvironmentName Microsoft.Extensions.Hosting.IApplicationLifetime Microsoft.Extensions.Hosting.IHostingEnvironment Hosting: ObjectPoolProvider removed from WebHostBuilder dependencies As part of making ASP.NET Core more pay for play, the ObjectPoolProvider was removed from the main set of dependencies. Specific components relying on ObjectPoolProvider now add it themselves. For discussion, see dotnet/aspnetcore#5944 Version introduced . 3.0 Old behavior WebHostBuilder provides ObjectPoolProvider by default in the DI container. New behavior WebHostBuilder no longer provides ObjectPoolProvider by default in the DI container. Reason for change This change was made to make ASP.NET Core more pay for play. Recommended action If your component requires ObjectPoolProvider , it needs to be added to your dependencies via the IServiceCollection . Category ASP.NET Core Affected APIs None HTTP: DefaultHttpContext extensibility removed As part of ASP.NET Core 3.0 performance improvements, the extensibility of DefaultHttpContext was removed. The class is now sealed . For more information, see dotnet/aspnetcore#6504 . If your unit tests use Mock<DefaultHttpContext> , use Mock<HttpContext> or new DefaultHttpContext() instead. For discussion, see dotnet/aspnetcore#6534 Version introduced . 3.0 Old behavior Classes can derive from DefaultHttpContext . New behavior Classes can't derive from DefaultHttpContext . Reason for change The extensibility was provided initially to allow pooling of the HttpContext , but it introduced unnecessary complexity and impeded other optimizations. Recommended action If you're using Mock<DefaultHttpContext> in your unit tests, begin using Mock<HttpContext> instead. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Http.DefaultHttpContext HTTP: HeaderNames constants changed to static readonly Starting in ASP.NET Core 3.0 Preview 5, the fields in Microsoft.Net.Http.Headers.HeaderNames changed from const to static readonly . For discussion, see dotnet/aspnetcore#9514 Version introduced 3.0 . Old behavior These fields used to be const . New behavior These fields are now static readonly . Reason for change The change: Prevents the values from being embedded across assembly boundaries, allowing for value corrections as needed. Enables faster reference equality checks. Recommended action Recompile against 3.0. Source code using these fields in the following ways can no longer do so: As an attribute argument As a case in a switch statement When defining another const To work around the breaking change, switch to using self-defined header name constants or string literals. Category ASP.NET Core Affected APIs Microsoft.Net.Http.Headers.HeaderNames HTTP: Response body infrastructure changes The infrastructure backing an HTTP response body has changed. If you're using HttpResponse directly, you shouldn't need to make any code changes. Read further if you're wrapping or replacing HttpResponse.Body or accessing HttpContext.Features . Version introduced 3.0 Old behavior There were three APIs associated with the HTTP response body: IHttpResponseFeature.Body IHttpSendFileFeature.SendFileAsync IHttpBufferingFeature.DisableResponseBuffering New behavior If you replace HttpResponse.Body , it replaces the entire IHttpResponseBodyFeature with a wrapper around your given stream using StreamResponseBodyFeature to provide default implementations for all of the expected APIs. Setting back the original stream reverts this change. Reason for change The motivation is to combine the response body APIs into a single new feature interface. Recommended action Use IHttpResponseBodyFeature where you previously were using IHttpResponseFeature.Body , IHttpSendFileFeature , or IHttpBufferingFeature . Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.Body Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature HTTP: Some cookie SameSite defaults changed to None SameSite is an option for cookies that can help mitigate some Cross-Site Request Forgery (CSRF) attacks. When this option was initially introduced, inconsistent defaults were used across various ASP.NET Core APIs. The inconsistency has led to confusing results. As of ASP.NET Core 3.0, these defaults are better aligned. You must opt in to this feature on a per-component basis. Version introduced 3.0 Old behavior Similar ASP.NET Core APIs used different default SameSiteMode values. An example of the inconsistency is seen in HttpResponse.Cookies.Append(String, String) and HttpResponse.Cookies.Append(String, String, CookieOptions) , which defaulted to SameSiteMode.None and SameSiteMode.Lax , respectively. New behavior All the affected APIs default to SameSiteMode.None . Reason for change The default value was changed to make SameSite an opt-in feature. Recommended action Each component that emits cookies needs to decide if SameSite is appropriate for its scenarios. Review your usage of the affected APIs and reconfigure SameSite as needed. Category ASP.NET Core Affected APIs IResponseCookies.Append(String, String, CookieOptions) CookiePolicyOptions.MinimumSameSitePolicy HTTP: Synchronous IO disabled in all servers Starting with ASP.NET Core 3.0, synchronous server operations are disabled by default. Change description AllowSynchronousIO is an option in each server that enables or disables synchronous IO APIs like HttpRequest.Body.Read , HttpResponse.Body.Write , and Stream.Flush . These APIs have long been a source of thread starvation and app hangs. Starting in ASP.NET Core 3.0 Preview 3, these synchronous operations are disabled by default. Affected servers: Kestrel HttpSys IIS in-process TestServer Expect errors similar to: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead. Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead. Each server has an AllowSynchronousIO option that controls this behavior and the default for all of them is now false . The behavior can also be overridden on a per-request basis as a temporary mitigation. For example: C# var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>(); if (syncIOFeature != null) { syncIOFeature.AllowSynchronousIO = true; } If you have trouble with a TextWriter or another stream calling a synchronous API in Dispose , call the new DisposeAsync API instead. For discussion, see dotnet/aspnetcore#7644 . Version introduced 3.0 Old behavior HttpRequest.Body.Read , HttpResponse.Body.Write , and Stream.Flush were allowed by default. New behavior These synchronous APIs are disallowed by default: Expect errors similar to: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead. Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead. Reason for change These synchronous APIs have long been a source of thread starvation and app hangs. Starting in ASP.NET Core 3.0 Preview 3, the synchronous operations are disabled by default. Recommended action Use the asynchronous versions of the methods. The behavior can also be overridden on a per-request basis as a temporary mitigation. C# var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>(); if (syncIOFeature != null) { syncIOFeature.AllowSynchronousIO = true; } Category ASP.NET Core Affected APIs Stream.Flush Stream.Read Stream.Write Identity: AddDefaultUI method overload removed Starting with ASP.NET Core 3.0, the IdentityBuilderUIExtensions.AddDefaultUI(IdentityBuilder,UIFramework) method overload no longer exists. Version introduced 3.0 Reason for change This change was a result of adoption of the static web assets feature. Recommended action Call IdentityBuilderUIExtensions.AddDefaultUI(IdentityBuilder) instead of the overload that takes two arguments. If you're using Bootstrap 3, also add the following line to a <PropertyGroup> element in your project file: XML <IdentityUIFrameworkVersion>Bootstrap3</IdentityUIFrameworkVersion> Category ASP.NET Core Affected APIs IdentityBuilderUIExtensions.AddDefaultUI(IdentityBuilder,UIFramework) Identity: Default Bootstrap version of UI changed Starting in ASP.NET Core 3.0, Identity UI defaults to using version 4 of Bootstrap. Version introduced 3.0 Old behavior The services.AddDefaultIdentity<IdentityUser>().AddDefaultUI(); method call was the same as services.AddDefaultIdentity<IdentityUser> ().AddDefaultUI(UIFramework.Bootstrap3); New behavior The services.AddDefaultIdentity<IdentityUser>().AddDefaultUI(); method call is the same as services.AddDefaultIdentity<IdentityUser> ().AddDefaultUI(UIFramework.Bootstrap4); Reason for change Bootstrap 4 was released during ASP.NET Core 3.0 timeframe. Recommended action You're impacted by this change if you use the default Identity UI and have added it in Startup.ConfigureServices as shown in the following example: C# services.AddDefaultIdentity<IdentityUser>().AddDefaultUI(); Take one of the following actions: Migrate your app to use Bootstrap 4 using their migration guide . Update Startup.ConfigureServices to enforce usage of Bootstrap 3. For example: C# services.AddDefaultIdentity<IdentityUser> ().AddDefaultUI(UIFramework.Bootstrap3); Category ASP.NET Core Affected APIs None Identity: SignInAsync throws exception for unauthenticated identity By default, SignInAsync throws an exception for principals / identities in which IsAuthenticated is false . Version introduced 3.0 Old behavior SignInAsync accepts any principals / identities, including identities in which IsAuthenticated is false . New behavior By default, SignInAsync throws an exception for principals / identities in which IsAuthenticated is false . There's a new flag to suppress this behavior, but the default behavior has changed. Reason for change The old behavior was problematic because, by default, these principals were rejected by [Authorize] / RequireAuthenticatedUser() . Recommended action In ASP.NET Core 3.0 Preview 6, there's a RequireAuthenticatedSignIn flag on AuthenticationOptions that is true by default. Set this flag to false to restore the old behavior. Category ASP.NET Core Affected APIs None Identity: SignInManager constructor accepts new parameter Starting with ASP.NET Core 3.0, a new IUserConfirmation<TUser> parameter was added to the SignInManager constructor. For more information, see dotnet/aspnetcore#8356 . Version introduced 3.0 Reason for change The motivation for the change was to add support for new email / confirmation flows in Identity. Recommended action If manually constructing a SignInManager , provide an implementation of IUserConfirmation or grab one from dependency injection to provide. Category ASP.NET Core Affected APIs SignInManager<TUser> Identity: UI uses static web assets feature ASP.NET Core 3.0 introduced a static web assets feature, and Identity UI has adopted it. Change description As a result of Identity UI adopting the static web assets feature: Framework selection is accomplished by using the IdentityUIFrameworkVersion property in your project file. Bootstrap 4 is the default UI framework for Identity UI. Bootstrap 3 has reached end of life, and you should consider migrating to a supported version. Version introduced 3.0 Old behavior The default UI framework for Identity UI was Bootstrap 3. The UI framework could be configured using a parameter to the AddDefaultUI method call in Startup.ConfigureServices . New behavior The default UI framework for Identity UI is Bootstrap 4. The UI framework must be configured in your project file, instead of in the AddDefaultUI method call. Reason for change Adoption of the static web assets feature required that the UI framework configuration move to MSBuild. The decision on which framework to embed is a build-time decision, not a runtime decision. Recommended action Review your site UI to ensure the new Bootstrap 4 components are compatible. If necessary, use the IdentityUIFrameworkVersion MSBuild property to revert to Bootstrap 3. Add the property to a <PropertyGroup> element in your project file: XML <IdentityUIFrameworkVersion>Bootstrap3</IdentityUIFrameworkVersion> Category ASP.NET Core Affected APIs IdentityBuilderUIExtensions.AddDefaultUI(IdentityBuilder, UIFramework) Kestrel: Connection adapters removed As part of the move to move "pubternal" APIs to public , the concept of an IConnectionAdapter was removed from Kestrel. Connection adapters are being replaced with connection middleware (similar to HTTP middleware in the ASP.NET Core pipeline, but for lower-level connections). HTTPS and connection logging have moved from connection adapters to connection middleware. Those extension methods should continue to work seamlessly, but the implementation details have changed. For more information, see dotnet/aspnetcore#11412 dotnet/aspnetcore#11475 . For discussion, see . Version introduced 3.0 Old behavior Kestrel extensibility components were created using IConnectionAdapter . New behavior Kestrel extensibility components are created as middleware . Reason for change This change is intended to provide a more flexible extensibility architecture. Recommended action Convert any implementations of IConnectionAdapter to use the new middleware pattern as shown here . Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal.IConnectionAdapter Kestrel: Empty HTTPS assembly removed The assembly Microsoft.AspNetCore.Server.Kestrel.Https has been removed. Version introduced 3.0 Reason for change In ASP.NET Core 2.1, the contents of Microsoft.AspNetCore.Server.Kestrel.Https were moved to Microsoft.AspNetCore.Server.Kestrel.Core. This change was done in a nonbreaking way using [TypeForwardedTo] attributes. Recommended action Libraries referencing Microsoft.AspNetCore.Server.Kestrel.Https 2.0 should update all ASP.NET Core dependencies to 2.1 or later. Otherwise, they may break when loaded into an ASP.NET Core 3.0 app. Apps and libraries targeting ASP.NET Core 2.1 and later should remove any direct references to the Microsoft.AspNetCore.Server.Kestrel.Https NuGet package. Category ASP.NET Core Affected APIs None Kestrel: Request trailer headers moved to new collection In prior versions, Kestrel added HTTP/1.1 chunked trailer headers into the request headers collection when the request body was read to the end. This behavior caused concerns about ambiguity between headers and trailers. The decision was made to move the trailers to a new collection. HTTP/2 request trailers were unavailable in ASP.NET Core 2.2 but are now also available in this new collection in ASP.NET Core 3.0. New request extension methods have been added to access these trailers. HTTP/1.1 trailers are available once the entire request body has been read. HTTP/2 trailers are available once they're received from the client. The client won't send the trailers until the entire request body has been at least buffered by the server. You may need to read the request body to free up buffer space. Trailers are always available if you read the request body to the end. The trailers mark the end of the body. Version introduced 3.0 Old behavior Request trailer headers would be added to the HttpRequest.Headers collection. New behavior Request trailer headers aren't present in the HttpRequest.Headers collection. Use the following extension methods on HttpRequest to access them: GetDeclaredTrailers() - Gets the request "Trailer" header that lists which trailers to expect after the body. SupportsTrailers() - Indicates if the request supports receiving trailer headers. CheckTrailersAvailable() - Determines if the request supports trailers and if they're available for reading. GetTrailer(string trailerName) - Gets the requested trailing header from the response. Reason for change Trailers are a key feature in scenarios like gRPC. Merging the trailers in to request headers was confusing to users. Recommended action Use the trailer-related extension methods on HttpRequest to access trailers. Category ASP.NET Core Affected APIs HttpRequest.Headers Kestrel: Transport abstractions removed and made public As part of moving away from "pubternal" APIs, the Kestrel transport layer APIs are exposed as a public interface in the Microsoft.AspNetCore.Connections.Abstractions library. Version introduced 3.0 Old behavior Transport-related abstractions were available in the Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions library. The ListenOptions.NoDelay property was available. New behavior The IConnectionListener interface was introduced in the Microsoft.AspNetCore.Connections.Abstractions library to expose the most used functionality from the ...Transport.Abstractions library. The NoDelay is now available in transport options ( LibuvTransportOptions and SocketTransportOptions ). SchedulingMode is no longer available. Reason for change ASP.NET Core 3.0 has moved away from "pubternal" APIs. Recommended action Category ASP.NET Core Affected APIs None Localization: ResourceManagerWithCultureStringLocalizer and WithCulture marked obsolete The ResourceManagerWithCultureStringLocalizer class and WithCulture interface member are often sources of confusion for users of localization, especially when creating their own IStringLocalizer implementation. These items give the user the impression that an IStringLocalizer instance is "per-language, per-resource". In reality, the instances should only be "per-resource". The language searched for is determined by the CultureInfo.CurrentUICulture at execution time. To eliminate the source of confusion, the APIs were marked as obsolete in ASP.NET Core 3.0 Preview 3. The APIs will be removed in a future release. For context, see dotnet/aspnetcore#3324 dotnet/aspnetcore#7756 . For discussion, see . Version introduced 3.0 Old behavior Methods weren't marked as Obsolete . New behavior Methods are marked Obsolete . Reason for change The APIs represented a use case that isn't recommended. There was confusion about the design of localization. Recommended action The recommendation is to use ResourceManagerStringLocalizer instead. Let the culture be set by the CurrentCulture . If that isn't an option, create and use a copy of ResourceManagerWithCultureStringLocalizer . Category ASP.NET Core Affected APIs ResourceManagerWithCultureStringLocalizer ResourceManagerStringLocalizer.WithCulture Logging: DebugLogger class made internal Prior to ASP.NET Core 3.0, DebugLogger 's access modifier was public . In ASP.NET Core 3.0, the access modifier changed to internal . Version introduced 3.0 Reason for change The change is being made to: Enforce consistency with other logger implementations such as ConsoleLogger . Reduce the API surface. Recommended action Use the AddDebug ILoggingBuilder extension method to enable debug logging. DebugLoggerProvider is also still public in the event the service needs to be registered manually. Category ASP.NET Core Affected APIs Microsoft.Extensions.Logging.Debug.DebugLogger MVC: Async suffix trimmed from controller action names As part of addressing dotnet/aspnetcore#4849 , ASP.NET Core MVC trims the suffix Async from action names by default. Starting with ASP.NET Core 3.0, this change affects both routing and link generation. Version introduced 3.0 Old behavior Consider the following ASP.NET Core MVC controller: C# public class ProductController : Controller { public async IActionResult ListAsync() { var model = await DbContext.Products.ToListAsync(); return View(model); } } The action is routable via Product/ListAsync . Link generation requires specifying the Async suffix. For example: CSHTML <a asp-controller="Product" asp-action="ListAsync">List</a> New behavior In ASP.NET Core 3.0, the action is routable via Product/List . Link generation code should omit the Async suffix. For example: CSHTML <a asp-controller="Product" asp-action="List">List</a> This change doesn't affect names specified using the [ActionName] attribute. The new behavior can be disabled by setting MvcOptions.SuppressAsyncSuffixInActionNames to false in Startup.ConfigureServices : C# services.AddMvc(options => { options.SuppressAsyncSuffixInActionNames = false; }); Reason for change By convention, asynchronous .NET methods are suffixed with Async . However, when a method defines an MVC action, it's undesirable to use the Async suffix. Recommended action If your app depends on MVC actions preserving the name's Async suffix, choose one of the following mitigations: Use the [ActionName] attribute to preserve the original name. Disable the renaming entirely by setting MvcOptions.SuppressAsyncSuffixInActionNames to false in Startup.ConfigureServices : C# services.AddMvc(options => { options.SuppressAsyncSuffixInActionNames = false; }); Category ASP.NET Core Affected APIs None MVC: JsonResult moved to Microsoft.AspNetCore.Mvc.Core JsonResult has moved to the Microsoft.AspNetCore.Mvc.Core assembly. This type used to be defined in Microsoft.AspNetCore.Mvc.Formatters.Json . An assembly-level [TypeForwardedTo] attribute was added to Microsoft.AspNetCore.Mvc.Formatters.Json to address this issue for the majority of users. Apps that use third-party libraries may encounter issues. Version introduced 3.0 Preview 6 Old behavior An app using a 2.2-based library builds successfully. New behavior An app using a 2.2-based library fails compilation. An error containing a variation of the following text is provided: Output The type 'JsonResult' exists in both 'Microsoft.AspNetCore.Mvc.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' and 'Microsoft.AspNetCore.Mvc.Formatters.Json, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' For an example of such an issue, see dotnet/aspnetcore#7220 . Reason for change Platform-level changes to the composition of ASP.NET Core as described at aspnet/Announcements#325 . Recommended action Libraries compiled against the 2.2 version of Microsoft.AspNetCore.Mvc.Formatters.Json may need to recompile to address the problem for all consumers. If affected, contact the library author. Request recompilation of the library to target ASP.NET Core 3.0. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Mvc.JsonResult MVC: Precompilation tool deprecated In ASP.NET Core 1.1, the Microsoft.AspNetCore.Mvc.Razor.ViewCompilation (MVC precompilation tool) package was introduced to add support for publish-time compilation of Razor files (.cshtml files). In ASP.NET Core 2.1, the Razor SDK was introduced to expand upon features of the precompilation tool. The Razor SDK added support for build- and publish-time compilation of Razor files. The SDK verifies the correctness of .cshtml files at build time while improving on app startup time. The Razor SDK is on by default, and no gesture is required to start using it. In ASP.NET Core 3.0, the ASP.NET Core 1.1-era MVC precompilation tool was removed. Earlier package versions will continue receiving important bug and security fixes in the patch release. Version introduced 3.0 Old behavior The Microsoft.AspNetCore.Mvc.Razor.ViewCompilation package was used to pre-compile MVC Razor views. New behavior The Razor SDK natively supports this functionality. The Microsoft.AspNetCore.Mvc.Razor.ViewCompilation package is no longer updated. Reason for change The Razor SDK provides more functionality and verifies the correctness of .cshtml files at build time. The SDK also improves app startup time. Recommended action For users of ASP.NET Core 2.1 or later, update to use the native support for precompilation in the Razor SDK. If bugs or missing features prevent migration to the Razor SDK, open an issue at dotnet/aspnetcore . Category ASP.NET Core Affected APIs None MVC: "Pubternal" types changed to internal In ASP.NET Core 3.0, all "pubternal" types in MVC were updated to either be public in a supported namespace or internal as appropriate. Change description In ASP.NET Core, "pubternal" types are declared as public but reside in a .Internal suffixed namespace. While these types are public , they have no support policy and are subject to breaking changes. Unfortunately, accidental use of these types has been common, resulting in breaking changes to these projects and limiting the ability to maintain the framework. Version introduced 3.0 Old behavior Some types in MVC were public but in a .Internal namespace. These types had no support policy and were subject to breaking changes. New behavior All such types are updated either to be public in a supported namespace or marked as internal . Reason for change Accidental use of the "pubternal" types has been common, resulting in breaking changes to these projects and limiting the ability to maintain the framework. Recommended action If you're using types that have become truly public and have been moved into a new, supported namespace, update your references to match the new namespaces. If you're using types that have become marked as internal , you'll need to find an alternative. The previously "pubternal" types were never supported for public use. If there are specific types in these namespaces that are critical to your apps, file an issue at dotnet/aspnetcore . Considerations may be made for making the requested types public . Category ASP.NET Core Affected APIs This change includes types in the following namespaces: Microsoft.AspNetCore.Mvc.Cors.Internal Microsoft.AspNetCore.Mvc.DataAnnotations.Internal Microsoft.AspNetCore.Mvc.Formatters.Internal Microsoft.AspNetCore.Mvc.Formatters.Json.Internal Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal Microsoft.AspNetCore.Mvc.Internal Microsoft.AspNetCore.Mvc.ModelBinding.Internal Microsoft.AspNetCore.Mvc.Razor.Internal Microsoft.AspNetCore.Mvc.RazorPages.Internal Microsoft.AspNetCore.Mvc.TagHelpers.Internal Microsoft.AspNetCore.Mvc.ViewFeatures.Internal MVC: Web API compatibility shim removed Starting with ASP.NET Core 3.0, the Microsoft.AspNetCore.Mvc.WebApiCompatShim package is no longer available. Change description The Microsoft.AspNetCore.Mvc.WebApiCompatShim (WebApiCompatShim) package provides partial compatibility in ASP.NET Core with ASP.NET 4.x Web API 2 to simplify migrating existing Web API implementations to ASP.NET Core. However, apps using the WebApiCompatShim don't benefit from the API-related features shipping in recent ASP.NET Core releases. Such features include improved Open API specification generation, standardized error handling, and client code generation. To better focus the API efforts in 3.0, WebApiCompatShim was removed. Existing apps using the WebApiCompatShim should migrate to the newer [ApiController] model. Version introduced 3.0 Reason for change The Web API compatibility shim was a migration tool. It restricts user access to new functionality added in ASP.NET Core. Recommended action Remove usage of this shim and migrate directly to the similar functionality in ASP.NET Core itself. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Mvc.WebApiCompatShim Razor: RazorTemplateEngine API removed The RazorTemplateEngine API was removed and replaced with Microsoft.AspNetCore.Razor.Language.RazorProjectEngine . For discussion, see GitHub issue dotnet/aspnetcore#25215 . Version introduced 3.0 Old behavior A template engine can be created and used to parse and generate code for Razor files. New behavior RazorProjectEngine can be created and provided the same type of information as RazorTemplateEngine to parse and generate code for Razor files. RazorProjectEngine also provides extra levels of configuration. Reason for change RazorTemplateEngine was too tightly coupled to the existing implementations. This tight coupling led to more questions when trying to properly configure a Razor parsing/generation pipeline. Recommended action Use RazorProjectEngine instead of RazorTemplateEngine . Consider the following examples. Create and configure the RazorProjectEngine C# RazorProjectEngine projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, RazorProjectFileSystem.Create(@"C:\source\repos\ConsoleApp4\ConsoleApp4"), builder => { builder.ConfigureClass((document, classNode) => { classNode.ClassName = "MyClassName"; // Can also configure other aspects of the class here. }); // More configuration can go here }); Generate code for a Razor file C# RazorProjectItem item = projectEngine.FileSystem.GetItem( @"C:\source\repos\ConsoleApp4\ConsoleApp4\Example.cshtml", FileKinds.Legacy); RazorCodeDocument output = projectEngine.Process(item); // Things available RazorSyntaxTree syntaxTree = output.GetSyntaxTree(); DocumentIntermediateNode intermediateDocument = output.GetDocumentIntermediateNode(); RazorCSharpDocument csharpDocument = output.GetCSharpDocument(); Category ASP.NET Core Affected APIs RazorTemplateEngine RazorTemplateEngineOptions Razor: Runtime compilation moved to a package Support for runtime compilation of Razor views and Razor Pages has moved to a separate package. Version introduced 3.0 Old behavior Runtime compilation is available without needing additional packages. New behavior The functionality has been moved to the Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package. The following APIs were previously available in Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions to support runtime compilation. The APIs are now available via Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.MvcRazorRuntimeCompilationOption s. RazorViewEngineOptions.FileProviders is now MvcRazorRuntimeCompilationOptions.FileProviders RazorViewEngineOptions.AdditionalCompilationReferences is now MvcRazorRuntimeCompilationOptions.AdditionalReferencePaths In addition, Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions.AllowRecompilingViewsOnFileC hange has been removed. Recompilation on file changes is enabled by default by referencing the Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package. Reason for change This change was necessary to remove the ASP.NET Core shared framework dependency on Roslyn. Recommended action Apps that require runtime compilation or recompilation of Razor files should take the following steps: 1. Add a reference to the Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package. 2. Update the project's Startup.ConfigureServices method to include a call to AddRazorRuntimeCompilation . For example: C# services.AddMvc() .AddRazorRuntimeCompilation(); Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions Session state: Obsolete APIs removed Obsolete APIs for configuring session cookies were removed. For more information, see aspnet/Announcements#257 . Version introduced 3.0 Reason for change This change enforces consistency across APIs for configuring features that use cookies. Recommended action Migrate usage of the removed APIs to their newer replacements. Consider the following example in Startup.ConfigureServices : C# public void ConfigureServices(ServiceCollection services) { services.AddSession(options => { // Removed obsolete APIs options.CookieName = "SessionCookie"; options.CookieDomain = "contoso.com"; options.CookiePath = "/"; options.CookieHttpOnly = true; options.CookieSecure = CookieSecurePolicy.Always; // new API options.Cookie.Name = "SessionCookie"; options.Cookie.Domain = "contoso.com"; options.Cookie.Path = "/"; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; }); } Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Builder.SessionOptions.CookieDomain Microsoft.AspNetCore.Builder.SessionOptions.CookieHttpOnly Microsoft.AspNetCore.Builder.SessionOptions.CookieName Microsoft.AspNetCore.Builder.SessionOptions.CookiePath Microsoft.AspNetCore.Builder.SessionOptions.CookieSecure Shared framework: Assemblies removed from Microsoft.AspNetCore.App Starting in ASP.NET Core 3.0, the ASP.NET Core shared framework ( Microsoft.AspNetCore.App ) only contains first-party assemblies that are fully developed, supported, and serviceable by Microsoft. Change description Think of the change as the redefining of boundaries for the ASP.NET Core "platform." The shared framework will be source-buildable by anybody via GitHub and will continue to offer the existing benefits of .NET Core shared frameworks to your apps. Some benefits include smaller deployment size, centralized patching, and faster startup time. As part of the change, some notable breaking changes are introduced in Microsoft.AspNetCore.App . Version introduced 3.0 Old behavior Projects referenced Microsoft.AspNetCore.App via a <PackageReference> element in the project file. Additionally, Microsoft.AspNetCore.App contained the following subcomponents: Json.NET ( Newtonsoft.Json ) Entity Framework Core (assemblies prefixed with Microsoft.EntityFrameworkCore. ) Roslyn ( Microsoft.CodeAnalysis ) New behavior A reference to Microsoft.AspNetCore.App no longer requires a <PackageReference> element in the project file. The .NET Core SDK supports a new element called <FrameworkReference> , which replaces the use of <PackageReference> . For more information, see dotnet/aspnetcore#3612 . Entity Framework Core ships as NuGet packages. This change aligns the shipping model with all other data access libraries on .NET. It provides Entity Framework Core the simplest path to continue innovating while supporting the various .NET platforms. The move of Entity Framework Core out of the shared framework has no impact on its status as a Microsoft-developed, supported, and serviceable library. The .NET Core support policy continues to cover it. Json.NET and Entity Framework Core continue to work with ASP.NET Core. They won't, however, be included in the shared framework. For more information, see The future of JSON in .NET Core 3.0 . Also see the complete list of binaries removed from the shared framework. Reason for change This change simplifies the consumption of Microsoft.AspNetCore.App and reduces the duplication between NuGet packages and shared frameworks. For more information on the motivation for this change, see this blog post . Recommended action Starting with ASP.NET Core 3.0, it is no longer necessary for projects to consume assemblies in Microsoft.AspNetCore.App as NuGet packages. To simplify the targeting and usage of the ASP.NET Core shared framework, many NuGet packages shipped since ASP.NET Core 1.0 are no longer produced. The APIs those packages provide are still available to apps by using a <FrameworkReference> to Microsoft.AspNetCore.App . Common API examples include Kestrel, MVC, and Razor. This change doesn't apply to all binaries referenced via Microsoft.AspNetCore.App in ASP.NET Core 2.x. Notable exceptions include: Microsoft.Extensions libraries that continue to target .NET Standard are available as NuGet packages (see https://github.com/dotnet/extensions ). APIs produced by the ASP.NET Core team that aren't part of Microsoft.AspNetCore.App . For example, the following components are available as NuGet packages: Entity Framework Core APIs that provide third-party integration Experimental features APIs with dependencies that couldn't fulfill the requirements to be in the shared framework Extensions to MVC that maintain support for Json.NET. An API is provided as a NuGet package to support using Json.NET and MVC. See the ASP.NET Core migration guide for more details. The SignalR .NET client continues to support .NET Standard and ships as a NuGet package . It's intended for use on many .NET runtimes, such as Xamarin and UWP. For more information, see Stop producing packages for shared framework assemblies in 3.0 . For discussion, see dotnet/aspnetcore#3757 . Category ASP.NET Core Affected APIs Microsoft.CodeAnalysis Microsoft.EntityFrameworkCore Shared framework: Removed Microsoft.AspNetCore.All Starting in ASP.NET Core 3.0, the Microsoft.AspNetCore.All metapackage and the matching Microsoft.AspNetCore.All shared framework are no longer produced. This package is available in ASP.NET Core 2.2 and will continue to receive servicing updates in ASP.NET Core 2.1. Version introduced 3.0 Old behavior Apps could use the Microsoft.AspNetCore.All metapackage to target the Microsoft.AspNetCore.All shared framework on .NET Core. New behavior .NET Core 3.0 doesn't include a Microsoft.AspNetCore.All shared framework. Reason for change The Microsoft.AspNetCore.All metapackage included a large number of external dependencies. Recommended action Migrate your project to use the Microsoft.AspNetCore.App framework. Components that were previously available in Microsoft.AspNetCore.All are still available on NuGet. Those components are now deployed with your app instead of being included in the shared framework. Category ASP.NET Core Affected APIs None SignalR: HandshakeProtocol.SuccessHandshakeData replaced The HandshakeProtocol.SuccessHandshakeData field was removed and replaced with a helper method that generates a successful handshake response given a specific IHubProtocol . Version introduced 3.0 Old behavior HandshakeProtocol.SuccessHandshakeData was a public static ReadOnlyMemory<byte> field. New behavior HandshakeProtocol.SuccessHandshakeData has been replaced by a static GetSuccessfulHandshake(IHubProtocol protocol) method that returns a ReadOnlyMemory<byte> based on the specified protocol. Reason for change Additional fields were added to the handshake response that are non-constant and change depending on the selected protocol. Recommended action None. This type isn't designed for use from user code. It's public , so it can be shared between the SignalR server and client. It may also be used by customer SignalR clients written in .NET. Users of SignalR shouldn't be affected by this change. Category ASP.NET Core Affected APIs HandshakeProtocol.SuccessHandshakeData SignalR: HubConnection ResetSendPing and ResetTimeout methods removed The ResetSendPing and ResetTimeout methods were removed from the SignalR HubConnection API. These methods were originally intended only for internal use but were made public in ASP.NET Core 2.2. These methods won't be available starting in the ASP.NET Core 3.0 Preview 4 release. For discussion, see dotnet/aspnetcore#8543 . Version introduced 3.0 Old behavior APIs were available. New behavior APIs are removed. Reason for change These methods were originally intended only for internal use but were made public in ASP.NET Core 2.2. Recommended action Don't use these methods. Category ASP.NET Core Affected APIs HubConnection.ResetSendPing() HubConnection.ResetTimeout() SignalR: HubConnectionContext constructors changed SignalR's HubConnectionContext constructors changed to accept an options type, rather than multiple parameters, to future-proof adding options. This change replaces two constructors with a single constructor that accepts an options type. Version introduced 3.0 Old behavior HubConnectionContext has two constructors: C# public HubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory); public HubConnectionContext(ConnectionContext connectionContext, TimeSpan keepAliveInterval, ILoggerFactory loggerFactory, TimeSpan clientTimeoutInterval); New behavior The two constructors were removed and replaced with one constructor: C# public HubConnectionContext(ConnectionContext connectionContext, HubConnectionContextOptions contextOptions, ILoggerFactory loggerFactory) Reason for change The new constructor uses a new options object. Consequently, the features of HubConnectionContext can be expanded in the future without making more constructors and breaking changes. Recommended action Instead of using the following constructor: C# HubConnectionContext connectionContext = new HubConnectionContext( connectionContext, keepAliveInterval: TimeSpan.FromSeconds(15), loggerFactory, clientTimeoutInterval: TimeSpan.FromSeconds(15)); Use the following constructor: C# HubConnectionContextOptions contextOptions = new HubConnectionContextOptions() { KeepAliveInterval = TimeSpan.FromSeconds(15), ClientTimeoutInterval = TimeSpan.FromSeconds(15) }; HubConnectionContext connectionContext = new HubConnectionContext(connectionContext, contextOptions, loggerFactory); Category ASP.NET Core Affected APIs HubConnectionContext(ConnectionContext, TimeSpan, ILoggerFactory) HubConnectionContext(ConnectionContext, TimeSpan, ILoggerFactory, TimeSpan) SignalR: JavaScript client package name changed In ASP.NET Core 3.0 Preview 7, the SignalR JavaScript client package name changed from @aspnet/signalr to @microsoft/signalr . The name change reflects the fact that SignalR is useful in more than just ASP.NET Core apps, thanks to the Azure SignalR Service. To react to this change, change references in your package.json files, require statements, and ECMAScript import statements. No API will change as part of this rename. For discussion, see dotnet/aspnetcore#11637 . Version introduced 3.0 Old behavior The client package was named @aspnet/signalr . New behavior The client package is named @microsoft/signalr . Reason for change The name change clarifies that SignalR is useful beyond ASP.NET Core apps, thanks to the Azure SignalR Service. Recommended action Switch to the new package @microsoft/signalr . Category ASP.NET Core Affected APIs None SignalR: UseSignalR and UseConnections methods marked obsolete The methods UseConnections and UseSignalR and the classes ConnectionsRouteBuilder and HubRouteBuilder are marked as obsolete in ASP.NET Core 3.0. Version introduced 3.0 Old behavior SignalR hub routing was configured using UseSignalR or UseConnections . New behavior The old way of configuring routing has been obsoleted and replaced with endpoint routing. Reason for change Middleware is being moved to the new endpoint routing system. The old way of adding middleware is being obsoleted. Recommended action Replace UseSignalR with UseEndpoints : Old code: C# app.UseSignalR(routes => { routes.MapHub<SomeHub>("/path"); }); New code: C# app.UseEndpoints(endpoints => { endpoints.MapHub<SomeHub>("/path"); }); Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Builder.ConnectionsAppBuilderExtensions.UseConnections(I ApplicationBuilder, Action<ConnectionsRouteBuilder>) Microsoft.AspNetCore.Builder.SignalRAppBuilderExtensions.UseSignalR(IApplicatio nBuilder, Action<HubRouteBuilder>) Microsoft.AspNetCore.Http.Connections.ConnectionsRouteBuilder Microsoft.AspNetCore.SignalR.HubRouteBuilder SPAs: SpaServices and NodeServices marked obsolete The contents of the following NuGet packages have all been unnecessary since ASP.NET Core 2.1. Consequently, the following packages are being marked as obsolete: Microsoft.AspNetCore.SpaServices Microsoft.AspNetCore.NodeServices For the same reason, the following npm modules are being marked as deprecated: aspnet-angular aspnet-prerendering aspnet-webpack aspnet-webpack-react domain-task The preceding packages and npm modules will later be removed in .NET 5. Version introduced 3.0 Old behavior The deprecated packages and npm modules were intended to integrate ASP.NET Core with various Single-Page App (SPA) frameworks. Such frameworks include Angular, React, and React with Redux. New behavior A new integration mechanism exists in the Microsoft.AspNetCore.SpaServices.Extensions NuGet package. The package remains the basis of the Angular and React project templates since ASP.NET Core 2.1. Reason for change ASP.NET Core supports integration with various Single-Page App (SPA) frameworks, including Angular, React, and React with Redux. Initially, integration with these frameworks was accomplished with ASP.NET Core-specific components that handled scenarios like server-side prerendering and integration with Webpack. As time went on, industry standards changed. Each of the SPA frameworks released their own standard command-line interfaces. For example, Angular CLI and create-react-app. When ASP.NET Core 2.1 was released in May 2018, the team responded to the change in standards. A newer and simpler way to integrate with the SPA frameworks' own toolchains was provided. The new integration mechanism exists in the package Microsoft.AspNetCore.SpaServices.Extensions and remains the basis of the Angular and React project templates since ASP.NET Core 2.1. To clarify that the older ASP.NET Core-specific components are irrelevant and not recommended: The pre-2.1 integration mechanism is marked as obsolete. The supporting npm packages are marked as deprecated. Recommended action If you're using these packages, update your apps to use the functionality: In the Microsoft.AspNetCore.SpaServices.Extensions package. Provided by the SPA frameworks you're using To enable features like server-side prerendering and hot module reload, see the documentation for the corresponding SPA framework. The functionality in Microsoft.AspNetCore.SpaServices.Extensions is not obsolete and will continue to be supported. Category ASP.NET Core Affected APIs Microsoft.AspNetCore.Builder.SpaRouteExtensions Microsoft.AspNetCore.Builder.WebpackDevMiddleware Microsoft.AspNetCore.NodeServices.EmbeddedResourceReader Microsoft.AspNetCore.NodeServices.INodeServices Microsoft.AspNetCore.NodeServices.NodeServicesFactory Microsoft.AspNetCore.NodeServices.NodeServicesOptions Microsoft.AspNetCore.NodeServices.StringAsTempFile Microsoft.AspNetCore.NodeServices.HostingModels.INodeInstance Microsoft.AspNetCore.NodeServices.HostingModels.NodeInvocationException Microsoft.AspNetCore.NodeServices.HostingModels.NodeInvocationInfo Microsoft.AspNetCore.NodeServices.HostingModels.NodeServicesOptionsExtensio ns Microsoft.AspNetCore.NodeServices.HostingModels.OutOfProcessNodeInstance Microsoft.AspNetCore.SpaServices.Prerendering.ISpaPrerenderer Microsoft.AspNetCore.SpaServices.Prerendering.ISpaPrerendererBuilder Microsoft.AspNetCore.SpaServices.Prerendering.JavaScriptModuleExport Microsoft.AspNetCore.SpaServices.Prerendering.Prerenderer Microsoft.AspNetCore.SpaServices.Prerendering.PrerenderTagHelper Microsoft.AspNetCore.SpaServices.Prerendering.RenderToStringResult Microsoft.AspNetCore.SpaServices.Webpack.WebpackDevMiddlewareOptions Microsoft.Extensions.DependencyInjection.NodeServicesServiceCollectionExtension s Microsoft.Extensions.DependencyInjection.PrerenderingServiceCollectionExtension s SPAs: SpaServices and NodeServices no longer fall back to console logger Microsoft.AspNetCore.SpaServices and Microsoft.AspNetCore.NodeServices won't display console logs unless logging is configured. Version introduced 3.0 Old behavior Microsoft.AspNetCore.SpaServices and Microsoft.AspNetCore.NodeServices used to automatically create a console logger when logging isn't configured. New behavior Microsoft.AspNetCore.SpaServices and Microsoft.AspNetCore.NodeServices won't display console logs unless logging is configured. Reason for change There's a need to align with how other ASP.NET Core packages implement logging. Recommended action If the old behavior is required, to configure console logging, add services.AddLogging(builder => builder.AddConsole()) to your Setup.ConfigureServices method. Category ASP.NET Core Affected APIs None Target framework: .NET Framework support dropped Starting with ASP.NET Core 3.0, .NET Framework is an unsupported target framework. Change description .NET Framework 4.8 is the last major version of .NET Framework. New ASP.NET Core apps should be built on .NET Core. Starting with the .NET Core 3.0 release, you can think of ASP.NET Core 3.0 as being part of .NET Core. Customers using ASP.NET Core with .NET Framework can continue in a fully supported fashion using the 2.1 LTS release . Support and servicing for 2.1 continues until at least August 21, 2021. This date is three years after declaration of the LTS release per the .NET Support Policy . Support for ASP.NET Core 2.1 packages on .NET Framework will extend indefinitely, similar to the servicing policy for other package-based ASP.NET frameworks . For more information about porting from .NET Framework to .NET Core, see Porting to .NET Core. Microsoft.Extensions packages (such as logging, dependency injection, and configuration) and Entity Framework Core aren't affected. They'll continue to support .NET Standard. For more information on the motivation for this change, see the original blog post . Version introduced 3.0 Old behavior ASP.NET Core apps could run on either .NET Core or .NET Framework. New behavior ASP.NET Core apps can only be run on .NET Core. Recommended action Take one of the following actions: Keep your app on ASP.NET Core 2.1. Migrate your app and dependencies to .NET Core. Category ASP.NET Core Affected APIs None Core .NET libraries APIs that report version now report product and not file version Custom EncoderFallbackBuffer instances cannot fall back recursively Floating point formatting and parsing behavior changes Floating-point parsing operations no longer fail or throw an OverflowException InvalidAsynchronousStateException moved to another assembly Replacing ill-formed UTF-8 byte sequences follows Unicode guidelines TypeDescriptionProviderAttribute moved to another assembly ZipArchiveEntry no longer handles archives with inconsistent entry sizes FieldInfo.SetValue throws exception for static, init-only fields Passing GroupCollection to extension methods taking IEnumerable<T> requires disambiguation APIs that report version now report product and not file version Many of the APIs that return versions in .NET Core now return the product version rather than the file version. Change description In .NET Core 2.2 and previous versions, methods such as Environment.Version, RuntimeInformation.FrameworkDescription, and the file properties dialog for .NET Core assemblies reflect the file version. Starting with .NET Core 3.0, they reflect the product version. The following figure illustrates the difference in version information for the System.Runtime.dll assembly for .NET Core 2.2 (on the left) and .NET Core 3.0 (on the right) as displayed by the Windows Explorer file properties dialog. Version introduced 3.0 Recommended action None. This change should make version detection intuitive rather than obtuse. Category Core .NET libraries Affected APIs Environment.Version RuntimeInformation.FrameworkDescription Custom EncoderFallbackBuffer instances cannot fall back recursively Custom EncoderFallbackBuffer instances cannot fall back recursively. The implementation of EncoderFallbackBuffer.GetNextChar() must result in a character sequence that is convertible to the destination encoding. Otherwise, an exception occurs. Change description During a character-to-byte transcoding operation, the runtime detects ill-formed or nonconvertible UTF-16 sequences and provides those characters to the EncoderFallbackBuffer.Fallback method. The Fallback method determines which characters should be substituted for the original nonconvertible data, and these characters are drained by calling EncoderFallbackBuffer.GetNextChar in a loop. The runtime then attempts to transcode these substitution characters to the target encoding. If this operation succeeds, the runtime continues transcoding from where it left off in the original input string. Previously, custom implementations of EncoderFallbackBuffer.GetNextChar() can return character sequences that are not convertible to the destination encoding. If the substituted characters cannot be transcoded to the target encoding, the runtime invokes the EncoderFallbackBuffer.Fallback method once again with the substitution characters, expecting the EncoderFallbackBuffer.GetNextChar() method to return a new substitution sequence. This process continues until the runtime eventually sees a wellformed, convertible substitution, or until a maximum recursion count is reached. Starting with .NET Core 3.0, custom implementations of EncoderFallbackBuffer.GetNextChar() must return character sequences that are convertible to the destination encoding. If the substituted characters cannot be transcoded to the target encoding, an ArgumentException is thrown. The runtime will no longer make recursive calls into the EncoderFallbackBuffer instance. This behavior only applies when all three of the following conditions are met: The runtime detects an ill-formed UTF-16 sequence or a UTF-16 sequence that cannot be converted to the target encoding. A custom EncoderFallback has been specified. The custom EncoderFallback attempts to substitute a new ill-formed or nonconvertible UTF-16 sequence. Version introduced 3.0 Recommended action Most developers needn't take any action. If an application uses a custom EncoderFallback and EncoderFallbackBuffer class, ensure the implementation of EncoderFallbackBuffer.Fallback populates the fallback buffer with well-formed UTF-16 data that is directly convertible to the target encoding when the Fallback method is first invoked by the runtime. Category Core .NET libraries Affected APIs EncoderFallbackBuffer.Fallback EncoderFallbackBuffer.GetNextChar() Floating-point formatting and parsing behavior changed Floating-point parsing and formatting behavior (by the Double and Single types) are now IEEE-compliant . This ensures that the behavior of floating-point types in .NET matches that of other IEEE-compliant languages. For example, double.Parse("SomeLiteral") should always match what C# produces for double x = SomeLiteral . Change description In .NET Core 2.2 and earlier versions, formatting with Double.ToString and Single.ToString, and parsing with Double.Parse, Double.TryParse, Single.Parse, and Single.TryParse are not IEEE-compliant. As a result, it's impossible to guarantee that a value will roundtrip with any supported standard or custom format string. For some inputs, the attempt to parse a formatted value can fail, and for others, the parsed value doesn't equal the original value. Starting with .NET Core 3.0, floating-point parsing and formatting operations are IEEE 754-compliant. The following table shows two code snippets and how the output changes between .NET Core 2.2 and .NET Core 3.1. Code snippet Output on .NET Core 2.2 Output on .NET Core 3.1 Console.WriteLine((-0.0).ToString()); 0 -0 var value = -3.123456789123456789; False True Console.WriteLine(value == double.Parse(value.ToString())); For more information, see the Floating-point parsing and formatting improvements in .NET Core 3.0 blog post. Version introduced 3.0 Recommended action The Potential impact to existing code section of the Floating-point parsing and formatting improvements in .NET Core 3.0 blog post suggests some changes you can make to your code if you want to maintain the previous behavior. For some differences in formatting, you can get behavior equivalent to the previous behavior by specifying a different format string. For differences in parsing, there's no mechanism to fall back to the previous behavior. Category Core .NET libraries Affected APIs Double.ToString Single.ToString Double.Parse Double.TryParse Single.Parse Single.TryParse Floating-point parsing operations no longer fail or throw an OverflowException The floating-point parsing methods no longer throw an OverflowException or return false when they parse a string whose numeric value is outside the range of the Single or Double floating-point type. Change description In .NET Core 2.2 and earlier versions, the Double.Parse and Single.Parse methods throw an OverflowException for values that outside the range of their respective type. The Double.TryParse and Single.TryParse methods return false for the string representations of out-of-range numeric values. Starting with .NET Core 3.0, the Double.Parse, Double.TryParse, Single.Parse, and Single.TryParse methods no longer fail when parsing out-of-range numeric strings. Instead, the Double parsing methods return Double.PositiveInfinity for values that exceed Double.MaxValue, and they return Double.NegativeInfinity for values that are less than Double.MinValue. Similarly, the Single parsing methods return Single.PositiveInfinity for values that exceed Single.MaxValue, and they return Single.NegativeInfinity for values that are less than Single.MinValue. This change was made for improved IEEE 754:2008 compliance. Version introduced 3.0 Recommended action This change can affect your code in either of two ways: Your code depends on the handler for the OverflowException to execute when an overflow occurs. In this case, you should remove the catch statement and place any necessary code in an If statement that tests whether Double.IsInfinity or Single.IsInfinity is true . Your code assumes that floating-point values are not Infinity . In this case, you should add the necessary code to check for floating-point values of PositiveInfinity and NegativeInfinity . Category Core .NET libraries Affected APIs Double.Parse Double.TryParse Single.Parse Single.TryParse InvalidAsynchronousStateException moved to another assembly The InvalidAsynchronousStateException class has been moved. Change description In .NET Core 2.2 and earlier versions, the InvalidAsynchronousStateException class is found in the System.ComponentModel.TypeConverter assembly. Starting with .NET Core 3.0, it is found in the System.ComponentModel.Primitives assembly. Version introduced 3.0 Recommended action This change only affects applications that use reflection to load the InvalidAsynchronousStateException by calling a method such as Assembly.GetType or an overload of Activator.CreateInstance that assumes the type is in a particular assembly. If that is the case, update the assembly referenced in the method call to reflect the type's new assembly location. Category Core .NET libraries Affected APIs None. Replacing ill-formed UTF-8 byte sequences follows Unicode guidelines When the UTF8Encoding class encounters an ill-formed UTF-8 byte sequence during a byte-to-character transcoding operation, it replaces that sequence with a '�' (U+FFFD REPLACEMENT CHARACTER) character in the output string. .NET Core 3.0 differs from previous versions of .NET Core and the .NET Framework by following the Unicode best practice for performing this replacement during the transcoding operation. This is part of a larger effort to improve UTF-8 handling throughout .NET, including by the new System.Text.Unicode.Utf8 and System.Text.Rune types. The UTF8Encoding type was given improved error handling mechanics so that it produces output consistent with the newly introduced types. Change description Starting with .NET Core 3.0, when transcoding bytes to characters, the UTF8Encoding class performs character substitution based on Unicode best practices. The substitution mechanism used is described by The Unicode Standard, Version 12.0, Sec. 3.9 (PDF) in the heading titled U+FFFD Substitution of Maximal Subparts. This behavior only applies when the input byte sequence contains ill-formed UTF-8 data. Additionally, if the UTF8Encoding instance has been constructed with throwOnInvalidBytes: true , the UTF8Encoding instance will continue to throw on invalid input rather than perform U+FFFD replacement. For more information about the UTF8Encoding constructor, see UTF8Encoding(Boolean, Boolean). The following table illustrates the impact of this change with an invalid 3-byte input: Ill-formed 3-byte input Output before .NET Core 3.0 Output starting with .NET Core 3.0 [ ED A0 90 ] [ FFFD FFFD ] (2-character [ FFFD FFFD FFFD ] (3-character output) output) The 3-char output is the preferred output, according to Table 3-9 of the previously linked Unicode Standard PDF. Version introduced 3.0 Recommended action No action is required on the part of the developer. Category Core .NET libraries Affected APIs UTF8Encoding.GetCharCount UTF8Encoding.GetChars UTF8Encoding.GetString(Byte[], Int32, Int32) TypeDescriptionProviderAttribute moved to another assembly The TypeDescriptionProviderAttribute class has been moved. Change description In .NET Core 2.2 and earlier versions, The TypeDescriptionProviderAttribute class is found in the System.ComponentModel.TypeConverter assembly. Starting with .NET Core 3.0, it is found in the System.ObjectModel assembly. Version introduced 3.0 Recommended action This change only affects applications that use reflection to load the TypeDescriptionProviderAttribute type by calling a method such as Assembly.GetType or an overload of Activator.CreateInstance that assumes the type is in a particular assembly. If that is the case, the assembly referenced in the method call should be updated to reflect the type's new assembly location. Category Windows Forms Affected APIs None. ZipArchiveEntry no longer handles archives with inconsistent entry sizes Zip archives list both compressed size and uncompressed size in the central directory and local header. The entry data itself also indicates its size. In .NET Core 2.2 and earlier versions, these values were never checked for consistency. Starting with .NET Core 3.0, they now are. Change description In .NET Core 2.2 and earlier versions, ZipArchiveEntry.Open() succeeds even if the local header disagrees with the central header of the zip file. Data is decompressed until the end of the compressed stream is reached, even if its length exceeds the uncompressed file size listed in the central directory/local header. Starting with .NET Core 3.0, the ZipArchiveEntry.Open() method checks that local header and central header agree on compressed and uncompressed sizes of an entry. If they do not, the method throws an InvalidDataException if the archive's local header and/or data descriptor list sizes that disagree with the central directory of the zip file. When reading an entry, decompressed data is truncated to the uncompressed file size listed in the header. This change was made to ensure that a ZipArchiveEntry correctly represents the size of its data and that only that amount of data is read. Version introduced 3.0 Recommended action Repackage any zip archive that exhibits these problems. Category Core .NET libraries Affected APIs ZipArchiveEntry.Open() ZipFileExtensions.ExtractToDirectory ZipFileExtensions.ExtractToFile ZipFile.ExtractToDirectory FieldInfo.SetValue throws exception for static, init-only fields Starting in .NET Core 3.0, an exception is thrown when you attempt to set a value on a static, InitOnly field by calling System.Reflection.FieldInfo.SetValue. Change description In .NET Framework and versions of .NET Core prior to 3.0, you could set the value of a static field that's constant after it is initialized (readonly in C#) by calling System.Reflection.FieldInfo.SetValue. However, setting such a field in this way resulted in unpredictable behavior based on the target framework and optimization settings. In .NET Core 3.0 and later versions, when you call SetValue on a static, InitOnly field, a System.FieldAccessException exception is thrown. Tip An InitOnly field is one that can only be set at the time it's declared or in the constructor for the containing class. In other words, it's constant after it is initialized. Version introduced 3.0 Recommended action Initialize static, InitOnly fields in a static constructor. This applies to both dynamic and non-dynamic types. Alternatively, you can remove the FieldAttributes.InitOnly attribute from the field, and then call FieldInfo.SetValue. Category Core .NET libraries Affected APIs FieldInfo.SetValue(Object, Object) FieldInfo.SetValue(Object, Object, BindingFlags, Binder, CultureInfo) Passing GroupCollection to extension methods taking IEnumerable<T> requires disambiguation When calling an extension method that takes an IEnumerable<T> on a GroupCollection, you must disambiguate the type using a cast. Change description Starting in .NET Core 3.0, System.Text.RegularExpressions.GroupCollection implements IEnumerable<KeyValuePair<String,Group>> in addition to the other types it implements, including IEnumerable<Group> . This results in ambiguity when calling an extension method that takes an IEnumerable<T>. If you call such an extension method on a GroupCollection instance, for example, Enumerable.Count, you'll see the following compiler error: CS1061: 'GroupCollection' does not contain a definition for 'Count' and no accessible extension method 'Count' accepting a first argument of type 'GroupCollection' could be found (are you missing a using directive or an assembly reference?) In previous versions of .NET, there was no ambiguity and no compiler error. Version introduced 3.0 Reason for change This was an unintentional breaking change . Because it has been like this for some time, we don't plan to revert it. In addition, such a change would itself be breaking. Recommended action For GroupCollection instances, disambiguate calls to extension methods that accept an IEnumerable<T> with a cast. C# // Without a cast - causes CS1061. match.Groups.Count(_ => true) // With a disambiguating cast. ((IEnumerable<Group>)m.Groups).Count(_ => true); Category Core .NET libraries Affected APIs Any extension method that accepts an IEnumerable<T> is affected. For example: System.Collections.Immutable.ImmutableArray.ToImmutableArray<TSource> (IEnumerable<TSource>) System.Collections.Immutable.ImmutableDictionary.ToImmutableDictionary System.Collections.Immutable.ImmutableHashSet.ToImmutableHashSet System.Collections.Immutable.ImmutableList.ToImmutableList<TSource> (IEnumerable<TSource>) System.Collections.Immutable.ImmutableSortedDictionary.ToImmutableSortedDicti onary System.Collections.Immutable.ImmutableSortedSet.ToImmutableSortedSet System.Data.DataTableExtensions.CopyToDataTable Most of the System.Linq.Enumerable methods, for example, System.Linq.Enumerable.Count System.Linq.ParallelEnumerable.AsParallel System.Linq.Queryable.AsQueryable Cryptography BEGIN TRUSTED CERTIFICATE syntax no longer supported on Linux EnvelopedCms defaults to AES-256 encryption Minimum size for RSAOpenSsl key generation has increased .NET Core 3.0 prefers OpenSSL 1.1.x to OpenSSL 1.0.x CryptoStream.Dispose transforms final block only when writing "BEGIN TRUSTED CERTIFICATE" syntax no longer supported for root certificates on Linux Root certificates on Linux and other Unix-like systems (but not macOS) can be presented in two forms: the standard BEGIN CERTIFICATE PEM header, and the OpenSSL-specific BEGIN TRUSTED CERTIFICATE PEM header. The latter syntax allows for additional configuration that has caused compatibility issues with .NET Core's System.Security.Cryptography.X509Certificates.X509Chain class. BEGIN TRUSTED CERTIFICATE root certificate contents are no longer loaded by the chain engine starting in .NET Core 3.0. Change description Previously, both the BEGIN CERTIFICATE and BEGIN TRUSTED CERTIFICATE syntaxes were used to populate the root trust list. If the BEGIN TRUSTED CERTIFICATE syntax was used and additional options were specified in the file, X509Chain may have reported that the chain trust was explicitly disallowed (X509ChainStatusFlags.ExplicitDistrust). However, if the certificate was also specified with the BEGIN CERTIFICATE syntax in a previously loaded file, the chain trust was allowed. Starting in .NET Core 3.0, BEGIN TRUSTED CERTIFICATE contents are no longer read. If the certificate is not also specified via a standard BEGIN CERTIFICATE syntax, the X509Chain reports that the root is not trusted (X509ChainStatusFlags.UntrustedRoot). Version introduced 3.0 Recommended action Most applications are unaffected by this change, but applications that cannot see both root certificate sources because of permissions problems may experience unexpected UntrustedRoot errors after upgrading. Many Linux distributions (or distros) write root certificates into two locations: a onecertificate-per-file directory, and a one-file concatenation. On some distros, the onecertificate-per-file directory uses the BEGIN TRUSTED CERTIFICATE syntax while the file concatenation uses the standard BEGIN CERTIFICATE syntax. Ensure that any custom root certificates are added as BEGIN CERTIFICATE in at least one of these locations, and that both locations can be read by your application. The typical directory is /etc/ssl/certs/ and the typical concatenated file is /etc/ssl/cert.pem. Use the command openssl version -d to determine the platformspecific root, which may differ from /etc/ssl/. For example, on Ubuntu 18.04, the directory is /usr/lib/ssl/certs/ and