|
| 1 | +# .NET 每周分享第 68 期 |
| 2 | + |
| 3 | +## 卷首语 |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +最新的`.NET 10`预览版中,推出了一个令人兴奋的功能,它将大大简化开发的繁琐程度和新人的学习曲线。没有解决方案文件(sln),没有工程项目文件(csproj),只需要一个代码文件 (cs) 即可。 |
| 8 | + |
| 9 | +```csharp |
| 10 | +Console.WriteLine("hello world"); |
| 11 | +``` |
| 12 | + |
| 13 | +使用 `dotnet run app.cs` 命令即可输出 `hello world`。如果项目使用了第三方库,那么可以通过类似条件编译一样引入第三方库 |
| 14 | + |
| 15 | +```csharp |
| 16 | +#:package Newtonsoft.Json@13.* |
| 17 | +var json = JsonConvert.SerializeObject(new { Name = "John", Age = 30 }); |
| 18 | +Console.WriteLine(json); |
| 19 | +``` |
| 20 | + |
| 21 | +这个新的命令还支持使用 SDK,比如想要运行一个 `Web` 应用程序 |
| 22 | + |
| 23 | +```csharp |
| 24 | +#:sdk Microsoft.NET.Sdk.Web |
| 25 | + |
| 26 | +var builder = WebApplication.CreateBuilder(args); |
| 27 | +var app = builder.Build(); |
| 28 | +app.MapGet("/", () => "Hello World!"); |
| 29 | +app.Run(); |
| 30 | +``` |
| 31 | + |
| 32 | +直接使用 `dotnet run app.cs` 就可以本地启动一个 `ASP.NET Core Web API` 的应用程序。 |
| 33 | +最后如果想要转换为传统的工程项目格式,可以使用 `dotnet project covert app.cs` 命令即可。 |
| 34 | + |
| 35 | +## 行业资讯 |
| 36 | + |
| 37 | +1、[MAUI的未来](https://x.com/migueldeicaza/status/1922409129567563855) |
| 38 | + |
| 39 | +在最近的微软裁员中,MAUI一些工程师收到了影响,估计 MAUI 的未来会受到影响。 |
| 40 | + |
| 41 | +## 文章推荐 |
| 42 | + |
| 43 | +1、[为什么要用 Aspire](https://csharp.christiannagel.com/2025/05/08/why-dotnet-aspire/) |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +开发与部署的统一框架 |
| 49 | + |
| 50 | +.NET Aspire 是一个旨在简化开发与部署流程的框架,适用于开发人员和 DevOps 工程师。它通过以下方式提升开发体验: |
| 51 | + |
| 52 | +- **基础设施自动化**:通过 Docker 集成,自动拉取所需的服务(如 SQL Server、Redis 等),并建立可视化的服务关系。 |
| 53 | +- **资源监控**:在开发过程中,实时监控内存使用、服务调用频率和数据库访问时长,帮助开发者及时发现并解决性能问题。 |
| 54 | +- **部署灵活性**:支持多种部署方式,包括 Microsoft Azure、Kubernetes 和 Docker Compose,且不强制要求使用特定的部署方式。 |
| 55 | + |
| 56 | +逐步集成至现有项目 |
| 57 | + |
| 58 | +.NET Aspire 允许将其功能逐步集成到现有项目中,无需完全重构。以下是集成的基本步骤: |
| 59 | + |
| 60 | +1. **创建 API 项目**:使用 `dotnet new webapi` 创建一个基础的 Web API 项目。 |
| 61 | +2. **添加 AppHost 项目**:使用 .NET Aspire CLI 创建一个 AppHost 项目,并将其与 API 项目关联。 |
| 62 | +3. **配置服务默认设置**:通过添加 `Weather.ServiceDefaults` 库,启用结构化日志、分布式追踪和指标收集。 |
| 63 | +4. **启动与监控**:运行 AppHost 项目后,使用仪表板查看服务状态、日志和性能指标。 |
| 64 | + |
| 65 | +部署与发布 |
| 66 | + |
| 67 | +.NET Aspire 提供了新的 Aspire CLI 工具,简化了部署过程。通过配置应用模型,可以为 Azure、Kubernetes 和 Docker Compose 创建发布工件。即使不使用 .NET Aspire 进行部署,现有的 .NET 应用仍然可以正常运行。 |
| 68 | + |
| 69 | +渐进式采用 |
| 70 | + |
| 71 | +.NET Aspire 支持渐进式采用,开发者可以根据项目的实际需求,选择性地使用其功能。无论是在本地开发环境中提升开发效率,还是在生产环境中增强监控能力,.NET Aspire 都能提供相应的支持。 |
| 72 | + |
| 73 | +结论 |
| 74 | + |
| 75 | +.NET Aspire 是一个强大的工具,旨在简化开发和部署流程。通过其自动化的基础设施管理、实时的资源监控和灵活的部署选项,开发者可以更专注于业务逻辑的实现,而将复杂的基础设施管理交给框架处理。无论是新项目的开发,还是现有项目的优化,.NET Aspire 都是一个值得考虑的选择。 |
| 76 | + |
| 77 | +2、[清理 nuget 缓存](https://steven-giesel.com/blogPost/ef7e9271-3b8d-4658-988f-b48bbd11e320/clearing-nuget-caches) |
| 78 | + |
| 79 | +NuGet 缓存机制虽然提高了构建效率,但在某些情况下(如版本冲突、包损坏或调试本地包)需要清除缓存。文章详细介绍了 NuGet 的缓存位置、类型,以及清除方式。 |
| 80 | + |
| 81 | +NuGet 缓存类型 |
| 82 | + |
| 83 | +1. **HTTP 缓存(Http Cache)** |
| 84 | + |
| 85 | +- 存储从 NuGet 源下载的 `.nupkg` 文件 |
| 86 | +- 默认位置:`%userprofile%\.nuget\packages\http-cache` |
| 87 | + |
| 88 | +2. **全局包缓存(Global packages)** |
| 89 | + |
| 90 | +- 存储所有使用的 NuGet 包解压后的内容 |
| 91 | +- 默认位置:`%userprofile%\.nuget\packages` |
| 92 | + |
| 93 | +3. **临时缓存(Temp Cache)** |
| 94 | + |
| 95 | +- 临时使用的缓存文件 |
| 96 | +- 默认位置:`%temp%\NuGetScratch` |
| 97 | + |
| 98 | +使用 CLI 工具 |
| 99 | + |
| 100 | +```bash |
| 101 | +dotnet nuget locals global-packages --clear |
| 102 | +dotnet nuget locals http-cache --clear |
| 103 | +dotnet nuget locals temp --clear |
| 104 | + |
| 105 | +dotnet nuget locals all --clear |
| 106 | +``` |
| 107 | + |
| 108 | +3、[.NET 实验性 GC 表现](https://blog.applied-algorithms.tech/a-sub-millisecond-gc-for-net) |
| 109 | + |
| 110 | +本文介绍了 .NET 运行时中一个名为 Satori 的实验性垃圾回收器(GC)。Satori 在多个关键性能指标上相较于传统的 Server GC 模式表现出显著的提升。 |
| 111 | + |
| 112 | +**主要成果** |
| 113 | + |
| 114 | +- 中位暂停时间:提升 50 倍 |
| 115 | +- 99% 分位暂停时间:提升超过 100 倍 |
| 116 | +- 堆大小:减少至原来的三分之一 |
| 117 | + |
| 118 | +这些改进使得 Satori 特别适用于对延迟敏感的应用场景,如实时系统和高频交易等。 |
| 119 | + |
| 120 | +自动垃圾回收简化了内存管理,但也带来了不可预测的“stop-the-world”暂停,这在大型或高吞吐量应用中可能导致性能瓶颈。 |
| 121 | + |
| 122 | +**Satori 的优势** |
| 123 | + |
| 124 | +- 极低的暂停时间:适用于对延迟要求极高的应用 |
| 125 | +- 更小的堆内存占用:提高资源利用率 |
| 126 | +- 更高的吞吐量:减少 GC 对应用性能的影响 |
| 127 | + |
| 128 | +**如何试用 Satori** |
| 129 | + |
| 130 | +Satori 目前作为实验性功能在 GitHub 上提供,开发者可以访问 [Satori 的 GitHub 页面](https://github.com/dotnet/runtime/discussions/115627) 获取最新信息。 |
| 131 | + |
| 132 | +## 视频推荐 |
| 133 | + |
| 134 | +1、[Scoped 服务的依赖注入生命周期](https://www.youtube.com/watch?v=AF224eUmWLc&ab_channel=NickChapsas) |
| 135 | + |
| 136 | +在 `Microsoft.Extensions.DependencyInjection` 中,所有注入到容器的服务有三种类型的生命周期 |
| 137 | + |
| 138 | +- Singleton |
| 139 | +- Scoped |
| 140 | +- Transient |
| 141 | + |
| 142 | +在构建 `IServiceProvider` 服务的时候,有一个 `ServiceProviderOptions` 类型的参数,其中 `ValidateScope` 属性是用来做什么的呢? |
| 143 | + |
| 144 | +```csharp |
| 145 | +interface IGenerater |
| 146 | +{ |
| 147 | + string Generate(); |
| 148 | +} |
| 149 | + |
| 150 | +class Generater : IGenerater |
| 151 | +{ |
| 152 | + public string Generate() => Guid.NewGuid().ToString(); |
| 153 | +} |
| 154 | + |
| 155 | +class MyService |
| 156 | +{ |
| 157 | + private readonly IGenerater _generater; |
| 158 | + |
| 159 | + public MyService(IGenerater generater) |
| 160 | + { |
| 161 | + _generater = generater; |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +这里有两个服务,其中 `MyService` 服务依赖一个 `IGenerater` 服务,如果我们注册服务的是这样的 |
| 167 | + |
| 168 | +```csharp |
| 169 | +var services = new ServiceCollection(); |
| 170 | +services.AddScoped<IGenerater, Generater>(); |
| 171 | +services.AddSingleton<MyService>(); |
| 172 | + |
| 173 | +var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions |
| 174 | +{ |
| 175 | + ValidateScopes = true, |
| 176 | +}); |
| 177 | +``` |
| 178 | + |
| 179 | +运行的时候,会有这样的错误 |
| 180 | + |
| 181 | +```txt |
| 182 | +Unhandled exception. System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: MyService Lifetime: Singleton ImplementationType: MyService': |
| 183 | +Cannot consume scoped service 'IGenerater' from singleton 'MyService'.) |
| 184 | +``` |
| 185 | + |
| 186 | +原因是 `Singleton` 服务如果依赖 `Scoped` 服务的话,在 `Scoped` 服务完成之后,并不会被垃圾回收收集,从而导致内存泄漏。所以正确的做法是,`MyService` 依赖于 `IServiceScopeFactory` 服务。 |
| 187 | + |
| 188 | +```csharp |
| 189 | +class MyService |
| 190 | +{ |
| 191 | + private readonly IServiceScopeFactory _serviceScopeFactory; |
| 192 | + |
| 193 | + public MyService(IServiceScopeFactory serviceScopeFactory) |
| 194 | + { |
| 195 | + _serviceScopeFactory = serviceScopeFactory; |
| 196 | + } |
| 197 | + |
| 198 | + public string GetNewGuid() |
| 199 | + { |
| 200 | + using var scope = _serviceScopeFactory.CreateScope(); |
| 201 | + var generater = scope.ServiceProvider.GetRequiredService<IGenerater>(); |
| 202 | + return generater.Generate(); |
| 203 | + } |
| 204 | +} |
| 205 | +``` |
| 206 | + |
| 207 | +在使用依赖服务的时候,使用 `CreateScope` 方法创建一个 Scope |
| 208 | + |
| 209 | +## 开源项目 |
| 210 | + |
| 211 | +1、[pgvector](https://github.com/pgvector/pgvector-dotnet) |
| 212 | + |
| 213 | +pgvector-dotnet 是一个为 .NET 平台(包括 C#、F# 和 Visual Basic)提供的开源库,旨在简化与 PostgreSQL 数据库中 pgvector 扩展的集成。pgvector 是一个 PostgreSQL 扩展,专门用于存储和查询高维向量,广泛应用于语义搜索、推荐系统、图像检索等领域。 |
| 214 | +🔧 核心功能 |
| 215 | + |
| 216 | +- 向量数据支持:提供 Vector、HalfVector、SparseVector 等数据类型,支持存储单精度、半精度和稀疏向量。 |
| 217 | +- 数据库库兼容性:支持与 Npgsql、Dapper、Entity Framework Core 和 Npgsql.FSharp 的集成,使得在 .NET 环境中操作 PostgreSQL 向量数据变得更加便捷。 |
| 218 | +- 扩展支持:支持 PostgreSQL 的 vector 扩展,允许在数据库中创建向量列,并执行向量插入、更新、查询等操作。 |
| 219 | +- 示例项目:提供多个示例,展示如何使用 OpenAI 生成嵌入、使用 Cohere 处理二进制嵌入、实现混合搜索、稀疏搜索、推荐系统、主题建模、水平扩展等功能。 |
| 220 | + |
| 221 | +2、[IdGen](https://github.com/RobThree/IdGen) |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | +IdGen 是一个为 .NET 平台设计的高性能、分布式、无协调的 ID 生成器,灵感来源于 Twitter 的 Snowflake 项目。该库生成 64 位(实际为 63 位)时间排序的唯一 ID,适用于需要高并发、低延迟且可扩展的场景,如分布式系统、数据库主键生成等。 |
| 226 | + |
| 227 | +核心特性 |
| 228 | + |
| 229 | +- **结构化 ID**:ID 由时间戳、生成器 ID 和序列号三部分组成,支持自定义结构。 |
| 230 | +- **高并发支持**:每毫秒内可生成数十万 ID。 |
| 231 | +- **可配置时间源**:默认使用系统时钟,也可自定义 `ITimeSource` 实现。 |
| 232 | +- **支持多种部署方式**:适用于单机、分布式、容器化等多种环境。 |
| 233 | +- **与 Azure Functions 兼容**:支持在 Azure Functions 等无状态环境中使用。 |
| 234 | + |
| 235 | +3、[ZLinq](https://github.com/Cysharp/ZLinq) |
| 236 | + |
| 237 | +`Zlinq` 是 `Linq` 的增强版,它通过减少内存分配的方式提高性能。使用方式也非常简单,只需要一个一行代码即可 |
| 238 | + |
| 239 | +```csharp |
| 240 | +using ZLinq; |
| 241 | + |
| 242 | +var seq = source |
| 243 | + .AsValueEnumerable() // only add this line |
| 244 | + .Where(x => x % 2 == 0) |
| 245 | + .Select(x => x * 3); |
| 246 | + |
| 247 | +foreach (var item in seq) { } |
| 248 | +``` |
| 249 | + |
| 250 | +而且 `Zlinq` 还支持 `Span<T>` 使用 linq 语法。 |
| 251 | + |
| 252 | +4、[ImageGlass](https://github.com/d2phap/ImageGlass) |
| 253 | + |
| 254 | +ImageGlass 是一款轻量级、开源的图片查看器,专为 Windows 系统设计,旨在提供快速、简洁且直观的图像浏览体验。支持超过 80 种常见图像格式,包括 WebP、GIF、SVG、PNG、HEIC 等,适用于日常图像浏览和设计工作流程。 |
| 255 | + |
| 256 | +核心特性 |
| 257 | + |
| 258 | +- **高兼容性**:支持多种图像格式,如 WebP、GIF、SVG、PNG、JXL、HEIC 等。 |
| 259 | +- **现代化界面**:提供干净、直观的用户界面,支持自定义主题。 |
| 260 | +- **轻量级设计**:启动迅速,占用系统资源少。 |
| 261 | +- **扩展支持**:支持插件和主题包,用户可根据需求进行扩展。 |
| 262 | +- **幻灯片功能**:支持图片幻灯片播放,提供平滑过渡效果。 |
| 263 | +- **EXIF 信息查看**:内置 EXIF 元数据查看工具,方便查看图片属性。 |
| 264 | +- **批量操作**:支持批量重命名、调整大小等功能,提高工作效率。 |
| 265 | + |
| 266 | +5、[CacheCow](https://github.com/aliostad/CacheCow) |
| 267 | + |
| 268 | +CacheCow 是一个用于 ASP.NET Core 和 ASP.NET Web API 的 HTTP 缓存中间件库,符合 HTTP Caching 标准(RFC 7232/7234)。该项目旨在提升 Web API 的性能和效率,通过智能地利用客户端缓存与服务器端缓存机制,减少不必要的数据传输和计算开销。 |
| 269 | + |
| 270 | +**核心功能** |
| 271 | + |
| 272 | +- ✅ 支持 ETag 和 Last-Modified 条件请求处理 |
| 273 | +- ✅ 自动生成缓存相关的 HTTP 响应头(如 `Cache-Control`, `ETag`, `Last-Modified`) |
| 274 | +- ✅ 支持内存缓存(In-Memory)、SQL Server 和 Redis 缓存提供程序 |
| 275 | +- ✅ 可扩展的缓存策略机制(支持自定义缓存策略) |
| 276 | +- ✅ 与 ASP.NET Core 中间件管道无缝集成 |
| 277 | + |
| 278 | +**组件模块** |
| 279 | + |
| 280 | +- `CacheCow.Server`: 提供服务器端缓存处理器,用于 ASP.NET Core 和 Web API。 |
| 281 | +- `CacheCow.Client`: 提供客户端缓存代理,可缓存 GET 请求结果。 |
| 282 | +- `CacheCow.Common`: 定义通用接口和实体类,如 `ICacheStore`、缓存键、缓存策略等。 |
| 283 | +- `CacheCow.RedisCacheStore`: Redis 缓存提供支持。 |
| 284 | +- `CacheCow.SqlServerCacheStore`: SQL Server 缓存实现。 |
| 285 | + |
| 286 | +**使用场景** |
| 287 | + |
| 288 | +- 减少频繁访问的数据接口压力 |
| 289 | +- 降低响应延迟、提升系统吞吐能力 |
| 290 | +- 利用标准 HTTP 缓存机制,无需客户端改动即可提高缓存命中率 |
| 291 | + |
| 292 | +6、[Chell](https://github.com/mayuki/Chell) |
| 293 | + |
| 294 | +Chell 是一个为 .NET 应用程序提供类 Shell 脚本体验的库和执行工具,灵感来自 [google/zx](https://github.com/google/zx)。 |
| 295 | + |
| 296 | +✨ 主要特点 |
| 297 | + |
| 298 | +- 类 Shell 脚本体验:使用 C# 编写脚本,享受类似 bash 或 cmd 的体验。 |
| 299 | +- 自动转义和数组展开:处理命令行参数时自动进行转义和数组展开。 |
| 300 | +- 流和进程管道:支持将进程的标准输入/输出连接到其他进程或流。 |
| 301 | +- 实用的脚本工具和快捷方式:提供如 Cd、Echo、Sleep 等方法,简化脚本编写。 |
| 302 | +- 跨平台支持:兼容 Windows、Linux 和 macOS。 |
| 303 | +- LINQPad 友好:可在 LINQPad 中方便地使用。 |
| 304 | + |
| 305 | +7、[DotNetCore.SKIT.FlurlHttpClient.Wechat](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) |
| 306 | + |
| 307 | +- 作者很专注在频繁维护这个库,社区里也很低调 |
| 308 | +- 几乎涵盖了所有的微信API,不像某些库只支持常用的API。 |
| 309 | +- 文档完整,且免费(不像某些库必须买书、买课) |
| 310 | +- 基于Flurl.Http实现,不存在实例化HttpClient导致的Socket泄漏问题 |
| 311 | +- 支持异步(Async)调用 |
| 312 | +- 支持 System.Text.Json(默认)和 Newtonsoft.Json两种序列化方法 |
0 commit comments