Skip to content
This repository was archived by the owner on Aug 30, 2023. It is now read-only.

Commit d8e6938

Browse files
authored
feat: Returns better version data than default API (#248)
* feat: Returns better version data than default API
1 parent 309a536 commit d8e6938

File tree

7 files changed

+159
-51
lines changed

7 files changed

+159
-51
lines changed

src/app/SharpRaven/Data/Context/Runtime.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ public class Runtime
6262
/// </remarks>
6363
[JsonProperty(PropertyName = "raw_description", NullValueHandling = NullValueHandling.Ignore)]
6464
public string RawDescription { get; set; }
65+
/// <summary>
66+
/// An optional build number
67+
/// </summary>
68+
/// <see href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed"/>
69+
[JsonProperty(PropertyName = "build", NullValueHandling = NullValueHandling.Ignore)]
70+
public string Build { get; set; }
6571

6672
/// <summary>
6773
/// Clones this instance
@@ -73,6 +79,7 @@ internal Runtime Clone()
7379
{
7480
Name = this.Name,
7581
Version = this.Version,
82+
Build = this.Build,
7683
RawDescription = this.RawDescription
7784
};
7885
}
@@ -85,12 +92,7 @@ public static Runtime Create()
8592
{
8693
try
8794
{
88-
var runtime = new Runtime
89-
{
90-
RawDescription = RuntimeInfoHelper.GetRuntimeVersion()
91-
};
92-
93-
return runtime;
95+
return RuntimeInfoHelper.GetRuntime();
9496
}
9597
catch (Exception e)
9698
{
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace SharpRaven.Data.Context
2+
{
3+
internal static class RuntimeExtensions
4+
{
5+
public static bool IsNetFx(this Runtime runtime) => runtime.IsRuntime(".NET Framework");
6+
public static bool IsNetCore(this Runtime runtime) => runtime.IsRuntime(".NET Core");
7+
8+
private static bool IsRuntime(this Runtime runtime, string runtimeName)
9+
{
10+
return runtime?.Name?.StartsWith(runtimeName) == true
11+
|| runtime?.RawDescription?.StartsWith(runtimeName) == true;
12+
}
13+
}
14+
}

src/app/SharpRaven/SharpRaven.csproj

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,37 @@
2121

2222
<Import Project="..\..\CommonConfigurations.targets" />
2323

24-
<ItemGroup Condition="'$(TargetFramework)' == 'net35' or '$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
24+
<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
2525
<Reference Include="System" />
26+
<Reference Include="System.Web" />
2627
<Reference Include="System.Configuration" />
2728
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
2829
</ItemGroup>
29-
30-
<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
31-
<Reference Include="System.Web" />
32-
</ItemGroup>
33-
34-
<ItemGroup Condition="'$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
30+
<PropertyGroup Condition="'$(TargetFramework)' == 'net35'">
31+
<DefineConstants>NETFX;$(AdditionalConstants)</DefineConstants>
32+
</PropertyGroup>
33+
34+
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
35+
<Reference Include="System" />
36+
<Reference Include="System.Configuration" />
3537
<Reference Include="Microsoft.CSharp" />
38+
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
3639
</ItemGroup>
37-
40+
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
41+
<DefineConstants>NETFX;$(AdditionalConstants)</DefineConstants>
42+
</PropertyGroup>
43+
3844
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
45+
<Reference Include="System" />
46+
<Reference Include="System.Configuration" />
47+
<Reference Include="Microsoft.CSharp" />
3948
<Reference Include="System.Net.Http" />
49+
<Reference Include="Microsoft.CSharp" />
50+
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
4051
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
4152
</ItemGroup>
4253
<PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
43-
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
54+
<DefineConstants>NETFX;HAS_RUNTIME_INFORMATION;NET45PLUS_REGISTRY_VERSION;$(AdditionalConstants)</DefineConstants>
4455
</PropertyGroup>
4556

4657
<ItemGroup Condition="'$(TargetFramework)' == 'net471'">
@@ -51,7 +62,7 @@
5162
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
5263
</ItemGroup>
5364
<PropertyGroup Condition="'$(TargetFramework)' == 'net471'">
54-
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
65+
<DefineConstants>NETFX;HAS_RUNTIME_INFORMATION;NET45PLUS_REGISTRY_VERSION;$(AdditionalConstants)</DefineConstants>
5566
</PropertyGroup>
5667

5768
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,98 @@
11
using System;
22
using System.Reflection;
3+
4+
using SharpRaven.Data.Context;
35
#if HAS_RUNTIME_INFORMATION
46
using System.Runtime.InteropServices;
57
#endif
8+
#if NET45PLUS_REGISTRY_VERSION
9+
using Microsoft.Win32;
10+
#endif
611

712
namespace SharpRaven.Utilities
813
{
914
internal static class RuntimeInfoHelper
1015
{
11-
public static string GetRuntimeVersion()
16+
public static Runtime GetRuntime()
1217
{
13-
#if HAS_RUNTIME_INFORMATION
18+
#if HAS_RUNTIME_INFORMATION // .NET Core 2+, .NET Framework 4.5+
1419
// Prefered API: netstandard2.0 and vNext
1520
// https://github.com/dotnet/corefx/blob/master/src/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.cs
1621
// e.g: .NET Framework 4.7.2633.0, .NET Native, WebAssembly
17-
var version = RuntimeInformation.FrameworkDescription;
22+
var runtime = new Runtime
23+
{
24+
RawDescription = RuntimeInformation.FrameworkDescription
25+
};
1826
#else
19-
var mono = GetFromMono();
20-
var version = mono
27+
var runtime = GetFromMono();
28+
runtime = runtime
2129
// Environment.Version: NET Framework 4, 4.5, 4.5.1, 4.5.2 = 4.0.30319.xxxxx
2230
// .NET Framework 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1 = 4.0.30319.42000
2331
// Not recommended on NET45+
24-
?? $".NET Framework {Environment.Version}";
32+
?? new Runtime
33+
{
34+
Name = ".NET Framework",
35+
Version = Environment.Version.ToString()
36+
};
37+
#endif
38+
39+
#if NET45PLUS_REGISTRY_VERSION // .NET Framework 4.5 and later
40+
if (runtime.IsNetFx())
41+
{
42+
runtime.Build = Get45PlusLatestInstallationFromRegistry()?.ToString();
43+
}
44+
#endif
45+
46+
#if !NETFX // Non .NET Framework (i.e: netstandard, netcoreapp)
47+
if (runtime.IsNetCore())
48+
{
49+
// RuntimeInformation.FrameworkDescription returns 4.6 on .NET Core 2.0 which is counter intuitive
50+
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
51+
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
52+
var netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
53+
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
54+
{
55+
runtime.Name = ".NET Core";
56+
runtime.Version = assemblyPath[netCoreAppIndex + 1];
57+
}
58+
}
2559
#endif
26-
return version;
60+
return runtime;
2761
}
2862

29-
private static string GetFromMono()
63+
private static Runtime GetFromMono()
3064
{
3165
// The implementation of Mono to RuntimeInformation:
3266
// https://github.com/mono/mono/blob/90b49aa3aebb594e0409341f9dca63b74f9df52e/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs
33-
// e.g; Mono 5.10.0 (Visual Studio built mono)
34-
var monoVersion = Type.GetType("Mono.Runtime", false)
35-
?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static)
36-
?.Invoke(null, null) as string;
37-
38-
if (monoVersion != null)
67+
if (Type.GetType("Mono.Runtime", false)
68+
?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static)
69+
?.Invoke(null, null) is string monoVersion)
3970
{
40-
monoVersion = "Mono " + monoVersion;
71+
return new Runtime
72+
{
73+
// Send complete (raw) and let Sentry parse it. UI can display short version but details are not lost
74+
// e.g; Mono 5.10.0 (Visual Studio built mono)
75+
// e.g: Mono 5.10.1.47 (tarball Tue Apr 17 09:23:16 UTC 2018)
76+
RawDescription = "Mono " + monoVersion
77+
};
4178
}
4279

43-
return monoVersion;
80+
return null;
81+
}
82+
83+
#if NET45PLUS_REGISTRY_VERSION
84+
// https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed#to-find-net-framework-versions-by-querying-the-registry-in-code-net-framework-45-and-later
85+
private static int? Get45PlusLatestInstallationFromRegistry()
86+
{
87+
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
88+
89+
using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
90+
{
91+
return int.TryParse(ndpKey?.GetValue("Release")?.ToString(), out var releaseId)
92+
? releaseId
93+
: (int?)null;
94+
}
4495
}
96+
#endif
4597
}
4698
}

