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

Silverlight 大檔案分塊上傳:WebClient 非同步串流實作 (客戶端 + 伺服端)

     編輯:ASP.NET 基礎

架構概覽

  • 客戶端 (Silverlight):使用 WebClient.OpenWriteTaskAsync 以 25MB 為單位分塊上傳,完成一塊才發送下一塊 (避免記憶體暴增)。
  • 伺服端 (ASHX / MVC Controller):接收 `InputStream` 追加寫入檔案,支援斷點續傳邏輯 (查詢字串 `t=1` 表示分塊模式)。

客戶端核心程式碼 (C# Silverlight)

public static class LargeFileUploader
{
    private const int ChunkSize = 25 * 1024 * 1024; // 25MB

    /// 
    /// 進入點:自動判斷檔案大小決定是否分塊
    /// 
    public static async Task<bool> UploadAsync(string url, Stream fileStream)
    {
        if (fileStream.Length > ChunkSize)
            url += "&t=1"; // 告知伺服器採用分塊模式

        try
        {
            await UploadChunkedAsync(url, fileStream);
            return true;
        }
        catch (Exception ex)
        {
            // 記錄錯誤
            return false;
        }
    }

    private static async Task UploadChunkedAsync(string url, Stream sourceStream)
    {
        var wc = new WebClient();
        byte[] buffer = new byte[ChunkSize];

        // 遞迴上傳每一塊
        Action uploadNext = null;
        uploadNext = async () =>
        {
            int read = sourceStream.Read(buffer, 0, buffer.Length);
            if (read == 0)
            {
                sourceStream.Close();
                return;
            }

            // 這一塊寫入完成後再遞迴下一塊
            wc.WriteStreamClosed += (s, e) => uploadNext();

            using (var serverStream = await wc.OpenWriteTaskAsync(new Uri(url, UriKind.Absolute), "POST"))
            {
                serverStream.Write(buffer, 0, read);
                // 關閉 serverStream 會觸發 WriteStreamClosed
            }
        };

        uploadNext();
    }
}

伺服端處理常式 (ASHX 範例)

public class UploadHandler : IHttpHandler, IRequiresSessionState
{
    public bool IsReusable => false;

    public void ProcessRequest(HttpContext context)
    {
        try
        {
            // 1. 解析上傳元資料 (Base64 + JSON)
            string metaB64 = context.Request.QueryString["data"];
            string metaJson = Base64Decode(metaB64, "YourSecretKey"); // 自行實作解密
            var meta = JsonConvert.DeserializeObject<FileMeta>(metaJson);

            bool isChunked = context.Request.QueryString["t"] == "1";

            // 2. 確保目錄存在
            string dir = Path.Combine(Config.UploadRoot, meta.Dir);
            Directory.CreateDirectory(dir);
            string filePath = Path.Combine(dir, meta.FileName);

            // 3. 非分塊模式先刪除舊檔
            if (!isChunked && File.Exists(filePath)) File.Delete(filePath);

            // 4. 追加寫入流
            using (var fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None))
            {
                const int BufSize = 4096;
                byte[] buffer = new byte[BufSize];
                int read;
                var input = context.Request.InputStream;
                while ((read = input.Read(buffer, 0, BufSize)) > 0)
                {
                    fs.Write(buffer, 0, read);
                }
            }

            // 5. 產生縮圖 (可選)
            if (meta.NeedThumbnail) GenerateThumbnail(filePath, meta);

            // 6. 清理舊檔 (替換上傳情境)
            CleanupOldFiles(meta);

            context.Response.Write("OK");
        }
        catch (Exception ex)
        {
            context.Response.StatusCode = 500;
            context.Response.Write(ex.Message);
        }
    }

    // 輔助方法略...
}

關鍵設計細節

議題處理方式
記憶體控制固定 25MB 緩衝區,讀一塊傳一塊,不將整檔載入記憶體。
順序保證`WriteStreamClosed` 事件串聯下一塊上傳,確保伺服端依序寫入,避免競態覆蓋。
斷點續傳伺服端可對比檔案大小與元資料 `FileSize`,決定是否略過已上傳分塊 (需客戶端支援 Range/Resume)。
錯誤重試客戶端捕捉例外後可指數退避重試特定分塊。
安全性元資料加密傳遞、伺服端驗證檔案類型 (Magic Number)、限制副檔名、掃毒。

現代替代方案

Silverlight 已於 2021 年停止支援。新專案建議採用:

  • HTML5 + JavaScript:`File.prototype.slice()` + `fetch`/`XMLHttpRequest` 分塊上傳,支援暫停/續傳/進度條 (如 Uppy、Resumable.js、Tus.io)。
  • Blazor WebAssembly:`InputFile` + 自訂分塊邏輯,共用 .NET 程式碼。
  • ASP.NET Core + Multipart/Form-Data:搭配 `IFormFile` 串流處理,配合 Kestrel `MaxRequestBodySize` 限制。

小結

Silverlight 時代的 `WebClient` 分塊上傳展現了「串流分塊、事件串聯、伺服端追加寫入」的核心模式,這些原理在現代 HTML5/Blazor 上傳元件中依然適用,理解底層機制有助於選型與除錯。

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