C# SocketException现有连接使用Flurl强制关闭

C# SocketException现有连接使用Flurl强制关闭,c#,.net-core,async-await,flurl,C#,.net Core,Async Await,Flurl,我正在尝试使用2.4.2版作为我的HTTP客户端库来查询公共NPPES NPI注册表 在4-5次成功的异步请求(通过单步执行循环中的每个请求进行调试)之后,它总是会失败,并出现SocketException,即连接被强制关闭。我假设API是有速率限制的,但是减慢请求速度似乎不起作用。这是我的相关代码 static async Task<Result> GetNpiEntry(string npiNumber) { var npiEntry = await "https://n

我正在尝试使用2.4.2版作为我的HTTP客户端库来查询公共NPPES NPI注册表

在4-5次成功的异步请求(通过单步执行循环中的每个请求进行调试)之后,它总是会失败,并出现SocketException,即连接被强制关闭。我假设API是有速率限制的,但是减慢请求速度似乎不起作用。这是我的相关代码

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];
}
是否有更适合我调试或执行此操作的方法?
我想我需要对客户端进行评级限制,但请求之间的大量等待时间是否至少对调试有用?

您没有在
任务中等待调用
GetNpiEntry
。运行
lambda。如果对
GetNpiEntry
的调用是同步执行的,那么您就没有问题了。如果对
GetNpiEntry
的调用异步执行,则
Task.Run
lambda将不会
等待其结果

请尝试以下操作:

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

static async Task Main( string[ ] args )

这允许您在
Main
中使用
wait
。问题不是Flurl或API节流,而是异步调用阻塞(正如@WBuck所说)

最佳做法是避免
.Result
甚至
.GetAwaiter().GetResult()
。这些和
Task.Run()
都是混合同步和异步代码的示例。网上有很多好文章可以解释为什么这不好-搜索
.net mix sync async
了解更多背景信息

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

这在我的机器上工作,即使没有睡眠:

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; }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Threading.Tasks;
使用Flurl;
使用Flurl.Http;
名称空间SO59567958
{
班级计划
{
静态异步任务主(字符串[]args)
{
var id=new[]{“1023086709”、“1659325215”、“1912946427”、“1740219450”、“1750497640”、“1538260823”、“1275625626”、“1144303488”、“1205919107”、“1730281890”、“1568453561”};
WriteLine($“检索{ids.Length}NPI记录…”);
var npiResults=新列表();
foreach(id中的变量id)
{
var retrievedFromApi=wait GetNpiEntry(id);
npiResults.Add(从API检索);
}
控制台。写入线(“完成”);
npiResults.ForEach(x=>Console.WriteLine(x.Number));
}
静态异步任务GetNpiEntry(字符串npiNumber)
{
var npiEntry=wait“https://npiregistry.cms.hhs.gov"
.AppendPathSegment(“api/”)
.SetQueryParams(新的{version=“2.1”,number=npiNumber})
.GetJsonAsync();
返回npiEntry.Results[0];
}
}
公共类根对象
{
public int ResultCount{get;set;}
公共IReadOnlyList结果{get;set;}
}
公开课成绩
{
公共整数{get;set;}
}
}

欢迎使用堆栈溢出!感谢您在问题中发布您的代码和详细的错误信息,这样更容易回答。:)你能完成你的
任务吗?运行
lambda
async
,然后
等待
调用
GetNpiEntry
。Ie:
Task.Run(async()=>await GetNpiEntry
@WBuck我不能添加它,因为它无法编译,foreach循环嵌套在
静态void Main(string[]args){}
入口点中。在Task.Run()之前添加另一个睡眠call允许它在遇到此错误之前完成约1000个请求,但它仍然会遇到此错误。我正在发布一个答案给我第二个WBUCK的答案是正确的。我在我的中添加了一些详细信息和一个复制。希望这对@tNAPA有帮助!感谢这对处理结果有帮助,但是之后(在本例中为101)请求远程主机关闭套接字并引发异常。发生这种情况时,我应该如何处理重新打开新套接字的问题,更直接地说,当我可以检索大约2000个NPI(按顺序)时,为什么会失败通过编程较少的客户端,在2分钟内不会出现问题,但是在这个C版本中,在请求之间等待几秒钟肯定会在几分钟后失败。网络异常会发生。这只是可以而且经常失败的事情之一。这取决于您是否捕捉到异常。一旦捕捉到异常,您需要决定如何从中恢复。通常我会使用“重试”逻辑,在失败时尝试相同的调用
N次
。通常我首先尝试重新连接
远程
,成功连接后,我将重新发出请求。简单的尝试{}捕获{wait and retry}似乎已经足够了。谢谢。感谢您解释如何正确地执行wait异步调用。但是,在经过足够多的迭代后,该示例仍然失败,出现了相同的套接字错误。我有一个不太有用的实现(由另一个程序生成的VB.NET),可以完成对整个数据集的查询(~2000个条目)在大约2分钟内不会出现错误或任何休眠,但经过几十次查询后,连接会被强制关闭。我想我只要捕获异常并等待重试就可以很好地处理它,谢谢。不客气!有关更复杂的重试策略,请查看:
static async Task Main( string[ ] args )
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; }
    }
}