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 { get; set; }
public string DbLink { get; set; }
public bool Fake { get; set; }
public List<string> ExcludeTables { get; set; } = 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<string, object>>(
$"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摘要
由于时间和空间,本文只能简要介绍“现代控制台应用”的发展思想。在下一个探索过程中,可能随时都有补充剂。我将继续在博客中添加这篇文章。如果您在博客公园或其他平台以外的其他平台上看到了本文,则可以“查看原始文本”以查看本文的最新版本。