我发现了BlazorInputFile库,但是自2019年10月以来仍有未关闭的PR,我不确定这个库是否仍在维护。此外,在一些博客文章中,我也发现了关于如何在Blazor中使用JS上传文件的方法。虽然如果可能的话,我不想使用JS,但是我确实需要使用Blazor上传文件……那么,是否可以不使用JavaScript实现呢?
我发现了BlazorInputFile库,但是自2019年10月以来仍有未关闭的PR,我不确定这个库是否仍在维护。此外,在一些博客文章中,我也发现了关于如何在Blazor中使用JS上传文件的方法。虽然如果可能的话,我不想使用JS,但是我确实需要使用Blazor上传文件……那么,是否可以不使用JavaScript实现呢?
我曾尝试安装SteveSandersonMS的存储库,后来意识到,从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
提供了一个IReadOnlyList
,其中包含IBrowserFile
,您可以使用它来获取Name
、LastModified
、Size
和ContentType
,以及一个用于获取Stream
的OpenReadStream
方法。
ASP.NET文档中有关于如何获取多个文件的好的文档和代码。
您还需要添加System.IO
命名空间:
@using System.IO
截至2020年6月,如果你正在使用表单(Form),最好的方法(WA)是使用Tewr's 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();
}
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());
}
}
截至2020年4月2日的现状,您将需要JS,这是不可避免的。
您可以采取两种主要方法:
在输入的onchange
事件中获取文件数据,并通过传递byte[]
调用C#方法 - 这基本上是您链接的文件选择器方法,其中您在Blazor应用程序中获取文件数据以进行任何想做的事情。
在输入的onchange
事件中获取文件数据,并使用JS调用远程端点来接收文件并对其进行处理(例如将其保存在NAS上或将其放入数据库中)。这是实际的文件上传,而不是文件选择器。
从编码角度来看,这两种方法相似 - 您需要JS。也许在Blazor的未来版本中,我们将获得一个<InputFile>
,它将执行选择,因此您可以使用C# HTTP请求进行上传。
@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];
}
}
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();
},
}
And here's a calling markup sample:
<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...
}
@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进行小修改)