I found the BlazorInputFile library, but there are still-open PRs from October of 2019, and I am not sure whether this library is still maintained. Also, I found a couple articles in blogs about how we can upload files with JS in Blazor. While I don't want to use JS if possible, I do need to upload files using Blazor... is it possible to do so without using JavaScript?
The Blazor File Manager is a graphical user interface component for managing the file system that allows users to perform most common file operations like accessing, editing, and sorting files or folders. This component also provides easy navigation for browsing folders to select a file or folder from the file system.
Static site hosting Blazor WebAssembly apps don't require a server to execute server-side code in order to download and run. Blazor WebAssembly apps can be delivered via a Content Delivery Network (CDN) (for example, Azure CDN). If static hosting is an app requirement, select Blazor WebAssembly.
Publish the app Publish a hosted Blazor WebAssembly solution from the Server project. Select the Publish {APPLICATION} command from the Build menu, where the {APPLICATION} placeholder the app's name. Select the publish target. To publish locally, select Folder.
We begin by creating a FileUpload component in the Pages folder: Here, we are using the @page attribute, to let Blazor know that we want this component to be routable. Next, we want to add the input element that allows us to select a file to upload, as well as an <img> HTML element that will display our uploaded image:
One of the additions for Blazor Server and Blazor WebAssembly is the InputFile component to deal with file uploads. In this article I am going to take a quick look at the InputFile component and discuss a possible file upload process for Blazor Server as well as Blazor WebAssembly (ASP.NET Core hosted) apps.
In Blazor WebAssembly, file data is streamed directly into the .NET code within the browser. In Blazor Server, file data is streamed over the SignalR connection into .NET code on the server as the file is read. Always follow security best practices when permitting users to upload files.
The file data needs to get into Blazor via the existing JS interop mechanism. Provides access to the file data as a regular .NET Stream, so other code can handle it just the same as if it were a normal file on disk. This must literally stream the content into the .NET process, since we don’t want to depend on loading it all into memory at once.
I was dabbling with installing SteveSandersonMS' repo and then realised that, as of February 2021, there is actually a native InputFile
component in ASP.NET Core 5.0.
It supports uploading of single and multiple files in Blazor and is easy to use (and you don't need to add your own JS files etc.).
I used it for single file uploads - all you need to do is add the InputFile
component in the Razor page:
<InputFile OnChange="@SingleUpload" />
and then in my case I needed the file in a byte array:
@code {
private async Task SingleUpload(InputFileChangeEventArgs e)
{
MemoryStream ms = new MemoryStream();
await e.File.OpenReadStream().CopyToAsync(ms);
var bytes = ms.ToArray();
//do something with bytes
}
}
InputFileChangeEventArgs
gives you an IReadOnlyList
of IBrowserFile
which you can use to get the Name
, LastModified
, Size
and ContentType
, as well as an OpenReadStream
method for getting a Stream
.
There is good documentation and code on how to get multiple files in the ASP.NET docs.
Your will also need to add the System.IO
namespace:
@using System.IO
As of June 2020, The best method (WA), assuming you are using a form is to use a Tewr's FileReader. Let start with the API, the post controller would be :
public async Task<IActionResult> PostMedia(
[FromForm] IFormFile Picture,
[FromForm] string Focus,
[FromForm] string ID,
[FromForm] string Title,
[FromForm] string FormType,
[FromForm] string AnimalType,
[FromForm] string Mode,
[FromForm] string AnimalID
)
{
Debug.WriteLine($"-------------------------------------{Focus}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{ID}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{Title}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{FormType}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{AnimalType}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{Mode}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{AnimalID}-----------------------------------------------");
//check if file was fully uploaded
if (Picture.Length == 0 || Picture == null)
return BadRequest("Upload a new File");
else
return Ok ("do something with this data....")
}
Then the post method on the client side would be:
public async Task PostFile()
{
//create content headers
var content = new MultipartFormDataContent();
content.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data");
//create content
content.Add(new StreamContent(Pic.Stream, (int)Pic.Stream.Length), "Picture", Pic.FileName);
content.Add(new StringContent(Pic.Title), "Title");
content.Add(new StringContent(Pic.Focus), "Focus");
content.Add(new StringContent(Pic.ID), "ID");
content.Add(new StringContent(Pic.FormType), "FormType");
content.Add(new StringContent(Pic.AnimalType), "AnimalType");
content.Add(new StringContent(Pic.Mode), "Mode");
content.Add(new StringContent(Pic.AnimalID), "AnimalID");
//call to the server
var upload = await Http.PostAsync("Media",content);
//get server response
Pic.Message = await upload.Content.ReadAsStringAsync();
}
Tewr File reader helps you read the file into a stream which in my case is passed to the Pic object. The reading function which is binded to the onchange of your input element in the form would be :
public async Task ReadFile()
{
var file = (await fileReaderService.CreateReference(Xelement).EnumerateFilesAsync()).FirstOrDefault();
if (file == null) return;
var fileInfo = await file.ReadFileInfoAsync();
Pic.FileName = fileInfo.Name;
// Read into RAM
using (var memoryStream = await file.CreateMemoryStreamAsync((int)fileInfo.Size))
{
// Copy store image into pic object
Pic.Stream = new MemoryStream(memoryStream.ToArray());
}
}
Note that Xelement is ElementReference, and it used as ref on the input element in the form.
At the current state of affairs (as 2 April 2020), you will require JS, it is inevitable.
There are two main approaches you can take:
get the file data in the onchange
event of the input, and call C# methods by passing the byte[]
to them - that's basically the file selector approach you linked where you get the file data in the Blazor app to do whatever you want with it.
get the file data in the onchange
event of the input, and use JS to call a remote endpoint that will receive the file and do something with it (like save it on your NAS or put it in your DB). This one is an actual file upload, as opposed to a file selector.
Both approaches are similar from coding perspective - you need JS. Perhaps in a future version of Blazor we will get an <InputFile>
that will do the selection so you can to uploads with C# HTTP requests.
The File Selector approach is relatively easy to implement (literally a few lines), but it does not give you a file on the server, you have to work for it a little. The File Upload approach is harder to get right. I would personally use someone else's package for either. For file uploads things like Telerik UI for Blazor can be a commercial fit, and for the simpler selectors there is already another answer that links examples. By the way, Telerik's demos also have one such example as a component implemented for some of the demos.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With