Ye Yint
Ye Yint

Reputation: 924

File upload with ASP.Net Core 2.0 Web API and React.js

I'm new to both react.js and ASP.Net core 2.0. And now writing a project using ASP.Net core 2.0 as back end API and react.js as application interface (front end). I'd like to know how to upload file. I have tried as follow but in the Back end side the parameter value (IFromFile file) is always null. And it seems that file was not posted correctly. Here are my codes:

.Net core (API)

[HttpPost]
        [Route("upload")]
        public async Task Upload(IFormFile file)
        {
            if (file == null) throw new Exception("File is null");
            if (file.Length == 0) throw new Exception("File is empty");

            using (Stream stream = file.OpenReadStream())
            {
                using (var binaryReader = new BinaryReader(stream))
                {
                    var fileContent =  binaryReader.ReadBytes((int)file.Length);
                   // await _uploadService.AddFile(fileContent, file.FileName, file.ContentType);
                }
            }
        }

React.js

handleClick(event){
        event.preventDefault();
        // console.log("handleClick",event);
        var self = this;
        var apiBaseUrl =  axios.defaults.baseURL + "user/upload";
        if(this.state.filesToBeSent.length>0){
            var filesArray = this.state.filesToBeSent;
            const reader = new FileReader();
            for(var i in filesArray){
                //console.log("files",filesArray[i][0]);
                var file = filesArray[i][0];
                axios.post(apiBaseUrl, {data: file});
            }
            alert("File upload completed");
        }
        else{
            alert("Please select files first");
        }
    }

Please advise how can I solve the issue.

Upvotes: 9

Views: 23983

Answers (4)

zahra banaeian
zahra banaeian

Reputation: 121

This answer is true but I have problem with saving an image in my API so I change the method as you see and then work nice. You should set the parameter as [FromForm] in your API method

public async Task<IActionResult> Upload([FromForm]FileUploadViewModel model){...}

Upvotes: 4

Janmejay Kumar
Janmejay Kumar

Reputation: 319

In my case i simply missed to add multipart/form-data in my form.

If your controller is accepting uploaded files using IFormFile but you find that the value is always null, confirm that your HTML form is specifying an enctype value of multipart/form-data. If this attribute isn't set on the element, the file upload won't occur and any bound IFormFile arguments will be null.

Example:-

<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index">
        <div class="form-group">
            <div class="col-md-10">
                <p>Upload one or more files using this form:</p>
                <input type="file" name="files" multiple />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-10">
                <input type="submit" value="Upload" />
            </div>
        </div>
    </form>

Remove the multiple attribute on this input element to allow just a single file to be uploaded.

Upvotes: 1

Mohammad Farahani
Mohammad Farahani

Reputation: 639

[Route("api/[controller]")]
[ApiController]
public class UploaderController : ControllerBase
{
    [HttpPost]
    public dynamic UploadJustFile(IFormCollection form)
    {
        try
        {
            foreach (var file in form.Files)
            {
                string path = Path.Combine(@"C:\uploadFiles");
                using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
                {
                    file.CopyToAsync(fs);
                }
                UploadFile(file);
            }

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

and in UI use this

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);
}
debugger;
axios.post('/api/uploader', form)
  .then((result) => {
    let message = "Success!"
    if (!result.data.success) {
      message = result.data.message;
    }
    this.setState({
      ...state,
      justFileServiceResponse: message
    });
  })
  .catch((ex) => {
    console.error(ex);
  });
 }

Upvotes: 2

Ye Yint
Ye Yint

Reputation: 924

I have done the job as follow:

at .Net core 2.0 web api

using Microsoft.AspNetCore.Http;

I created a model class

namespace Marter_MRM.Models
{
    public class FileUploadViewModel
    {
        public IFormFile File { get; set; }
        public string source { get; set; }
        public long Size { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public string Extension { get; set; }
    }
}

And then I created a controller class and wrote the function as follow.

[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload(FileUploadViewModel model) {
      var file = model.File;

      if (file.Length > 0) {
           string path = Path.Combine(_env.WebRootPath, "uploadFiles");
           using (var fs = new FileStream(Path.Combine(path, file.FileName), FileMode.Create))
           {
                await file.CopyToAsync(fs);
           }

           model.source = $"/uploadFiles{file.FileName}";
           model.Extension = Path.GetExtension(file.FileName).Substring(1);
      }
    return BadRequest();
}

And write api call function in react as follow:

handleUploadClick(event){
    event.preventDefault();
    var self = this;
    var apiBaseUrl =  axios.defaults.baseURL + "user/upload";
    if(this.state.filesToBeSent.length>0){
        var filesArray = this.state.filesToBeSent;
        let f = new FormData();
        for(var i in filesArray){
        //console.log("files",filesArray[i][0]);
             f = new FormData();
             f.append("File",filesArray[i][0] )
             axios.post(apiBaseUrl, f, {
                    headers: {'Content-Type': 'multipart/form-data'}
             });
        }
        alert("File upload completed");
    }
    else{
        alert("Please select files first");
    }
}

It works perfect. Thanks!

Upvotes: 13

Related Questions