Introduction
A great way for a developer to expand their knowledge is by creating side projects, which can turn out to be useful applications or code that can be used in another project.
The incentive for this project came from a Stackoverflow question.
Is there a way to check for a C# .NET application to check if the used .NET version is still supported?
Working on a solution
💡 If a developer decides to use AI to assist with the solution, try to keep its use to a minimum to support learning.
In the Stackoverflow question, there is a URL in the comments that returns JSON for each .NET Core version.
Each property has a lower-case property name, along with commas in most of the properties. In the class representing information JsonPropertyNameAttribute provides a way to map a property to be used to store information.
[JsonPropertyName("support-phase")]
public string? SupportPhase { get; set; }
Complete class for storing data found here.
Next, a method is needed to read data back, which may need some research, or a developer might use AI to write the method.
public static class DotNetReleaseService
{
private static readonly HttpClient _httpClient = new();
public static async Task<List<ReleaseIndexItem>> GetReleaseIndexAsync(CancellationToken cancellationToken = default)
{
const string url = "https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json";
using HttpResponseMessage response = await _httpClient.GetAsync(url, cancellationToken);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
var root = await JsonSerializer.DeserializeAsync<ReleasesIndexRoot>(
stream,
Options,
cancellationToken);
return root?.ReleasesIndex ?? [];
}
public static JsonSerializerOptions Options => new() { PropertyNameCaseInsensitive = true };
}
Possible enhancements: wrap code that may fail in a try/catch and a CancellationToken.
The code above shows how to return details of frameworks, and the code below shows how to determine whether the current project framework is not considered end of life.
public static class FrameworkUtilities
{
public static Version? GetTargetFrameworkVersion(this Assembly assembly)
{
var framework = assembly.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
if (string.IsNullOrWhiteSpace(framework))
return null;
// Common format: ".NETCoreApp,Version=v9.0"
const string marker = "Version=v";
var id = framework.IndexOf(marker, StringComparison.OrdinalIgnoreCase);
if (id >= 0)
{
var versionText = framework[(id + marker.Length)..].Trim();
var comma = versionText.IndexOf(',');
if (comma >= 0) versionText = versionText[..comma];
return Version.TryParse(versionText, out var v) ? v : null;
}
// Alternate format some devs may see: ".NET 9.0"
var lastSpace = framework.LastIndexOf(' ');
if (lastSpace < 0 || lastSpace + 1 >= framework.Length) return Version.TryParse(framework, out var direct) ? direct : null;
{
var versionText = framework[(lastSpace + 1)..].Trim();
return Version.TryParse(versionText, out var v) ? v : null;
}
}
public static string IsProjectFramework(string sender)
{
if (string.IsNullOrWhiteSpace(sender))
{
return sender;
}
var frameworkVersion = FrameworkVersion();
var currentFramework = frameworkVersion?.ToString();
return string.Equals(sender, currentFramework, StringComparison.OrdinalIgnoreCase)
? $"{sender} :check_mark:"
: $"{sender}";
}
public static async Task<(bool found, bool isActive)> ProjectFrameworkActive()
{
var frameworkVersion = FrameworkVersion();
var currentFramework = frameworkVersion?.ToString();
var current = (await DotNetReleaseService.GetReleaseIndexAsync()).FirstOrDefault(x => x.ChannelVersion == currentFramework);
if (current is not null)
{
return (true, current.SupportPhase.Contains("active", StringComparison.OrdinalIgnoreCase));
}
else
{
return (false, false);
}
}
private static Version? FrameworkVersion()
{
Assembly? entryAssembly = Assembly.GetEntryAssembly();
Version? frameworkVersion = entryAssembly?.GetTargetFrameworkVersion();
return frameworkVersion;
}
}
Usage
internal partial class Program
{
static async Task Main(string[] args)
{
var (found, isActive) = await FrameworkUtilities.ProjectFrameworkActive();
if (found)
{
Console.WriteLine($"Project framework is {(isActive ? "active" : "not active")}.");
}
else
{
Console.WriteLine("Project framework not found.");
}
}
}
Summary
An idea has been presented to expand a developer’s knowledge, along with possible use in an application. The source code provided goes past usage to what has been presented. Rather than simply using the provided code, take time to understand the code and consider the following.
- Adding exception handling which includes logging errors to a log file.
- Creating a class project so the code can be used in other projects
- Create a NuGet package on NuGet or local source.

Top comments (0)