developerlife.pl

Web & .NET development, business and my life

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

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

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

  • En Aldemita says:

    Hi,

    Do you have an example that is using an .Net Api and not .Net Core?

    Thanks,

    En

  • Milan Ostojic says:

    Hi,

    I am using the same method for receiving file from React.js form to the .net core backend and upload works for any type of files. But seems that when uploading .zip file somehow it’s corrupted after I download it from server. When call the same upload method through the postman download works ok and zip is not corrupted.
    For uploading files I am using http client and code like =>
    using var multipartContent = new MultipartFormDataContent();
    ByteArrayContent fileContent = new ByteArrayContent(br);
    request.Content = multipartContent;
    var response = await client.SendAsync(request);

    Do you know is there any thing I missed while uploading .zip ?

    *’br’ is byte[] which get from file like you show in example..
    multipartContent.Add(fileContent, “file”, fileName);

    • artur says:

      Hi Milan, thank you for the comment.
      If something work fine from postman and you use the same API maybe Postman automatically adds some header during request? I don’t have experience with uploading/downloading zip files but I suppose it can be problem with some headers or content types during returning data.

Leave a Reply

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