博客 (39)

以下是 Spectre.Console 的核心功能示例,涵盖最常用的输出和交互场景:


1. 基础富文本输出

image.png

using Spectre.Console;

// 使用 Markup 语法(类似 BBCode)
AnsiConsole.Markup("[bold green]成功![/] 文件已保存。\n");
AnsiConsole.Markup("[red]错误:[/] 无法连接到服务器。\n");

// 混合样式
AnsiConsole.Markup("[underline blue]https://example.com[/]\n");

// 自动换行写
AnsiConsole.Write(new Panel("[yellow]警告[/] 磁盘空间不足")
    .Header("系统通知")
    .Border(BoxBorder.Rounded));


2. 表格

image.png

var table = new Table();
table.AddColumn("[u]ID[/]");
table.AddColumn(new TableColumn("[u]名称[/]").Centered());
table.AddColumn("[u]状态[/]");

table.AddRow("1", "订单服务", "[green]运行中[/]");
table.AddRow("2", "支付网关", "[red]离线[/]");
table.AddRow("3", "消息队列", "[yellow]警告[/]");

AnsiConsole.Write(table);


3. 进度条 / 状态指示

image.pngimage.png

// 带进度条的循环任务
await AnsiConsole.Progress()
    .StartAsync(async ctx =>
    {
        var task1 = ctx.AddTask("[green]下载文件[/]", maxValue: 100);
        var task2 = ctx.AddTask("[green]处理数据[/]", maxValue: 100);

        while (!ctx.IsFinished)
        {
            task1.Increment(1.5);
            task2.Increment(0.8);
            await Task.Delay(50);
        }
    });

// 不确定时长的旋转状态
await AnsiConsole.Status()
    .StartAsync("正在连接...", async ctx =>
    {
        await Task.Delay(3000); // 模拟工作
        AnsiConsole.MarkupLine("[green]连接成功![/]");
    });


4. 交互式提示

image.png

// 确认
if (AnsiConsole.Confirm("是否继续安装?"))
{
    // 执行安装
}

// 文本输入(带验证)
var name = AnsiConsole.Prompt(
    new TextPrompt<string>("请输入用户名:")
        .ValidationErrorMessage("[red]用户名不能为空[/]")
        .Validate(input => !string.IsNullOrWhiteSpace(input)));

// 选择列表
var fruit = AnsiConsole.Prompt(
    new SelectionPrompt<string>()
        .Title("请选择最喜欢的水果")
        .AddChoices(new[] { "苹果", "香蕉", "橙子", "葡萄" }));

AnsiConsole.MarkupLine($"你选择了:[green]{fruit}[/]");

// 多选
var colors = AnsiConsole.Prompt(
    new MultiSelectionPrompt<string>()
        .Title("请选择颜色")
        .AddChoices(new[] { "红色", "绿色", "蓝色", "黄色" }));


5. 树形结构

image.png

var root = new Tree("[yellow]项目结构[/]");
var src = root.AddNode("src");
src.AddNode("Program.cs");
src.AddNode("Services");
src.AddNode("Models");

var tests = root.AddNode("tests");
tests.AddNode("UnitTests");

AnsiConsole.Write(root);


6. 布局 / 网格

image.png

var layout = new Layout("Root")
    .SplitColumns(
        new Layout("Left").Size(30),
        new Layout("Right")
            .SplitRows(
                new Layout("Top"),
                new Layout("Bottom")));

layout["Left"].Update(new Panel("导航栏"));
layout["Top"].Update(new Panel("主内容区"));
layout["Bottom"].Update(new Panel("日志输出"));

AnsiConsole.Write(layout);


7. 实时更新

image.png

var table = new Table().AddColumn("Time").AddColumn("Message");
table.AddRow("10:00", "系统启动");

await AnsiConsole.Live(table)
    .StartAsync(async ctx =>
    {
        for (int i = 1; i <= 5; i++)
        {
            await Task.Delay(1000);
            table.AddRow($"10:0{i}", $"事件 {i}");
            ctx.Refresh(); // 刷新显示
        }
    });


8. 带样式的异常显示

image.png

try
{
    throw new InvalidOperationException("操作失败");
}
catch (Exception ex)
{
    AnsiConsole.WriteException(ex, ExceptionFormats.ShortenPaths);
}


9. 日历

image.png

var calendar = new Calendar(2026, 4);
calendar.AddCalendarEvent(2026, 4, 22); // 标记日期
calendar.HighlightStyle(Style.Parse("yellow bold"));
AnsiConsole.Write(calendar);


10. 条形图 / 柱状图

image.png

AnsiConsole.Write(new BarChart()
    .Width(60)
    .Label("[green bold]项目进度[/]")
    .CenterLabel()
    .AddItem("后端", 80, Color.Green)
    .AddItem("前端", 65, Color.Blue)
    .AddItem("测试", 40, Color.Red));


11. 分解图

image.png

AnsiConsole.Write(new BreakdownChart()
    .Width(60)
    .AddItem("CPU", 45, Color.Red)
    .AddItem("内存", 30, Color.Blue)
    .AddItem("磁盘", 25, Color.Green));


12. 规则线

image.png

AnsiConsole.Write(new Rule("[red]警告区域[/]").RuleStyle("red").LeftJustified());
AnsiConsole.WriteLine("内容");
AnsiConsole.Write(new Rule().RuleStyle("green"));


13. 文本样式

image.png

// 大字标题
AnsiConsole.Write(new FigletText("Hello").Color(Color.Green));
// Emoji
AnsiConsole.Markup(":check_mark_button: 成功 :cross_mark: 失败");


14. 网格

image.png

var grid = new Grid();
grid.AddColumn(new GridColumn().NoWrap().PadRight(4));
grid.AddColumn();

grid.AddRow("[b]名称[/]", "Spectre.Console");
grid.AddRow("[b]版本[/]", "0.49.1");
grid.AddRow("[b]许可[/]", "MIT");

AnsiConsole.Write(grid);






xoyozo 半个月前
120

AutoUpdater.NET 是一个开源库,专为 .NET 桌面应用程序设计,支持 Windows Forms 和 WPF 应用。它通过从服务器获取 XML 文件来检测新版本信息,当发现新版本时向用户显示更新对话框。

相对于 ClickOnce,AutoUpdater.NET 的配置更简单一些。

首先通过 NuGet 包管理器安装 Autoupdater.NET.Official,然后在应用程序入口点添加以下代码:

AutoUpdater.Start("http://yourserver.com/path/to/update.xml");

XML 文件结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<item>
  <version>2.0.0.0</version> <!--必填:最新版本号-->
  <url>http://yourserver.com/path/to/updatefile.zip</url> <!--必填:更新文件下载地址-->
  <changelog>http://yourserver.com/path/to/changelog.txt</changelog> <!--可选:更新日志-->
  <mandatory>False</mandatory> <!--可选:是否强制更新-->
</item>

Windows Forms 在 Program.cs 文件的 Main() 方法中,WPF 在 App.xaml.cs 的 OnStartup() 中添加:

