通过 StructureMap 定义“HttpClient”单例会导致有关“HttpMessageHandler”未在运行时配置的错误
Posted
技术标签:
【中文标题】通过 StructureMap 定义“HttpClient”单例会导致有关“HttpMessageHandler”未在运行时配置的错误【英文标题】:Defining an 'HttpClient' singleton via StructureMap causes an error about 'HttpMessageHandler' being not configured in runtime 【发布时间】:2019-01-03 14:55:05 【问题描述】:试图在 StructureMap ala 中定义一个 HttpClient 单例:
For<HttpClient>().Singleton().UseIfNone<HttpClient>();
这会导致运行时出现以下错误(依赖注入时):
StructureMap.StructureMapConfigurationException: No default Instance is registered and cannot be automatically determined for type 'System.Net.Http.HttpMessageHandler'
There is no configuration specified for System.Net.Http.HttpMessageHandler
1.) new HttpClient(*Default of HttpMessageHandler*)
2.) System.Net.Http.HttpClient
3.) Instance of System.Net.Http.HttpClient
4.) new AdmanAdapter(*Default of HttpClient*)
5.) Organotiki.vNext.PostEval.Data.Adapters.ADMAN.AdmanAdapter
6.) Instance of [....]
at lambda_method(Closure , IBuildSession , IContext )
at StructureMap.Building.BuildPlan.Build(IBuildSession session, IContext context)
at StructureMap.BuildSession.BuildNewInSession(Type pluginType, Instance instance)
at StructureMap.Pipeline.NulloTransientCache.Get(Type pluginType, Instance instance, IBuildSession session)
at StructureMap.BuildSession.ResolveFromLifecycle(Type pluginType, Instance instance)
at StructureMap.SessionCache.GetObject(Type pluginType, Instance instance, ILifecycle lifecycle)
如果我们也像这样配置HttpMessageHandler:
For<HttpClient>().Singleton().UseIfNone<HttpClient>();
For<HttpMessageHandler>().UseIfNone(x => new HttpClientHandler());
然后问题就消失了。问题是为什么? HttpClient 的默认构造函数负责自己的依赖注入:
/// <summary>Initializes a new instance of the <see cref="T:System.Net.Http.HttpClient" /> class.</summary>
[__DynamicallyInvokable]
public HttpClient()
: this((HttpMessageHandler) new HttpClientHandler())
我错过了什么吗?
【问题讨论】:
容器默认不使用默认构造函数。如果找到多个构造函数,则使用依赖关系最多的构造函数。 【参考方案1】:来自http://structuremap.github.io/registration/constructor-selection的结构图文档
如果混凝土上有多个公共构造函数 类,StructureMap 的默认行为是选择“最贪婪的” 构造函数,即参数最多的构造函数。
如果你查看HttpClient
的可能构造函数,它应该是
public HttpClient();
public HttpClient(HttpMessageHandler handler);
public HttpClient(HttpMessageHandler handler, bool disposeHandler);
【讨论】:
感谢您的洞察力。还有一个问题:如果我使用“ForHttpClient
是一个具体的类,因此结构映射总是能够“尝试”创建它的实例。如果它是一个接口,例如IFoo
,那么它将求助于使用您的 lamdba 表达式来获取实例。就像现在一样,它完全忽略了您的UseIfNone
。
我想我必须继承 HttpClient 的子类,然后用接口装饰子类,然后配置那个接口。这将是一次多么奇怪的旅行。谢谢顺便说一句。我自己永远无法想象出所有这些微妙之处。竖起大拇指,伙计。
您应该能够执行类似于以下的操作...For<HttpClient>().Singleton().Use(x => new HttpClient())
。在这里,您明确告诉结构映射“这正是我希望创建 HttpClient
实例的方式”【参考方案2】:
扩展@Brad M 的答案,对我有用的是.SelectConstructor(() => new HttpClient())
。指定应显式使用的构造函数。
【讨论】:
以上是关于通过 StructureMap 定义“HttpClient”单例会导致有关“HttpMessageHandler”未在运行时配置的错误的主要内容,如果未能解决你的问题,请参考以下文章