在含额外参数的类中注入Typed HttpClient遇问题求解析
类型化HttpClient的绑定逻辑
用AddHttpClient<MyService>注册时,DI容器并不会直接把MyService注册为服务,而是注册了一个专属工厂。这个工厂的作用是:当DI需要创建MyService实例时,自动生成带有你配置的BaseAddress的HttpClient,并注入到MyService中。手动实例化的问题所在
当你手动new MyService(...)时,调用GetRequiredService<HttpClient>()拿到的是DI容器里的默认HttpClient实例——这个实例和AddHttpClient<MyService>配置的专属实例完全没关系。只有让DI容器全权负责创建MyService(也就是移除字符串参数,让DI自动解析),才会触发那个专属工厂,拿到带配置的HttpClient。命名HttpClient为什么正常
命名HttpClient是通过字符串标识来绑定配置的,不管你是自动注入还是手动创建服务,只要调用IHttpClientFactory.CreateClient("你的命名"),就能直接拿到对应配置的HttpClient实例,不存在和特定服务类绑定的限制。
绑定关系不同
- 类型化:和特定服务类强绑定,配置是该类的专属资源,DI会自动关联两者,无需额外指定标识。
- 命名:通过自定义字符串名称标识配置,配置和服务类是分离的,一个命名配置可以被多个服务复用。
使用方式不同
- 类型化:只能依赖DI容器自动解析服务类来获取绑定的
HttpClient,手动提取HttpClient拿不到专属配置。 - 命名:通过
IHttpClientFactory.CreateClient("名称")主动获取,不管是自动注入还是手动实例化服务,都能直接拿到配置好的实例。
- 类型化:只能依赖DI容器自动解析服务类来获取绑定的
适用场景不同
- 类型化:适合单个服务对应一套HttpClient配置的场景,代码更简洁,不用记命名标识。
- 命名:适合多服务共享同一配置、或者需要动态切换不同HttpClient配置的场景,灵活性更高。
如果必须手动创建MyService实例,又要用到AddHttpClient<MyService>配置的HttpClient,可以通过IHttpClientFactory.CreateClient(typeof(MyService).FullName)来获取——因为类型化HttpClient的默认命名就是对应服务类的完整名称。
内容的提问来源于stack exchange,提问作者exSnake

