网站中有哪些标签需要优化,成都网站优化步骤,青海西宁高端网站建设,wordpress文件上传.NET 8 中的 KeyedService#xff1a;新特性解析与使用示例
一、引言
在 .NET 8 的 Preview 7 版本中#xff0c;引入了 KeyedService 支持。这一特性为开发者提供了按名称#xff08;name#xff09;获取服务的便利#xff0c;在某些场景下#xff0c;开发者无需再自行….NET 8 中的 KeyedService新特性解析与使用示例
一、引言
在 .NET 8 的 Preview 7 版本中引入了 KeyedService 支持。这一特性为开发者提供了按名称name获取服务的便利在某些场景下开发者无需再自行创建工厂类来管理服务。接下来我们将深入探讨 KeyedService 的使用方法、特殊情况以及存在的一些问题。
二、基本使用示例
1. 简单示例代码
var serviceCollection new ServiceCollection();
serviceCollection.AddKeyedSingletonIUserIdProvider, EnvironmentUserIdProvider(env);
serviceCollection.AddKeyedSingletonIUserIdProvider, NullUserIdProvider();using var services serviceCollection.BuildServiceProvider();
var userIdProvider services.GetRequiredKeyedServiceIUserIdProvider();
Console.WriteLine(userIdProvider.GetUserId());var envUserIdProvider services.GetRequiredKeyedServiceIUserIdProvider(env);
Console.WriteLine(envUserIdProvider.GetUserId());file interface IUserIdProvider
{string GetUserId();
}
file sealed class EnvUserIdProvider : IUserIdProvider
{public string GetUserId() Environment.MachineName;
}
file sealed class NullUserIdProvider : IUserIdProvider
{public string GetUserId() (null);
}2. 代码解释
上述代码展示了 KeyedService 的基本使用。我们通过 AddKeyedSingleton 方法注册了两个不同的 IUserIdProvider 实现并分别使用不同的键“env” 和 “”进行标识。然后通过 GetRequiredKeyedService 方法根据键来获取相应的服务实例。
3. 输出结果分析
运行代码后输出结果为
(null)
WEIHANLI - SURFACE这表明我们成功地根据不同的键获取到了对应的服务实例并调用了其方法。
三、特殊的 serviceKeyAnyKey
1. 使用 AnyKey 捕获未注册的 serviceKey
var serviceCollection new ServiceCollection();
serviceCollection.AddKeyedSingletonIUserIdProvider, NullUserIdProvider(KeyedService.AnyKey);using var services serviceCollection.BuildServiceProvider();
var userIdProvider services.GetRequiredKeyedServiceIUserIdProvider();
Console.WriteLine(userIdProvider.GetUserId());var envUserIdProvider services.GetRequiredKeyedServiceIUserIdProvider(env);
Console.WriteLine(envUserIdProvider.GetUserId());2. 代码解释
这里我们使用 KeyedService.AnyKey 来注册服务。当我们获取服务时即使使用了未注册的键如 “” 和 “env”也不会报错而是使用 AnyKey 注册的服务。
3. 输出结果及对象验证
输出结果为
(null)
(null)为了验证不同键获取的服务实例是否为同一个对象我们添加了以下代码
Console.WriteLine(userIdProvider envUserIdProvider ?? {0}, userIdProvider envUserIdProvider);输出结果为
userIdProvider envUserIdProvider ?? False这表明不同的 serviceKey 获取的是不同的对象。
4. serviceKey 为 null 的情况
当 serviceKey 为 null 时情况比较特殊。在当前的 API 设计中虽然允许 serviceKey 为 null但实际上这会导致问题。例如
var nullUserIdProvider services.GetRequiredKeyedServiceIUserIdProvider(null);
Console.WriteLine(nullUserIdProvider.GetUserId());会抛出异常
System.InvalidOperationException: No service for type Net8Sample.__ScriptFE1DBF3BE6F8384813B223E3EAA03DBABDC4153F95C5B3EBB0E0807E84E7C20E4__IUserIdProvider has been registered.这说明当 serviceKey 为 null 时并不会像使用 AnyKey 那样获取服务而是直接报错。并且如果注册 keyed service 时使用 null 作为 serviceKey实际上相当于注册了一个非 keyed service。
四、构造方法中的 ServiceKeyAttribute
1. 示例代码
var serviceCollection new ServiceCollection();
serviceCollection.AddKeyedTransientMyNamedService(KeyedService.AnyKey);
using var services serviceCollection.BuildServiceProvider();
Console.WriteLine(services.GetRequiredKeyedServiceMyNamedService(Foo).Name);
Console.WriteLine(services.GetRequiredKeyedServiceMyNamedService(Hello).Name);file sealed class MyNamedService
{public MyNamedService([ServiceKey] string name){Name name;}public string Name { get; }
}2. 代码解释
在构造方法中我们可以使用 ServiceKeyAttribute 来获取注册的 serviceKey。在上述示例中我们使用 KeyedService.AnyKey 注册服务然后通过不同的键获取服务实例并输出构造方法中获取的 serviceKey。
3. 输出结果
Foo
Hello这表明我们成功地在构造方法中获取到了实际使用的 serviceKey。
4. 类型一致性问题
需要注意的是构造方法中的 serviceKey 类型和获取服务时的类型应该保持一致否则会抛出异常。例如
Console.WriteLine(services.GetRequiredKeyedServiceMyNamedService(123).Name);会导致异常
System.InvalidOperationException: The type of the key used for lookup doesnt match the type in the constructor parameter with the ServiceKey attribute.5. serviceKey 类型的灵活性
虽然需要类型一致但 serviceKey 是 object 类型因此可以使用任意类型。例如
var serviceCollection new ServiceCollection();
serviceCollection.AddKeyedTransientMyKeyedService(KeyedService.AnyKey);
using var services serviceCollection.BuildServiceProvider();Console.WriteLine(services.GetRequiredKeyedServiceMyKeyedService(new Category()
{Id 1,Name test
}).Name);会输出 test。
五、Scoped Service 的问题
1. 示例代码及异常
var serviceCollection new ServiceCollection();
serviceCollection.AddKeyedScopedIUserIdProvider, NullUserIdProvider();
using var services serviceCollection.BuildServiceProvider();using var scope services.CreateScope();
var newId scope.ServiceProvider.GetRequiredKeyedServiceIIdGenerator().NewId();
Console.WriteLine(newId);运行上述代码会抛出异常
System.InvalidOperationException: This service provider doesnt support keyed services.2. 问题分析
这表明目前对于 scoped service 的支持存在问题。在 aspnetcore 中基于 HttpContext.RequestServices 获取 keyedService 也会出现同样的问题因为 HttpContext.RequestServices 是一个 scoped service provider。不过已经有 PR 修复了这个问题预计在 RC1 版本中发布。
六、结合 Options 使用 KeyedService
1. 示例代码
var serviceCollection new ServiceCollection();serviceCollection.ConfigureTotpOptions(x
{x.Salt 1234;
});
serviceCollection.AddKeyedTransientITotpService, TotpService(KeyedService.AnyKey,(sp, key) new TotpService(sp.GetRequiredServiceIOptionsMonitorTotpOptions().Get(key is string name ? name : Options.DefaultName)));using var services serviceCollection.BuildServiceProvider();
var totpService services.GetRequiredKeyedServiceITotpService(string.Empty);
Console.WriteLine(Totp1: {0}, totpService.GetCode(Test1234));
var totpService2 services.GetRequiredKeyedServiceITotpService(test);
Console.WriteLine(Totp2: {0}, totpService2.GetCode(Test1234));2. 代码解释
通过结合 Options我们可以方便地实现基于选项的命名服务。在上述示例中我们根据不同的键获取不同的 ITotpService 实例并调用其 GetCode 方法。
3. 输出结果
Totp1: 356934
Totp2: 626994七、总结与见解
1. 优点
KeyedService 解决了一些命名服务的痛点让开发者可以更方便地按名称获取服务减少了手动创建工厂类的工作量。结合 Options 使用时还能实现更灵活的服务配置。
2. 不足
然而目前该特性还存在一些问题如 serviceKey 可以为 null 的设计不太合理scoped service 支持存在 bug 等。不过考虑到这是预览版这些问题是可以接受的希望在正式版中能够得到妥善解决。
总体而言KeyedService 是 .NET 8 中一个很有潜力的特性为服务管理提供了新的思路和方法。开发者可以在项目中尝试使用但在正式项目中使用时需要谨慎考虑其稳定性。 前些天发现了一个比较好玩的人工智能学习网站通俗易懂风趣幽默可以了解了解AI基础知识人工智能教程不是一堆数学公式和算法的那种用各种举例子来学习读起来比较轻松有兴趣可以看一下。 人工智能教程