Как исправить исключение RemoteJSDataStream NullReferenceException?

#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();
            }
        }