首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Flurl强行关闭SocketException现有连接

使用Flurl强行关闭SocketException现有连接
EN

Stack Overflow用户
提问于 2020-01-02 18:03:39
回答 2查看 968关注 0票数 1

我试图使用弗勒尔作为我的HTTP库(Version2.4.2)查询公共NPPES注册表。

在4-5成功的异步请求(通过遍历循环中的每个请求进行调试)之后,对于SocketException来说,连接被强制关闭总是失败的。我假设API的速率是有限的,但是放慢请求的速度似乎不起作用。这是我的相关代码。

代码语言:javascript
复制
static async Task<Result> GetNpiEntry(string npiNumber)
{
    var npiEntry = await "https://npiregistry.cms.hhs.gov"
        .AppendPathSegment("api/")
        .SetQueryParams(new { version = "2.1", number = npiNumber }).GetJsonAsync<RootObject>();

    return npiEntry.results[0];
}

循环在请求之间有很大的睡眠来调用它。

代码语言:javascript
复制
List<Result> npiResults = new List<Result>(npiTable.Rows.Count);

foreach (DataRow row in npiTable.Rows)
{
    Result npiEntry = Task.Run(() => GetNpiEntry((string)row[0])).Result;
    npiResults.Add(npiEntry);
    Thread.Sleep(2000);
}

这是实际的例外。

代码语言:javascript
复制
 ---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
 ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.  

是否有更合适的方法来调试或执行此操作?我想我需要限制客户端的等级,但是请求之间的等待时间是否至少对于调试是有效的呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-02 19:19:23

问题不是Flurl或API节流,而是阻塞异步调用(如@WBuck所说)。

最佳实践是避免.Result甚至.GetAwaiter().GetResult()。这些和Task.Run()都是同步和异步代码混合的例子。有好的文章在线,为什么这是坏-搜索.net mix sync async获得更多的背景信息。

正确的解决方案是使用异步“一路向下”。现在几乎每个入口点都可以标记为async,包括控制台应用程序。

这在我的机器上工作,甚至在没有的情况下也适用于:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;

namespace SO_59567958
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var ids = new[] { "1023086709", "1659325215", "1912946427", "1740219450", "1750497640", "1538260823", "1275625626", "1144303488", "1205919107", "1730281890", "1568453561" };
            Console.WriteLine($"Retrieving {ids.Length} NPI records...");

            var npiResults = new List<Result>();
            foreach (var id in ids)
            {
                var retrievedFromApi = await GetNpiEntry(id);
                npiResults.Add(retrievedFromApi);
            }

            Console.WriteLine("Done");
            npiResults.ForEach(x => Console.WriteLine(x.Number));
        }

        static async Task<Result> GetNpiEntry(string npiNumber)
        {
            var npiEntry = await "https://npiregistry.cms.hhs.gov"
                .AppendPathSegment("api/")
                .SetQueryParams(new { version = "2.1", number = npiNumber })
                .GetJsonAsync<RootObject>();

            return npiEntry.Results[0];
        }
    }

    public class RootObject
    {
        public int ResultCount { get; set; }

        public IReadOnlyList<Result> Results { get; set; }
    }

    public class Result
    {
        public int Number { get; set; }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2020-01-02 19:10:13

您不是在await中调用Task.Run lambda中的GetNpiEntry。如果对GetNpiEntry的调用是同步执行的,那么您就没有问题。如果对GetNpiEntry的调用异步执行,那么Task.Run lambda将不会对其结果进行await

相反,请尝试以下几点:

代码语言:javascript
复制
foreach (DataRow row in npiTable.Rows)
{
    Result npiEntry = Task.Run( async () => await GetNpiEntry((string)row[0])).GetAwaiter( ).GetResult( );
    npiResults.Add(npiEntry);
    Thread.Sleep(2000);
}

我还看到您使用的是.NetCore,因此您应该能够使用下面的main

代码语言:javascript
复制
static async Task Main( string[ ] args )

这允许您在await中使用Main

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59567958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档