[英]How do I upload files with Blazor?
我找到了BlazorInputFile庫,但從 2019 年 10 月起仍有未打開的 PR,我不確定該庫是否仍在維護。 另外,我在博客中發現了幾篇關於我們如何在 Blazor 中使用 JS 上傳文件的文章。 雖然如果可能的話我不想使用 JS,但我確實需要使用 Blazor 上傳文件......是否可以在不使用 JavaScript 的情況下這樣做?
為像我這樣仍在尋找在 Blazor 中上傳文件的最佳方式的人回答這個問題。 我也在嘗試安裝SteveSandersonMS 的 repo ,然后意識到截至 2021 年 2 月,ASP.NET Core 5.0 中實際上有一個本機InputFile
組件。
它支持在 Blazor 中上傳單個和多個文件,並且易於使用。 (而且您不需要添加自己的 js 文件等)
我將它用於單個文件上傳 - 您需要做的就是在 Razor 頁面中添加InputFile
組件:
<InputFile OnChange="@SingleUpload" />
然后在我的情況下,我需要字節數組中的文件:
@code {
private async Task SingleUpload(InputFileChangeEventArgs e)
{
MemoryStream ms = new MemoryStream();
await e.File.OpenReadStream().CopyToAsync(ms);
var bytes = ms.ToArray();
//do something with bytes
}
}
InputFileChangeEventArgs
為您提供了IBrowserFile
的IReadOnlyList
,您可以使用它來獲取Name
、 LastModified
、 Size
和ContentType
,以及用於獲取Stream
的OpenReadStream
方法。
希望這會有所幫助,關於如何在ASP.NET 文檔中獲取多個文件有很好的文檔和代碼。
編輯:您還需要添加System.IO
命名空間:
@using Sytem.IO
,謝謝沒有。
截至 2020 年 6 月,假設您使用表單的最佳方法 (WA) 是使用Tewr 的FileReader。 讓我們從 API 開始,post 控制器是:
public async Task<IActionResult> PostMedia(
[FromForm] IFormFile Picture,
[FromForm] string Focus,
[FromForm] string ID,
[FromForm] string Title,
[FromForm] string FormType,
[FromForm] string AnimalType,
[FromForm] string Mode,
[FromForm] string AnimalID
)
{
Debug.WriteLine($"-------------------------------------{Focus}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{ID}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{Title}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{FormType}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{AnimalType}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{Mode}-----------------------------------------------");
Debug.WriteLine($"-------------------------------------{AnimalID}-----------------------------------------------");
//check if file was fully uploaded
if (Picture.Length == 0 || Picture == null)
return BadRequest("Upload a new File");
else
return Ok ("do something with this data....")
}
那么客戶端的 post 方法將是:
public async Task PostFile()
{
//create content headers
var content = new MultipartFormDataContent();
content.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data");
//create content
content.Add(new StreamContent(Pic.Stream, (int)Pic.Stream.Length), "Picture", Pic.FileName);
content.Add(new StringContent(Pic.Title), "Title");
content.Add(new StringContent(Pic.Focus), "Focus");
content.Add(new StringContent(Pic.ID), "ID");
content.Add(new StringContent(Pic.FormType), "FormType");
content.Add(new StringContent(Pic.AnimalType), "AnimalType");
content.Add(new StringContent(Pic.Mode), "Mode");
content.Add(new StringContent(Pic.AnimalID), "AnimalID");
//call to the server
var upload = await Http.PostAsync("Media",content);
//get server response
Pic.Message = await upload.Content.ReadAsStringAsync();
}
Tewr 文件閱讀器可幫助您將文件讀入流中,在我的情況下,該流被傳遞給 Pic 對象。 綁定到表單中輸入元素的 onchange 的閱讀功能將是:
public async Task ReadFile()
{
var file = (await fileReaderService.CreateReference(Xelement).EnumerateFilesAsync()).FirstOrDefault();
if (file == null) return;
var fileInfo = await file.ReadFileInfoAsync();
Pic.FileName = fileInfo.Name;
// Read into RAM
using (var memoryStream = await file.CreateMemoryStreamAsync((int)fileInfo.Size))
{
// Copy store image into pic object
Pic.Stream = new MemoryStream(memoryStream.ToArray());
}
}
請注意,Xelement 是 ElementReference,它用作表單中輸入元素的引用。
我通過使用一個組件和一些 javascript(看起來像一個按鈕)來做到這一點。 一旦組件和 js 合並,你就再也不用擔心了……
這是上傳組件 (Upload.Razor):
@inject IJSRuntime JSRuntime @if (AllowMulitple) { <input id="Xinputfile00" type="file" accept="@Filter" @onchange="UploadFile" multiple hidden /> } else { <input id="Xinputfile00" type="file" accept="@Filter" @onchange="UploadFile" hidden /> } <button class="btn btn-default" @onclick="ClickUpload">@Title</button> @code { [Parameter] public FileData[] Files { get; set; } [Parameter] public string Filter { get; set; } [Parameter] public string Title { get; set; } [Parameter] public bool AllowMulitple { get; set; } [Parameter] public Action Uploaded { get; set; } async Task UploadFile() { string[] result = await JSRuntime.InvokeAsync<string[]>("blazorExtensions.GetFileData", "Xinputfile00"); List<FileData> results = new List<FileData>(); foreach (string file in result) { results.Add(new FileData(file)); } this.Files = results.ToArray(); if (Uploaded != null) { Uploaded(); } } async Task ClickUpload() { await JSRuntime.InvokeVoidAsync("blazorExtensions.InvokeClick", "Xinputfile00"); } public class FileData { public string Base64 { get; set; } public string MIMEType { get; set; } public byte[] Bytes { get { return Convert.FromBase64String(this.Base64); } } public FileData(string data) { if (string.IsNullOrWhiteSpace(data) || !data.Contains(",")) { return; } string[] alldata = data.Split(','); this.MIMEType = alldata[0].Remove(0, 5).Replace(";base64", ""); this.Base64 = alldata[1]; } }
這是javascript摘錄:
window.blazorExtensions = { GetFileData: async function (id) { var target = document.getElementById(id); var filesArray = Array.prototype.slice.call(target.files); return Promise.all(filesArray.map(window.blazorExtensions.fileToDataURL)); }, fileToDataURL: async function (file) { var reader = new FileReader(); return new Promise(function (resolve, reject) { reader.onerror = function () { reader.abort(); reject(new DOMException('Error occurred reading file ' + file)); }; reader.onload = function (event) { resolve(reader.result); console.log('resolved'); }; reader.readAsDataURL(file); console.log('returned'); }) }, InvokeClick: function (id) { var elem = document.getElementById(id); if (typeof elem.onclick == "function") { elem.onclick.apply(elem); } elem.click(); }, }
這是一個調用標記示例:
<Upload @ref="upload" Filter=".xlsx" Title="Upload" AllowMulitple="false" Uploaded="DoMyExcelThingOrSomething" />
以及上傳后調用的方法:
Upload upload;
void DoMyExcelThingOrSomething()
{
if (upload.Files.Length < 1 || string.IsNullOrWhiteSpace(upload.Files[0].Base64))
{
//...nothing good here...
return;
}
//play with upload.Files here...
}
在目前的情況下(截至 2020 年 4 月 2 日),您將需要 JS,這是不可避免的。
您可以采取兩種主要方法:
在輸入的onchange
事件中獲取文件數據,並通過將byte[]
傳遞給 C# 方法來調用 C# 方法 - 這基本上是您鏈接的文件選擇器方法,您可以在 Blazor 應用程序中獲取文件數據以執行任何您想做的事情.
在輸入的onchange
事件中獲取文件數據,並使用 JS 調用將接收文件並對其進行處理的遠程端點(例如將其保存在您的 NAS 上或將其放入您的數據庫中)。 這是一個實際的文件上傳,而不是文件選擇器。
從編碼的角度來看,這兩種方法都是相似的——你需要 JS。 也許在 Blazor 的未來版本中,我們將獲得一個<InputFile>
來進行選擇,以便您可以使用 C# HTTP 請求上傳。
文件選擇器方法相對容易實現(字面意思是幾行),但它不會在服務器上為您提供文件,您必須為此付出一些努力。 文件上傳方法更難做到正確。 我個人會使用別人的包。 對於文件上傳,Blazor 的 Telerik UI 之類的東西可能適合商業用途,對於更簡單的選擇器,已經有另一個鏈接示例的答案。 順便說一下,Telerik 的演示也有一個這樣的例子,作為為一些演示實現的組件。
對於 Blazor 服務器,以下將文件上傳到服務器。 無需單獨的 API 服務器,也無需使用 JS 代碼。 並將 stream 轉換為文件。
@using System.IO
@inject IWebHostEnvironment env
@*for ibrowser*@
@using Microsoft.AspNetCore.Components.Forms;
<h1>Blazor Server File Upload</h1>
<h3>@Message</h3>
<form @onsubmit="OnSubmit">
<InputFile OnChange="OnInputFileChange" multiple />
<br /><br />
<button type="submit">Upload Selected File(s)</button>
</form>
@code {
string Message = "No file(s) selected";
IReadOnlyList<IBrowserFile> selectedFiles;
void OnInputFileChange(InputFileChangeEventArgs e)
{
selectedFiles = e.GetMultipleFiles();
Message = $"{selectedFiles.Count} file(s) selected";
this.StateHasChanged();
}
async void OnSubmit()
{
foreach (var file in selectedFiles)
{
Stream stream = file.OpenReadStream();
var path = $"{env.WebRootPath}\\{file.Name}";
FileStream fs = File.Create(path);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
}
Message = $"{selectedFiles.Count} file(s) uploaded on server";
this.StateHasChanged();
}
}
( http 的小幅編輯://www.bipinjoshi.net/articles/06473cc7-a391-409e-948d-3752ba3b4a6c.aspx )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.