Comparison · v5.3

<asp:FileUpload> vs AjaxUploader

The control that ships with ASP.NET is genuinely fine for a lot of forms. This page is about the point where it stops being fine - and it is a specific, recognisable point, not a matter of taste.

Use the built-in control when it fits

If you are attaching a CV to a job form or a logo to a settings page, <asp:FileUpload> is the right answer. It is part of the framework, there is nothing to license, deploy or keep updated, and the whole thing is four lines:

<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="Upload" runat="server" Text="Upload" OnClick="Upload_Click" />

protected void Upload_Click(object sender, EventArgs e)
{
    if (FileUpload1.HasFile)
        FileUpload1.SaveAs(Server.MapPath("~/App_Data/uploads/") + FileUpload1.FileName);
}

Nothing below is an argument against that page. Keep it.

Where teams outgrow it

The built-in control publishes nine members you would actually use: AllowMultiple, HasFile, HasFiles, PostedFile, PostedFiles, FileName, FileBytes, FileContent and SaveAs. That list is the whole story, and what is absent from it matters more than what is present: there is no progress, no chunking, no resume and no drop target, because the control is a thin wrapper over an ordinary form post.

Four consequences follow from that one design fact:

  • The upload is a postback. The browser sends the entire file as part of the form. Your Click handler does not run until the last byte has arrived, so there is nothing to report progress from and nothing to cancel.
  • One request means one size ceiling. The whole file has to fit inside maxRequestLength (4 MB by default) and IIS's maxAllowedContentLength. Raising them raises the ceiling for every request on the site.
  • A failure at 99% is a failure at 0%. There is no resume, so a dropped connection on a large file means starting again.
  • Validation happens after the transfer. The file is already on the server before you can reject it for being the wrong type or the wrong size.

Side by side

 <asp:FileUpload>AjaxUploader
TransferOne form postSingle, chunked, tus, or direct to S3 / Azure / GCS
ProgressNonePer-file and overall, with speed and ETA
Practical sizeBounded by request limitsMulti-gigabyte via chunking
Interrupted uploadStarts overResumes from the last completed chunk
Drag and dropNot providedOn by default, plus full-page and folder drops
ValidationServer-side, after transferIn the browser first, re-checked on arrival
CostIn the frameworkCommercial licence

The honest summary: if your files are small and your users are on a good connection, the framework control wins on simplicity and price. The case for a component starts when files get big, connections get bad, or users need to see what is happening.

Migrating a page

The server-side shape is deliberately similar - a control on the page and one handler - so a swap is usually two edits:

<au:AjaxFileUpload ID="Uploader1" runat="server" AllowMultiple="true"
                   AutoPostBack="true" OnFileUploaded="Uploader1_FileUploaded" />

protected void Uploader1_FileUploaded(object sender, FileUploadedEventArgs e)
{
    var destination = Path.Combine(Server.MapPath("~/App_Data/uploads"), e.FileName);
    new UploadService().CopyFile(e.FileGuid, destination);
}

The difference is that the handler now runs per file as each one finishes, rather than once after the whole form has been posted.