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

WCF 流模式傳輸文件:利用 SOAP 消息頭攜帶元數據 (文件名/路徑/長度)

     編輯:關於.NET

流模式契約約束

操作契約參數/返回值**只能**是 Stream 或 void:

void SendStream(Stream inStream);
Stream ReceiveStream();
Stream SendAndReceiveStream(Stream inStream);
void SendAndReceiveStream(Stream inStream, out Stream outStream);
void ReceiveStream(out Stream outStream);

無法直接傳遞文件名等元數據 → **消息頭** 成為最佳載體。

核心類與方法

類關鍵成員用途
OperationContextIncomingMessageHeaders, OutgoingMessageHeaders當前操作上下文,訪問輸入/輸出消息頭集合
MessageHeader<T>GetUntypedHeader(name, ns)泛型消息頭,類型安全,轉為無類型頭寫入集合
MessageHeadersGetHeader<T>(name, ns)消息頭集合,泛型讀取指定頭
OperationContextScope構造函數, Dispose()創建新上下文作用域,離開時自動恢復

自定義數據契約:StreamContext

[DataContract]
public class StreamContext {
    [DataMember] public string FileName;
    [DataMember] public string FilePath;
    [DataMember] public int FileLength;

    // 消息頭封裝邏輯
    public static StreamContext Current {
        get {
            var ctx = OperationContext.Current;
            if (ctx == null) return null;
            try {
                return ctx.IncomingMessageHeaders.GetHeader<StreamContext>("StreamContext", "https://tempuri.org");
            } catch { return null; }
        }
        set {
            var ctx = OperationContext.Current;
            Debug.Assert(ctx != null);
            bool exists = false;
            try {
                ctx.OutgoingMessageHeaders.GetHeader<StreamContext>("StreamContext", "https://tempuri.org");
                exists = true;
            } catch (MessageHeaderException ex) { /* 不存在 */ }
            if (exists) throw new InvalidOperationException("同名消息頭已存在");
            var header = new MessageHeader<StreamContext>(value);
            ctx.OutgoingMessageHeaders.Add(header.GetUntypedHeader("StreamContext", "https://tempuri.org"));
        }
    }
}

服務端實現

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class SendStreamService : ISendStreamService {
    public void SendStream(Stream stream) {
        var ctx = StreamContext.Current; // 從消息頭讀取元數據
        string fullPath = ctx.FilePath + "\\" + ctx.FileName;
        
        using (var fs = new FileStream(fullPath, FileMode.OpenOrCreate, FileAccess.Write)) {
            byte[] buffer = new byte[8192];
            int read;
            while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                fs.Write(buffer, 0, read);
        }
        Debug.WriteLine($"文件 {ctx.FileName} 上傳成功,大小 {ctx.FileLength} bytes");
    }
}

客戶端調用

string file = FileUpload1.PostedFile.FileName;
using (var inStream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
    file = file.Substring(file.LastIndexOf("\\") + 1);
    string path = Server.MapPath(Request.Path).Substring(0, Server.MapPath(Request.Path).LastIndexOf("\\"));
    
    var ctx = new StreamContext(file, path, 0);
    var client = new SendStreamClient("setEndpoint");
    
    using (new OperationContextScope(client.InnerChannel)) { // 建立新上下文
        StreamContext.Current = ctx; // 寫入消息頭
        client.Open();
        client.BeginSendStream(inStream, Callback, file);
    }
}

配置要點

<binding name="streamBinding" transferMode="Streamed" 
         maxReceivedMessageSize="2147483647" />

優缺點總結

  • ✅ 契約乾淨,業務參數不污染
  • ✅ 支持流式大文件傳輸
  • ✅ 消息頭可攜帶任意擴展信息
  • ⚠️ 客戶端需正確管理 OperationContextScope 生命週期
  • ⚠️ 非標準參數傳遞,團隊需約定規範
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved