将使用WebRequestHandler的代码迁移至.NET Standard 2.0适配问题
你可以根据项目实际情况选择以下任意一种方案,不需要迁移到.NET Core 2.1,也不会影响现有.NET Framework 4.8程序的依赖。
方案1:多目标框架(推荐,零行为差异)
这是兼容性最好的方案,不需要改写原有业务逻辑,只需要修改类库的项目配置,让它同时针对net48和netstandard2.0两个目标框架编译:
- 右键项目编辑csproj文件,将原本的单目标配置修改为多目标配置:
<TargetFrameworks>net48;netstandard2.0</TargetFrameworks>
- 用条件编译符号拆分不同目标框架下的Handler初始化逻辑,.NET Framework 4.8编译时继续沿用原有
WebRequestHandler逻辑,.NET Standard 2.0编译时用兼容实现,示例代码如下:
private static HttpClient CreateHttpClientItem(Uri uri, TimeSpan timeout, HttpMessageHandler messageHandler) { if (messageHandler == null) { #if NET48 messageHandler = new WebRequestHandler { Credentials = new CredentialCache { { uri, "NTLM", CredentialCache.DefaultNetworkCredentials } }, AllowAutoRedirect = true, UnsafeAuthenticatedConnectionSharing = true }; #else // .NET Standard 2.0下用WinHttpHandler,行为和WebRequestHandler高度一致 messageHandler = new WinHttpHandler { Credentials = new CredentialCache { { uri, "NTLM", CredentialCache.DefaultNetworkCredentials } }, AllowAutoRedirect = true, UnsafeAuthenticatedConnectionSharing = true, // 配置连接池参数,从根源避免TIME_WAIT端口堆积 MaxConnectionsPerServer = 10, TcpKeepAliveEnabled = true, TcpKeepAliveTime = TimeSpan.FromMinutes(5) }; #endif } return new HttpClient(messageHandler) { BaseAddress = uri, Timeout = timeout }; }
- 给netstandard2.0的目标框架添加
System.Net.Http.WinHttpHandler的NuGet包引用,用条件引用避免net48下引入多余依赖:
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <PackageReference Include="System.Net.Http.WinHttpHandler" Version="7.0.0" /> </ItemGroup>
该方案下,原有依赖类库的.NET Framework 4.8程序引用的是net48版本的编译输出,完全沿用之前的逻辑,不会有任何行为变化;需要.NET Standard 2.0版本的引用方拿到的是对应编译输出,也能正常使用NTLM认证、连接复用能力。
方案2:单目标.NET Standard 2.0,直接替换为WinHttpHandler
如果不想做多目标编译,可以直接把项目目标保持为netstandard2.0,移除.NET Framework专属的WebRequestHandler相关引用,安装System.Net.Http.WinHttpHandlerNuGet包,直接用方案1中#else块的WinHttpHandler初始化逻辑替换原来的WebRequestHandler即可。
WinHttpHandler是微软官方提供的HTTP消息实现,底层基于Windows WinHTTP接口(和WebRequestHandler底层同源),完全支持NTLM默认认证、自动重定向、非安全认证连接共享等特性,同时暴露了完整的连接池配置参数,只要正确设置MaxConnectionsPerServer、开启TCP KeepAlive,就不会出现静态HttpClient产生大量TIME_WAIT端口的问题。
方案3:原生HttpClientHandler兼容配置(无额外依赖)
如果不想引入额外的NuGet包,也可以用.NET Standard 2.0自带的HttpClientHandler,手动补齐对应的属性配置和连接池参数,也能达到同样效果:
messageHandler = new HttpClientHandler { Credentials = new CredentialCache { { uri, "NTLM", CredentialCache.DefaultNetworkCredentials } }, AllowAutoRedirect = true, UnsafeAuthenticatedConnectionSharing = true, MaxConnectionsPerServer = 10, UseProxy = false, // 根据实际代理需求配置 UseDefaultCredentials = false };
该方案下必须确保HttpClient实例是长生命周期(静态/单例),不要每次请求都新建HttpClient实例,同时MaxConnectionsPerServer不要设置为int.MaxValue,就能避免TIME_WAIT端口堆积问题。
注意:无论选择哪种方案,都不要在每次HTTP请求时新建HttpClient和对应的HttpMessageHandler,应该将初始化好的HttpClient实例缓存起来复用,这是避免TIME_WAIT端口问题的核心前提。
内容的提问来源于stack exchange,提问作者Marcin

