【问题标题】:Web API Controller returning Task not always waits for task completion (puppeteer-sharp)Web API 控制器返回 Task 并不总是等待任务完成(puppeteer-sharp)
【发布时间】:2020-01-07 08:12:08
【问题描述】:

我有 Web API 控制器,它返回最初在外部库服务中创建的任务。我在从服务到控制器的所有链中返回任务,但问题是当我对该控制器进行 HTTP 调用时,当我第一次启动 API 时(第一次总是需要更长的时间)它返回完美的预期结果,但是当我第二次发出请求时等等..它返回一些部分结果。

当我调试它时,它总是返回预期的正确结果。显然现在有一些东西在等待..

代码如下:

        public async Task<HttpResponseMessage> DownloadBinary(string content)
        {
            byte[] recordToDown =  await ExternalLibraryConverter.GetAsync(content);

            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(recordToDown)
            };
            result.Content.Headers.ContentDisposition =
                new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                {
                    FileName = "Test file"
                };

            // added so Angular can see the Content-Disposition header
            result.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

            result.Content.Headers.ContentType =
                new MediaTypeHeaderValue("application/pdf");

            return result;
        }

和服务:

        public static async Task<byte[]> GetAsync(string content)
        {

            await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision)
                .ConfigureAwait(false);
            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
            }).ConfigureAwait(false);

            using (var page = await browser.NewPageAsync().ConfigureAwait(false))
            {
                await page.SetCacheEnabledAsync(false).ConfigureAwait(false);

                await page.SetContentAsync(content).ConfigureAwait(false);

                await page.AddStyleTagAsync("https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,600,700").ConfigureAwait(false);

                // few more styles add

                var result = await page.GetContentAsync().ConfigureAwait(false);

                PdfOptions pdfOptions = new PdfOptions()
                {
                    PrintBackground = true,
                    MarginOptions = new PuppeteerSharp.Media.MarginOptions {
                        Right = "15mm", Left = "15mm", Top = "20mm", Bottom = "20mm" },
                };
                byte[] streamResult = await page.PdfDataAsync(pdfOptions)
                    .ConfigureAwait(false);

                browser.Dispose();

                return streamResult;
            }
        }

如您所见,使用外部库的服务中有很多等待。我尝试在使用 await 的任何地方使用 ConfigureAwait(false),但这也无济于事。

【问题讨论】:

  • “部分结果”是什么意思?我看到您正在将网页转换为 PDF。您是否收到部分无效的 PDF 文件,甚至无法打开?或者您是否获得了仅包含网页一部分的有效 PDF 文件?
  • 您是否测试过在GetAsync方法中删除所有.ConfigureAwait(false)
  • @GabrielLuci 我得到了有效的 PDF,只有网页的一部分。当我使用调试时,所有数据都在那里。但是在nirmal Run中,除了第一次总是部分数据。
  • @FredrikStigsson 是的。结果相同
  • 顺便说一句,您无需致电page.Dispose(),因为using 会为您代劳。这就是using 的全部目的。

标签: c# asp.net asp.net-web-api async-await puppeteer-sharp


【解决方案1】:

我认为您不应该在控制器级别上执行 .ConfigureAwait,请参阅本文了解更多信息:https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html

ASP.NET 团队放弃了对 SynchronizationContext 的使用,因此在控制器中使用它毫无意义。

正如文章所述,您仍应在服务级别上使用它,因为您不知道 UI 是否可以将自己插入服务并使用它,但在您的 WEB API 上,您可以放弃它。

【讨论】:

  • 你是对的,是的。我将编辑帖子。然而,这并没有改变态度。
猜你喜欢
  • 1970-01-01
  • 2016-09-10
  • 1970-01-01
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多