Direct-to-S3 / Azure tus 1.0 resume IndexedDB Golden Retriever 30 locales Webcam & screen capture

File uploads in ASP.NET Core MVC

Everything from the Razor Pages setup applies to MVC unchanged — the endpoints are minimal-API routes, and Tag Helpers work in MVC views. The MVC-specific part is wiring uploads into a controller form post.

1. Register and map

// Program.cs
builder.Services.AddControllersWithViews();
builder.Services.AddCoreUpload(options => {
    options.MaxFileSizeBytes = 100 * 1024 * 1024;
    options.AllowedExtensions = new[] { ".jpg", ".png", ".pdf" };
});

var app = builder.Build();
app.MapDefaultControllerRoute();
app.MapCoreUploadEndpoints();

2. Enable the Tag Helper

@* Views/_ViewImports.cshtml *@
@addTagHelper *, CoreUpload

3. Use it inside a form

The key idea: files upload asynchronously while the user fills the rest of the form. The component keeps a hidden field of completed file GUIDs, so your POST carries references, not bytes.

@* Views/Ticket/Create.cshtml *@
<form asp-controller="Ticket" asp-action="Create" method="post">
    <input asp-for="Subject" />

    <core-upload asp-upload-url="/api/upload/upload"
                 asp-multiple="true"
                 asp-chunked="true"
                 asp-hidden-input-id="AttachmentGuids"
                 asp-progress="true"></core-upload>
    <input type="hidden" id="AttachmentGuids" name="AttachmentGuids" />

    <button type="submit">Create ticket</button>
</form>

4. Consume the GUIDs in the controller

[HttpPost]
public async Task<IActionResult> Create(string subject, string attachmentGuids,
                                        [FromServices] IUploadService uploads)
{
    foreach (var id in (attachmentGuids ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries))
    {
        var guid = Guid.Parse(id);
        var info = await uploads.GetFileInfoAsync(guid);        // metadata
        await uploads.MoveFileAsync(guid, $"tickets/{subject}/{info!.FileName}");
    }
    return RedirectToAction("Index");
}

Uploads land in temporary storage first; MoveFileAsync / CopyFileAsync promote them once the form is actually submitted. Abandoned temp files age out via the cleanup service.

Antiforgery

Upload requests are plain HTTP calls, so include your antiforgery token via the headers option — see the antiforgery demo for the exact pattern.