.NETowo


.NET Core, web development with React and other JavaScript Frameworks

Upload your files with React JS and .NET Core Web API

tags: dotnet, JavaScript, React, Visual Studio Code

Hi!

Today I would like to show you how you can upload files with React JS and .NET Core Web API. I created this article because a few days ago I had similar task in my work and I found nothing interesting about this solution in Internet. So maybe this short article will be helpfull for you :).

Add just file

In this section I will show you how you can make upload of files from your form to server side.
First you need to create a simple controller.

 
Route("uploader/justfile")]
public dynamic UploadJustFile(IFormCollection form)
{
    try
    {
        foreach (var file in form.Files)
        {
            UploadFile(file);
        }

        return new { Success = true };
    }
    catch (Exception ex)
    {
        return new { Success = false, ex.Message };
    }
}

private static void UploadFile(IFormFile file)
{
    if (file == null || file.Length == 0)
        throw new Exception("File is empty!");

    byte[] fileArray;
    using (var stream = file.OpenReadStream())
    using (var memoryStream = new MemoryStream())
    {
        stream.CopyTo(memoryStream);
        fileArray = memoryStream.ToArray();
    }

    //TODO: You can do it what you want with you file, I just skip this step
}

How you can see I created a simple controller action which as argument has IFormCollection object. There is a foreach loop which check our files and invokes UploadFile method. The implementation of the UploadFile method depends on you.

Let’s move to frontend side and create a simple form.

 
render() {
     return (
         <div>
             <form>
                 <h2>Just file</h2>
                 <p><b>{this.state.justFileServiceResponse}</b></p>
                 <input type="file" id="case-one" onChange={this.filesOnChange} />
                 <br />
                 <button type="text" onClick={this.uploadJustFile}>Upload just file</button>
             </form>
         </div>
     );
}

The form contains only one input controll and button which invoke uploading method. There is assigned a file in method filesOnChange during onChange event.

 
    filesOnChange(sender) {
        let files = sender.target.files;
        let state = this.state;

        this.setState({
            ...state,
            files: files
        });
    }

A method uploadJustFile looks like below

 
    uploadJustFile(e) {
        e.preventDefault();
        let state = this.state;

        this.setState({
            ...state,
            justFileServiceResponse: 'Please wait'
        });

        if (!state.hasOwnProperty('files')) {
            this.setState({
                ...state,
                justFileServiceResponse: 'First select a file!'
            });
            return;
        }

        let form = new FormData();

        for (var index = 0; index < state.files.length; index++) {
            var element = state.files[index];
            form.append('file', element);
        }

        axios.post('uploader/justfile', form)
            .then((result) => {
                let message = "Success!"
                if (!result.data.success) {
                    message = result.data.message;
                }
                this.setState({
                    ...state,
                    justFileServiceResponse: message
                });
            })
            .catch((ex) => {
                console.error(ex);
            });
    }

First of all, there is state object validation where I checked if there are any files. If yes I create FormData object and I add files from input. Last step is Web API invoking.

Add form with a file and some fields

Please add two methods in your web api controller and a person class which will be a incoming data model.

Person.cs

 
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
}       

UploaderController.cs

 
[Route("uploader/upload")]
public dynamic Upload(IFormCollection form)
{
    try
    {
        Person person = MapFormCollectionToPerson(form);

        foreach (var file in form.Files)
        {
            UploadFile(file);
        }

        return new { Success = true };
    }
    catch (Exception ex)
    {
        return new { Success = false, ex.Message };
    }
}

private static Person MapFormCollectionToPerson(IFormCollection form)
{
    var person = new Person();

    string firstNameKey = "firstName";
    string lastNameKey = "lastName";
    string phoneNumberKey = "phoneNumber";

    if (form.Any())
    {
        if (form.Keys.Contains(firstNameKey))
            person.FirstName = form[firstNameKey];

        if (form.Keys.Contains(lastNameKey))
            person.LastName = form[lastNameKey];

        if (form.Keys.Contains(phoneNumberKey))
            person.PhoneNumber = form[phoneNumberKey];
    }

    return p
}

As you can see there was only few changes. Beside a file in form object will be transfered a field collection. Next all the fields will be mapped to Person.cs instance.

On the frontend side please add next form with few text fields and with a input field. There is necessary to add event which makes update of state object. You have to add new method which inovke new web api method too.

 
    uploadForm(e) {
        e.preventDefault();
        let state = this.state;

        this.setState({
            ...state,
            formServiceResponse: 'Please wait'
        });

        if (!state.hasOwnProperty('files')) {
            this.setState({
                ...state,
                formServiceResponse: 'First select a file!'
            });
            return;
        }

        let form = new FormData();
        for (var index = 0; index < state.files.length; index++) {
            var element = state.files[index];
            form.append('file', element);
        }

        for (var key in state.fields) {
            if (state.fields.hasOwnProperty(key)) {
                var element = state.fields[key];
                form.append(key, element);
            }
        }

        axios.post('uploader/upload', form)
            .then((result) => {
                let message = "Success!"
                if (!result.data.success) {
                    message = result.data.message;
                }
                this.setState({
                    ...state,
                    formServiceResponse: message
                });
            })
            .catch((ex) => {
                console.error(ex);
            });
    }

    filesOnChange(sender) {
        let files = sender.target.files;
        let state = this.state;

        this.setState({
            ...state,
            files: files
        });
    }

    fieldOnChange(sender) {
        let fieldName = sender.target.name;
        let value = sender.target.value;
        let state = this.state;

        this.setState({
            ...state,
            fields: {...state.fields, [fieldName]: value}
        });
    }

    render() {
        return (
            <div>
                <form>
                    <h2>Just file</h2>
                    <p><b>{this.state.justFileServiceResponse}</b></p>
                    <input type="file" id="case-one" onChange={this.filesOnChange} />
                    <br />
                    <button type="text" onClick={this.uploadJustFile}>Upload just file</button>
                </form>
                <hr />
                <form>
                    <h2>Form</h2>
                    <p><b>{this.state.formServiceResponse}</b></p>
                    <div>
                        <input name="firstName" type="text" placeholder="First name" onChange={this.fieldOnChange} />
                    </div>
                    <div>
                        <input name="lastName" type="text" placeholder="Last name" onChange={this.fieldOnChange} />
                    </div>
                    <div>
                        <input name="phoneNumber" type="text" placeholder="Phone number" onChange={this.fieldOnChange} />
                    </div>
                    <input type="file" onChange={this.filesOnChange} />
                    <br />
                    <button type="text" onClick={this.uploadForm}>Upload form </button>
                </form>
            </div>
        );
    }

The uploadForm function looks similar to previous method. There was only one change – adding field values from state object to a FormData object.

Summary

I showed you how you can in easy way send files from React JS application to server side. Have a fun with this and please give some feedback. Thanks 🙂

GIT repository: https://github.com/artzie92/dotnetowo-upload-file-react-dotnet-core


Got Something To Say:

Your email address will not be published. Required fields are marked *