soap-errorswcfsapsoapaction

The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher

SOAPless Team7 min read

このエラーは、サーバーが SOAP リクエストを受信したものの、サービスコントラクト内のどの operation にもルーティングできなかったことを意味します。

The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher.

WCF サービス、SAP 連携(背後に .NET エンドポイントがあるもの)、WS-Addressing や Action ベースのディスパッチを使う SOAP サービス全般でよく発生します。

SOAPAction ルーティングの仕組み

SOAP サービスは Action 値を使って呼び出すべき operation を判定します。この仕組みは SOAP 1.1 と 1.2 で異なります。

SOAP 1.1: SOAPAction HTTP ヘッダー

SOAP 1.1 では Action は独立した HTTP ヘッダーとして送ります。サーバーが期待する値と完全に一致しなければなりません。

POST /service.svc HTTP/1.1
Host: example.com
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IUserService/GetUser"

注意点:

  • 値はダブルクォートで囲むのが一般的です
  • 大文字・小文字が区別されます
  • SOAPAction: "" は「Action 未指定」を意味し、Action '' エラーの直接的な原因になります
  • ヘッダー自体を省略した場合も同様にエラーになり得ます

SOAP 1.2: Content-Type 内の action パラメータ

SOAP 1.2 では Action は Content-Type ヘッダーのパラメータとして指定します。

POST /service.svc HTTP/1.1
Host: example.com
Content-Type: application/soap+xml; charset=utf-8; action="http://tempuri.org/IUserService/GetUser"

SOAP 1.2 のリクエストで SOAPAction ヘッダーだけを付けて Content-Type 内の action パラメータを省略すると、サーバーが Action を認識できず、同じ ContractFilter mismatch エラーになることがあります。

ステップ 1: WSDL から正しい Action を特定する

WSDL は各 operation の Action を定義しています。

<wsdl:binding name="UserServiceSoap" type="tns:IUserService">
  <soap:binding style="document"
    transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="GetUser">
    <soap:operation
      soapAction="http://tempuri.org/IUserService/GetUser"
      style="document" />
    <wsdl:input>
      <soap:body use="literal" />
    </wsdl:input>
    <wsdl:output>
      <soap:body use="literal" />
    </wsdl:output>
  </wsdl:operation>
</wsdl:binding>

<soap:operation>soapAction 属性が、送信すべき正確な文字列です。パス、大文字・小文字、末尾のスラッシュまで一字一句コピーしてください。

WCF サービスの場合、Action は通常以下のパターンに従います。

http://tempuri.org/IServiceName/OperationName

カスタム名前空間を使用している場合は WSDL に反映されています。

ステップ 2: curl でデバッグする

最小限のリクエストを送ってレスポンスを確認します。

# SOAP 1.1 — SOAPAction を独立ヘッダーで指定
curl -v \
  -H "Content-Type: text/xml; charset=utf-8" \
  -H 'SOAPAction: "http://tempuri.org/IUserService/GetUser"' \
  -d '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetUser xmlns="http://tempuri.org/">
      <userId>1</userId>
    </GetUser>
  </soap:Body>
</soap:Envelope>' \
  https://example.com/service.svc
# SOAP 1.2 — Content-Type 内に action を指定
curl -v \
  -H "Content-Type: application/soap+xml; charset=utf-8; action=\"http://tempuri.org/IUserService/GetUser\"" \
  -d '<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <GetUser xmlns="http://tempuri.org/">
      <userId>1</userId>
    </GetUser>
  </soap12:Body>
</soap12:Envelope>' \
  https://example.com/service.svc

正しい SOAPAction を指定した SOAP 1.1 リクエストで正常なレスポンスが返れば、Action ヘッダーの欠落・誤りが原因です。それでも失敗する場合は、サービスが SOAP 1.2 のみに対応していないか確認してください。

ステップ 3: クライアント設定を修正する

WCF クライアント — web.config

WCF で最も多い原因は、binding が Action を含んでいない、またはエンドポイントが誤ったサービスコントラクトを指しているケースです。

<system.serviceModel>
  <bindings>
    <basicHttpBinding>
      <binding name="UserServiceSoap" />
    </basicHttpBinding>
  </bindings>
  <client>
    <endpoint
      address="https://example.com/service.svc"
      binding="basicHttpBinding"
      bindingConfiguration="UserServiceSoap"
      contract="UserService.IUserService"
      name="UserServiceSoap" />
  </client>
</system.serviceModel>

確認すべき項目:

  1. contract 属性がサービスインターフェースと完全一致していること
  2. address が正しいエンドポイントを指していること(WSDL URL ではない)
  3. binding の種類がサーバーの SOAP バージョンと一致していること
  4. wsHttpBinding を使う場合、security 設定(message / transport)がサーバーと合っていること

WCF — プログラムで Action を上書きする

生成されたクライアントが Action を正しく送信しない場合、手動で上書きできます。

using (var scope = new OperationContextScope(client.InnerChannel))
{
    var action = new HttpRequestMessageProperty();
    action.Headers["SOAPAction"] = "\"http://tempuri.org/IUserService/GetUser\"";
    OperationContext.Current.OutgoingMessageProperties[
        HttpRequestMessageProperty.Name] = action;

    var result = client.GetUser(userId);
}

よくある落とし穴

  • 末尾スラッシュ: http://tempuri.org/IUserService/GetUserhttp://tempuri.org/IUserService/GetUser/ は別の Action です
  • 名前空間の不一致: Action URI はサービスコントラクトで定義された名前空間と一致する必要があり、エンドポイント URL とは限りません
  • プロキシツールによる Action の欠落: 一部の HTTP プロキシツールは SOAPAction ヘッダーを削除・変更することがあります。必ず curl で生のリクエストを検証してください
  • 複数エンドポイント: WCF サービスが複数のエンドポイントを異なるコントラクトで公開している場合、正しいエンドポイントを呼んでいるか確認してください

なぜチームをまたいで同じ問題が起きるのか

SOAP サービスに直接連携する consumer は、それぞれ独自に以下を調べなければなりません。

  • 各 operation の正しい Action URI
  • SOAP 1.1 / 1.2 どちらの Action セマンティクスを使うか
  • 正しい binding に対応するエンドポイント URL

これはチームごとに重複する連携作業であり、同じデバッグセッションが何度も発生する原因です。

SOAPless による自動解決

SOAPless に WSDL を登録すると、エンジンがすべての operation とその soapAction 値を WSDL から解析します。下流の consumer が REST JSON エンドポイントを呼び出す際、SOAPless が自動的に正しい Action ヘッダーを持つ SOAP リクエストを構築します。SOAP 1.1 の SOAPAction ヘッダーも、SOAP 1.2 の Content-Type 内 action パラメータも、すべて自動で設定されます。

どの consumer も SOAPAction の文字列を知る必要はありません。WSDL が唯一の信頼できるソースであり、SOAPless がそれを一度読み取ることで、チーム全体が同じ問題を繰り返し調べる必要がなくなります。