C# SocketException现有连接使用Flurl强制关闭
我正在尝试使用2.4.2版作为我的HTTP客户端库来查询公共NPPES NPI注册表 在4-5次成功的异步请求(通过单步执行循环中的每个请求进行调试)之后,它总是会失败,并出现SocketException,即连接被强制关闭。我假设API是有速率限制的,但是减慢请求速度似乎不起作用。这是我的相关代码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
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;}
}
}
欢迎使用堆栈溢出!感谢您在问题中发布您的代码和详细的错误信息,这样更容易回答。:)你能完成你的任务吗?运行lambdaasync
,然后等待调用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; }
}
}