We take many environmental factors for granted when it comes to running our .NET applications. Information about the operating system may seem insignificant for folks deploying to rigorously maintained target environments. Still, for folks who publish desktop client software, the luxury of choosing the destination is not an option. This post will be using .NET to determine the operating system and architecture our .NET application is currently running within. We’ll also resolve the SDK version our app is utilizing. Finally, we’ll run our .NET code under three different operating systems to see the results: macOS, Windows, and Linux.
Why Does It Matter?
Most of the .NET Base Class Libraries (BCL) operate agnostically to the system they execute within. Some APIs delegate responsibility to the underlying operating system and utilize environment-specific implementations. Examples include interfaces for Linux, the
FileSystemWatcher class, and cryptography. We only need to search the
dotnet/runtime repository for “Linux” and see all the operating system mentions.
Understanding that behavior may be different depending on the target environment can save hours of debugging and frustration. The variance in behavior may also make us consider whether we want to try deploying to different target operating systems. We may not realize that high-level frameworks like ASP.NET Core depend on these low-level behaviors, so we can’t be entirely agnostic.
.NET has a particular namespace that contains many helper classes for folks interested in revealing information about an app’s current environment; that namespace is
System.Runtime.InteropServices. Under the
System.Runtime.InteropServices namespace, we see two especially helpful classes:
RuntimeInformation, we can see information about our current operating system and machine. We have the following static properties.
string FrameworkDescription; Architecture ProcessArchitecture; string RuntimeIdentifier; Architecture OSArchitecture; string OSDescription;
We also have access to a method of
IsOSPlatform, which takes an enum parameter of type
Our next class,
RunTimeEnvironment, where we have access to the following methods:
string GetRuntimeDirectory(); string GetSystemVersion(); bool FromGlobalAccessCache(); object GetRuntimeInterfaceAsObject(); IntPtr GetRuntimeInterfaceAsIntPtr();
We also have a
string property of
SystemConfigurationFile. The support for this property is unavailable by most newer implementations of .NET and is likely still here for legacy support.
Let’s write an example using top-level statements that will give us an idea of our runtime environment.
using System.Runtime.InteropServices; using static System.Console; Clear(); WriteLine(RuntimeInformation.FrameworkDescription); WriteLine(RuntimeInformation.OSDescription); WriteLine(RuntimeInformation.OSArchitecture); WriteLine(RuntimeEnvironment.GetRuntimeDirectory());
Let’s run these in three different environments and see what we get!
Let’s start with macOS, my native development environment.
As we can see, the output is reflective of the host environment.
.NET 5.0.0-rc.1.20451.14 Darwin 19.6.0 Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-6153.141.2~1/RELEASE_X86_64 X64 /usr/local/share/dotnet/shared/Microsoft.NETCore.App/5.0.0-rc.1.20451.14/
Let’s move onto Windows.
Running the same code on Windows yields different Windows-specific results.
With the results in the console being:
.NET 5.0.0-rc.1.20451.14 Microsoft Windows 10.0.19041 X64 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.0-rc.1.20451.14\
Finally, let’s run the same code under Linux.
.NET 5.0.0-rc.1.20451.14 Linux 5.4.0-42-generic #46~18.04.1-Ubuntu SMP Fri Jul 10 07:21:24 UTC 2020 X64 /usr/share/dotnet/shared/Microsoft.NETCore.App/5.0.0-rc.1.20451.14/
If we’re writing code that needs to ship to multiple environments, the
System.Runtime.InteropServices is invaluable. An implementation may differ for each OS, and using these helper runtime features can help us branch and handle strange edge cases. I hope you found this post helpful. Please leave a comment below if you’ve had to use either
RunTimeEnvironment in your codebase.