src/tests/SharpRaven.UnitTests/Data/Context/RuntimeTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ namespace SharpRaven.UnitTests.Data.Context
1010
public class RuntimeTests
1111
{
1212
[Test]
13-
public void Create_RawDescription_NotNullAndAsHelper()
13+
public void Create_Runtime_NotNullAndAsHelper()
1414
{
15-
var runtime = Runtime.Create();
15+
var actual = Runtime.Create();
1616

17-
var expected = RuntimeInfoHelper.GetRuntimeVersion();
18-
Assert.NotNull(runtime.RawDescription);
19-
Assert.AreEqual(expected, runtime.RawDescription);
17+
var expected = RuntimeInfoHelper.GetRuntime();
18+
Assert.NotNull(actual);
19+
Assert.AreEqual(expected.Build, actual.Build);
20+
Assert.AreEqual(expected.Version, actual.Version);
21+
Assert.AreEqual(expected.Name, actual.Name);
22+
Assert.AreEqual(expected.RawDescription, actual.RawDescription);
2023
}
2124

2225
[Test]

src/tests/SharpRaven.UnitTests/SharpRaven.UnitTests.csproj

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,44 @@
1212
<ProjectReference Include="..\..\app\SharpRaven\SharpRaven.csproj" />
1313
</ItemGroup>
1414

15+
<ItemGroup>
16+
<PackageReference Include="NSubstitute" Version="1.8.0.0" />
17+
<PackageReference Include="NUnit" Version="2.6.4" />
18+
</ItemGroup>
19+
1520
<ItemGroup Condition="'$(TargetFramework)' == 'net471'">
1621
<Reference Include="System.Web" />
1722
<Reference Include="System.Configuration" />
1823
<Reference Include="Microsoft.CSharp" />
24+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
1925
</ItemGroup>
26+
<PropertyGroup Condition="'$(TargetFramework)' == 'net471'">
27+
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
28+
</PropertyGroup>
2029

21-
<ItemGroup Condition="'$(TargetFramework)' == 'net35' or '$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
30+
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
2231
<Reference Include="System" />
2332
<Reference Include="System.Web" />
24-
</ItemGroup>
25-
26-
<ItemGroup Condition="'$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
2733
<Reference Include="Microsoft.CSharp" />
2834
<Reference Include="Microsoft.VisualBasic" />
29-
</ItemGroup>
30-
31-
<ItemGroup Condition="'$(TargetFramework)' != 'net35' and '$(TargetFramework)' != 'net40'">
3235
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
3336
</ItemGroup>
34-
35-
<ItemGroup>
36-
<PackageReference Include="NSubstitute" Version="1.8.0.0" />
37-
<PackageReference Include="NUnit" Version="2.6.4" />
38-
</ItemGroup>
39-
40-
<PropertyGroup Condition="'$(TargetFramework)' == 'net471' OR '$(TargetFramework)' == 'net45'">
37+
<PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
4138
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
4239
</PropertyGroup>
4340

41+
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
42+
<Reference Include="System" />
43+
<Reference Include="System.Web" />
44+
<Reference Include="Microsoft.CSharp" />
45+
<Reference Include="Microsoft.VisualBasic" />
46+
</ItemGroup>
47+
48+
<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
49+
<Reference Include="System" />
50+
<Reference Include="System.Web" />
51+
</ItemGroup>
52+
4453
<ItemGroup>
4554
<Compile Include="..\..\CommonAssemblyInfo.cs" Link="Properties\CommonAssemblyInfo.cs" />
4655
<EmbeddedResource Include="schema.json" />
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
using NUnit.Framework;
4+
using SharpRaven.Utilities;
5+
6+
namespace SharpRaven.UnitTests.Utilities
7+
{
8+
public class RuntimeInfoHelperTests
9+
{
10+
[Test]
11+
public void GetRuntime_NotNull()
12+
{
13+
var runtime = RuntimeInfoHelper.GetRuntime();
14+
Assert.That(runtime, Is.Not.Null);
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)