惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
GbyAI
GbyAI
aimingoo的专栏
aimingoo的专栏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence
腾讯CDC
博客园 - Franky
Engineering at Meta
Engineering at Meta
C
Check Point Blog
T
The Blog of Author Tim Ferriss
有赞技术团队
有赞技术团队
Microsoft Azure Blog
Microsoft Azure Blog
MyScale Blog
MyScale Blog
I
InfoQ
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
N
Netflix TechBlog - Medium
Last Week in AI
Last Week in AI
S
SegmentFault 最新的问题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
WordPress大学
WordPress大学

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
dotnet Framework life cycle tool
Karen Payne · 2026-05-26 · via 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.