In this post we will see how to upload files (jpeg/png) to the ASP.NET Core 3.1 WEB API. We all know that WEB APIs are mainly used for Data Communication using JSON format across applications. But what if we want to use WEB APIs for accepting binary files from the client applications?
In ASP.NET Core WEB API, the Request property of the type HttpRequest object from the ControllerBase class can be used to read the FormData posted by the client application. The following figure explains the approach of the application development
Figure 1: Uploading file from the Client Application to the ASP.NET Core WEB API
As seen in Figure 1, the WEB API project must be configured with Body Request limit to allow how much HTTP request body size will be accepted to process request. This is the FromData posted by the client application. The Static File middleware must be configured to define which folder will be used to store all uploaded files.
Creating ASP.NET Core WEB API
For WEB API development, I am using the latest Visual Studio 2019 and the ASP.NET Core 3.1 Web Application template which is used for WEB API Creation. .NET Core 3.1 SDK can be downloaded from this link.
Step 1: Open Visual Studio 2019 and create a new ASP.NET Core 3.1 Web application. Name this application as FileUploadAPI. Select the API template and ASP.NET Core 3.1 framework as shown in Figure 2.
Figure 2: Creating ASP.NET Core WEB API
Step 2: Modify the ConfigureServices() method of the Startup class in the Startup.cs to configure FormOptions for MultiPart length in the posted Form body, this is required when the client posts the File from the Form Body.
Since we will be creating a React.js client application to post the file from a different port, we need to configure CORS policy.
Add the code as shown in Listing 1 in the ConfigureServices() method
Since we will be creating a React.js client application to post the file from a different port, we need to configure CORS policy.
Add the code as shown in Listing 1 in the ConfigureServices() method
public void ConfigureServices(IServiceCollection services) { // adding the MultiPartBodyLength Configuration services.Configure(options => { // the max length of individual form values options.ValueLengthLimit = int.MaxValue; // length of the each multipart body options.MultipartBodyLengthLimit = int.MaxValue; // this is used for buddering the form body into the memory options.MemoryBufferThreshold = int.MaxValue; }); // ends here services.AddControllers(); // The cors policy definition services.AddCors(options => { options.AddPolicy("cors", policy=>{ policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); }); }); // ends here }
Listing 1: The Code in ConfigureServices() for the CORS policy and FormOptions
Step 3: In the project, add a new folder and name it as UploadedFiles. To configure this folder in the StaticFile middleware, modify the code in the Configure() method of the Startup class in the Startup.cs file and customize the static file middleware along with the configuration of using the CORS policy as shown in Listing 2.app.UseCors("cors"); app.UseStaticFiles(); app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider (Path.Combine(Directory.GetCurrentDirectory(), @"UploadedFiles")), RequestPath = new PathString("/UploadedFiles") });Listing 2: The Customization of Static file middleware and CORS policy in Configure method
Step 4: In the Controllers folder, add a new empty API Controller and name it as FileUploadController.cs. In this controller, add the a new Action method of name UploadFile() with code as shown in the following listing:
using Microsoft.AspNetCore.Mvc; using System; using System.IO; using System.Net.Http.Headers; namespace FileUploadAPI.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class FileUploadController : ControllerBase { // the HTTP post request. The Body size limit is disabled [HttpPost, DisableRequestSizeLimit] [ActionName("Upload")] public IActionResult UploadFile() { try { // 1. get the file form the request var postedFile = Request.Form.Files[0]; // 2. set the file uploaded folder var uploadFolder = Path.Combine(Directory.GetCurrentDirectory(), "UploadedFiles"); // 3. check for the file length, if it is more than 0 the save it if (postedFile.Length > 0) { // 3a. read the file name of the received file var fileName = ContentDispositionHeaderValue.Parse(postedFile.ContentDisposition) .FileName.Trim('"'); // 3b. save the file on Path var finalPath = Path.Combine(uploadFolder, fileName); using (var fileStream = new FileStream(finalPath, FileMode.Create)) { postedFile.CopyTo(fileStream); } return Ok($"File is uploaded Successfully"); } else { return BadRequest("The File is not received."); } } catch (Exception ex) { return StatusCode(500, $"Some Error Occcured while uploading File {ex.Message}"); } } } }
Listing 3: The File Uploading logic
The code in the UploadFile has following specification (Note: The following numbers match with the comments applied on the code)
- Read the posted body as form object from the HttpRequest object.
- Set the folder where uploaded files will be stored
- Check for the file length - if its more that 0 then process the file
- 3a. Read the file name of the posted file using the ContentDisposition property
- 3b. Write the file into the folder using FileStream object.
If the write operation is successful, then the success response will be sent, else an error will be returned. The Upload method contains DisableRequestSizeLinit attribute, this is used to disable the request body limit. This is useful for the large files to be posted to the WEB API.
Note: Since while creating the API project, we kept the Configure for HTTP checkbox checked we will un-check HTTPS for this application. To do so, go to the the project properties and un-check Enable SSL checkbox.
So this is how we can create ASP.NET Core WEB API that will accept a file from the client and save it on the server. You can test this using clients like Postman, Advance REST Client.
Creating React.js Client application
In this section we will create a new React.js application. We will create this application using Visual Studio Code, which is a free IDE from Microsoft. This can be downloaded from this link. We also need Node.js. This can be downloaded from this link.
Step 5: Open Node.js command prompt and run the following command to install CLI from React.js application
npm install -g create-react-app
We can use this CLI to create a new React.js application.
Step 6: Create a new folder on the drive of name clientapp. Navigate to this folder from the command prompt and run the following command to create new React.js application
create-react-app my-react-app
This will create a new project with all dependencies. Open this folder in VSCode. Now we have the React.js application ready so we can add the logic to upload file by creating new component.
Step 7: Since we will be making HTTP Post request from the React application, we require the axios package. To install this package, run the following command from the Node.js command prompt from the my-react-app path
npm install --save-dev axios
Step 8: In the src folder, add a new file and name it as FileUploadComponent.jsx. Add the following code in this file as shown in the following listing:
import React, { Component } from 'react'; import axios from 'axios'; class FileUploadComponent extends Component { constructor(props) { super(props); this.state = { selectedFile:'', status: '', progress:0 } } selectFileHandler = (event)=>{ //1. define the array for the file type e.g. png, jpeg const fileTypes = ['image/png', 'image/jpeg']; // 2. get the file type let file = event.target.files; console.log(`File ${file}`); // 3. the message for error if the file type of not matched let errMessage = []; // 4. to check the file type to match with the fileTypes array iterate // through the types array if(fileTypes.every(extension=> file[0].type !=extension)){ errMessage.push(`The file ${file.type} extension is not supported`); } else { this.setState({ selectedFile: file[0] }); } }; // method contain logic to upload file uploadHandler = (event) => { // 1. the FormData object that contains the data to be posted to the // WEB API const formData = new FormData(); formData.append('file', this.state.selectedFile); // 2. post the file to the WEB API axios.post("http://localhost:38790/api/FileUpload/Upload", formData, { onUploadProgress: progressEvent => { this.setState({ progress: (progressEvent.loaded / progressEvent.total*100) }) } }) .then((response) => { this.setState({status:`upload success ${response.data}`}); }) .catch((error) => { this.setState({status:`upload failed ${error}`}); }) } render() { return ( <div> <h2>The File Upload DEMO</h2> <div> <label>Select File to Upload</label> <input type="file" onChange={this.selectFileHandler}/> </div> <hr/> <div> <button type="button" onClick={this.uploadHandler}>Upload</button></div> <hr/> <div>{this.state.progress}</div> <br/> <div>{this.state.status}</div> </div> ); } } export default FileUploadComponent;
Listing 4: The File Upload Logic
The above code has methods for selecting file and uploading the file. The selectFileHandler() method defines and array of the file types which will be used for uploading e.g. jpg/png files. This method reads selected files using HTML input file element and then verifies the file type so that it can decide whether the file can be uploaded. If the selected file is of the type .jpg or .png then it will be assigned to the selectedFile state property.
The uploadHandler() method defines an instance of the FormData object. This is the object that carries the posted form values using key/value pair.
The selected file is appended into the FormData object and then it is posted to the WEB API using axios object and its post method. The onUploadProgressEvent is used to manage the file upload in stream.
Based on the status of upload operation, the status state variable will show the uploading status. The render() method contains the HTML where selectFileHandler() method is bound to the onChange event of the input file element and the uploadHandler() method is bound to the onClick event of the button element.
The selected file is appended into the FormData object and then it is posted to the WEB API using axios object and its post method. The onUploadProgressEvent is used to manage the file upload in stream.
Based on the status of upload operation, the status state variable will show the uploading status. The render() method contains the HTML where selectFileHandler() method is bound to the onChange event of the input file element and the uploadHandler() method is bound to the onClick event of the button element.
import FileUploadComponent from './FileUploadComponent'; ReactDOM.render(, document.getElementById('root'));
Listing 5: The FileUploadComponent rendering
Run the WEB API Project and to run the React.js client application. Run the following command from the command prompt (the same folder path where the React.js application is created)
npm run start
The browser will show the result as shown in Figure 3:
Figure 3: The FileUploadComponent rendered
Click on choose file button, this will show the Open Dialog where you can select the jpg/png file as shown in figure 4.
Figure 4: The Open Dialog for choosing file
Click on open. The file will be selected, to upload the file click on the Upload button, the file will be posted to the WEB API. Once the post is successful, the page will display a result as shown in Figure 5.
Figure 5: File Upload Success
To verify the upload, check the UploadedFiles folder in the WEB API project, it should show the newly uploaded file.
Conclusion: File Upload is a frequently required feature in modern applications. HttpRequest object in ASP.NET Core 3.1 provides an easy implementation of this feature. React.js (or any other JavaScript based application) can use HTTP communication objects (like axios) to post file to WEB API.
No comments:
Post a Comment