简体   繁体   English

如何使用 Blazor 上传文件?

[英]How do I upload files with Blazor?

I found the BlazorInputFile library, but there are still-open PRs from October of 2019, and I am not sure whether this library is still maintained.我找到了BlazorInputFile库,但从 2019 年 10 月起仍有未打开的 PR,我不确定该库是否仍在维护。 Also, I found a couple articles in blogs about how we can upload files with JS in Blazor.另外,我在博客中发现了几篇关于我们如何在 Blazor 中使用 JS 上传文件的文章。 While I don't want to use JS if possible, I do need to upload files using Blazor... is it possible to do so without using JavaScript?虽然如果可能的话我不想使用 JS,但我确实需要使用 Blazor 上传文件......是否可以在不使用 JavaScript 的情况下这样做?

Answering this question for those like me who are still searching the best way to upload files in Blazor.为像我这样仍在寻找在 Blazor 中上传文件的最佳方式的人回答这个问题。 I too was dabbling with installing SteveSandersonMS' repo and then realised that as of February 2021 there is actually a native InputFile component in ASP.NET Core 5.0.我也在尝试安装SteveSandersonMS 的 repo ,然后意识到截至 2021 年 2 月,ASP.NET Core 5.0 中实际上有一个本机InputFile组件。

It supports uploading of single and multiple files in Blazor and is easy to use.它支持在 Blazor 中上传单个和多个文件,并且易于使用。 (And you don't need to add your own js files etc.) (而且您不需要添加自己的 js 文件等)

I used it for single file uploads - all you need to do is add the InputFile component in the Razor page:我将它用于单个文件上传 - 您需要做的就是在 Razor 页面中添加InputFile组件:

<InputFile OnChange="@SingleUpload" />

and then in my case I needed the file in a byte array:然后在我的情况下,我需要字节数组中的文件:

@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 gives you an IReadOnlyList of IBrowserFile which you can use to get the Name , LastModified , Size and ContentType , as well as an OpenReadStream method for getting a Stream . InputFileChangeEventArgs为您提供了IBrowserFileIReadOnlyList ,您可以使用它来获取NameLastModifiedSizeContentType ,以及用于获取StreamOpenReadStream方法。

Hopefully this helps, there is good documentation and code on how to get multiple files in the ASP.NET docs.希望这会有所帮助,关于如何在ASP.NET 文档中获取多个文件有很好的文档和代码

Edit: You will also need to add the System.IO namespace:编辑:您还需要添加System.IO命名空间:

@using Sytem.IO

, thanks nogood. ,谢谢没有。

As of June 2020, The best method (WA), assuming you are using a form is to use a Tewr's FileReader.截至 2020 年 6 月,假设您使用表单的最佳方法 (WA) 是使用Tewr 的FileReader。 Let start with the API, the post controller would be :让我们从 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....") 
     }

Then the post method on the client side would be:那么客户端的 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 File reader helps you read the file into a stream which in my case is passed to the Pic object. Tewr 文件阅读器可帮助您将文件读入流中,在我的情况下,该流被传递给 Pic 对象。 The reading function which is binded to the onchange of your input element in the form would be :绑定到表单中输入元素的 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());
    }

}

Note that Xelement is ElementReference, and it used as ref on the input element in the form.请注意,Xelement 是 ElementReference,它用作表单中输入元素的引用。

I do this by using a component and some javascript (looks like a button).我通过使用一个组件和一些 javascript(看起来像一个按钮)来做到这一点。 Once the component and js are incorporated, you never have to worry about it again...一旦组件和 js 合并,你就再也不用担心了……

Here's the Upload Component (Upload.Razor):这是上传组件 (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]; } }

Here's the javascript excerpt:这是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(); }, }

And here's a calling markup sample:这是一个调用标记示例:

 <Upload @ref="upload" Filter=".xlsx" Title="Upload" AllowMulitple="false" Uploaded="DoMyExcelThingOrSomething" />

and the method it calls after upload:以及上传后调用的方法:

    Upload upload;
    void DoMyExcelThingOrSomething()
{
    if (upload.Files.Length < 1 || string.IsNullOrWhiteSpace(upload.Files[0].Base64))
    {
        //...nothing good here...
        return;
    }
    //play with upload.Files here...
}

At the current state of affairs (as 2 April 2020), you will require JS, it is inevitable.在目前的情况下(截至 2020 年 4 月 2 日),您将需要 JS,这是不可避免的。

There are two main approaches you can take:您可以采取两种主要方法:

  • get the file data in the onchange event of the input, and call C# methods by passing the byte[] to them - that's basically the file selector approach you linked where you get the file data in the Blazor app to do whatever you want with it.在输入的onchange事件中获取文件数据,并通过将byte[]传递给 C# 方法来调用 C# 方法 - 这基本上是您链接的文件选择器方法,您可以在 Blazor 应用程序中获取文件数据以执行任何您想做的事情.

  • get the file data in the onchange event of the input, and use JS to call a remote endpoint that will receive the file and do something with it (like save it on your NAS or put it in your DB).在输入的onchange事件中获取文件数据,并使用 JS 调用将接收文件并对其进行处理的远程端点(例如将其保存在您的 NAS 上或将其放入您的数据库中)。 This one is an actual file upload, as opposed to a file selector.这是一个实际的文件上传,而不是文件选择器。

Both approaches are similar from coding perspective - you need JS.从编码的角度来看,这两种方法都是相似的——你需要 JS。 Perhaps in a future version of Blazor we will get an <InputFile> that will do the selection so you can to uploads with C# HTTP requests.也许在 Blazor 的未来版本中,我们将获得一个<InputFile>来进行选择,以便您可以使用 C# HTTP 请求上传。

The File Selector approach is relatively easy to implement (literally a few lines), but it does not give you a file on the server, you have to work for it a little.文件选择器方法相对容易实现(字面意思是几行),但它不会在服务器上为您提供文件,您必须为此付出一些努力。 The File Upload approach is harder to get right.文件上传方法更难做到正确。 I would personally use someone else's package for either.我个人会使用别人的包。 For file uploads things like Telerik UI for Blazor can be a commercial fit, and for the simpler selectors there is already another answer that links examples.对于文件上传,Blazor 的 Telerik UI 之类的东西可能适合商业用途,对于更简单的选择器,已经有另一个链接示例的答案。 By the way, Telerik's demos also have one such example as a component implemented for some of the demos.顺便说一下,Telerik 的演示也有一个这样的例子,作为为一些演示实现的组件。

For Blazor Server, the following would upload the file to the server.对于 Blazor 服务器,以下将文件上传到服务器。 There's no need to have a separate API server, or to use JS code.无需单独的 API 服务器,也无需使用 JS 代码。 And it converts the stream into a file.并将 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();
    }
}

(Minor edit of http://www.bipinjoshi.net/articles/06473cc7-a391-409e-948d-3752ba3b4a6c.aspx ) http 的小幅编辑://www.bipinjoshi.net/articles/06473cc7-a391-409e-948d-3752ba3b4a6c.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM