Я столкнулся со странной проблемой при обновлении моего веб-приложения с dotnet core 2.2 до 3.0. Я выполнил соответствующие шаги из шагов миграции .
Один из моих вызовов API возвращает HTTP 500. Более глубокое исследование показывает, что вызов UploadObjectAsync
для Google.Cloud.Storage.V1.StorageClient
дает мне ошибку ниже:
Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead
Я могу быстро исправить это, используя следующий фрагмент (но я не хочу принимать это в качестве окончательного решения).
WebHost.CreateDefaultBuilder(args)
.ConfigureKestrel(options => { })
.ConfigureServices(services =>
{
services.Configure<IISServerOptions>(options => { options.AllowSynchronousIO = true; });
})
Неисправный API работает с несколькими-частая загрузка в Google Storage. Я сузил проблему до MultipartSection или еще лучше MultipartSection.Body свойство, которое возвращает внутренний класс MultipartReaderStream
из сборки Microsoft.AspNetCore.WebUtilities
(v3.0.0.0).
Что-то в MultipartReaderStream
не соответствует. Временная замена MultipartSection.Body
для простого файла на диске (например, File.Open(@"c:\file")
) работает нормально. Это наводит меня на мысль, что проблема не в StorageClient
Google, а в MultipartReaderStream
. Теперь, прежде чем я получу предложения прочитать весь поток в MemoryStream
перед загрузкой в Google Storage, позвольте мне сказать, что я имею дело с огромными файлами, которые лучше не буферизировать.
Просмотр источника MultipartReaderStream Оказывается, есть несколько случаев синхронного _innerStream.Read()
. Может ли это быть причиной проблемы? То же самое присутствует даже в MultipartReaderStream v3.1 .
[EDIT]
После копания еще глубже выясняется, что это может быть не ошибка MultipartReaderStream
после всего. Эксперименты привели меня к выводу, что проблема может быть в реализации Google (или даже в обоих). Если я добавлю свою собственную реализацию Stream
и установлю точку останова на Read
, меня вызовет код Google. Класс ResumableUpload , кажется, также использует синхронные чтения. В частности, метод PrepareNextChunkUnknownSize
НЕ является асинхронным и использует синхронное чтение.