【问题标题】:ObjectDisposedException / SocketsHttpHandler in .NET 3.1.NET 3.1 中的 ObjectDisposedException / SocketsHttpHandler
【发布时间】:2020-06-29 11:31:00
【问题描述】:

我在我的一个项目中使用 asp.net 核心,并且我正在使用客户端证书发出一些 https 请求。为此,我创建了一个类型化的 http 客户端并将其注入到我的 startup.cs 中,如下所示:

services.AddHttpClient<IClientService, ClientService>(c =>
            {
            }).ConfigurePrimaryHttpMessageHandler(() =>
            {
                var handler = new HttpClientHandler();
                handler.ClientCertificateOptions = ClientCertificateOption.Manual;
                handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.Tls11;
                handler.ClientCertificates.Add(clientCertificate);
                handler.ServerCertificateCustomValidationCallback = delegate { return true; };
                return handler;
            }
            );

我的服务实现如下:

 public class ClientService : IClientService
    {
        public HttpClient _httpClient { get; private set; }
        private readonly string _remoteServiceBaseUrl;
        

        private readonly IOptions<AppSettings> _settings;


        public ClientService(HttpClient httpClient, IOptions<AppSettings> settings)
        {
            _httpClient = httpClient;
            _httpClient.Timeout = TimeSpan.FromSeconds(60);
            _settings = settings;
            _remoteServiceBaseUrl = $"{settings.Value.ClientUrl}";  /


        }

        async public Task<Model> GetInfo(string id)
        {
            var uri = ServiceAPI.API.GetOperation(_remoteServiceBaseUrl, id);
            var stream = await _httpClient.GetAsync(uri).Result.Content.ReadAsStreamAsync();
            var cbor = CBORObject.Read(stream);
            return JsonConvert.DeserializeObject<ModelDTO>(cbor.ToJSONString());
                
        }
    }

在我的调用类中,我正在使用以下代码:

public class CommandsApi 
    {
        IClientService _clientService;
       
        public CommandsApi( IclientService clientService)
           : base(applicationService, loggerFactory)
        {
            _clientService = clientService;
            _loggerfactory = loggerFactory;
        }
        public async Task<IActionResult> Post(V1.AddTransaction command)
        {

           
            var result = await _clientService.GetInfo(command.id);
        }
    }

它工作得很好,但是在发送了许多请求后,我收到了以下错误:

Cannot access a disposed object. Object name: 'SocketsHttpHandler'.
 at System.Net.Http.SocketsHttpHandler.CheckDisposed()
 at System.Net.Http.SocketsHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

我尝试了一些在以前的问题(asp.net core github)和 stackoverflow 中找到的解决方案,但它们不起作用。 任何的想法 ?谢谢

【问题讨论】:

  • 这是一个严重的安全漏洞:handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.Tls11; 它告诉 .NET 即使可用 TLS1.3 也要避免,并强制使用 TLS1.1 和过时的 TLS1 .0 即使它们默认被禁用。您不应该设置 SslProtocols 属性并让 .NET Core 使用操作系统提供的最佳加密
  • 是的,这只是给开发者
  • 那根本不需要

标签: c# asp.net-core .net-core-3.1 objectdisposedexception


【解决方案1】:

我怀疑这是由于资源没有被正确处理造成的。对 .Result 进行了不必要的调用,并且您创建了一个流,但您没有处理它。如果您使用 using 语句,则应处理流。 (你可以随时调用 stream.dispose() 但我不推荐它)。

var stream = await _httpClient.GetAsync(uri).Result.Content.ReadAsStreamAsync();

我没有运行这个,但考虑一下:

public async Task<Model> GetInfo(string id)
{
    var uri = ServiceAPI.API.GetOperation(_remoteServiceBaseUrl, id);
    var response = await _httpClient.GetAsync(uri);

    using (var stream = await response.Content.ReadAsStreamAsync())
    {
        var cbor = CBORObject.Read(stream);
        return JsonConvert.DeserializeObject<ModelDTO>(cbor.ToJSONString());
    }
}

【讨论】:

  • 我尝试了您的解决方案,但仍然遇到同样的错误。
  • 我知道问题是由 HttpClientHandler 引起的,但我仍在尝试解决它,但没有成功
  • 在 GetInfo 上,你有错误的公共异步方式,你能仔细检查一下吗?
  • GetInfo 只是一个简化的例子,我的 API 比较复杂,我只是给出了我如何调用服务的例子。
  • 对此感到抱歉。我已经做了一些挖掘,作为一个起点,您可能想要创建一个继承自 HttpClientHandler 的类(并包含自定义代码)并注入该类。请参阅来自:stackoverflow.com/questions/57875320/… 的答案
【解决方案2】:

所以经过多次测试后,我遵循@Greg 的建议,实现了一个继承自 HttpClientHandler 的类,并将其注入如下:

services.AddTransient<MyHttpClientHandler>();
services.AddHttpClient<IClientService, ClientService>().
                ConfigurePrimaryHttpMessageHandler<MyHttpClientHandler>();

这解决了我的问题。 谢谢@Greg 的链接 How to use ConfigurePrimaryHttpMessageHandler generic

【讨论】:

    猜你喜欢
    • 2012-06-03
    • 2021-05-05
    • 2020-04-01
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 2021-11-25
    相关资源
    最近更新 更多