The upcoming release of .NET 5 introduces many breaking changes. While the vast majority of them involve edge cases or previously incorrect behavior, some may take developers by surprise. In the first of this multi-part series, InfoQ looks at the Base Class Library.
.NET Version Information
It may seem foolish, but a lot of developers have a bad habit of looking at the string representation of the version instead of the numeric form. This led to the infamous “Windows 9” story where Microsoft skipped from Windows 8 to Windows 10 to avoid problems in applications that were looking for Windows 95/98.
In the case of .NET, developers weren’t given a choice. Due in part to the odd numbering scheme, they had to rely on the string representation, looking for “.NET Framework #.#” or “.NET Core #.#”.
With .NET 5, the moniker is now simply “.NET #.#”. Applications and libraries that depend on detecting the runtime version will need to be updated.
OS Version Information
Previously, Environment.OSVersion could lie to the application. Rather than returning the actual OS version, it would return the emulated OS based on the Windows compatibility mode setting for the application. Microsoft explains,
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.
File Location for Bundled Applications
When an application is bundled into a single file along with its dependencies, the behavior of some Reflection APIs are no longer obvious. Previously, bundled applications would have their dependencies extracted into a temporary location, so the Reflection calls would reference this. With .NET 5, those dependencies are loaded directly from memory. This means there is no physical Assembly file to reference. As such, the following APIs needed to be altered. Below are the new behaviors.
Assembly.Location
: Returns empty string for bundled assembliesAssembly.CodeBase
: Throws exception for bundled assembliesAssembly.GetFile(String)
: Throws exception for bundled assembliesEnvironment.GetCommandLineArgs()[0]
: Value is the name of the host executableAppContext.BaseDirectory
: Value is the containing directory of the host executable
Logging
The following ConsoleLoggerOptions
have been marked as obsolete. They are replaced with one of several subclasses of ConsoleFormatterOptions
.
ConsoleLoggerOptions.DisableColors
ConsoleLoggerOptions.IncludeScopes
ConsoleLoggerOptions.TimestampFormat
ConsoleLoggerOptions.UseUtcTimestamp
ConsoleLoggerOptions.Format
BinaryFormatter Serialization is Blocked
The BinaryFormatter for .NET’s serialization library has been around since the very beginning. The intention was for it to be faster and more compact than the XML-based SoapFormatter
, which was shipped at the same time.
Unfortunately, it suffers from several problems, the most significant being it is impossible to use safely. Warnings from the BinaryFormatter
security guide Microsoft include,
The
BinaryFormatter.Deserialize
method is never safe when used with untrusted input. We strongly recommend that consumers instead consider using one of the alternatives outlined later in this article.
and
We recommend that
BinaryFormatter
consumers perform individual risk assessments on their apps. It is the consumer's sole responsibility to determine whether to utilizeBinaryFormatter
. Consumers should risk assess the security, technical, reputation, legal, and regulatory requirements of usingBinaryFormatter
.
This is not the only serialization library that Microsoft considers unsafe. The following, while not as dangerous, should still be avoided because they are suspectable to unrestricted polymorphic deserialization.
SoapFormatter
LosFormatter
NetDataContractSerializer
ObjectStateFormatter
In .NET 5, BinaryFormatter
is disabled by default in ASP.NET applications and produces a compiler warning for all other application frameworks. If you must use BinaryFormatter
in a web site, you can reenable it via the EnableUnsafeBinaryFormatterSerialization
flag.
UTF-7 is Blocked
Another blocked technology is UTF-7. This format is already forbidden in many standards such as HTML5. It is forbidden because it is easy to slip malicious strings into an application by tricking part of the application into thinking the data is in UTF-8 format while other parts correctly treat it as UTF-7.
Wikipedia elaborates,
UTF-7 allows multiple representations of the same source string. In particular, ASCII characters can be represented as part of Unicode blocks. As such, if standard ASCII-based escaping or validation processes are used on strings that may be later interpreted as UTF-7, then Unicode blocks may be used to slip malicious strings past them. To mitigate this problem, systems should perform decoding before validation and should avoid attempting to autodetect UTF-7.
Older versions of Internet Explorer can be tricked into interpreting the page as UTF-7. This can be used for a cross-site scripting attack as the < and > marks can be encoded as +ADw- and +AD4- in UTF-7, which most validators let through as simple text.
If needed for processing legacy data, UTF-7 can be enabled using the EnableUnsafeUTF7Encoding
flag.
Microsoft.DotNet.PlatformAbstractions Package Deprecated
While technically not a breaking change, developers are strongly encouraged to stop using Microsoft.DotNet.PlatformAbstractions to detect information about the operating system. This library won’t be updated in the future and will become less accurate over time.
The following shows the deprecated methods and their replacements.
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
In part 2 of this series, we’ll look at the breaking changes that relate to some of .NET’s historical technologies.