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

查看:198
本文介绍了极慢的文件上传到部署为Azure Web App的Blazor Server应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了Blazor Server应用程序,该应用程序允许最终用户上传大型excel文件,这些文件将在下游逻辑中使用.

我使用标准的.NET Core 5 InputFile组件将excel文件上传到应用程序,在应用程序中,我读取了异步流,将其复制到内存流中,然后使用ExcelDataReader将其转换为数据集./p>

我看到的挑战是,特别是在将App部署到Azure时,上传需要很长时间.为了更深入地了解实际消耗的时间,我跟踪了StreamCopy操作的进度:

以下代码处理了我的上载:

 私有异步任务OnInputFileChange(InputFileChangeEventArgs e){this.StateHasChanged();IReadOnlyList< IBrowserFile>selectedFiles;selectedFiles = e.GetMultipleFiles();foreach(selectedFiles中的var文件){DataSet ds = new DataSet();{bool filesuccesfullRead = false;//一次允许一个100MB的文件var timer = new Timer(new TimerCallback(_ =>{如果(fileTemplateData.uploadProgressInfo.percentage< = 100){//注意,以下行是必需的,因为否则//Blazor无法识别状态更改并且不会刷新UIInvokeAsync(()=>{StateHasChanged();});}}),null,1000,1000);使用(Stream stream = file.OpenReadStream(104857600))使用(MemoryStream ms = new MemoryStream()){fileTemplateData.uploadProgressInfo = new GlobalDataClass.CopyProgressInfo();等待ExtensionsGeneric.CopyToAsync(stream,ms,128000,fileTemplateData.uploadProgressInfo);System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);尝试{使用(var reader = ExcelReaderFactory.CreateReader(ms)){ds = reader.AsDataSet(new ExcelDataSetConfiguration(){ConfigureDataTable = _ =>新的ExcelDataTableConfiguration(){UseHeaderRow =假}});filesuccesfullRead = true;}}抓住(前例外){消息=无法读取提供的文件,例外".+ ex.ToString();}stream.Close();ms.Close();}}ds.Dispose();ds = null;}fileTemplateData.fileloading = false;this.StateHasChanged();} 

这里是CopyToAsync函数,它与常规流复制相同,但提供进度跟踪:

 公共静态异步任务CopyToAsync(此Stream fromStream,Stream目标,int bufferSize,GlobalDataClass.CopyProgressInfo progressInfo){var buffer = new byte [bufferSize];整数计数progressInfo.TotalLengthinBytes = fromStream.Length;while((count =等待fromStream.ReadAsync(buffer,0,buffer.Length))!= 0){progressInfo.BytesTransfered + =计数;progressInfo.percentage = Math.Round((((((double)progressInfo.BytesTransfered/(double)progressInfo.TotalLengthinBytes)* 100),1);等待目的地.WriteAsync(buffer,0,count);}}公共类CopyProgressInfo{公共长BytesTransfered {get;放;}公共长TotalLengthinBytes {get;放;}公开双倍百分比{放;}公共DateTime LastProgressUpdateVisualized =新的DateTime();} 

现在让我提出一个问题:

  1. 使用此代码,当应用程序在本地主机上运行时,我实现了合理的上载速度(一个75MB的文件,其中包含大量数据,将在18秒内上载).将应用程序部署到Azure应用程序服务计划时,同一文件将花费10分钟以上的时间上传,这使我感到有些严重错误.使用进度跟踪,我可以确认时间是由CopytoAsync函数消耗的,而不是其后的逻辑.

这是我所调查的:

  1. 我在两个单独的连接上检查了我的Internet上传速度,它们的上传带宽稳定在25Mbps以上,因此这不是问题.
  2. 我暂时将应用程序服务计划升级到更高的层,以查看上传带宽是否与Azure App Service计划层建立了某种联系,甚至将其增加到功能强大的P3V2层也没有影响.
  3. 要查看我的应用程序服务所在的特定数据中心是否在我所在的地区提供了较差的上载性能,我使用 https://www.azurespeed.com/Azure/UploadLargeFile 和一个75Mb的文件将在大约38秒内上传到Azure西欧数据中心.因此,我看不出这里是否存在连接问题.

通过上述所有操作,将文件上传到已部署 Blazor Server Web应用程序时,可能导致文件上传速度如此之慢.

解决方案

我终于设法提高了上传性能,不幸的是Blazor内置的InputFile组件似乎不适用于大型文件上传,特别是当应用程序具有已部署.我使用了Tewr的上传文件组件,该文件组件的缓冲区大小较大(128000),并且性能显着提高(减少了3倍).Tewr的示例代码可在此处找到:

https://github.com/Tewr/BlazorFileReader/blob/master/src/Demo/Blazor.FileReader.Demo.Common/IndexCommon.razor

I created a Blazor Server app that would allow end users to upload large excel files that would be consumed in downstream logic.

I use a the standard .NET core 5 InputFile component to upload the excel file to the app, within the app, I read the stream async, copy it into a memory stream and then use ExcelDataReader to convert it into dataset.

The challenge I see is that the upload takes a long time specifically when App is deployed to Azure. To dig a bit deeper into what exactly was consuming the time, I track progress of the StreamCopy operation:

The following code handles my upload:

private async Task OnInputFileChange(InputFileChangeEventArgs e)
{

    this.StateHasChanged();


    IReadOnlyList<IBrowserFile> selectedFiles;
    selectedFiles = e.GetMultipleFiles();

    foreach (var file in selectedFiles)
    {

        DataSet ds = new DataSet();
        {
            bool filesuccesfullRead = false;
            //allowing a 100MB file at once
            var timer = new Timer(new TimerCallback(_ =>
            {
                if (fileTemplateData.uploadProgressInfo.percentage <= 100)
                {
                    // Note that the following line is necessary because otherwise
                    // Blazor would not recognize the state change and not refresh the UI
                    InvokeAsync(() =>
                    {

                        StateHasChanged();
                    });
                }
            }), null, 1000, 1000);



            using (Stream stream = file.OpenReadStream(104857600))
            using (MemoryStream ms = new MemoryStream())
            {
                
                fileTemplateData.uploadProgressInfo = new GlobalDataClass.CopyProgressInfo();
                await ExtensionsGeneric.CopyToAsync(stream, ms, 128000, fileTemplateData.uploadProgressInfo);
                System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

                try
                {
                    using (var reader = ExcelReaderFactory.CreateReader(ms))
                    {
                        ds = reader.AsDataSet(new ExcelDataSetConfiguration()
                        {
                            ConfigureDataTable = _ => new ExcelDataTableConfiguration()
                            {
                                UseHeaderRow = false
                            }
                        });
                        filesuccesfullRead = true;
                    }

                }
                catch (Exception ex)
                {
                    Message = "Unable to read provided file(s) with exception " + ex.ToString();
                }

                stream.Close();
                ms.Close();
            }
        }
        ds.Dispose();
        ds = null;
    }

    fileTemplateData.fileloading = false;

    this.StateHasChanged();


}

Here is the CopyToAsync Function which is same as regular stream copy but provides progress tracking:

 public static async Task CopyToAsync(this Stream fromStream, Stream destination, int bufferSize, GlobalDataClass.CopyProgressInfo progressInfo)
    {
        var buffer = new byte[bufferSize];
        int count;
        progressInfo.TotalLengthinBytes = fromStream.Length;


        while ((count = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            progressInfo.BytesTransfered += count;
            progressInfo.percentage = Math.Round((((double)progressInfo.BytesTransfered /(double) progressInfo.TotalLengthinBytes) * 100), 1);

            await destination.WriteAsync(buffer, 0, count);

        }
    }

public class CopyProgressInfo
    {
        public long BytesTransfered { get; set; }

        public long TotalLengthinBytes { get; set; }

        public double percentage { get; set; }
        public DateTime LastProgressUpdateVisualized = new DateTime();
    }

Now Let me put the question:

  1. Using this code, I achieve a fair upload speed when the app is running on a local host(A 75MB file with tonnes of data would upload in around 18 seconds). When the app is deployed to an Azure App service plan, the same file would take more than 10 minutes to upload, which makes me feel something is seriously wrong. Using progress tracking, I was able to confirm that the time is being consumed by the CopytoAsync function and not the logic after that.

Here's what I have investigated:

  1. I checked my internet upload speed on two seprate connections with a stable upload bandwidth of more than 25Mbps, so this is not an issue.
  2. I upgraded the app service plan to a higher tier momentarily to see if upload bandwidth was somehow linked with Azure App Service plan tier, even increasing it to a powerful P3V2 tier made no difference.
  3. To see if the specific Datacenter where my App service sits in was offering poor upload performance from my part of the world, I checked average upload speed using https://www.azurespeed.com/Azure/UploadLargeFile and a 75Mb file would upload in around 38 seconds to Azure West Europe Datacenter. So I donot see if the connectivity is the problem here.

With all that is mentioned above, what could be causing such a poor file upload speed when uploading the file onto a Deployed Blazor Server Web App.

解决方案

I finally managed to improve the upload performance, unfortunately Blazor's built in InputFile component doesn't seem to be designed very well for large file uploads specially when the app has been deployed. I used Tewr's upload file component with a larger buffer size(128000) and that has significantly improved performance(3X reduction). Tewr's sample code is available here:

https://github.com/Tewr/BlazorFileReader/blob/master/src/Demo/Blazor.FileReader.Demo.Common/IndexCommon.razor

这篇关于极慢的文件上传到部署为Azure Web App的Blazor Server应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