7

My .NET Core 3.0 app is published for different operating systems, using the commands dotnet publish -r win10-x64 or dotnet publish -r ubuntu.18.04-x64 for example.

During runtime, in my C# code I want to find out the target the app was built for. I do not mean just the general operating system like Windows or Linux (as asked here), but the exact runtime target, like ubuntu-18.04-x64.

I already found out, that there is a file <AssemblyName>.deps.json. It contains the property "runtimeTarget": { "name": ".NETCoreApp,Version=v3.0/ubuntu.18.04-x64", ..., but maybe there is a better way?

Andi
  • 3,234
  • 4
  • 32
  • 37
  • 2
    You specifically need the entire runtime identifier? You wouldn't be able to get the information you need from any of the other [`RuntimeInformation` class](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.runtimeinformation?view=netcore-3.0) members? – Joe Sewell Oct 24 '19 at 16:03
  • 1
    Yes, I need the whole identifier. For example, `RuntimeInformation.OSDescription` = `Microsoft Windows 10.0.17763` and `RuntimeInformation.OSArchitecture` = `X64`, and I see no reliable and future-proof way to reconstruct the `win10-x64` runtime platform from these values. – Andi Oct 25 '19 at 09:23

2 Answers2

3

I am using the code given below with .Net core version 2 (and 1.2 in the past) -

    public static void PrintTargetRuntime()
    {
            var framework = Assembly
                    .GetEntryAssembly()?
                    .GetCustomAttribute<TargetFrameworkAttribute>()?
                    .FrameworkName;

            var stats = new
        {
            OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription,
            OSArchitecture = System.Runtime.InteropServices.RuntimeInformation.OSArchitecture,
            ProcesArchitecture = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture,
            FrameworkDescription = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription,
            AspDotnetVersion = framework
        };

        Console.WriteLine("Framework version is " + framework);
        Console.WriteLine("OS Platform is : " + stats.OsPlatform );
        Console.WriteLine("OS Architecture is : " + stats.OSArchitecture);
        Console.WriteLine("Framework description is " + stats.FrameworkDescription);
        Console.WriteLine("ASPDotNetVersion is " + stats.AspDotnetVersion);

        if (stats.ProcesArchitecture == Architecture.Arm)
        {
            Console.WriteLine("ARM process.");
        }
        else if (stats.ProcesArchitecture == Architecture.Arm64)
        {
            Console.WriteLine("ARM64 process.");
        }
        else if (stats.ProcesArchitecture == Architecture.X64)
        {
            Console.WriteLine("X64 process.");
        }
        else if (stats.ProcesArchitecture == Architecture.X86)
        {
            Console.WriteLine("x86 process.");
        }
    }

I have tested this on Windows 10 and MacOS Mojave. This comes from here - https://weblog.west-wind.com/posts/2018/Apr/12/Getting-the-NET-Core-Runtime-Version-in-a-Running-Application

On my windows machine the output looks as below - Image displaying version output of code above

Amogh Sarpotdar
  • 544
  • 4
  • 15
  • I can only find the value `.NETCoreApp,Version=v3.0` there, but what I need is something like `win10-x64` or `ubuntu.18.04-x64`. – Andi Oct 25 '19 at 09:28
  • Check the stats.OSPlatform contents, it prints the OS version there. Updating picture in answer above. – Amogh Sarpotdar Oct 25 '19 at 09:40
  • 2
    See my comments above under the questions. `RuntimeInformation` does not help me: I need the whole identifier. For example, `RuntimeInformation.OSDescription` = `Microsoft Windows 10.0.17763` and `RuntimeInformation.OSArchitecture` = `X64`, and I see no reliable and future-proof way to reconstruct the `win10-x64` runtime platform from these values. – Andi Oct 25 '19 at 09:53
  • 1
    Apologies, I got what you are looking for but a bit late. What you are talking about is an RID (https://learn.microsoft.com/en-us/dotnet/core/rid-catalog) but that is same as the information that is being extracted from RuntimeInformation class. In fact, as per the documentation, published RIDs are specific to your project file and not the binary/process that you run. – Amogh Sarpotdar Oct 25 '19 at 10:19
  • This was amazingly helpful and saved me from having to ask the question myself. For future searchers: "C# Determining .NET runtime name" – MisterNad Nov 29 '19 at 21:54
0

Since I found no other way, I am using the value found in the .deps.json file. Here is my code:

using Newtonsoft.Json.Linq;
using System;
using System.IO;

/// <summary>
/// Returns the current RID (Runtime IDentifier) where this applications runs.
/// See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog for possible values, e.g. "ubuntu.18.04-x64".
/// The value is read from the first found .deps.json file in the application folder, at the path
/// "runtimeTarget"/"name" the value behind the last "/".
/// When the file or the value behind the last "/" is missing, this application folder was not compiled
/// for a specific runtime, and null is returned.
/// </summary>
public static string? GetRuntimeIdentifier() {
    try {
        // Find first (and probably only) .deps.json file in the application's folder.
        var dir = AppDomain.CurrentDomain.BaseDirectory;
        var files = Directory.GetFiles(dir, "*.deps.json");
        if (files.Length == 0)
            return null;
        // Read JSON content
        var json = JObject.Parse(File.ReadAllText(Path.Combine(dir, files[0])));
        var name = json["runtimeTarget"]["name"].ToString();
        // Read RID after slash
        var slashPos = name.LastIndexOf('/');
        if (slashPos == -1)
            return null;
        return name.Substring(slashPos + 1);
    }
    catch {
        // Unexpected file format or other problem
        return null;
    }
}
Andi
  • 3,234
  • 4
  • 32
  • 37