.NET 每周分享第 52 期
卷首语
garent 是微软研究院推出的内存 key-value 存储系统,它可以完全兼容 Redis 的所有协议,而且在性能上比 Redis 还要好,而且这个完全是使用 C# 开发,只需要 执行 dotnet run -c Release -f net8.0 命令就可以将服务端运行起来。 最近 Redis 也修改协议,或许这是 garent 的一个机会。
文章推荐
在ASP.NET Core中,依赖注入有三种类型的服务,分别为Transient,Scoped和Signleton ,其中对于 Transient 和 Singleton 比较容易理解,而且如果高级别的服务依赖于低级别的服务,程序在运行的时候会抛出异常,比如 Singleton 的服务依赖于一个 Transient 的服务。
对于 Scoped 服务,该怎么解决这个问题呢,比如
internal class WeatherReport (
ILogger<WeatherReport> logger,
WeatherSerivce weahtherService)
: BackgroundService
{
private readonly TimeSpan _period = TimeSpan.FromSeconds(5);
}
builder.Services.AddHostedService<WeatherReport>();
builder.Services.AddScoped<WeatherSerivce>();
这里的 WeatherReport 是一个注册为 singleton 的服务,而 WeatherService 是注册为 Scoped 类型的服务,所以在运行的时候就会抛出异常。该怎么解决这个问题呢?
internal class WeatherReport (
ILogger<WeatherReport> logger,
IServiceScopeFactory serviceScopeFactory)
: BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var scope = serviceScopeFactory.CreateScope();
var weatherService = scope.ServiceProvider. GetRequiredService<WeatherSerivce>();
}
}
在这里,WeatherReport 依赖了一个 ISeviceScopeFactory 对象,通过创建一个 IServiceScope 对象,就能获得 WeatherService 的服务,并且在执行完毕了,IServiceScope 对象会调用 Dispose 方法释放当前创建的对象。
那么在 ASP.NET Core 中什么时候会使用 IServiceScope 呢?答案是每一次 HTTP 请求的处理声明周期内,会分享这个 IServiceSecope 对象,比如
public class RequestLoggingMiddleware(RequestDelegate next)
{
public async Task Invoke(HttpContext context, AppDbContext appDbContext)
{
appDbContext.ApiRequests.Add(new ApiRequest(context.TraceIdentifier));
await appDbContext.SaveChangesAsync();
await next(context);
}
}
app.MapGet("current-request", async (HttpContext httpContext, AppDbContext dbContext) =>
{
var entity = dbContext.ApiRequests.Local.FindEntry(httpContext.TraceIdentifier);
return entity?.Entity;
});
builder.Services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase("db"));
在这里,AddDbContext 会将 AppDbContext 注册为一个 Scoped 类型的服务,那么每个请求中间件中看到的 AppDbContext 都是同一个对象。
2、集合表达式
C# 12 引入了集合表达式,它简化了集合的字面表达方式,比如之前
var array = new[] { 1, 2 };
var spread = array.Concat(new[] { 3, 4 });
那么现在就可以这么
int[] array = [1, 2];
int[] spread = [..array, 3, 4];
注意由于 C#集合是强类型的,所以不能使用 var 方式去定义。我们都知道这些背后都是编译器帮助实现的,那么可以借助 sharplab.io 展示生成 C# 代码。而且也可以自定义类型来支持集合表达式。
这是微软开源的一本 Rust 语言学习手册,主要是针对已经熟悉 .NET 开发的程序员。
最近 .NET 9 开发计划中的一个 Epic 引来了巨大的讨论,它主要讨论是在 .NET 9 中引入事件框架。但是 .NET 社区中已经包含了很多这样的框架。这个给开发人员带来的疑问:为什么微软作为第一方为什么要吃掉开源社区的市场?
这篇文章的作者分析了这种现象,并且认为这种做法是伤害 .NET 社区的生态。
MSBuild 是 .NET 生态中非常重要的组成部分,在 C# 项目中体现为 csproj 文件。不管是经验丰富还是萌新,对于直接修改 csproj 文件都是一个充满挑战的事情。Vistual Studio 最近为 csproj 文件编辑提供了新的功能,更多的智能提示和补全,已经错误提示。
.NET 社区的大佬 Stephen Toub 教你从头写一个异步实现,这个将会帮助你更加容易理解 C# 的异步。
开源项目
Spectre.Console 是 dotnet 的一款开源库,它能够绘制出非常漂亮的控制台交互页面。
dotnet-outdated 是一款检测 dotnet 项目的依赖是否出现过时的情况。安装只需要执行 dotnet outdated 命令,就可以知道那些包出现了最新的版本。
WireMock-Net 是一款模拟服务端的库,这样可以在单元测试或者集成测试中访问远端的 HTTP 服务器,并且设定相应的返回结果。