简体   繁体   English

Blazor 服务器文件上传很慢

[英]Blazor Server File Upload Very Slow

Update更新

I set this aside for a bit but I'm back on it now.我把它放在一边,但我现在又回来了。 I haven't been able to find anything that helps.我找不到任何有帮助的东西。 Does anyone know a way I can debug what is happening inside the CopyToAsync function or a way I can see where the bottle neck is.有谁知道我可以调试 CopyToAsync function 内部发生的事情的方法,或者我可以看到瓶颈在哪里的方法。 Either from the client machine end or the web server end.从客户端机器端或 web 服务器端。 I've been a developer for some time but am new to web development so I'm not familiar with the browser dev tools or anything that could help me locate this issue.我做开发人员已经有一段时间了,但对 web 开发很陌生,所以我不熟悉浏览器开发工具或任何可以帮助我找到这个问题的东西。 Any suggestions would be appreciated as I'm completely stuck at this point.任何建议都将不胜感激,因为我完全被困在这一点上。

Problem问题

I'm experiencing what seems to be very slow upload speeds.我遇到的上传速度似乎很慢。 About 22 or 23 seconds to upload an 8MB file.上传一个 8MB 的文件大约需要 22 或 23 秒。 Within the LAN the webserver is on it takes 2 or 3 seconds.在 LAN 内,网络服务器启动需要 2 或 3 秒。 Through some logging I've narrowed it down that all the time is spent in my call to Stream.CopyToAsync().通过一些日志记录,我缩小了所有时间都花在了对 Stream.CopyToAsync() 的调用上。 At the bottom I put the two log outputs to show the upload difference between local and remote.在底部,我放置了两个日志输出以显示本地和远程之间的上传差异。 All the other code before and after the CopyToAsync runs fast. CopyToAsync 之前和之后的所有其他代码都运行得很快。 I've included the code for the blazor component I made below.我已经包含了我在下面制作的 blazor 组件的代码。

Research研究

I've checked the following cases plus lots of other reading but haven't seemed to find anything yet that has helped.我检查了以下案例以及许多其他阅读材料,但似乎还没有找到任何有帮助的东西。

Should I call ConfigureAwait(false) on every awaited operation 我应该在每个等待的操作上调用 ConfigureAwait(false)

Increase Speed for Streaming Large(1-10 gb) files.Net Core 提高流式传输大型(1-10 gb)文件的速度.Net Core

Extremely Slow file upload to a Blazor Server app deployed as Azure Web App 极慢的文件上传到部署为 Azure Web 应用程序的 Blazor 服务器应用程序

What I've Tried我试过的

As you can see in the code I tried adding adding some FileOptions to the FileStream but that had no effect on the speed.正如您在代码中看到的那样,我尝试将一些 FileOptions 添加到 FileStream 中,但这对速度没有影响。 I've also tried ConfigureAwait but that didn't improve speed and also crashed it after the first file.我也尝试过 ConfigureAwait,但这并没有提高速度,而且在第一个文件之后也崩溃了。 I think that is because this is in the UI thread.我认为这是因为这是在 UI 线程中。 At least that's what I assumed from my research.至少这是我从研究中假设的。 I'm not new to programming but I am new to web programming and especially Blazor.我对编程并不陌生,但我对 web 编程,尤其是 Blazor 并不陌生。

Other Points其他要点

Both server and remote client are in locations with high speed internet (within the same city) and the web server does not have a heavy load on it.服务器和远程客户端都位于具有高速互联网的位置(在同一城市内),并且 web 服务器的负载不重。

Questions问题

Is 23 seconds for 8MB normal for the way the code is designed or do you think this is excessive too? 8MB 的 23 秒对于代码的设计方式是正常的,还是您认为这也太过分了?

Is my code the correct approach?我的代码是正确的方法吗? It does function pretty solid except for the speed.除了速度之外,它确实 function 相当稳定。

Any suggestions on things to try or to research to fix this?关于尝试或研究解决此问题的任何建议?

Code代码

@using System.IO
@inject SessionService session
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment env
@inject IJSRuntime JSRuntime

@if (showMessage)
{
    <div style="font-size: 20px;" class="alert-danger border-danger">
        <p>@userMessage</p>
    </div>
}

<button class="btn btn-primary m-2" onclick="document.getElementById('filepicker').click()" disabled="@disabled">@buttonText</button>
<InputFile id="filepicker" OnChange="@OnInputFileChange" hidden multiple="@multipleFiles" />

@code
{
    [Parameter] public EventCallback<FileModel> OnFileAdd { get; set; }
    [Parameter] public EventCallback<int> OnUploadStart { get; set; }
    [Parameter] public EventCallback<bool> OnUploadEnd { get; set; }
    [Parameter] public string buttonText { get; set; } = "Upload";
    [Parameter] public bool multipleFiles { get; set; } = false;
    [Parameter] public int callBackRefID { get; set; } = 0;
    private IReadOnlyList<IBrowserFile> selectedFiles;
    private bool showMessage = false;
    private bool disabled = false;
    private MarkupString userMessage;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        if (e.FileCount > 0)
        {
            disabled = true;
            await JSRuntime.InvokeAsync<string>("console.log", "Starting " + e.FileCount + " files - " + DateTime.Now.ToString());
            await OnUploadStart.InvokeAsync(e.FileCount);
            selectedFiles = e.GetMultipleFiles(e.FileCount);

            foreach (var file in selectedFiles)
            {
                await JSRuntime.InvokeAsync<string>("console.log", "Starting " + file.Name + " - " + DateTime.Now.ToString());
                Stream stream = file.OpenReadStream((long)2147483648);
                var path = $"{env.WebRootPath}\\Uploads\\{file.Name}";

                //FileOptions had no effect on performance
                FileStream fs = File.Create(path, 1048576, FileOptions.Asynchronous | FileOptions.SequentialScan);
                //FileStream fs = File.Create(path, 1048576);

                await JSRuntime.InvokeAsync<string>("console.log", "Before stream.CopyToAsync - " + DateTime.Now.ToString());
                await stream.CopyToAsync(fs, 1048576);
                //ConfigureAwait causes crash after first file is done.
                //await stream.CopyToAsync(fs, 1048576).ConfigureAwait(false);
                await JSRuntime.InvokeAsync<string>("console.log", "After stream.CopyToAsync - " + DateTime.Now.ToString());

                stream.Close();
                fs.Close();

                FileModel upFile = new();
                upFile.S_ID = session.CurrentUser.ID;
                upFile.Name = file.Name;
                upFile.DisplayName = "";
                upFile.Descr = "";
                upFile.ContentType = file.ContentType;

                if (upFile.GetFileData(path, file.ContentType) == false)
                {
                    userMessage = new(upFile.ErrMsg);
                    showMessage = true;
                    await OnUploadEnd.InvokeAsync(false);
                    return;
                }

                await OnFileAdd.InvokeAsync(upFile);
                await JSRuntime.InvokeAsync<string>("console.log", "Finished " + file.Name + " - " + DateTime.Now.ToString());
            }

            await OnUploadEnd.InvokeAsync(true);
            await JSRuntime.InvokeAsync<string>("console.log", "Finished - " + DateTime.Now.ToString());
            disabled = false;
        }
    }
}

Local Log本地日志

blazor.server.js:1 Starting 3 files - 2021-04-12 2:01:33 PM

blazor.server.js:1 Starting IMG_7830.JPG - 2021-04-12 2:01:33 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:33 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:36 PM
blazor.server.js:1 Finished IMG_7830.JPG - 2021-04-12 2:01:37 PM

blazor.server.js:1 Starting IMG_7831.JPG - 2021-04-12 2:01:37 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:37 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:40 PM
blazor.server.js:1 Finished IMG_7831.JPG - 2021-04-12 2:01:41 PM

blazor.server.js:1 Starting IMG_7832.JPG - 2021-04-12 2:01:41 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:41 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:43 PM
blazor.server.js:1 Finished IMG_7832.JPG - 2021-04-12 2:01:44 PM

blazor.server.js:1 Finished - 2021-04-12 2:01:44 PM

Remote Log远程日志

blazor.server.js:1 Starting 3 files - 2021-04-12 12:01:44 PM

blazor.server.js:1 Starting IMG_7830.JPG - 2021-04-12 12:01:45 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:01:45 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:07 PM
blazor.server.js:1 Finished IMG_7830.JPG - 2021-04-12 12:02:08 PM

blazor.server.js:1 Starting IMG_7831.JPG - 2021-04-12 12:02:08 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:02:08 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:30 PM
blazor.server.js:1 Finished IMG_7831.JPG - 2021-04-12 12:02:31 PM

blazor.server.js:1 Starting IMG_7832.JPG - 2021-04-12 12:02:31 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:02:31 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:53 PM
blazor.server.js:1 Finished IMG_7832.JPG - 2021-04-12 12:02:54 PM

blazor.server.js:1 Finished - 2021-04-12 12:02:54 PM

For me, an 8MB file upload to my server would take well less than one second.对我来说,将 8MB 的文件上传到我的服务器只需不到一秒钟的时间。 I regularly upload 50MB stock photo images to my site-- INCLUDING processing and image resizing, each averages a few seconds.我定期将 50MB 库存照片图像上传到我的网站——包括处理和图像大小调整,每个平均需要几秒钟。

So, as you suspect, there's a problem here.所以,正如你所怀疑的,这里有一个问题。

At a glance, the only thing substantially different I did was that I didn't specify a buffer length for the stream copy.乍一看,我所做的唯一显着不同的是我没有为 stream 副本指定缓冲区长度。 I suppose you've already played around with all that stuff, though.不过,我想你已经玩过所有这些东西了。

You talk about the server being in the same city, but what kind of server?你说服务器在同一个城市,但是什么样的服务器呢? I'm assuming you aren't using shared hosting or anything like that, right?我假设您没有使用共享主机或类似的东西,对吧? I used Godaddy for about 2 days before I signed up for a Microsoft VM.在注册 Microsoft VM 之前,我使用了 Godaddy 大约 2 天。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM