Before moving forward, it is important to point out that WASM-based Blazor is still in preview as I write, and the BlazorInputFile package is no more than a prototype, which may in fact make its way into the Blazor framework at some stage but could undergo radical redesign before that happens, if it ever happens.
Disclaimers out of the way, if you want to play along, you need to create a Blazor WebAssembly App, with ASP.NET Core Hosted checked:
Install Steve's
BlazorInput package into the client project. Then include a reference in index.html (in wwwroot) to the inputfile.js file that is included as part of the package using the _content
file path:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>BlazorWasmTests<title/> <base href="/" /> <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /> <link href="css/app.css" rel="stylesheet" /> </head> <body> <app>Loading...</app> <script src="_content/BlazorInputFile/inputfile.js"></script> <script src="_framework/blazor.webassembly.js"></script> </body> </html>
Next, add two using
statements to the _Imports.razor file to make the
component available to the project along with the System.IO
namespace:
@using System.IO @using BlazorInputFile
Now add a Razor component to the Pages folder in the client project. Name it Single.razor and replace the existing code with the following:
@page "/singlefile" <h1>Single file</h1> <p>A single file input that uploads automatically on file selection</p> <InputFile OnChange="HandleSelection" /> <p>@status</p> @code { string status; async Task HandleSelection(IFileListEntry[] files) { var file = files.FirstOrDefault(); if (file != null) { // Just load into .NET memory to show it can be done // Alternatively it could be saved to disk, or parsed in memory, or similar var ms = new MemoryStream(); await file.Data.CopyToAsync(ms); status = $"Finished loading {file.Size} bytes from {file.Name}"; } } }
This is lifted straight from the samples provided by Steve. If you run this
page (navigating to /singlefile
), the file that you select is loaded into a
MemoryStream
. And that's all the processing code does. Further processing is left to
you.
The next step is to create an endpoint that can receive and process an uploaded file. Add a new Web API controller to the Server application and name it UploadController.cs. Replace the content with the following code:
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.IO; using System.Linq; using System.Threading.Tasks; namespace BlazorWasmTests.Server.Controllers { [Route("[controller]")] [ApiController] public class UploadController : ControllerBase { private readonly IWebHostEnvironment environment; public UploadController(IWebHostEnvironment environment) { this.environment = environment; } [HttpPost] public async Task Post() { if (HttpContext.Request.Form.Files.Any()) { foreach(var file in HttpContext.Request.Form.Files) { var path = Path.Combine(environment.ContentRootPath, "uploads", file.FileName); using (var stream = new FileStream(path, FileMode.Create)) { await file.CopyToAsync(stream); } } } } } }
The code should be familiar to anyone who has worked with uploaded files in ASP.NET Core. It checks to see if any files were uploaded, and if any were, they are saved to a folder named uploads. So the next step is to create the uploads folder in the root of the Server project.
Once you have done that, amend the code in the SingleFile.razor file to inject an
instance of the HttpClient
service, and use it to post the file:
@page "/singlefile" @inject HttpClient client <h1>Single file</h1> <p>A single file input that uploads automatically on file selection</p> <InputFile OnChange="HandleSelection" /> <p>@status</p> @code { string status; async Task HandleSelection(IFileListEntry[] files) { var file = files.FirstOrDefault(); if (file != null) { // Just load into .NET memory to show it can be done // Alternatively it could be saved to disk, or parsed in memory, or similar var ms = new MemoryStream(); await file.Data.CopyToAsync(ms); status = $"Finished loading {file.Size} bytes from {file.Name}"; var content = new MultipartFormDataContent { { new ByteArrayContent(ms.GetBuffer()), "\"upload\"", file.Name } }; await client.PostAsync("upload", content); } } }
The alterations are the second line which injects the HttpClient
,
and the last 4 lines in the HandleSelection
method that create an
instance of HttpContent
, incorporating the file and post it to the
Upload controller that you created.
When you run this, ensure that the Server project is set as the Startup project otherwise routing is unlikely to work properly:
You should find that uploaded files are saved to the uploads folder.
Summary
This simple example shows how to create a Web API end point to manage processing of uploaded files on the server, and the minimal amount of code required to post the file content from the Blazor client application to the server.