VOOZH about

URL: https://dev.to/karenpayneoregon/dotnet-framework-life-cycle-tool-103d

⇱ dotnet Framework life cycle tool - DEV Community


Introduction

Learn how to create a dotnet Global Tool that lists all NET Core Frameworks with release and end-of-life information.

💡 For my other article on creating various dotnet tools see
C# .NET Tools with System.CommandLine.

This tool is extremely simple: unlike most tools, there are no required arguments or help; the code reads information from the following URL and displays it.

👁 SCREENSHOT

Main code

Core Source code

Located in CommonLibrary project

using CommonLibrary.Models;
using System.Text.Json;

namespace CommonLibrary;

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 };
}


public sealed class ReleaseIndexItem
{
 [JsonPropertyName("channel-version")]
 public string? ChannelVersion { get; set; }

 [JsonPropertyName("latest-release")]
 public string? LatestRelease { get; set; }

 [JsonPropertyName("latest-release-date")]
 public DateTime? LatestReleaseDate { get; set; }

 [JsonPropertyName("security")]
 public bool Security { get; set; }

 [JsonPropertyName("latest-runtime")]
 public string? LatestRuntime { get; set; }

 [JsonPropertyName("latest-sdk")]
 public string? LatestSdk { get; set; }

 [JsonPropertyName("product")]
 public string? Product { get; set; }

 /// <summary>
 /// Gets or sets the support phase of the release.
 /// </summary>
 /// <remarks>
 /// The support phase indicates the current lifecycle stage of the release, 
 /// such as "active", "preview", or "eol" (end of life).
 /// </remarks>
 [JsonPropertyName("support-phase")]
 public string? SupportPhase { get; set; }

 [JsonPropertyName("eol-date")]
 public DateTime? EndOfLifeDate { get; set; }

 [JsonPropertyName("release-type")]
 public string? ReleaseType { get; set; }

 [JsonPropertyName("releases.json")]
 public string? ReleasesJsonUrl { get; set; }
}


public sealed class ReleasesIndexRoot
{
 [JsonPropertyName("releases-index")]
 public List<ReleaseIndexItem>? ReleasesIndex { get; set; }

Entry point code

Source code

using CommonLibrary;
using Spectre.Console;
using SpectreConsoleLibrary.Core;
using System.CommandLine;

namespace FrameworkLifeCycle;

internal partial class Program
{
 static async Task Main(string[] args)
 {
 RootCommand rootCommand = new("Get dotnet framework life cycles");

 var releases = await DotNetReleaseService.GetReleaseIndexAsync();

 SpectreConsoleHelpers.InfoPill(Justify.Left, $"Found {releases.Count} releases.");
 Console.WriteLine();

 var table = new Table().Title("[bold blue] .NET Release Information [/]");
 table.AddColumn(new TableColumn("[bold yellow]Channel[/]"));
 table.AddColumn(new TableColumn("[bold yellow]Latest[/]"));
 table.AddColumn(new TableColumn("[bold yellow]ReleaseType[/]"));
 table.AddColumn(new TableColumn("[bold yellow]End Of Life Date[/]"));
 table.AddColumn(new TableColumn("[bold yellow]Support[/]"));

 foreach (var item in releases)
 {

 var eolText = item.EndOfLifeDate.HasValue
 ? item.EndOfLifeDate.Value.ToString("MM/dd/yyyy")
 : "Not set";

 var releaseType = item.ReleaseType ?? "Unknown";
 if (releaseType != "Unknown")
 {
 releaseType = releaseType.ToUpper();
 }

 table.AddRow(
 FrameworkUtilities.IsProjectFramework(item.ChannelVersion ?? ""),
 item.LatestRelease ?? "",
 releaseType,
 eolText,
 Colorize(item.SupportPhase ?? "Unknown"));
 }

 AnsiConsole.Write(table);
 Console.WriteLine();

 }

 private static string Colorize(string input) =>
 input switch
 {
 { } s when s.Contains("active", StringComparison.OrdinalIgnoreCase) => "[green]Active[/]",
 { } s when s.Contains("eol", StringComparison.OrdinalIgnoreCase) => "[red]eol[/]",
 { } s when s.Contains("preview", StringComparison.OrdinalIgnoreCase) => "[yellow]preview[/]",
 _ => input,
 };
}

Project file

<PropertyGroup>
 <OutputType>Exe</OutputType>
 <TargetFramework>net10.0</TargetFramework>
 <ImplicitUsings>enable</ImplicitUsings>
 <Nullable>enable</Nullable>
 <PackAsTool>true</PackAsTool>
 <ToolCommandName>flc</ToolCommandName>
 <PackageOutputPath>./nupkg</PackageOutputPath>
 <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
 <Version>1.0.0</Version>
</PropertyGroup>
  • PackAsTool Indicate this as a dotnet tool
  • ToolCommandName the command to run as at the command line
  • PackageOutputPath Path to binaries

Summary

Once installed, typing flc will list all dot net Framework life cycles and for many developers be their first useful donet tool.

💡 For my other article on creating various dotnet tools, see
C# .NET Tools with System.CommandLine, which shows how to work with arguments and provide help.