#c# #.net-core #stream #blazor #blazor-server-side
#c# #.net-ядро #поток #blazor #blazor-на стороне сервера
Вопрос:
Я получаю сообщение об ошибке при параллельной загрузке файлов в качестве StreamContent со стороны сервера .NET 6 / Blazor в API через HttpClient. Вот урезанный код и полный текст ошибки:
PS RemoteJSRuntime
То, что передается Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSDataStream.ReceiveData
фреймворком, является NULL
, поэтому выдается ошибка. Однако я не понимаю, почему NULL
передается. Я не могу его поймать, погасить, как-то повлиять на него.
P.S.S. Это не связано с ApiClient, все работает нормально. Ошибка возникает только при запуске после первой загрузки страницы, как ни странно, после перезагрузки страницы и повторного запуска все работает.
Исходный код:
https://github.com/abberdeen/BlazorServer.ParallelFileUpload
Связанная проблема:
https://github.com/dotnet/aspnetcore/issues/38854
public void AddFilesToUploadQueue(List<FileUploadDto> files)
{
foreach (var item in files)
{
fileUploadQueue.Enqueue(item);
}
for (int i = 0; i < files.Count; i )
{
Task t = factory.StartNew(() => UploadOne());
tasks.Add(t);
}
}
private async Task UploadOne()
{
semaphore.WaitOne();
FileUploadDto item;
if (!fileUploadQueue.TryDequeue(out item))
{
return;
}
// Make HttpRequest
await UploadFileAsync(item);
semaphore.Release();
}
blazor.server.js:1 [2021-12-06T19:07:53.123Z] Error: System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSDataStream.ReceiveData(RemoteJSRuntime runtime, Int64 streamId, Int64 chunkId, Byte[] chunk, String error)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c__11`1.<<InvokeAsync>b__11_0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost.ReceiveJSDataChunk(Int64 streamId, Int64 chunkId, Byte[] chunk, String error)
Ошибки в окне вывода:
System.TimeoutException: Did not receive any data in the allotted time.
at System.IO.Pipelines.Pipe.GetReadResult(ReadResultamp; result)
at System.IO.Pipelines.Pipe.GetReadAsyncResult()
at System.IO.Pipelines.PipeReaderStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSDataStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Components.Forms.BrowserFileStream.CopyFileDataIntoBuffer(Int64 sourceOffset, Memory`1 destination, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Components.Forms.BrowserFileStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at System.IO.Stream.<CopyToAsync>g__Core|29_0(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
at System.Net.Http.StreamToStreamCopy.<CopyAsync>g__DisposeSourceAsync|1_0(Task copyTask, Stream source)
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
at System.Net.Http.MultipartContent.SerializeToStreamAsyncCore(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at ~~~~~BlazorApp.Services.AuthHttpClientHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in ~~~~~BlazorAppServicesAuthHttpClientHandler.cs:line 27
at System.Net.Http.Handlers.ProgressMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at ~~~~~BlazorApp.Services.FileUploadApiService.PostAndReportProgress(String url, MultipartFormDataContent formData, String guid, EventHandler`1 progressHandler, CancellationToken cancellationToken) in ~~~~~BlazorAppServicesFileUploadApiService.cs:line 106
--- End of inner exception stack trace ---
at ~~~~~BlazorApp.Services.FileUploadApiService.PostAndReportProgress(String url, MultipartFormDataContent formData, String guid, EventHandler`1 progressHandler, CancellationToken cancellationToken) in ~~~~~BlazorAppServicesFileUploadApiService.cs:line 122
at ~~~~~BlazorApp.Services.FileUploadApiService.ChatUploadFileAsync(StreamContent file, Int32 chatId, String guid, EventHandler`1 progressHandler, CancellationToken cancellationToken) in ~~~~~BlazorAppServicesFileUploadApiService.cs:line 59
at ~~~~~BlazorApp.Services.FileUploadManager.UploadFileAsync(FileUploadDto item) in ~~~~~BlazorAppServicesFileUploadManager.cs:line 171
at ~~~~~BlazorApp.Services.FileUploadManager.<StartUploadTask>b__18_0() in ~~~~~BlazorAppServicesFileUploadManager.cs:line 108
Ответ №1:
Спасибо за образец. Я смог воспроизвести System.TimeoutException
.
Я не могу воспроизвести ошибку с этим кодом ( FileUploadManager
только изменения). Вы можете попробовать это?
public async void AddFilesToUploadQueue(IReadOnlyList<IBrowserFile> files)
{
lock (fileUploadQueue)
{
foreach (var item in files)
{
fileUploadQueue.Enqueue(item);
}
}
for (int i = 0; i < files.Count; i )
{
IBrowserFile? file = null;
lock(fileUploadQueue)
{
fileUploadQueue.TryDequeue(out file);
}
tasks.Add(UploadOneFile(file));
}
//await Task.WhenAll(tasks);
}
protected async Task UploadOneFile(IBrowserFile file)
{
await semaphoreSlim.WaitAsync();
try
{
using (var readStream = file.OpenReadStream(int.MaxValue))
{
var streamContent = fileUploadService.CreateStreamContent(readStream, file.Name, file.ContentType);
var result = await fileUploadService.UploadFileAsync(streamContent);
}
}
finally
{
semaphoreSlim.Release();
}
}