在大部分的网站中,上传图片也是很重要的功能,今天我们就来实作。
(注:这是用 Blazor Server 的方式,但最好不要上传太多档案,所以限定上传4张照片的话就会提示,毕竟这些事都是在服务器上做,负担太大,微软也建议用 .NET Core API 的方式实作)
我们先建立一个 Component FileUpload
。
下面程序码为FileUpload.razor
,使用 Blazor 提供的 Component <InputFile>
,multiple代表可以传送多个档案
@page "/FileUpload"
<div>
<div>
<InputFile OnChange="OnChange" multiple></InputFile>
</div>
<div>
<MyButton value="Submit" class="btn btn-primary" type="submit" @onclick="OnSubmit" />
</div>
</div>
@if (ImageList != null)
{
<table>
<tr>
@foreach (var img in ImageList)
{
<td>
<img src="@img" width="150" height="150" />
</td>
}
</tr>
</table>
}
下面程序码为FileUpload.razor.cs
,这里用partial class
using BlazorServer.ViewModels;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Hosting;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
namespace BlazorServer.Shared
{
public partial class FileUpload
{
[Inject] protected IJSRuntime js { get; set; }
//用以判断runtime期间在什麽环境执行
[Inject] protected IWebHostEnvironment env { get; set; }
private JsInteropClasses jsClass;
public List<string> ImageList = new List<string>();
//取得`<InputFile>`的档案内容
public IReadOnlyList<IBrowserFile> ImgFiles;
public string ImgSrc;
protected override Task OnInitializedAsync()
{
jsClass = new(js);
return base.OnInitializedAsync();
}
public async Task OnChange(InputFileChangeEventArgs e)
{
ImageList = new List<string>();
string format = "image/jpeg";
//取得档案
ImgFiles = e.GetMultipleFiles();
foreach (var file in ImgFiles)
{
//将图片内容转换成指定类型及最大尺寸
var imageFile = await file.RequestImageFileAsync(format, 1280, 960);
//利用 Stream 读取图片内容
using var fileStream = imageFile.OpenReadStream();
//将 Stream 读到记忆体中,如果没有要上传前预览就不要这麽做,以免耗费记忆体
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream);
ImgSrc = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}";
//以 Data URI 的方式将图片呈现
ImageList.Add(ImgSrc);
}
}
public async Task OnSubmit()
{
//将提示讯息变成 ViewModel
SweetConfirmViewModel sweetConfirm = new SweetConfirmViewModel()
{
RequestTitle = "是否确定上传图片?",
ResponseTitle = "上传成功",
};
string jsonString = JsonSerializer.Serialize(sweetConfirm);
bool result = await jsClass.Confirm(jsonString);
if (result && ImgFiles.Any())
{
long maxFileSize = 1024 * 1024 * 15;
//指定图片要存到哪个路径
string folder = $@"{env.WebRootPath}\images";
foreach (var file in ImgFiles)
{
//使用 Stream 将档案存到指定路径
using (var stream = file.OpenReadStream(maxFileSize))
{
//如果资料夹不在会先建立
Directory.CreateDirectory(folder);
var path = $@"{env.WebRootPath}\images\{file.Name}";
//建立档案
FileStream fs = File.Create(path);
//将图片 Stream 复制到档案中
await stream.CopyToAsync(fs);
//Stream 用完一定要关闭
stream.Close();
fs.Close();
}
}
}
}
}
}
为了方便,NavMenu.razor.cs
加上路由通往这个 Component
<li class="nav-item px-3">
<NavLink class="nav-link" href="FileUpload" Match="NavLinkMatch.All">
<span class="bi bi-card-image h4 p-2 mb-0" aria-hidden="true"></span> File Upload
</NavLink>
</li>
建立新的 ViewModel 让SweetConfirm
可以通用
namespace BlazorServer.ViewModels
{
public class SweetConfirmViewModel
{
public string RequestTitle { get; set; }
public string RequestText { get; set; }
public string ResponseTitle { get; set; }
public string ResponseText { get; set; }
}
}
再把_Host.cshtml
的SweetConfirm
修改一下
function SweetConfirm(jsonString) {
// 这边要 parse 才能正常转回来
var arg = JSON.parse(jsonString);
return new Promise((resolve) => {
Swal.fire({
title: arg.RequestTitle,
text: arg.RequestText,
icon: "warning",
showCancelButton: true,
cancelButtonText: "取消",
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "确定"
}).then((result) => {
resolve(result.isConfirmed);
if (result.isConfirmed) {
Swal.fire(
arg.ResponseTitle,
arg.ResponseText,
"success"
);
}
})
});
}
既然这边改了,PostBase.razor.cs
的deletePost
也要修改
protected async Task deletePost()
{
// 改成 ViewModel
SweetConfirmViewModel sweetConfirm = new SweetConfirmViewModel()
{
RequestTitle = $"是否确定删除日志{Post.Title}?",
RequestText = "这个动作不可复原",
ResponseTitle = "删除成功",
ResponseText = "日志被删除了",
};
string jsonString = JsonSerializer.Serialize(sweetConfirm);
bool result = await jsClass.Confirm(jsonString);
if (result)
{
var deleted = await PostRepository.DeletePost(Post.PostId);
if (deleted.IsSuccess)
{
await getPostId.InvokeAsync(Post.PostId);
}
else
{
await jsClass.Alert(deleted.Message);
}
}
}
JsInteropClasses.cs
的Confirm()
改成 JSON 字串
public async ValueTask<bool> Confirm(string jsonString)
{
bool confirm = await js.InvokeAsync<bool>("SweetConfirm", jsonString);
return confirm;
}
可以看到图片上传成功了
Ref: ASP.NET Core Blazor file uploads
Ref: Upload Files Using InputFile Component In Blazor
Ref:What scope does a using statement have without curly braces
Ref:BrowserFileExtensions.RequestImageFileAsync(IBrowserFile, String, Int32, Int32) 方法
Ref:Day 26:Blazor WebAssembly 上传档案
CocoaPods CocoaPods 是一款第三方套件的相依管理器,我们可以透过它来安装许多第三方...
AR介绍 AR为Augmented Reality(扩增实境)的简称,透过照相镜头和APP将真实世界...
Unity Package汇入方式 Unity Package汇入Unity有以下3种方式 双击两...
大家午安 ~ 昨天我们已经启用 VPC Flow Log 并且存放到 S3,今天我们会设定 AWS ...
今天是 Build Optimizations 主题的最後一篇了,到目前为止我们已经认识了 Cod...