WCF 預設使用 Text/XML 編碼傳輸 SOAP 訊息,當訊息本文包含大量二進位資料 (如圖片、文件、影音) 時,Base64 編碼會使資料量膨脹約 33%,嚴重影響頻寬與效能。MTOM (Message Transmission Optimization Mechanism) 透過將二進位區塊以原始位元組形式附加於 SOAP 訊息外部 (XOP 封裝),僅在 XML 中保留引用,能大幅降低傳輸體積。本篇以 Web 方式上傳大檔案為例,示範如何在 wsHttpBinding 上啟用 MTOM。
<xop:Include href="cid:..."/> 引用 → 體積接近原始大小using System;
using System.ServiceModel;
namespace WCF.ServiceLib.Message
{
[ServiceContract]
public interface IMtom
{
///
/// 上傳檔案 (以位元組陣列接收)
///
/// 伺服器端儲存路徑
/// 檔案二進位內容
[OperationContract]
void UploadFile(string path, byte[] fileData);
}
}
using System;
using System.IO;
using WCF.ServiceLib.Message;
namespace WCF.ServiceLib.Message
{
public class Mtom : IMtom
{
public void UploadFile(string path, byte[] fileData)
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
{
fs.Write(fileData, 0, fileData.Length);
}
}
}
}
<%@ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Message.Mtom" %>
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF.ServiceLib.Message.Mtom" behaviorConfiguration="MessageBehavior">
<endpoint address=""
binding="wsHttpBinding"
contract="WCF.ServiceLib.Message.IMtom"
bindingConfiguration="MtomBindingConfiguration" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MtomBindingConfiguration"
messageEncoding="Mtom" <!-- 核心設定 -->
maxReceivedMessageSize="1073741824" <!-- 1 GB -->
receiveTimeout="00:10:00">
<readerQuotas maxArrayLength="1073741824" /> <!-- 允許大型位元組陣列 -->
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MessageBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="Mtom.aspx.cs" Inherits="Message_Mtom"
Title="MTOM 檔案上傳示範" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"></asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<p>MTOM (Message Transmission Optimization Mechanism) - 訊息傳輸優化機制</p>
<div>
<ul>
<li>指定 SOAP 訊息以 MTOM 或 Text 編碼</li>
<li>抓取 SOAP 封包可使用 tcpTrace 工具</li>
<li>實測 17.7 MB 檔案:Text 編碼 SOAP 31.6 MB → MTOM 編碼 SOAP 23.7 MB (減少 25%)</li>
</ul>
</div>
<div>
源檔案: <asp:FileUpload ID="file" runat="server" />
上傳路徑: <asp:TextBox ID="txtDestination" runat="server" Text="C:\Uploads\" />
<asp:Button ID="btnUpload" runat="server" Text="上傳" OnClick="btnUpload_Click" />
</div>
</asp:Content>
using System;
using System.IO;
using System.Web.UI;
public partial class Message_Mtom : Page
{
protected void btnUpload_Click(object sender, EventArgs e)
{
if (!file.HasFile) return;
var proxy = new MessageSvc.Mtom.MtomClient();
try
{
var bytes = file.FileBytes; // 直接取得位元組陣列
string destPath = Path.Combine(txtDestination.Text.Trim(), file.FileName);
proxy.UploadFile(destPath, bytes);
ClientScript.RegisterStartupScript(GetType(), "ok", "alert('上傳成功');", true);
}
catch (Exception ex)
{
ClientScript.RegisterStartupScript(GetType(), "err", $"alert('{ex.Message}');", true);
}
finally
{
proxy.Close();
}
}
}
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="https://localhost:3502/ServiceHost/Message/Mtom.svc"
binding="wsHttpBinding"
contract="MessageSvc.Mtom.IMtom"
bindingConfiguration="MtomBindingConfiguration" />
</client>
<bindings>
<wsHttpBinding>
<binding name="MtomBindingConfiguration"
messageEncoding="Mtom"
sendTimeout="00:10:00">
<readerQuotas maxArrayLength="1073741824" />
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
| 檔案大小 | Text 編碼 SOAP 大小 | MTOM 編碼 SOAP 大小 | 體積縮減 |
|---|---|---|---|
| 1 MB | 1.33 MB | 1.02 MB | 23% |
| 10 MB | 13.3 MB | 10.1 MB | 24% |
| 17.7 MB | 31.6 MB | 23.7 MB | 25% |
messageEncoding 皆需設為 Mtom,否則會發生解碼錯誤。maxArrayLength、maxBytesPerRead 等配額需配合最大檔案大小調整,否則大檔案會拋出配額超過例外。Service Trace Viewer (SvcTraceViewer.exe)。address 指向 https://localhost:8888/...,即可在 tcpTrace 視窗看到完整 MTOM 封包結構。