Miroslav Holec
Premium

Upload souborů v Blazor SSR

Miroslav Holec   13. března 2025

Upload souborů v Blazoru je obecně zajímavá disciplína, protože každý režim fungování (SSR, Server, Wasm) vyžaduje odlišný přístup. V případě Blazor SSR není k dispozici žádná interaktivita a tudíž je potřeba kompletně zpracovat formulář se všemi poli a to včetně těch odkazujících na soubory.

Code Behind

Code behind se nijak neliší od jiných formulářů, jen je potřeba zvolit u property reprezentující soubor typ IFormFile.

public partial class Profile
{
    [SupplyParameterFromForm] private ProfileForm Form { get; set; } = new ();
}

public class ProfileForm
{
    public string Description { get; set; }
    public IFormFile File { get; set; }
}

Formulář v UI

Zdroj chyb a dlouhého trápení je zakopaný v UI. Ve formuláři se totiž musí splnit následující dvě pravidla:

  • formulář musí mít nastaven enctype="multipart/form-data"
  • InputFile nesmí použít two-way binding, ale pouze name

Příklad tedy může vypadat následovně:

<EditForm OnSubmit="OnSubmit" Model="Form" FormName="profile" enctype="multipart/form-data">
    <DataAnnotationsValidator/>

    <div class="form-group">
        <label for="file">File</label>
        <InputFile id="file" class="form-control" name="Form.File"/>
    </div>

    <InputText type="hidden" @bind-Value="Form.Description"/>

    <br/>
    <button class="btn btn-primary">Odeslat</button>
</EditForm>

Zpracování formuláře

Pro zpracování už stačí implementovat připravenou metodu OnSubmit. Ve většině aplikací používám Azure Storage, ale pro jednoduchost zde ukazuji práci se souborem...

private async Task OnSubmit(EditContext ctx)
    {
        await using var str = new FileStream("/Users/mholec/Temporary/" + Form.File.FileName, FileMode.Create);
        await Form.File.CopyToAsync(str);
    }

Alternativní řešení

Místo práce s IFormFile by bylo možné pracovat přímo s HttpRequest. Dá se k němu dostat přes HttpContext, který lze do komponenty předat jako cascading parameter, nikoliv přes inject.

public partial class Profile
{
    [SupplyParameterFromForm] private ProfileForm Form { get; set; } = new ();
    [CascadingParameter] private HttpContext Context { get; set; }
}

Výhodné je to při práci s více soubory nebo většími soubory. Vývojář tím získává větší flexibilitu při práci se streamem dat. Více o uploadu velkých souborů najdete v dokumentaci.

Nakonec bych ještě dodal, že místo <EditForm> lze použít úplně obyčejný <form> a k mapování použít u formulářových polí pouze name. Připravíte se tím ale o two-way binding a o validace. Pokud touto cestou půjdete, nesmíte zapomenout na vygenerování antiforgery tokenu.

<form>
  <AntiforgeryToken/>
</form>

Pro úplnost dodávám, že nový antiforgery middleware musí být v pipeline uveden vždy za authn a authz middlewares. Tedy ověřte, že v Program.cs máte pořadí následovně:

app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();

Dokumentace říká:

CleanShot 2025-03-13 at 12.25.11@2x

Miroslav Holec | Pomáhám vývojářským týmům správně používat technologii .NET a vytvářet špičkové aplikace a REST služby.