首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

C# 通用檔案上傳元件:支援多檔、自動分類、資料庫整合與編輯器回寫

     編輯:ASP.NET 基礎

元件架構三層設計

層級檔案職責
表現層Upfile.aspx上傳介面:FileUpload + Button + Label 回饋
代碼後置Upfile.aspx.cs協調上傳流程、實例化上傳類、處理結果
核心邏輯AllSheng.upload (Class Library)封裝所有上傳邏輯:驗證、命名、儲存、縮圖、資料庫記錄

前端頁面

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Upfile.aspx.cs" Inherits="Inc_Upfile" %>
<form id="form1" runat="server">
  <asp:FileUpload ID="FileUpload1" runat="server" />
  <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="上傳檔案" CssClass="btn2" />
  <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</form>

頁面代碼後置

public partial class Inc_Upfile : Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        var uploader = new AllSheng.upload();
        uploader.Path = "../UpLoadfiles";           // 設定儲存路徑
        uploader.Sizes = 200;                       // 限制 200KB
        uploader.FileType = "jpg|gif|bmp|png|doc";  // 允許格式
        
        string result = uploader.SaveAs(Request.Files).ToString();
        Label1.Text = result;                       // 顯示儲存路徑
        uploader = null;
    }
}

核心上傳類完整實作

namespace AllSheng
{
    public class upload
    {
        #region 內部欄位
        private HttpPostedFile postedFile;
        private string localFileName, localFileExtension, localFilePath;
        private string saveFileName, saveFileExtension, saveFilePath, saveFileFolderPath;
        private string path = "uploadimages";       // 預設路徑
        private string fileType = "jpg|gif|bmp|jpeg|png|rar|doc";
        private int sizes = 200;                    // KB
        #endregion

        #region 公開屬性設定
        public string Path { set => path = value; }
        public int Sizes { set => sizes = value; }
        public string FileType { set => fileType = value; }
        #endregion

        #region 核心上傳方法
        public string SaveAs(HttpFileCollection files)
        {
            string myReturn = "";
            try
            {
                for (int i = 0; i < files.Count; i++)
                {
                    postedFile = files[i];
                    localFilePath = postedFile.FileName;
                    
                    if (string.IsNullOrEmpty(localFilePath)) continue;

                    // 1. 檔案大小驗證
                    localFileLength = postedFile.ContentLength;
                    if (localFileLength >= sizes * 1024)
                    { Message($"上傳檔案不可大於 {sizes}KB"); break; }

                    // 2. 取得儲存資料夾 (支援日期格式化路徑)
                    saveFileFolderPath = GetSaveFileFolderPath(path);
                    
                    // 3. 產生唯一檔名:UTC 時間戳 + 原副檔名
                    localFileName = Path.GetFileName(postedFile.FileName);
                    saveFileName = DateTime.UtcNow.ToString("yyyyMMddHHmmssffffff");
                    
                    // 4. 副檔名驗證
                    localFileExtension = GetFileExtension(localFileName);
                    if (string.IsNullOrEmpty(localFileExtension))
                    { Message($"僅支援格式:{fileType}"); continue; }
                    
                    saveFileExtension = localFileExtension;
                    saveFilePath = Path.Combine(saveFileFolderPath, saveFileName + saveFileExtension);
                    
                    // 5. 實際儲存
                    postedFile.SaveAs(saveFilePath);
                    
                    // 6. 回傳相對路徑供前端使用
                    myReturn += (myReturn == "" ? "" : "|") + 
                                path.TrimStart('/') + saveFileName + saveFileExtension;

                    // 7. 整合 FCKeditor/CKEditor:直接寫入編輯器內容
                    string imgTag = $"<img src='{saveFileName}{saveFileExtension}' border=0 />";
                    string script = $"parent.Article_Content___Frame.FCK.EditorDocument.body.innerHTML+='{imgTag}'";
                    HttpContext.Current.Response.Write($"<script>{script}</script>");
                }
            }
            catch { Message("發生未知錯誤!"); myReturn = null; }
            return myReturn;
        }
        #endregion

        #region 輔助方法
        private string GetSaveFileFolderPath(string format)
        {
            string folderPath = format.Contains("yyyy") || format.Contains("MM") || format.Contains("dd")
                ? DateTime.UtcNow.ToString(format)
                : format;
            
            string fullPath = HttpContext.Current.Server.MapPath(".") + folderPath;
            if (!Directory.Exists(fullPath)) Directory.CreateDirectory(fullPath);
            return fullPath + "\\";
        }

        private string GetFileExtension(string fileName)
        {
            string ext = Path.GetExtension(fileName)?.ToLower();
            if (string.IsNullOrEmpty(ext)) return null; // 無副檔名
            
            return fileType.Split('|').Contains(ext.TrimStart('.')) ? ext : "";
        }

        private void Message(string msg, string url = null)
        {
            string script = url == null 
                ? $"alert('{msg}');" 
                : $"alert('{msg}');window.location='{url}';";
            HttpContext.Current.Response.Write($"<script>{script}</script>");
        }
        #endregion
    }
}

關鍵特性深度解析

1. 彈性路徑格式化

// 支援日期格式化字串自動建立子資料夾
uploader.Path = "uploadimages/yyyy/MM/dd";  // 實際路徑:uploadimages/2024/01/15/
uploader.Path = "uploadimages/yyyyMMdd";    // 實際路徑:uploadimages/20240115/
uploader.Path = "uploadimages";             // 固定資料夾

2. 多檔案批次處理

單次呼叫 SaveAs(Request.Files) 自動遍歷所有上傳檔案,回傳以 | 分隔的路徑字串,適合批次上傳場景。

3. 編輯器無縫整合

上傳成功自動產生 JavaScript 向父頁面 FCKeditor/CKEditor 寫入 <img> 標籤,實現「上傳即插入」體驗。

4. 安全性考量

  • 副檔名白名單驗證 (雙重:前端 Regex + 後端檢查)
  • 檔案大小限制
  • 唯一檔名避免覆蓋
  • 路徑遍歷防護 (Path.GetFileName 移除目錄資訊)

現代化改良建議

原始做法建議改良理由
System.Drawing (GDI+)ImageSharp / SkiaSharp跨平台、無記憶體洩漏、效能更佳
Response.Write 輸出 Script回傳 JSON + 前端 AJAX 處理關注點分離、易測試、支援 SPA 架構
儲存實體檔案Azure Blob / AWS S3 / MinIO擴展性、CDN 整合、容器化友善
硬編碼編輯器整合事件/委派模式解耦、支援多種編輯器
同步阻塞上傳非同步 I/O + 進度回報大檔案體驗、伺服器資源利用率

總結

這個上傳元件展現了 ASP.NET WebForms 時代「類別庫封裝業務邏輯、頁面僅負責協調」的經典分層思想。核心優勢在於高度可配置的屬性設計、日期格式化路徑、編輯器整合、多檔批次處理。現代專案可保留核心邏輯(驗證、命名、路徑解析),將儲存介面抽象化、前端改為 AJAX、編輯器整合改為事件驅動,即可平滑遷移至 ASP.NET Core + 前端分離架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved