You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

何时用GetRequiredService()而非直接注册类?Redis场景解惑

问题场景与疑问

背景代码

原Startup.ConfigureServices()中的服务注册代码如下:

...
services
.AddSingleton(x =>
                {
                    IConnectionMultiplexer connection = ...
                    string keyPrefix = ...
                    return new RedisSessionService(connection, keyPrefix);
                })
.AddSingleton<ITicketStore>(x => x.GetRequiredService<RedisSessionService>())
.AddSingleton<ISessionService>(x => x.GetRequiredService<RedisSessionService>())
.AddSingleton<ILookupNormalizer, LowerInvariantLookupNormalizer>()
...

其中RedisSessionService同时实现了ITicketStore(来自Microsoft.AspNetCore.Authentication.Cookies命名空间)和自定义接口ISessionService。

错误场景

若改用直接注册方式:

.AddSingleton<ITicketStore, RedisSessionService>()
.AddSingleton<ISessionService, RedisSessionService>()

则会抛出以下错误:

Unable to resolve service for type 'System.String' while attempting to activate 'MyNamespace.IdentityServer4.Server.Services.RedisSessionService'.

疑问

  1. 此场景下为何必须使用GetRequiredService()?
  2. 何时应使用GetRequiredService(),何时应使用AddSingleton<ISomeInterface, SomeClass>()?

问题解答

一、此场景必须用GetRequiredService()的原因

核心问题出在RedisSessionService的构造函数依赖上:它需要IConnectionMultiplexer和string类型的keyPrefix参数,而string是简单值类型,DI容器无法自动解析这类未注册的基础类型(DI只能自动解析已在容器中注册的服务实例,不会凭空生成一个字符串)。

原代码中,你通过工厂委托AddSingleton(x => { ... })手动完成了RedisSessionService的实例化——手动传入了connection和keyPrefix,同时把这个实例以自身类型RedisSessionService注册到了DI容器中。

而改用AddSingleton<ITicketStore, RedisSessionService>()这种方式时,DI容器会尝试自动构造RedisSessionService实例,但它找不到string类型的注册项,因此抛出无法解析System.String的错误。

此时使用GetRequiredService<RedisSessionService>(),本质是告诉DI容器:不要重新创建新的RedisSessionService实例,直接复用之前通过工厂委托创建好的那个实例,将其映射到ITicketStore和ISessionService接口上。这样既保证了单例实例的唯一性,又避免了DI容器尝试解析无法自动处理的构造函数依赖。

二、两种注册方式的适用场景

1. 优先使用AddSingleton<ISomeInterface, SomeClass>()的场景

  • 服务类(SomeClass)的构造函数依赖全部是已注册的服务类型(比如其他接口、自定义类,不包含string、int这类无法自动解析的简单类型)。
  • 不需要手动干预实例化过程,希望DI容器自动管理实例的创建逻辑。
  • 服务类的实例化逻辑简单,无需额外参数拼接、条件判断等自定义操作。

2. 需要使用GetRequiredService()的场景

  • 已通过工厂委托手动创建并注册了某个类的实例,需要将同一个实例映射到多个不同的接口上(如你的场景:一个实例实现两个接口,需同时注册到两个接口)。
  • 需要复用已有的实例,避免DI容器创建多个相同类的实例,保证单例唯一性。
  • 服务类的实例化需要自定义逻辑,无法通过DI自动解析构造函数依赖(比如需要传入简单类型参数、动态生成的参数等),此时先通过工厂委托创建实例,再用GetRequiredService将实例映射到对应接口。

内容的提问来源于stack exchange,提问作者David Klempfner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:42:53