在.NET 5 Blazor PostAsJsonAsync中从文件上传获取进度信息/制作进度条



我正在(.Net5(Blazor WebAssembly应用程序中上传多个文件。我有一个"ObjectDTO",它包含信息和文件对象列表,如下所示:

public class ObjectDTO
{
public int Id { get; set; }

public string Name { get; set; }

public string Description { get; set; }
public decimal ActualCost { get; set; }   // Not sent to app.
public decimal NormalRetailPrice { get; set; }
public string StatusMsg { get; set; }
public ICollection<ExternalFileDTO> ImageFiles { get; set; } // Videos/Images 
}

"Icollection"是包含文件的对象,如下所示:

public class ExternalFileDTO
{
public int Id { get; set; }
public string CreatedById { get; set; }  // All images have a user - at least who uploaded it.
public DateTimeOffset? CreatedDate { get; set; }   
public string FileExtension { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public string ExternalUrl { get; set; }
public string LocalFileName { get; set; }
public string FileType { get; set; }
//Only in the DTO
public byte[] FileContent { get; set; }
}

我有一个向服务器发送更新的"对象"的服务:

public async Task<HttpResponseMessage> UpdateObject(ObjectDTO object)
{
return await Http.PostAsJsonAsync(Routes.UpdateObjectRoute, object);
}

由于这可能会非常大,我希望能够向用户显示进度条。在PostAsJsonAsync函数中有没有一种"简单"的方法来获取进度信息,或者我处理得很糟糕。。。我看到过上传单个文件的例子,但我更喜欢将数据放在一起。

我通过采取不同的方法解决了这个问题,并在所有情况下从客户端直接上传到azure。我把这个放在那里是为了帮助其他有同样问题的人。

为此,我创建了服务器api调用来处理一个可以来回传递的"ExternalFileDTO"对象。服务器被调用以获取上传SAS密钥,提供上传URI,并在此过程中创建DB记录。

文件被直接上传到azure,然后对每个文件再次调用服务器以验证完成情况。

我真的很感谢Andrew Hoefling的博客:在C#中上传大文件

此外,在浏览文档时,我发现了如何设置iProgress Handlers。

这是代码:

public long maxFileSize = 2000000000;
const int BufferSize = 1000000;
const int maxAllowedFiles = 5;
//string AllowedFileTypes = String.Join(",", Permitted.Extensions);
public string AllowedFileTypes = string.Join(",", FileExtensions.ValidExtensionsAll);
public async Task<InfoBool> HandleFilesUpload(FileChangedEventArgs e, IProgress<Tuple<int, int, string>> progressHandler,
IProgress<Tuple<int,string>> fileCountHandler, ExternalFileDTO fileTemplate, InfoBool isCancelling)
{
int FileCount =0;
fileTemplate.CreatedBy = _userservice.CurrentUser;
Tuple<int, string> reportfile;
Tuple<int, int, string> CountProgressName;
foreach (var file in e.Files)
{
FileCount++;
reportfile = Tuple.Create(FileCount, file.Name);
fileCountHandler.Report(reportfile);
try
{
if (file == null)
{
return new InfoBool(false, "File is null");
}
long filesize = file.Size;
if (filesize > maxFileSize)
{
return new InfoBool(false, "File exceeds Max Size");
}
fileTemplate.OriginalFileName = file.Name;
var sendfile = await _azureservice.GetAzureUploadURLFile(fileTemplate);
if (!sendfile.Status.Success) // There was an error so return the details
{
return sendfile.Status;
}
CurrentFiles.Add(sendfile); // Add the returned sendfile object to the list
BlockBlobClient blockBlobclient = new BlockBlobClient(sendfile.CloudURI);
byte[] buffer = new byte[BufferSize];
using (var bufferedStream = new BufferedStream(file.OpenReadStream(maxFileSize), BufferSize))
{
int readCount = 0;
int bytesRead;
long TotalBytesSent = 0;
// track the current block number as the code iterates through the file
int blockNumber = 0;
// Create list to track blockIds, it will be needed after the loop
List<string> blockList = new List<string>();
while ((bytesRead = await bufferedStream.ReadAsync(buffer, 0, BufferSize)) > 0)
{
blockNumber++;
// set block ID as a string and convert it to Base64 which is the required format
string blockId = $"{blockNumber:0000000}";
string base64BlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(blockId));
Console.WriteLine($"Read:{readCount++} {bytesRead / (double)BufferSize} MB");
// Do work on the block of data
await blockBlobclient.StageBlockAsync(base64BlockId, new MemoryStream(buffer, 0, bytesRead));
// add the current blockId into our list
blockList.Add(base64BlockId);
TotalBytesSent += bytesRead;
int PercentageSent = (int)(TotalBytesSent * 100 / filesize);
CountProgressName = Tuple.Create(FileCount, PercentageSent, file.Name);
if (isCancelling.Success) //Used an InfoBool so its passed by reference
{
break; // The user has cancelled, so wind up.
}
progressHandler.Report(CountProgressName);
}
// add the blockList to the Azure which allows the resource to stick together the chunks
if (isCancelling.Success)
{
await blockBlobclient.DeleteIfExistsAsync(); // Delete the blob created
}
else
{
await blockBlobclient.CommitBlockListAsync(blockList);
}
// make sure to dispose the stream once your are done
bufferedStream.Dispose();   // Belt and braces
}
//
// Now make a server API call to verify the file upload was successful
//
// Set the file status to the cancelling, cos the server can delete the file.
sendfile.Status = isCancelling;
await _azureservice.VerifyFileAsync(sendfile);
if (isCancelling.Success)
{
break;      // This breaks out of the foreach loop
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
}
}
return new InfoBool(true, "All Ok");
}

下面是Blazor UI线程页面的代码:

public InfoBool IsCancelling = new InfoBool(false, "Not Cancelling"); // To allow cancel of upload
protected override void OnInitialized()
{
progressHandler = new Progress<Tuple<int, int, string>>(UploadProgressChanged);
fileCountHandler = new Progress<Tuple<int,string>>(FileCountChanged);
FileService.CurrentFilesChanged += Refresh; // Refresh the page on the change of files
}
private void FileCountChanged(Tuple<int,string> FileNoAndNameSending)
{
Console.WriteLine($"FileCount Changed  = {FileNoAndNameSending}");
FileCount = FileNoAndNameSending.Item1;
FileNameUploading = FileNoAndNameSending.Item2;
this.StateHasChanged();
}
private void UploadProgressChanged(Tuple<int, int, string> CountProgressName)
{
Console.WriteLine($"File Name: {CountProgressName.Item3} /n Fileno: {CountProgressName.Item1}, Upload Progress Changed Percentage = {CountProgressName.Item2}");
FileCount = CountProgressName.Item1;
ProgressPercent = CountProgressName.Item2;
FileNameUploading = CountProgressName.Item3;
if (FileCount >= TotalFilesUploading && ProgressPercent >=100)
{
// This is the last file and it is complete
Console.WriteLine($"Last File reached at 100%");
IsUploading = false;
// UploadingComplete = true; // Set the finished flag
HideModal();    //File has finished uploading close and refresh
OnUserFilesUploaded.InvokeAsync();
}
// ShowStatusMsg($"Uploading no {FileCount} - {FileNameUploading} -{ProgressPercent}% Complete");
this.StateHasChanged();
}

我正在整理"isCancelling",但它确实被传递到主循环并取消了它。我在删除blockBlob时遇到了问题(这个网站上的另一个问题(。

不管怎样,祝你工作顺利。。。确实如此。

相关内容

  • 没有找到相关文章

最新更新