学习ASP.NET Core Blazor编程系列十七——文件上传(上)
从本篇文章开始我们来讲在图书租赁系统中如何使用内置的文件上传组件进行文件上传功能的开发。本文的示例适合上传小型文件。本篇文章演示如何通过Blazor的内置组件InputFile将文件上传至服务器。
安全注意事项
在向用户提供向上传文件的功能时,必须格外注意安全性。攻击者可能对系统执行拒绝服务和其他攻击。所以在提供上传功能时需要注意以下安全措施:
1. 将文件上传到系统上的专用文件上传目录,这样可以更轻松地对上传内容实施安全措施。如果允许文件上传,请确保在上传目录禁用执行权限。
2. 上传文件的文件名在服务器端保存时要由应用程序自动重新命名文件名称,而不是采用用户输入或已上传文件的文件名。
3.请不要将上传的文件保存在与应用程序相同的目录下。
4. 仅允许使用一组特定的文件扩展名。
5. 在服务端重新执行客户端检查。 不要相信客户端检查,因为客户端检查很容易规避。
6. 检查上传文件大小,防止上传文件的大小比预期的文件大小大。
7. 对上传文件的内容进行病毒/恶意软件扫描程序。
8.应用程序中的文件不能被具有相同名称的上传文件覆盖。
警告
将恶意代码上传到系统通常是执行代码的第一步,这些代码可以实现以下功能:
1. 完全接管系统。
2. 重载系统,导致系统完全崩溃。
3. 泄露用户或系统数据。
一、添加一个用于上传文件的文件辅助类FileHelpers
为避免处理上传文件文件时出现重复代码,我们首先创建一个静态类用于处理上传功能。
1.在Visual Studio 2022 的解决方案资源管理器中创建一个“Utils”文件夹。
2.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Utils”文件夹,右键单击,在弹出菜单中选择“添加—>类”(如下图)。 将类命名为“FileHelpers”。
3.在Visual Studio 2022的文本编辑器中打开我们刚才创建的“FileHelpers.cs”类文件,并添加以下内容。其中方法 ProcessFormFile 接受 IBrowserFile 和 ModelStateDictionary等参数,保存成功则空字符串,否则返回错误信息。 检查内容类型和长度。 如果上传文件未通过校验,将向 ModelState 添加一个错误。
using BlazorAppDemo.Models;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Reflection;
using System.Text;
namespace BlazorAppDemo.Utils
{
public class FileHelpers
{
public static async Task<string> ProcessFormFile(IBrowserFile formFile, ModelStateDictionary modelState,IWebHostEnvironment envir,int maxFileSize)
{
var fieldDisplayName = string.Empty;
if (!string.IsNullOrEmpty(formFile.Name))
{
// 如果名称没有找到,将会有一个简单的错误消息,但不会显示文件名称
string displayFileName = formFile.Name.Substring(formFile.Name.IndexOf(".") + 1);
fieldDisplayName = $"{displayFileName} ";
}
//使用path.GetFileName获取一个带路径的全文件名。
//通过HtmlEncode进行编码的结果必须在错误消息中返回。
var fileName = WebUtility.HtmlEncode(Path.GetFileName(formFile.Name));
if (formFile.ContentType.ToLower() != "text/plain")
{
modelState.AddModelError(formFile.Name,
$"The {fieldDisplayName}file ({fileName}) must be a text file.");
}
//校验文件长度,如果文件不包含内容,则不必读取文件长度。
//此校验不会检查仅具有BOM(字节顺序标记)作为内容的文件,
//因此在读取文件内容后再次检验文件内容长度,以校验仅包含BOM的文件。
if (formFile.Size == 0)
{
modelState.AddModelError(formFile.Name, $"The {fieldDisplayName}file ({fileName}) is empty.");
}
else if (formFile.Size > maxFileSize)
{
modelState.AddModelError(formFile.Name, $"The {fieldDisplayName}file ({fileName}) exceeds 1 MB.");
}
else
{
try
{
//获取一个随机文件名
var trustedFileNameForFileStorage=Path.GetRandomFileName();
var path = Path.Combine(envir.ContentRootPath, envir.EnvironmentName, "unsafeUploads", trustedFileNameForFileStorage);
using (
var reader =
new FileStream(
path,
FileMode.Create))
{
await formFile.OpenReadStream(maxFileSize).CopyToAsync(reader);
}
}
catch (Exception ex)
{
modelState.AddModelError(formFile.Name,
$"The {fieldDisplayName}file ({fileName}) upload failed. " +
$"Please contact the Help Desk for support. Error: {ex.Message}");
//return ex.Message;
throw ex;
}
}
return string.Empty;
}
}
}
1. 在Visual Studio 2022的解决方案资源管理器中,鼠标右键单击“Pages”文件夹。在弹出菜单中选择,添加-->Razor组件。如下图。
2.在弹出对话框,名称中输入FileUpload1.razor。如下图。
3. 在Visual Studio 2022的解决方案资源管理器中,鼠标左键双击“Pages\FileUpload1.razor”文件,在文本编辑器中打开,在文件的顶部添加@page指令。并添加如下代码。
@page "/FileUpload1"
@using BlazorAppDemo.Utils
@using Microsoft.AspNetCore.Mvc.ModelBinding
@inject IWebHostEnvironment Environ
<h3>多文件上传示例</h3>
<p>
<label>
提示信息:@Message
</label>
</p>
<p>
<label>
上传文件最大可以为:<input type="number" @bind="maxFileSize"/>字节
</label>
</p>
<p>
<label>
一次可上传:<input type="number" @bind="maxAllowedFiles" />个文件
</label>
</p>
<p>
<label>
选择上传文件:<InputFile OnChange="@LoadFiles" multiple />
</label>
</p>
@if (isLoading)
{
<p>文件上传中......</p>
}
else
{
<ul>
@foreach (var file in loadedFiles)
{
<li>
<ul>
<li>文件名:@file.Name</li>
<li>最后修改时间:@file.LastModified.ToString()</li>
<li>文件大小(byte):@file.Size</li>
<li>文件类型:@file.ContentType</li>
</ul>
</li>
}
</ul>
}
@code {
private List<IBrowserFile> loadedFiles = new();
private long maxFileSize = 1024 * 18;
private int maxAllowedFiles = 2;
private bool isLoading;
private string Message = string.Empty;
private async Task LoadFiles(InputFileChangeEventArgs e)
{
isLoading = true;
loadedFiles.Clear();
foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
{
try
{
ModelStateDictionary modelState = new ModelStateDictionary();
loadedFiles.Add(file);
string result= await FileHelpers.ProcessFormFile(file, modelState, Environ, maxFileSize);
if (string.IsNullOrEmpty(result))
{
Message = "上传成功!";
}else
Message = "上传失败!";
}
catch (Exception ex)
{
Message = ex.Message;
}
}
isLoading = false;
}
}
4. 在Visual Studio 2022的解决方案资源管理器中,鼠标左键双击“Shared\NavMenu.razor”文件,在文本编辑器中打开,我们在此文中添加指向上传文件的菜单。具体代码如下:
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">BlazorAppDemo</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="BookIndex">
<span class="oi oi-list-rich" aria-hidden="true"></span> 图书列表
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="AddBook">
<span class="oi oi-list-rich" aria-hidden="true"></span> 添加图书
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="FileUpload1">
<span class="oi oi-list-rich" aria-hidden="true"></span> 上传文件
</NavLink>
</div>
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
5. 在Visual Studio 2022的菜单栏上,找到“调试à开始调试”或是按F5键,Visual Studio 2022会生成BlazorAppDemo应用程序,并在浏览器中打开Home页面,我们使用鼠标点击左边的菜单栏上的“上传文件”菜单项,页面会进入“FileUpload1”页面,我们会看到我们写的图书列表页面,如下图。
6. 我们在“多文件上传示例”中选择一个上传文件,然后应用程序会自动上传文件,但是却会提示错误,错误信息如下图中1处,指明“找不到路径的一部分”。我们打开资源管理器,在项目中找一下图中2处的目录,发现没有这样的目录结构。我们手动创建一下即可。
7. 我们在“多文件上传示例”中选择一个上传文件,然后应用程序会自动上传文件,上传到到目录中却不是我们选择的文件名,是一个随机的文件名。如下图。
相关文章
- ASP.NET MVC之文件上传【二】(九)
- ASP.NET实现二维码 ASP.Net上传文件 SQL基础语法 C# 动态创建数据库三(MySQL) Net Core 实现谷歌翻译ApI 免费版 C#发布和调试WebService ajax调用WebService实现数据库操作 C# 实体类转json数据过滤掉字段为null的字段
- JavaScript日历控件开发 C# 读取 appconfig文件配置数据库连接字符串,和配置文件 List<T>.ForEach 调用异步方法的意外 ef 增加或者更新的习惯思维 asp.net core导入excel 一个二级联动
- SQL 横转竖 、竖专横 (转载) 使用Dapper.Contrib 开发.net core程序,兼容多种数据库 C# 读取PDF多级书签 Json.net日期格式化设置 ASPNET 下载共享文件 ASPNET 文件批量下载 递归,循环,尾递归 利用IDisposable接口构建包含非托管资源对象 《.NET 进阶指南》读书笔记2------定义不可改变类型
- asp.net NPOI导出xlsx格式文件,打开文件报“Excel 已完成文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃” HSSF,XSSF和SXSSF的区别 使用XSSFWork创建的xlsx后缀Excel文件无法打开
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
- MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
- (六)Net Core项目使用Controller之一 c# log4net 不输出日志 .NET Standard库引用导致的FileNotFoundException探究 获取json串里的某个属性值 common.js 如何调用common.js js 筛选数据 Join 具体用法
- C#字符串数组排序 C#排序算法大全 C#字符串比较方法 一个.NET通用JSON解析/构建类的实现(c#) C#处理Json文件 asp.net使用Jquery+iframe传值问题
- 【.Net Core】上传文件-IFormFile
- 【asp.net】MVC模板中各个文件的功能和作用(持续更新中...)
- maven 依赖文件 pom.xml 编译 mvn compile 运行 不用mvn exec:java -Dexec.mainClass="hello.HelloWorld" 打成jar包 mvn package mvn install http://blog.csdn.net/yaya1943/article/details/48464371
- Asp.net实现直接在浏览器预览Word、Excel、PDF、Txt文件(附源码)
- asp.net-Creating JavaScript objects from ASP.NET objects
- ASP.NET MVC实现Excel文件的上传下载