Uploading Files with JavaScript and C# MVC: Define the Server Boundary

Editorial illustration.

Originally published 23 June 2023; rewritten and reviewed on 15 October 2026.

The browser shows a filename and the progress bar moves to the end. That proves some bytes travelled, but it does not establish that the server accepted the document for its intended use. I would define the server response before polishing the upload indicator.

Send the file with the form’s security context

A simple browser fragment uses FormData:

const input = document.querySelector('#fileInput');
if (!input.files.length) throw new Error('Choose a file first.');
const data = new FormData();
data.append('file', input.files[0]);
// Include the application's required antiforgery field or header.
const response = await fetch('/documents/upload', {
  method: 'POST',
  body: data,
  credentials: 'same-origin'
});
if (!response.ok) throw new Error('The server did not accept the upload.');

Let the browser set the multipart content type and boundary. The route and antiforgery handling must match the actual MVC application; classic ASP.NET MVC and ASP.NET Core use different server types and configuration.

Validate before making the file available

Authenticate and authorise the request, enforce limits and inspect the permitted format on the server. Choose a server-generated storage name and keep untrusted files away from executable locations. Preserve a user-facing filename only as controlled metadata.

The original sample saved a file using its supplied filename. A revised implementation should not treat that input as a trusted server path. Separate upload storage from the permission-checked download route.

Explain acceptance accurately

Return a document identifier and processing state when appropriate. If scanning or conversion happens later, say “received” or “processing” rather than “ready.” Handle cancellation and retries without creating unexplained duplicates.

Test empty and oversized uploads, misleading extensions, unauthorised access and interrupted requests. The feature is complete when a user can tell whether the application has accepted the file and support staff can trace what happened to it.

Related reading