c# - 尝试从分页网址中获取所有项目时结果不一致

标签 c# .net asynchronous pagination dotnet-httpclient

我在获取当前托管在 hubspot 中的所有表单时遇到问题。

我尝试使用一个简单的 for 循环,一次发出一个请求,一次获取一个表单,这种方法有效,但速度非常慢。

然后我认为如果我为每个请求创建一个单独的任务,然后让任务创建每个请求,并将它们存储在一个公共(public)列表中,可能会更好。

问题是我希望列表有 2000 个项目,但我似乎从来没有得到,我得到的项目数量似乎很不一致?

但是怎么会呢?

这就是我设置抓取方案的方式。

private static async Task<IEnumerable<HubspotModel>> GetForms(
    string hubspotPath, int pageSize)
{
    int totalResults;
    int offset = 0;
    List<HubspotModel> output = new();
    List<Task> tasks = new();
    using var client = new HttpClient();
    {
        System.Net.Http.Headers.HttpResponseHeaders requestHeader = client
            .GetAsync($"https://api.hubapi.com{hubspotPath}?" +
                $"hapikey={HubspotConfiguration.ApiKey}&limit={1}&offset={0}")
            .Result.Headers;
        totalResults = int.Parse(requestHeader.GetValues("x-total-count").First());
        do
        {
            tasks.Add(Task.Run(() =>
            {
                int scopedOffset = offset;
                IEnumerable<HubspotModel> forms = GetFormsFromHubspot(hubspotPath,
                    pageSize, offset, client);
                output.AddRange(forms);

            }).ContinueWith(requestReponse =>
            {
                if (requestReponse.IsFaulted)
                {
                    Console.WriteLine("it failed");
                }
            }));
            offset += pageSize;
        }
        while (totalResults > offset);

        await Task.WhenAll(tasks);
    }

    return output;
}

private static IEnumerable<HubspotModel> GetFormsFromHubspot(string hubspotPath,
    int pageSize, int offset, HttpClient client)
{
    HttpResponseMessage request = client
        .GetAsync($"https://api.hubapi.com{hubspotPath}?" +
            $"hapikey={HubspotConfiguration.ApiKey}&limit={pageSize}&offset={offset}")
        .Result;
    request.EnsureSuccessStatusCode();
    string content = request.Content.ReadAsStringAsync().Result;
    IEnumerable<Dictionary<string, object>> jsonResponse = JsonSerializer
        .Deserialize<IEnumerable<Dictionary<string, object>>>(content,
        new JsonSerializerOptions() { });
    var guid = Guid.Parse(jsonResponse.First()["guid"].ToString());
    var forms = jsonResponse.Select(x => new HubspotModel()
    {
        id = Guid.Parse(x["guid"].ToString()),
        FormName = x["name"].ToString(),
        Form = x
    });
    return forms;
}

最佳答案

首先,我建议将 GetFormsFromHotspot 也设为 async 并使用 await client.GetAsync( ...)await request.Content.ReadAsStringAsync() 分别代替 client.GetAsync(...).ResultReadAsStringAsync().Result,因为使用 .Result 会阻塞当前线程,因此您将失去异步任务的优势。

但问题的主要原因应该是以下几点

GetFormsFromHubspot(hubspotPath, pageSize, offset, client);

在这里,您使用来自外部作用域的 offset 参数调用 GetFormsFromHubspot(并且该值不断变化),因此它不会使用您使用时的值创建了那个任务,但是当代码的特定部分真正被执行时,它使用它实际拥有的值。所以用作偏移量的值是非常随机的。您已经尝试创建一个

int scopedOffset = offset;

但你不使用它。而且你在错误的位置创建它。创建 scopedOffset 在任务的外部,但在循环体的内部。因此它将在任务创建时创建。因为它在循环体内,所以将为每个任务创建一个新值。

以下应该可以解决问题(在将 GetFormsFromHubspot 重构为异步之后。

do {
  int scopedOffset = offset
  tasks.Add(Task.Run(async () => {
      IEnumerable<HubspotModel> forms = await GetFormsFromHubspot(hubspotPath, pageSize, scopedOffset, client);
      output.AddRange(forms);
    })     
    .ContinueWith(...);
  );
  offset += pageSize;
} while (totalResults > offset);

关于c# - 尝试从分页网址中获取所有项目时结果不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72949740/

相关文章:

c# - 是否应该为 Process.GetCurrentProcess() 调用 Dispose?

asynchronous - 当mapcat破坏core.async中的背压时,内存泄漏在哪里?

node.js - 多个 bash 脚本无法在生成的子进程中异步运行

c# - 从 VSTO 项目中的 Excel 工作簿中读取五十万条记录

c# - 单击 WPF richtextbox 中的 TextBlock

c# - NHibernate 3.0 IQueryable<T> 完全支持哪些 linq 函数

c# - 导入哪些目录以使用 Xml 和 Linq - C#

c# - Entity Framework 异常 : Invalid object name

c# - 在异步函数上使用 await 时出现异常

c# - 响应式用户界面提示