操作契約參數/返回值**只能**是 Stream 或 void:
void SendStream(Stream inStream);
Stream ReceiveStream();
Stream SendAndReceiveStream(Stream inStream);
void SendAndReceiveStream(Stream inStream, out Stream outStream);
void ReceiveStream(out Stream outStream);
無法直接傳遞文件名等元數據 → **消息頭** 成為最佳載體。
| 類 | 關鍵成員 | 用途 |
|---|---|---|
OperationContext | IncomingMessageHeaders, OutgoingMessageHeaders | 當前操作上下文,訪問輸入/輸出消息頭集合 |
MessageHeader<T> | GetUntypedHeader(name, ns) | 泛型消息頭,類型安全,轉為無類型頭寫入集合 |
MessageHeaders | GetHeader<T>(name, ns) | 消息頭集合,泛型讀取指定頭 |
OperationContextScope | 構造函數, Dispose() | 創建新上下文作用域,離開時自動恢復 |
[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 生命週期