使用C#和.Net Core开发现代化控制台小工具的完整指南

2025-03-13
来源:网络整理

1简介

最近有很多情况需要开发小工具。上次我开发了一个GO语言的Hive 工具。体验非常好,但我真的不喜欢Go语言的语法。这次,我继续尝试使用C#开发小工具。

该小工具的功能非常简单,数据库数据迁移,但这并不重要。它主要是记录更适合.net核心婴儿体质的游戏机小工具开发过程

在本文中,我定义了“现代控制台应用程序的开发体验”:它可以像可以实施所提供的工具一样优雅地集成各种组件,例如Web应用程序。我使用了..*系列组件,包括依赖项注入,配置,记录,然后添加到环境变量读取,调试和其他功能的第三方组件中。

本文中的小部件非常简单,针对非专业用户,不需要知道命令行知识,因此所有功能均在配置文件中控制。如果要开发传统的CLI工具,则可以使用此库。

2个依赖项

该项目中使用的依赖项如下

<ItemGroup>
  <PackageReference Include="dotenv.net" Version="3.1.3" />
  <PackageReference Include="Dumpify" Version="0.6.0" />
  <PackageReference Include="FreeSql" Version="3.2.802" />
  <PackageReference Include="FreeSql.Provider.Dameng" Version="3.2.802" />
  <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
  <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
  <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
  <PackageReference Include="Serilog" Version="3.0.1" />
  <PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
  <PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
ItemGroup>

尽管它是一个游戏机小工具,但我构建了一个简单的项目骨架,以获得更柔滑的开发体验。

3个配置

我一开始想使用的是

写作和去时大量使用它感觉很方便

它也很容易在C#中使用,安装此库

.load();要读取.env文件中的配置到环境变量

然后只需直接从环境变量加载它,例如.le()方法

..

使用此组件的学生应该熟悉它。

最初,我计划将其用于配置,但最终我仍然使用JSON文件匹配此配置组件。原因是该组件很方便且易于使用。

安装相关依赖项后,执行以下代码初始化

var configBuilder = new ConfigurationBuilder();
configBuilder.AddEnvironmentVariables();
configBuilder.SetBasePath(Environment.CurrentDirectory);
configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
var config = configBuilder.Build();

这样,您可以获得对象

写配置文件

熟悉的.json,对于写作的人:DNA,搬了!

{
  "Logging": {
    "LogLevel": {
      "Default""Debug"
    }
  },
  "ConnectionStrings": {
    "Default""server=host;port=1234;user=user;password=pwd;database=db;poolsize=5"
  },
  "DmTableMigration": {
    "Schema""schema",
    "DbLink""link_test",
    "Fake"true,
    "ExcludeTables": ["table1""table2"]
  }
}

定义强烈键入的配置实体

为了获得更好的开发体验,我们使用强大的配置

创建new.cs

public class AppSettings {
  public string Schema { getset; }
  public string DbLink { getset; }
  public bool Fake { getset; }
  public List<string> ExcludeTables { getset; } = new();
}

登记

...库实现配置绑定。在结合或注入配置中使用它时,它可以实现配置热更新。

services.AddOptions().Configure(e => config.GetSection("DmTableMigration").Bind(e));

微信程序日志是什么_日志输出规范_微信小程序开发控制台日志输出

初始化上述配置时。(“。json”,:,:); ,您可以将其设置为True,以自动在修改配置文件时自动加载配置文件。

如果不需要热门更新,则可以简化注册方法

services.AddOptions("DmTableMigration");

这意味着在启动程序时读取配置,并且随后的配置修改将不会生效。您只能在注射期间使用它

注射配置

注射时写这个

private readonly AppSettings _settings = options.Value;

ctor(IOptions options) {
  _settings = options.Value;
}

CTOR代表施工方法

4个日志

日志是程序的重要组成部分

我使用了...日志框架,该框架没有正式文件可以写入文件,因此我还使用它记录了日志到文件。实际上,您还可以自己实现写文件。我有时间的时候会这样做。

PS:。该平台推荐的日志组件包括NLOG,我认为它更方便。 NLOG必须写的XML配置,使我想起了害怕被XML统治的恐惧,拒绝×

配置

只需在程序中配置它

Log.Logger = new LoggerConfiguration()
  .MinimumLevel.Information()
  .WriteTo.File("logs/migration-logs.log")
  .CreateLogger();

配置

同时将日志输出到控制台和

日志编写文件已配置

services.AddLogging(builder => {
  builder.AddConfiguration(config.GetSection("Logging"));
  builder.AddConsole();
  builder.AddSerilog(dispose: true);
});

5依赖注射

使用...实施依赖注入

这也是一个选择。据说有更多功能,我还没有使用它们。让我们找时间体验它。

注册服务

var services = new ServiceCollection();
services.AddLogging(builder => {
    builder.AddConfiguration(config.GetSection("Logging"));
    builder.AddConsole();
    builder.AddSerilog(dispose: true);
});
services.AddSingleton(fsql);
services.AddOptions().Configure(e => config.GetSection("DmTableMigration").Bind(e));
services.AddScoped();

使用服务

可以使用在IOC容器中注册的服务,请参阅以下代码。

await using (var sp = services.BuildServiceProvider()) {
    var migrationService = sp.GetRequiredService();
    migrationService.Run();
}

服务具有不同的生活周期,例如服务类型。您可以使用以下代码创建一个代码并将其注入其中。

await using (var sp = services.BuildServiceProvider()) {
    using (var scope = sp.CreateScope()) {
        var spScope = scope.ServiceProvider;
        var service = spScope.GetRequiredService();
    }
}

有关使用依赖注入的其他方法,请参阅官方文档。

6个调试小工具

日志输出规范_微信程序日志是什么_微信小程序开发控制台日志输出

我也会在这里推荐此调试工具

使用非常方便。安装软件包后,将.dump()添加到任何对象中以输出其结构。

我认为这个小工具现在非常好〜

&发布

对于这个简单的小工具,我习惯于在项目配置中编写发布配置

对于此小工具,我的发布计划是:包括运行时 +

实际的测试软件包约为22MB,然后使用ZIP压缩。最终尺寸为9MB,大小控制非常好。

编辑。文件,配置如下

<PropertyGroup>
    <OutputType>ExeOutputType>
    <TargetFramework>net8.0TargetFramework>
    <ImplicitUsings>enableImplicitUsings>
    <Nullable>enableNullable>
    <PublishSingleFile>truePublishSingleFile>
    <PublishTrimmed>truePublishTrimmed>
    <TrimMode>partialTrimMode>
    <PublishRelease>truePublishRelease>
PropertyGroup>

我的修剪时也遇到了一个小问题。默认值已满,可以最大程度地减少已发布的程序规模。目前,大约是17MB。但是,我在JSON序列化时遇到了问题,因此我切换到模式,此后该程序运行良好。

关于AOT

至于最近非常受欢迎的.NET8 AOT解决方案,我也尝试过,但这并不理想。首先,该小工具建立在依赖注入框架上。 AOT自然对依赖注入不是很友好,这是一项基于反射的技术,因此,当我尝试AOT时,我发现配置加载的第一步不是很好。

然后,在解决了配置加载问题之后,我遇到了JSON序列化问题,该问题也基于反射,不容易做到。

我真的不想花太多时间在小工具开发上,所以我没有深入研究它,但是接下来,AOT似乎是一个很小的热门趋势,也许我会找到时间去探索。

顺便说一句,如果要发布AOT,则只需要执行以下配置

<PropertyGroup>
    <OutputType>ExeOutputType>
    <TargetFramework>net8.0TargetFramework>
    <ImplicitUsings>enableImplicitUsings>
    <Nullable>enableNullable>
    <PublishAot>truePublishAot>
PropertyGroup>

8杂项在数据库下获取所有桌子

从此视图获取(表?)。

PS:等国内数据库中有很多技巧。当然一样

logger.LogInformation("获取Table列表");

var list = fsql.Ado.Query<stringobject>>(
    $"SELECT OBJECT_NAME FROM all_objects WHERE owner='{_settings.Schema}' AND object_type='TABLE'");

var tableList = list.Select(e => e["OBJECT_NAME"].ToString() ?? "")
    .Where(e => !string.IsNullOrWhiteSpace(e))
    .Where(e => !_settings.ExcludeTables.Contains(e))
    .ToList();

logger.LogInformation("Table列表:{List}"string.Join(",", tableList));

C#新语法CTOR

应该是这个名字吗?

当只有一个带有参数的构造函数时,可以使用它来简化代码。

原始代码

public class MigrationService {
    AppSettings _settings;
    IFreeSql _fsql;
    ILogger _logger;
    
    MigrationService(IFreeSql fsql, IOptions options, ILogger logger) {
        _settings = options.Value;
        _fsql = fsql;
        _logger = logger;
    }
}

新语法

public class MigrationService(IFreeSql fsql, IOptions options, ILogger logger) {
    private readonly AppSettings _settings = options.Value;
}

9摘要

由于时间和空间,本文只能简要介绍“现代控制台应用”的发展思想。在下一个探索过程中,可能随时都有补充剂。我将继续在博客中添加这篇文章。如果您在博客公园或其他平台以外的其他平台上看到了本文,则可以“查看原始文本”以查看本文的最新版本。

分享