Upload Files with Blazor WebAssembly

This example uses ASP.NET 5 and it requires .NET 5. It is incompatible with earlier versions of .NET including .NET Core.

This is an example of using the new InputFile of .NET 5.

This example involves turning the files into base64 strings to be uploaded via JSON to the server. It resizes images on the client-side, utilizing client resources and freeing server resources.

This example uploads image files, but it can be used to upload any kind of file.

Create a new Blazor WebAssembly project with an ASP.NET Core backend — not sure why it is still called "Core" when this has been dropped everywhere else.

Add New File Class to Project

In the root of the shared project, create a file named ImageFile.cs.

// ImageFile.cs
public class ImageFile
{
	public string base64data { get; set; }
	public string contentType { get; set; }
	public string fileName { get; set; }
}

Create the Upload Controller

In the root of the server project, create a file named UploadController.cs.

// UploadController.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System;
using Microsoft.AspNetCore.Hosting;

namespace BlazorApp1.Server.Controllers
{
	[ApiController]
	[Route("api/[controller]")]
	public class UploadController : ControllerBase
	{
		private readonly IWebHostEnvironment env;

		public UploadController(IWebHostEnvironment env)
		{
			this.env = env;
		}

		[HttpPost]
		public async Task Post([FromBody] ImageFile[] files)
		{
			foreach (var file in files)
			{
				var buf = Convert.FromBase64String(file.base64data);
				await System.IO.File.WriteAllBytesAsync(env.ContentRootPath + "\\" + Guid.NewGuid().ToString("N") + "-" + file.fileName, buf);
			}
		}
	}
}

Modify Index.razor

In the client project, modify Index.razor.

@page "/"
@inject HttpClient Http

<h1>@message</h1>

<div class="input-group">
	<div class="custom-file">
		<InputFile class="custom-file-input" multiple OnChange="OnChange" accept="image/png, image/jpeg, image/gif" id="inputFile" />
		<label class="custom-file-label" for="inputFile">Choose file</label>
	</div>
	<div class="input-group-append">
		<button class="btn btn-success" @onclick="Upload" disabled="@isDisabled">Upload</button>
	</div>
</div>

@foreach (var item in filesBase64)
{
	<img src="data:@item.contentType;base64,@item.base64data" />
}

@code {
	List<ImageFile> filesBase64 = new List<ImageFile>();
	string message = "InputFile";
	bool isDisabled = false;

	async Task OnChange(InputFileChangeEventArgs e)
	{
		var files = e.GetMultipleFiles();
		foreach(var file in files)
		{
			var resizedFile = await file.RequestImageFileAsync(file.ContentType, 640, 480); // resize the image file
			var buf = new byte[resizedFile.Size];
			using (var stream = resizedFile.OpenReadStream())
			{
				await stream.ReadAsync(buf);
			}
			filesBase64.Add(new ImageFile { base64data = Convert.ToBase64String(buf), contentType = file.ContentType, fileName = file.Name });
		}
		message = "Click UPLOAD to continue";
	}

	async Task Upload()
	{
		isDisabled = true;
		using (var msg = await Http.PostAsJsonAsync<List<ImageFile>>("/api/upload", filesBase64, System.Threading.CancellationToken.None))
		{
			isDisabled = false;
			if (msg.IsSuccessStatusCode)
			{
				message = $"{filesBase64.Count} files uploaded";
				filesBase64.Clear();
			}
		}
	}
}

Try the Home Page of The Project

Run the application to preview and then upload images to the server where they are saved in the server's content directory.

Coding Video

https://youtu.be/7oNhDxdZ3u8