Progress For Blazor File Upload (#24172)
parent
ee25ade249
commit
d282ce6ea3
|
@ -361,6 +361,29 @@ public class FilesaveController : ControllerBase
|
|||
|
||||
In the preceding code, <xref:System.IO.Path.GetRandomFileName%2A> is called to generate a secure filename. Never trust the filename provided by the browser, as an attacker may choose an existing filename that overwrites an existing file or send a path that attempts to write outside of the app.
|
||||
|
||||
::: zone pivot="server"
|
||||
|
||||
## Upload files with progress
|
||||
|
||||
The following example demonstrates how to upload files in a Blazor Server app with upload progress displayed to the user.
|
||||
|
||||
To use the following example in a test app:
|
||||
|
||||
* Create a folder to save uploaded files for the `Development` environment: `Development/unsafe_uploads`.
|
||||
* Configure the maximum file size (`maxFileSize`, 15 MB in the following example) and maximum number of allowed files (`maxAllowedFiles`, 3 in the following example).
|
||||
* Set the buffer to a different value (10 KB in the following example), if desired, for increased granularity in progress reporting. We don't recommended using a buffer larger than 30 KB due to performance and security concerns.
|
||||
|
||||
`Pages/FileUpload3.razor`:
|
||||
|
||||
[!code-razor[](~/blazor/samples/6.0/BlazorSample_Server/Pages/file-uploads/FileUpload3.razor)]
|
||||
|
||||
For more information, see the following API resources:
|
||||
|
||||
* <xref:System.IO.FileStream>: Provides a <xref:System.IO.Stream> for a file, supporting both synchronous and asynchronous read and write operations.
|
||||
* <xref:System.IO.FileStream.ReadAsync%2A?displayProperty=nameWithType>: The preceding `FileUpload3` component reads the stream asynchronously with <xref:System.IO.FileStream.ReadAsync%2A>. Reading a stream synchronously with <xref:System.IO.FileStream.Read%2A> isn't supported in Razor components.
|
||||
|
||||
::: zone-end
|
||||
|
||||
## File streams
|
||||
|
||||
::: zone pivot="webassembly"
|
||||
|
@ -729,6 +752,29 @@ public class FilesaveController : ControllerBase
|
|||
}
|
||||
```
|
||||
|
||||
::: zone pivot="server"
|
||||
|
||||
## Upload files with progress
|
||||
|
||||
The following example demonstrates how to upload files in a Blazor Server app with upload progress displayed to the user.
|
||||
|
||||
To use the following example in a test app:
|
||||
|
||||
* Create a folder to save uploaded files for the `Development` environment: `Development/unsafe_uploads`.
|
||||
* Configure the maximum file size (`maxFileSize`, 15 MB in the following example) and maximum number of allowed files (`maxAllowedFiles`, 3 in the following example).
|
||||
* Set the buffer to a different value (10 KB in the following example), if desired, for increased granularity in progress reporting. We don't recommended using a buffer larger than 30 KB due to performance and security concerns.
|
||||
|
||||
`Pages/FileUpload3.razor`:
|
||||
|
||||
[!code-razor[](~/blazor/samples/5.0/BlazorSample_Server/Pages/file-uploads/FileUpload3.razor)]
|
||||
|
||||
For more information, see the following API resources:
|
||||
|
||||
* <xref:System.IO.FileStream>: Provides a <xref:System.IO.Stream> for a file, supporting both synchronous and asynchronous read and write operations.
|
||||
* <xref:System.IO.FileStream.ReadAsync%2A?displayProperty=nameWithType>: The preceding `FileUpload3` component reads the stream asynchronously with <xref:System.IO.FileStream.ReadAsync%2A>. Reading a stream synchronously with <xref:System.IO.FileStream.Read%2A> isn't supported in Razor components.
|
||||
|
||||
::: zone-end
|
||||
|
||||
## File streams
|
||||
|
||||
::: zone pivot="webassembly"
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
@page "/file-upload-3"
|
||||
@using System
|
||||
@using System.IO
|
||||
@using Microsoft.AspNetCore.Hosting
|
||||
@using Microsoft.Extensions.Logging
|
||||
@inject ILogger<FileUpload3> Logger
|
||||
@inject IWebHostEnvironment Environment
|
||||
|
||||
<h3>Upload Files</h3>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max file size:
|
||||
<input type="number" @bind="maxFileSize" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max allowed files:
|
||||
<input type="number" @bind="maxAllowedFiles" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
|
||||
<InputFile OnChange="@LoadFiles" multiple />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p>Progress: @string.Format("{0:P0}", progressPercent)</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
@foreach (var file in loadedFiles)
|
||||
{
|
||||
<li>
|
||||
<ul>
|
||||
<li>Name: @file.Name</li>
|
||||
<li>Last modified: @file.LastModified.ToString()</li>
|
||||
<li>Size (bytes): @file.Size</li>
|
||||
<li>Content type: @file.ContentType</li>
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<IBrowserFile> loadedFiles = new();
|
||||
private long maxFileSize = 1024 * 1024 * 15;
|
||||
private int maxAllowedFiles = 3;
|
||||
private bool isLoading;
|
||||
private decimal progressPercent;
|
||||
|
||||
private async Task LoadFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
isLoading = true;
|
||||
loadedFiles.Clear();
|
||||
progressPercent = 0;
|
||||
|
||||
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
|
||||
{
|
||||
try
|
||||
{
|
||||
var trustedFileName = Path.GetRandomFileName();
|
||||
var path = Path.Combine(Environment.ContentRootPath,
|
||||
Environment.EnvironmentName, "unsafe_uploads", trustedFileName);
|
||||
|
||||
await using FileStream writeStream = new(path, FileMode.Create);
|
||||
using var readStream = file.OpenReadStream(maxFileSize);
|
||||
var bytesRead = 0;
|
||||
var totalRead = 0;
|
||||
var buffer = new byte[1024 * 10];
|
||||
|
||||
while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
|
||||
{
|
||||
totalRead += bytesRead;
|
||||
|
||||
await writeStream.WriteAsync(buffer, 0, bytesRead);
|
||||
|
||||
progressPercent = Decimal.Divide(totalRead, file.Size);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
loadedFiles.Add(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("File: {Filename} Error: {Error}",
|
||||
file.Name, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
@page "/file-upload-3"
|
||||
@using System
|
||||
@using System.IO
|
||||
@using Microsoft.AspNetCore.Hosting
|
||||
@using Microsoft.Extensions.Logging
|
||||
@inject ILogger<FileUpload3> Logger
|
||||
@inject IWebHostEnvironment Environment
|
||||
|
||||
<h3>Upload Files</h3>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max file size:
|
||||
<input type="number" @bind="maxFileSize" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Max allowed files:
|
||||
<input type="number" @bind="maxAllowedFiles" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Upload up to @maxAllowedFiles of up to @maxFileSize bytes:
|
||||
<InputFile OnChange="@LoadFiles" multiple />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p>Progress: @string.Format("{0:P0}", progressPercent)</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
@foreach (var file in loadedFiles)
|
||||
{
|
||||
<li>
|
||||
<ul>
|
||||
<li>Name: @file.Name</li>
|
||||
<li>Last modified: @file.LastModified.ToString()</li>
|
||||
<li>Size (bytes): @file.Size</li>
|
||||
<li>Content type: @file.ContentType</li>
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<IBrowserFile> loadedFiles = new();
|
||||
private long maxFileSize = 1024 * 1024 * 15;
|
||||
private int maxAllowedFiles = 3;
|
||||
private bool isLoading;
|
||||
private decimal progressPercent;
|
||||
|
||||
private async Task LoadFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
isLoading = true;
|
||||
loadedFiles.Clear();
|
||||
progressPercent = 0;
|
||||
|
||||
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
|
||||
{
|
||||
try
|
||||
{
|
||||
var trustedFileName = Path.GetRandomFileName();
|
||||
var path = Path.Combine(Environment.ContentRootPath,
|
||||
Environment.EnvironmentName, "unsafe_uploads", trustedFileName);
|
||||
|
||||
await using FileStream writeStream = new(path, FileMode.Create);
|
||||
using var readStream = file.OpenReadStream(maxFileSize);
|
||||
var bytesRead = 0;
|
||||
var totalRead = 0;
|
||||
var buffer = new byte[1024 * 10];
|
||||
|
||||
while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
|
||||
{
|
||||
totalRead += bytesRead;
|
||||
|
||||
await writeStream.WriteAsync(buffer, 0, bytesRead);
|
||||
|
||||
progressPercent = Decimal.Divide(totalRead, file.Size);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
loadedFiles.Add(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("File: {Filename} Error: {Error}",
|
||||
file.Name, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue