HowTo: upload files with Aurelia to ASP.NET Core (API) controller

Within ASP.NET Core file uploads are somewhat different than we used to. In previous versions ASP.NET uses HttpPostedFileBase to bind files server-side. This concept is replaced by IFormFile in ASP.NET Core.

The basics of uploading a file with ASP.NET MVC is very well explained here goed uitgelegd. To upload files with Razor and ASP.NET Core take a look at the file upload docs from Microsoft.

Because nowadays there is much use of JavaScript client frameworks such as Angular and Aurelia I'll focus on how to upload a file from a Aurelia web application to MVC 6 (api) controller.

Aurelia is a JavaScript client framework uses the fetch-api to request the backend.

To begin, we'll show you the HTML so that the user can select a file in his browser:

    <form submit.delegate="doUpload()">
        <input id="files" type="file" accept=".xlsx" files.bind="selectedFiles" class="form-control">
        <input type="submit" class="btn btn-primary" value="Upload" if.bind="selectedFiles.length > 0" />
    </form>

When there is a file selected the selectedFiles property will be bound to the file and submit button is visible.

Next we can call the upload function, when the user clicks the submit button.

    doUpload() {
        return this.upload('api/upload', {}, this.selectedFiles[0]).then(() => this.clearFiles());
    }

     clearFiles() {
        document.getElementById("files").value = "";
    }

De upload function looks like:

    upload(url, data, files, method = "POST") {
        let formData = new FormData();

        for (let i = 0; i < files.length; i++) {
            formData.append(`files[${i}]`, files[i]);
        }

        return this.http.fetch(url, {
            method: method,
            body: formData,
            headers: new Headers()
        }).then(response => response.json());
    }

To be able to use the fetch method we need to import HttpClient and initialize it in the constructor:

    import {HttpClient} from "aurelia-fetch-client";

    export default class UploadExample {
        constructor () {

            this.http = new HttpClient();
            this.http.configure(config => { config
                .useStandardConfiguration()
                .withBaseUrl(`api/upload`);
            });
        }
    }

At this point we are able to do a request to the MVC controller which uses the IFormFile interface:

    [HttpPost, Route("api/upload")]
    public async Task<IActionResult> Upload()
    {
        try
        {
            var form = await Request.ReadFormAsync();
            var file = form.Files.First();

            //do something with your file => file.OpenReadStream()

            return Ok(true);
        }
        catch (Exception ex)
        {
            var originalMessage = ex.Message;

            while (ex.InnerException != null)
                ex = ex.InnerException;
                return BadRequest($"{originalMessage} | {ex.Message}");
            }
        }
    }

Striking is the abscence of the method-parameter. The default (synchronous) way as described the ASP.NET Core docs uses the method-parameter to make the file available in the controller through modelbinding. In our SPA scenario my expierence is that this method-parameter always have a null value. Therefore I've chosen to asynchronous path with await Request.ReadFormAsync().

That's it! This is how you could upload a file (or more) from a Aurelia web application to an ASP.NET Core (API) controller.


This was originally a guest blog for KPIT Recruitment. If you want to read the original, written in Dutch, head to their site