AutoUpdater.Start("http://yourserver.com/path/to/update.xml");
AutoUpdater.CheckForUpdateEvent += (e) =>
{
    if (e.Error != null)
    {
        MessageBox.Show($"检查版本更新失败:{e.Error.Message}");
    }
    if (e.IsUpdateAvailable)
    {
        if (e.Mandatory.Value)
        {
            // 强制更新
            AutoUpdater.DownloadUpdate(e);
        }
        else
        {
            // 可选更新
            if (MessageBox.Show("发现新版本,是否立即更新?", "更新提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
            {
                AutoUpdater.DownloadUpdate(e);
            }
        }
    }
};

这样就能简单实现打开应用时判断是否有更新。具体用法参:GitHub

对于控制台应用程序,AutoUpdater.NET 并不直接支持。可以使用 GeneralUpdate 等轻量级自动更新库。

其它:

  • 若希望通过标准安装流程(如添加到开始菜单),优先选择 ClickOnce,适合长期维护的内部工具。

  • 若追求快速集成和无感更新,AutoUpdater.NET 更灵活。

  • 无论哪种方案,务必对程序进行代码签名(如购买企业证书或生成测试证书),否则系统可能拦截安装。(你要允许来自未知发布者的此应用对你的设备进行更改吗)

  • 可以购买“OV 代码签名”证书或“EV 代码签名”证书,注意:“代码签名证书”与“域名证书”互不通用。

xoyozo 9 个月前
7,330

image.png

现象:

VS2022 的“管理 nuget 程序包”页面的“更新”和“已安装”选项卡无限循环加载刷新,状态栏一直循环显示“正在还原 NuGet 程序包”、“就绪”。点开来有很多“正在加载 IntelliSense 任务已成功完成”。我有很多解决方案和项目,只有其中一个出现上述情况。

解决方法:

image.png

点击“设置”,在“常规”页面点击“清除所有 NuGet 存储”。

image.png

xoyozo 1 年前
832

.NET Framework 项目中使用 MySql.Data.EntityFramework 连接 MySQL 8.0 时遇到以下错误:

NotSupportedException: Character set 'utf8mb3' is not supported by .Net Framework.

解决方法:

Nuget 中将 MySql.Data 和 MySql.Data.EntityFramework 更新到最新版。

xoyozo 2 年前
2,180

未能找到路径“\roslyn\csc.exe”的一部分。

解决方法:

在 nuget 中直接卸载 Microsoft.CodeDom.Providers.DotNetCompilerPlatform


如果 web.config 报错,删除与 Microsoft.CodeDom.Providers.DotNetCompilerPlatform 相关的项,如:

<system.codedom>
	<compilers>
		<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701;612;618" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
		<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008,40000,40008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
	</compilers>
</system.codedom>


然后遇到错误:

功能 空传播运算符 在 C# 5 中不可用。请使用 6 或更高的语言版本


所以还是少不了 Microsoft.CodeDom.Providers.DotNetCompilerPlatform

又把这货装上了,竟然不报错了。

这期间我更改过在 Release 模式下调试,将 .NET Framework 4.8 升级到 .NET Framework 4.8.1 等,然后又退回到原来的状态和版本,竟然都正常了。

就这样吧!

xoyozo 2 年前
2,304

System.NotSupportedException: Serialization and deserialization of 'System.DateOnly' instances are not supported.

The unsupported member type is located on type 'System.Nullable`1[System.DateOnly]'.

解决方法:

https://www.nuget.org/packages/DateOnlyTimeOnly.AspNet/

builder.Services
    .AddControllers(options => options.UseDateOnlyTimeOnlyStringConverters())
    .AddJsonOptions(options => options.UseDateOnlyTimeOnlyStringConverters());


M
转自 Maksym Koshovyi 4 年前
7,308

当 ASP.NET 发布一个新的小版本更新时(以 .NET 5.0.10 为例),生产环境服务器端可以直接下载安装 .NET 5.0.10 来自动替换 .NET 5.0.9。

倘若这时直接使用 VS 将 nuget 中版本为 5.0.9 的组件更新到 5.0.10 发布到服务器上的话,可能会发生错误:

HTTP Error 500.30 - ASP.NET Core app failed to start

这里我们可以在 nuget 回滚相关组件的版本至 5.0.9,等 VS 发现新的版本更新时,更新 VS 开发工具后,再更新 nuget 组件并进行发布即可。

着急的小伙伴可以直接前往 Microsoft .NET 网站下载安装包含 Runtime 5.0.10 的 SDK:

image.png

该情况同样发生在 ASP.NET Core 3.1 等大版本上。

若仍未生效,请重启服务器

----------------

后注:安装完成后重启服务器可避免以上烦恼!

xoyozo 5 年前
2,803

Nuget 包:System.Runtime.Caching

依赖注入:

public class HomeController : Controller
{
    private IMemoryCache _cache;

    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

定义键:

public static class CacheKeys
{
    public static string Entry { get { return "_Entry"; } }
}

赋值与取值:

public IActionResult CacheTryGetValueSet()
{
    DateTime cacheEntry;

    // 尝试从缓存获取,若获取失败则重新赋值
    if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
    {
        // 新的内容
        cacheEntry = DateTime.Now;

        // 缓存选项
        var cacheEntryOptions = new MemoryCacheEntryOptions()
            // Keep in cache for this time, reset time if accessed.
            .SetAbsoluteExpiration(TimeSpan.FromSeconds(3));

        // 保存到缓存中
        _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
    }

    return View("Cache", cacheEntry);
}

注意:

.SetAbsoluteExpiration() 用于设置绝对过期时间,它表示只要时间一到就过期

.SetSlidingExpiration() 用于设置可调过期时间,它表示当离最后访问超过某个时间段后就过期

xoyozo 5 年前
3,296

本文使用 Oracle 官方提供的 MySql.EntityFrameworkCore,如使用 Pomelo.EntityFrameworkCore.MySql 请移步

MySql.EntityFrameworkCore 是 MySql.Data.EntityFrameworkCore 的升级版


本文以 Visual Studio 2019、ASP.NET Core 5.0 开发环境为例。

  1. 新建 ASP.NET Core Web 应用程序。

  2. 安装 NuGet 包:

    MySql.EntityFrameworkCore

    Microsoft.EntityFrameworkCore.Design

    image.png

  3. 根据已有数据库创建数据模型。在 NuGet 的程序包管理(Package Manager)控制台中(PowerShell)执行命令:

    Scaffold-DbContext "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.EntityFrameworkCore -OutputDir Data -f

    .Net Core CLi:

    dotnet ef dbcontext scaffold "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.EntityFrameworkCore -o Data -f
  4. 搞定。


注:开发环境和生产环境都不需要安装 Connector/NET,只需要安装 ASP.NET Core。

补充:其它数据库提供程序请参考:https://docs.microsoft.com/zh-cn/ef/core/providers/

更多高级用法请参考官方文档


xoyozo 5 年前
5,197