Isaac.

web

Efficient File Uploads

Handle file uploads securely and efficiently.

By Emem IsaacJanuary 7, 20232 min read
#file uploads#streaming#validation#security
Share:

A Simple Analogy

File uploads are like mail delivery. Check packages at the door, validate contents, store safely.


Why Optimization?

  • Performance: Don't buffer entire file in memory
  • Security: Validate file types and size
  • UX: Progress tracking for large files
  • Reliability: Handle failures gracefully
  • Cost: Minimize bandwidth usage

Basic Upload

[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
    if (file == null || file.Length == 0)
        return BadRequest("File is required");
    
    if (file.Length > 10 * 1024 * 1024)  // 10MB
        return BadRequest("File too large");
    
    var allowedExtensions = new[] { ".pdf", ".docx", ".xlsx" };
    var fileExtension = Path.GetExtension(file.FileName).ToLower();
    
    if (!allowedExtensions.Contains(fileExtension))
        return BadRequest("Invalid file type");
    
    var filename = Path.Combine(_uploadPath, Guid.NewGuid() + fileExtension);
    
    using (var stream = System.IO.File.Create(filename))
    {
        await file.CopyToAsync(stream);
    }
    
    return Ok(new { filename });
}

Streaming Upload

[HttpPost("stream-upload")]
public async Task<IActionResult> StreamUpload()
{
    var boundary = GetBoundary(Request.ContentType);
    var reader = new MultipartReader(boundary, Request.Body);
    
    var section = await reader.ReadNextSectionAsync();
    
    while (section != null)
    {
        var hasContentDispositionHeader = 
            ContentDispositionHeaderValue.TryParse(
                section.ContentDisposition, 
                out var contentDisposition);
        
        if (hasContentDispositionHeader && contentDisposition.DispositionType.Equals("form-data"))
        {
            if (!section.ContentType.StartsWith("image/"))
            {
                section = await reader.ReadNextSectionAsync();
                continue;
            }
            
            var filename = contentDisposition.FileName.Value;
            var filepath = Path.Combine(_uploadPath, Guid.NewGuid() + Path.GetExtension(filename));
            
            using (var targetStream = System.IO.File.Create(filepath))
            {
                await section.Body.CopyToAsync(targetStream);
            }
        }
        
        section = await reader.ReadNextSectionAsync();
    }
    
    return Ok();
}

Progress Tracking

const input = document.querySelector('input[type="file"]');
const progressBar = document.querySelector('progress');

input.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const formData = new FormData();
  formData.append('file', file);
  
  const xhr = new XMLHttpRequest();
  
  xhr.upload.addEventListener('progress', (event) => {
    if (event.lengthComputable) {
      const percent = (event.loaded / event.total) * 100;
      progressBar.value = percent;
    }
  });
  
  xhr.addEventListener('load', () => {
    console.log('Upload complete');
  });
  
  xhr.open('POST', '/upload');
  xhr.send(formData);
});

Best Practices

  1. Validate: Check type, size, content
  2. Rename: Use GUIDs to prevent conflicts
  3. Stream: Don't load entire file into memory
  4. Sanitize: Clean filenames
  5. Quarantine: Scan for malware

Related Concepts

  • Chunked uploads
  • Resumable uploads
  • Progress tracking
  • Cloud storage

Summary

Handle file uploads securely with validation, streaming, and progress tracking. Store safely with sanitized names.

Share:

Written by Emem Isaac

Expert Software Engineer with 15+ years of experience building scalable enterprise applications. Specialized in ASP.NET Core, Azure, Docker, and modern web development. Passionate about sharing knowledge and helping developers grow.

Ready to Build Something Amazing?

Let's discuss your project and explore how my expertise can help you achieve your goals. Free consultation available.

💼 Trusted by 50+ companies worldwide | ⚡ Average response time: 24 hours