Upload souborů v Blazor SSR
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 pouzename
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á: