Http.IMiddleware Не создавайте задачи без передачи TaskScheduler - PullRequest
0 голосов
/ 14 апреля 2020

(. Net 3.1, Visual Studio 2019)

В примере кода Dev Express: https://github.com/DevExpress-Examples/blazor-server-dxdatagrid-export/blob/19.2.2%2B/CS/DxDataGridExportingWithReports/Helpers/ExportMiddleware.cs следующий код промежуточного ПО http получил предупреждение

Не создавать задачи без передачи TaskScheduler ...

Как правильно переписать код для запуска новой задачи?

public class ExportMiddleware : IMiddleware
{
    ......

    public Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
       ......

        _ = await new TaskFactory().StartNew(() => // warning: Do not create tasks without passing a TaskScheduler
        {
            report.CreateDocument();
            using (MemoryStream fs = new MemoryStream())
            {
                if (format == pdf)
                    report.ExportToPdf(fs);
                else if (format == xlsx)
                    report.ExportToXlsx(fs);
                else if (format == docx)
                    report.ExportToDocx(fs);
                context.Response.Clear();
                context.Response.Headers.Append("Content-Type", "application/" + format);
                context.Response.Headers.Append("Content-Transfer-Encoding", "binary");
                context.Response.Headers.Append("Content-Disposition", "attachment; filename=ExportedDocument." + format);
                context.Response.Body.WriteAsync(fs.ToArray(), 0, fs.ToArray().Length);
                return context.Response.CompleteAsync();
            }
        });

1 Ответ

2 голосов
/ 16 апреля 2020

Технически, чтобы ответить на реальный вопрос, код должен использовать Task.Run вместо StartNew:

_ = Task.Run(() =>

Однако это феноменально плохая идея. Мало того, что он делает fire-and-Forgot , он будет использовать context.Response в случайное время в будущем. И он начнет запись в поток ответов, а затем завершит поток до завершения записи. Он просто полностью сломан.

Я считаю более подходящим решением было бы просто полностью удалить заводские настройки / запустить / запустить и использовать await, где это необходимо:

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
  ......
  report.CreateDocument();
  using (MemoryStream fs = new MemoryStream())
  {
    if (format == pdf)
      report.ExportToPdf(fs);
    else if (format == xlsx)
      report.ExportToXlsx(fs);
    else if (format == docx)
      report.ExportToDocx(fs);
    context.Response.Clear();
    context.Response.Headers.Append("Content-Type", "application/" + format);
    context.Response.Headers.Append("Content-Transfer-Encoding", "binary");
    context.Response.Headers.Append("Content-Disposition", "attachment; filename=ExportedDocument." + format);
    await context.Response.Body.WriteAsync(fs.ToArray(), 0, fs.ToArray().Length);
    await context.Response.CompleteAsync();
  }
}
...