Isaac.

Handle File Uploads Efficiently

File uploads are a common feature in web applications, but handling them inefficiently can lead to performance issues, security vulnerabilities, and poor user experience. In this article, we'll explore best practices and provide examples in various backend frameworks.

ASP.NET (Primary Focus)

In ASP.NET, handling file uploads efficiently involves streaming files directly to storage instead of loading them fully into memory.

[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{{
    if(file == null || file.Length == 0)
        return BadRequest("File not selected");

    var filePath = Path.Combine("Uploads", file.FileName);

    using(var stream = new FileStream(filePath, FileMode.Create))
    {{
        await file.CopyToAsync(stream);
    }}

    return Ok(new {{ file.FileName, file.Length }});
}}

Explanation: We use IFormFile and stream the file directly to a directory. This avoids memory overhead for large files and is safe for production environments.

Spring Boot

@RestController
@RequestMapping("/upload")
public class FileUploadController {{

    @PostMapping
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {{
        if(file.isEmpty()) return ResponseEntity.badRequest().body("No file selected");
        try {{
            Path path = Paths.get("uploads/" + file.getOriginalFilename());
            Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
            return ResponseEntity.ok("File uploaded: " + file.getOriginalFilename());
        }} catch (IOException e) {{
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Upload failed");
        }}
    }}
}}

Express.js

const express = require('express');
const multer = require('multer');
const upload = multer({{ dest: 'uploads/' }});

const app = express();

app.post('/upload', upload.single('file'), (req, res) => {{
    if(!req.file) return res.status(400).send('No file uploaded.');
    res.send({{ filename: req.file.originalname, size: req.file.size }});
}});

app.listen(3000);

Next.js

import formidable from 'formidable';
export const config = {{ api: {{ bodyParser: false }} }};

export default async function handler(req, res) {{
    const form = new formidable.IncomingForm();
    form.uploadDir = './uploads';
    form.keepExtensions = true;

    form.parse(req, (err, fields, files) => {{
        if(err) return res.status(500).json({{ error: 'Upload failed' }});
        res.status(200).json({{ files }});
    }});
}}

Flask

from flask import Flask, request
import os

app = Flask(__name__)
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files.get('file')
    if not file:
        return 'No file uploaded', 400
    file.save(os.path.join(UPLOAD_FOLDER, file.filename))
    return {{'filename': file.filename, 'size': os.path.getsize(os.path.join(UPLOAD_FOLDER, file.filename))}}

Laravel

public function upload(Request $request) {{
    $request->validate(['file' => 'required|file']);
    $path = $request->file('file')->store('uploads');
    return response()->json(['path' => $path]);
}}

Conclusion

Efficient file upload handling improves application performance, prevents memory issues, and ensures a smooth user experience.

Key practices include streaming files directly, validating file types/sizes, and storing files securely.

Ignoring these best practices can lead to server crashes, slow performance, and security vulnerabilities.