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

WCF 實戰教學 (7):啟用 MTOM 機制優化二進位資料傳輸效能

     編輯:關於.NET

前言

WCF 預設使用 Text/XML 編碼傳輸 SOAP 訊息,當訊息本文包含大量二進位資料 (如圖片、文件、影音) 時,Base64 編碼會使資料量膨脹約 33%,嚴重影響頻寬與效能。MTOM (Message Transmission Optimization Mechanism) 透過將二進位區塊以原始位元組形式附加於 SOAP 訊息外部 (XOP 封裝),僅在 XML 中保留引用,能大幅降低傳輸體積。本篇以 Web 方式上傳大檔案為例,示範如何在 wsHttpBinding 上啟用 MTOM。

MTOM 運作原理速覽

  • Text 編碼:二進位資料 → Base64 字串 → 內嵌 XML → 體積 +33%
  • MTOM 編碼:二進位資料 → 原始位元組區塊 (MIME Part) → XML 僅保留 <xop:Include href="cid:..."/> 引用 → 體積接近原始大小
  • 適用場景:傳輸圖片、PDF、Office 文件、影音檔等二進位大型物件

完整程式碼範例

1. 服務端契約與實作

IMtom.cs - 服務契約

using System;
using System.ServiceModel;

namespace WCF.ServiceLib.Message
{
    [ServiceContract]
    public interface IMtom
    {
        /// 
        /// 上傳檔案 (以位元組陣列接收)
        /// 
        /// 伺服器端儲存路徑
        /// 檔案二進位內容
        [OperationContract]
        void UploadFile(string path, byte[] fileData);
    }
}

Mtom.cs - 服務實作

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);
            }
        }
    }
}

2. 宿主與設定檔 (IIS 裝載)

Mtom.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Message.Mtom" %>

Web.config - 關鍵:messageEncoding="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>

3. 用戶端 (ASP.NET Web Form)

Mtom.aspx - 上傳介面

<%@ 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>

Mtom.aspx.cs - 後台程式碼

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();
        }
    }
}

用戶端 Web.config

<?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 MB1.33 MB1.02 MB23%
10 MB13.3 MB10.1 MB24%
17.7 MB31.6 MB23.7 MB25%

注意事項與最佳實務

  1. 雙端必須一致:服務端與用戶端 messageEncoding 皆需設為 Mtom,否則會發生解碼錯誤。
  2. readerQuotas 要放大:maxArrayLength、maxBytesPerRead 等配額需配合最大檔案大小調整,否則大檔案會拋出配額超過例外。
  3. 非二進位資料不適用:純文字 XML、JSON 等資料啟用 MTOM 反而會增加 MIME 封裝開銷,請視資料類型決定。
  4. 防火牆/Proxy 相容性:MTOM 產生 multipart/related MIME 封包,部分老舊 Proxy 可能攔截,建議搭配 HTTPS 使用。

除錯技巧:使用 tcpTrace 捕獲 SOAP 封包

  1. 下載 tcpTrace 或 WCF 內建 Service Trace Viewer (SvcTraceViewer.exe)。
  2. 設定監聽連接埠 (如 8888),轉發至真實服務連接埠 (3502)。
  3. 用戶端端點 address 指向 https://localhost:8888/...,即可在 tcpTrace 視窗看到完整 MTOM 封包結構。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved