我试图使用弗勒尔作为我的HTTP库(Version2.4.2)查询公共NPPES注册表。
在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];
}循环在请求之间有很大的睡眠来调用它。
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);
}这是实际的例外。
---> 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. 是否有更合适的方法来调试或执行此操作?我想我需要限制客户端的等级,但是请求之间的等待时间是否至少对于调试是有效的呢?
发布于 2020-01-02 19:19:23
问题不是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; }
}
}发布于 2020-01-02 19:10:13
您不是在await中调用Task.Run lambda中的GetNpiEntry。如果对GetNpiEntry的调用是同步执行的,那么您就没有问题。如果对GetNpiEntry的调用异步执行,那么Task.Run lambda将不会对其结果进行await。
相反,请尝试以下几点:
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 )这允许您在await中使用Main。
https://stackoverflow.com/questions/59567958
复制相似问题