首页 > 编程语言 > 学习ASP.NET Core Blazor编程系列十七——文件上传(上)

学习ASP.NET Core Blazor编程系列十七——文件上传(上)

时间:2022-12-18 17:45:43浏览次数:68  
标签:Core ASP 文件 formFile NET 上传 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编程系列八——数据校验 学习ASP.NET Core Blazor编程系列十——路由(上) 学习ASP.NET Core Blazor编程系列十三——路由(完) 学习ASP.NET Core Blazor编程系列十五——查询 学习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. 我们在“多文件上传示例”中选择一个上传文件,然后应用程序会自动上传文件,上传到到目录中却不是我们选择的文件名,是一个随机的文件名。如下图。

 

 

标签:Core,ASP,文件,formFile,NET,上传,Blazor
From: https://www.cnblogs.com/chillsrc/p/16990664.html

相关文章

  • windows10 netsh wlan命令连接新wifi
    通过修改已存在的profile的ssid和密码来连接新的wifi。1. 查看当前存在的profile(本机连接过的wifi会生成一个profile)netshwlanshowprofilesUserprofiles------......
  • .net 类似python写法例子
    1//[3]*102Enumerable.Range(0,10).ToArray();34//[X*2forxinrange(5)ifx%3==0]5Enumerable.Range(0,5).Select(x=>x*2).ToArray();67//m......
  • .net core mvc中session的应用
    1、首先新建一个空的web项目,在Program.cs中打开和使用sessionpublicclassProgram{publicstaticvoidMain(string[]args){var......
  • 使用WPF或AspNetCore创建简易版ChatGPT客户端,让ChatGPT成为你的私人助理
    前言:前一天写的一个ChatGPT服务端,貌似大家用起来还不是那么方便,所以我顺便用WPF和AspNetCore的webapi程序做个客户端吧,通过客户端来快速访问chatgpt模型生成对话。 1、......
  • .NET&Web前端-大三-员工疫情管理
    .NET&Web前端-大三-员工疫情管理目录​​.NET&Web前端-大三-员工疫情管理 ​​​​语言和环境​​​​素材​​​​实现功能​​​​数据库设计​​​​具体要求及推荐实现......
  • ADO.NET连接MySQL注意细节
    Nuget安装MySQL包MySql.Data.MySqlClient几个数据库对象的前缀为:MySQL比如:MySqlConnection连接字符串可以参考这里:https://www.cnblogs.com/cqpanda/p/16316311.......
  • EF Core无法翻译groupby等子查询
    烦人的表达式转化错误varquery1=emps.Grouby(v=>v.DeptId).Select(g=>new{DeptId=g.Key,Salary=g.Max(x=>x.Salary);varresult=fromdindeptsjoi......
  • telnet、wirshark等工具介绍
    1. telnet工具  1.1介绍       (1)telnet是一个命令行运行的客户端TCP通信工具      (2)可以接收数据、也可发送数据,windows和linux上都能用......
  • Kubernetes(k8s) kubectl rollout status常用命令
    kubectl在$HOME/.kube目录中查找一个名为config的配置文件。可以通过设置KUBECONFIG环境变量或设置--kubeconfig参数来指定其它kubeconfig文件。本文主要介绍K......
  • CSharp: Chain of Responsibility Pattern in donet core 6
     usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceGeovin.Du.DuChainOfResponsib......