学习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 Core Blazor编程系列十七——文件上传(上)的更多相关文章
- 学习ASP.NET Core Blazor编程系列六——新增图书(上)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(上)
学习ASP.NET Core Blazor编程系列一--综述 一.概述 Blazor 是一个生成交互式客户端 Web UI 的框架: 使用 C# 代替 JavaScript 来创建信息丰富的交互式 U ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(下)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(完)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 022年9月12日 学习ASP.NET Core Blazor编程系列三——实体
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列四——迁移
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列五——列表页面
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列六——初始化数据
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- 学习ASP.NET Core Blazor编程系列八——数据校验
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
随机推荐
- C++ 高级数据类型(六)—— 自定义数据类型
转载:https://blog.csdn.net/zjy900507/article/details/79623829 定义自己的数据类型 (typedef) C++ 允许我们在现有数据类型的基础上定 ...
- Lombok好用是好用,就是容易踩坑,这份避坑指南请查收
序言 各位好啊,我是会编程的蜗牛,作为java开发者,我们平常在开发过程中,总是希望能够尽量少敲代码.这一方面,当然是为了偷懒,另一方面,当然也是为了代码看起来更加简洁一点,不断往编程规范上靠.然后其 ...
- CEOI2020 道路(Roads) Solution
直接来构造. 考虑扫描线.从左到右扫,考虑当前扫到了一个左端点,我们把这个左端点连到其他点上. 我们可以找到这个点下方离他最近的线段,并且记下每条线段上方在扫描线左侧且最靠右,与这条线段中间没有其他线 ...
- 从0开始写一个简单的vite hmr 插件
从0开始写一个简单的vite hmr 插件 0. 写在前面 在构建前端项目的时候,除开基本的资源格式(图片,json)以外,还常常会需要导入一些其他格式的资源,这些资源如果没有第三方vite插件的支持 ...
- Qt Quick 用cmake怎么玩子项目
以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://mp.weixin.qq.com/s/o-_aGqreuQda-ZmKktvxwA 以往在公司开发众多的项目中 ...
- jsp中使用Servlet查询SQLSERVER数据库中的表的信息,并且打印在屏幕上
jsp中使用Servlet查询SQLSERVER数据库中的表的信息,并且打印在屏幕上 1.JavaBean的使用 package com.zheng; public class BookBean { ...
- break ,continue,retrun的区别
break ,continue,retrun的区别 1:break 在循环体内结束整个循环过程 for (var i = 1; i <= 5; i++) { if(i == 3){ break; ...
- 京东云开发者|关于“React 和 Vue 该用哪个”我真的栓Q
一.前言:我全都要 面对当今前端界两座大山一样的主流框架,React和Vue,相信很多小伙伴都或多或少都产生过这样疑问,而这样的问题也往往很让人头疼和犹豫不决: 业务场景中是不是团队用什么我就用什么? ...
- 廖---list tuple dic set
list 有序集合,可随时添加和删除其中的数据. 在 Python 列表中删除元素主要分为以下 3 种场景: 根据目标元素所在位置的索引进行删除,可以使用 del 关键字或者 pop() 方法: 根据 ...
- C#.NET实现二分查找
二分搜索法 定义 二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法. 适用范围 当数据量很大并且有序时,适宜采用该方法. 基本思想 假设数据是按升序排序的,对于给定值key,从序列的 ...