8

SOAP リクエストに添付ファイルを追加する方法について、私は迷っています。Java で構築されたサード パーティの Web サービスを使用する必要がありますが、これは私が今まで遭遇した中で最も複雑なものです。添付ファイルを必要とする他の Web サービスには、添付ファイルを追加するためのメソッドまたはプロパティがあります。単純。ただし、これはそのような方法を提供しません。

必要な XML とまったく同じバージョンの SOAP メッセージを一緒に取得しましたが、追加できないのはファイルの MIME 部分です。

例:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<soap:Header>
<payloadManifest xmlns="http://<examplePayload>">
<manifest contentID="Content0" namespaceURI="http://<exampleManifest>" element="ProcessRepairOrder" version="2.01" />
</payloadManifest>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2011-12-19T15:25:13Z</wsu:Created>
<wsu:Expires>2011-12-19T15:30:00Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken><wsse:Username>username</wsse:Username><wsse:Password>password</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ProcessMessage xmlns="<examplePayload"><payload><content id="Content0">

<s:ProcessRepairOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.xsd" xmlns:s="http://<exampleManifest>" xmlns:gwm="http://example">
    <s:ApplicationArea>
        <s:Sender>
            <s:Component>Test</s:Component>
            <s:Task>ProcessAttachment</s:Task>
            <s:CreatorNameCode>Test</s:CreatorNameCode>
            <s:SenderNameCode>XX</s:SenderNameCode>
            <s:DealerNumber>111111</s:DealerNumber>
            <s:DealerCountry>GB</s:DealerCountry>
        </s:Sender>
        <s:CreationDateTime>2010-03-26T13:37:05Z</s:CreationDateTime>
        <s:Destination>
            <s:DestinationNameCode>GM</s:DestinationNameCode>
            <s:DestinationURI/>
            <s:DestinationSoftwareCode>GWM</s:DestinationSoftwareCode>
        </s:Destination>
    </s:ApplicationArea>
    <s:DataArea xsi:type="gwm:DataAreaExtended">
        <s:Process/>
        <s:RepairOrder>
            <s:Header xsi:type="gwm:RepairOrderHeaderExtended">
                <s:DocumentId/>
            </s:Header>
            <s:Job xsi:type="gwm:JobExtended">
                <s:JobNumber/>
                <s:OperationId>Test</s:OperationId>
                <s:OperationName/>
                <s:CodesAndComments/>
                <s:Diagnostics/>
                <s:WarrantyClaim xsi:type="gwm:WarrantyClaimExtended">
                    <s:OEMClaimNumber>00112233445566778899</s:OEMClaimNumber>
                    <gwm:Attachment>
                        <gwm:File><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:test.gif"/></gwm:File>
                        <gwm:Filename>test.gif</gwm:Filename>
                    </gwm:Attachment>
                </s:WarrantyClaim>
                <s:LaborActualHours>0.0</s:LaborActualHours>
                <s:Technician/>
            </s:Job>
        </s:RepairOrder>
    </s:DataArea>
</s:ProcessRepairOrder>
</content></payload></ProcessMessage></soap:Body></soap:Envelope>

これは、生成して送信できる XML 部分ですが、次のような MIME 部分が必要なため、正しくありません。

XML の前:

--MIMEBoundary
Content-Type: application/xop+xml; charset=utf-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <rootpart>

XMLの後

--MIMEBoundary
Content-Type: image/gif; name=test.gif
Content-Transfer-Encoding: binary
Content-ID: <test.gif>
GIF89a@�

--MIMEBoundary--

インターネットで答えを探しましたが、空白になりました。この目的での WSE の使用に関するドキュメントはあまりないようです。WSE はサーバー側の要件であることを強調しなければなりません。この問題に対処するためにテクノロジを変更する方法はありません。

これらの MIME セクションを追加する方法はありますか?

編集: SoapUI を介して添付ファイル付きで送信された動作中の XML ドキュメントを取得できることを追加する必要がありますが、コード内で方法を見つけることができないようです。

この問題を解決するための報奨金を追加しました。他のアイデアがある場合は、お知らせください。

もう一度編集: ここで回答を確認できてから 1 週間が経ちましたが、どこを見ればよいかについて良い考えを示している人もいますが、まだ空白を描いています。ひどいドキュメンテーションXopDocumentとそのメソッドは大きな問題です。誰かが使用例を持っている場合は、SaveToXopPackage提供してください。

4

6 に答える 6

9

私は同じ問題に直面していましたが、最終的な解決策は HttpWebRequest によるものでした。サンプルコード:

    public string ProcessAttachment(string fileInput)
    {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Settings.Default.GWM_WS_WebReference_GWM);
        req.Headers.Add("SOAPAction", "\"http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage/v1_01/ProcessAttachment\"");
        req.Headers.Add("Accept-Encoding", "gzip,deflate");
        req.ContentType = "multipart/related; type=\"application/xop+xml\"; start=\"<rootpart@soapui.org>\"; start-info=\"text/xml\"; boundary=\"----=_Part_14_1350106.1324254402199\"";
        req.Method = "POST";
        req.UserAgent = "Jakarta Commons-HttpClient/3.1";
        req.Headers.Add("MIME-Version", "1.0");
        System.Net.ServicePointManager.Expect100Continue = false;
        Stream memStream = new System.IO.MemoryStream();
        FileStream fileStream = new FileStream(fileInput, FileMode.Open, FileAccess.Read);
        byte[] buffer = new byte[1024];
        int bytesRead = 0;
        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
        {
            memStream.Write(buffer, 0, bytesRead);
        }
        fileStream.Close();
        Stream stm = req.GetRequestStream();
        memStream.Position = 0;
        byte[] tempBuffer = new byte[memStream.Length];
        memStream.Read(tempBuffer, 0, tempBuffer.Length);
        memStream.Close();
        stm.Write(tempBuffer, 0, tempBuffer.Length);
        stm.Close();
        HttpWebResponse resp = null;
        resp = (HttpWebResponse)req.GetResponse();
        stm = resp.GetResponseStream();
        StreamReader r = new StreamReader(stm);
        return r.ReadToEnd();            
    }

パラメータ fileInput は、MIME Boundary で区切られた最後に添付されるファイルの生のバイナリ データも含む SOAP リクエストを含むファイルの絶対パスです。

于 2011-12-20T21:18:36.600 に答える
5

いくつかのオプションがあると思います:

1) MTOMを使用します。これにより、送信メッセージが MIME ブロックで自動的にラップされるように見えます。

2) Microsoft は実際に、SoapEnvelope の継承元である XopDocument クラスを介して MIME を使用して XOP を生成および読み取るためのサポートを提供しています。

保存メソッドはSaveToXopPackageで、読み取りメソッドはLoadFromXopPackageです。

ただし、このアプローチでは、HttpWebRequest を介して自分でメッセージの送信を実行する必要があると思います。このブログには、これを実装する方法の例があります。欠点は、これが正しく機能するために多くの余分なコードと構成が必要になることです。

理想的な解決策は、エンベロープ送信を実行するコードを傍受することですが、パイプライン内でこれの正しい場所を見つけることができませんでした。

于 2011-12-31T04:38:40.760 に答える
2

私はあなたたちとまったく同じプロジェクトに取り組んでいると90%確信しています。その石鹸のリクエストは少し馴染みがあります:-)

ほとんどの場合、WCFに切り替えて、リクエストオブジェクトを手動でコーディングします(soap形式に一致するクラスを作成し、xmlelement属性を使用して、soapリクエストのように装飾します。ファイル自体は、AttachmentクラスでByte()として宣言され、xmlelementで装飾されています。

WCFコントラクトとデータモデルの一部は次のようになります。実際のデータモデルには多数の追加クラス(アプリケーション領域、データ領域、ジョブなど)がありますが、これにより、モデルがどのように構造化されているかを十分に理解できます。重要な部分はByte()としてのファイルです。ここにそれはVb.netにあります...

Public Class WarrantyClaim
    <XmlElement(Order:=0)> Public OEMClaimNumber As String = ""
    <XmlElement(Order:=1, namespace:="http://www.gm.com/2006/GWM")> Public Attachment As New Attachment
End Class

Public Class Attachment
    <XmlElement(Order:=0)> Public File As Byte()
    <XmlElement(Order:=1)> Public Filename As String
End Class

<ServiceContract(XmlSerializerFormat()> _
Public Interface IService
    <OperationContract(action:="http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage/v1_01/ProcessAttachment")> _
    Sub ProcessMessage(ByVal payload As WarrantyClaim)
End Interface

次に、WCFクライアントがあります。これは、すべてのWCFクライアントとほとんど同じです。

Public Class GmgwClient
    Inherits System.ServiceModel.ClientBase(Of IService)
    Implements IService

    Public Sub New()
        MyBase.New()
    End Sub
    Public Sub New(ByVal configName As String)
        MyBase.New(configName)
    End Sub
    Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
        MyBase.New(binding, remoteAddress)
    End Sub

    Public Sub ProcessMessage(ByVal payload As Payload) Implements IService.ProcessMessage
        MyBase.Channel.ProcessMessage(payload)
    End Sub
End Class

最後に、app.configがあります。これが魔法です。WCFにMtomを使用してメッセージを送信するように指示しているからです。これにより、Byte()が取得され、別のMIMEセクションに削除され、XOP:Includeに置き換えられます。今のところ、ローカルホストを介して送信しているだけなので、tcpTraceを使用してリクエストを確認できます。そのアプリをグーグルで検索することはできますが、基本的にリクエストをキャプチャするので、どのように表示されるかを確認できます。ポート84でリッスンするようにtcpTraceを設定します。

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="WsHttpMtomBinding" messageEncoding="Mtom">
        <security mode="None">
          <transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
        </security>
        <reliableSession enabled="false" />
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address="http://localhost:84/ProcessMessage" binding="wsHttpBinding" bindingConfiguration="WsHttpMtomBinding" contract="MyAppNameSpace.IService" name="preprod"/>
  </client>
</system.serviceModel>

最後に、リクエストを行うためのWCFクライアントへの実際の呼び出しを次に示します。

Dim x As New WarrantyClaim
x.OEmClaimNumber = "12345"
x.Attachment = New Attachment
x.Attachment.Filename = "sample.gif"
x.Attachment.File = IO.File.ReadAllBytes("C:\sample.gif")

Dim y As New GmgwClient("preprod")
y.ProcessMessage(x)

これがtcpTraceで得たトレースです。基本的な構造が正しく、XMLからバイナリデータを引き出して別のMIMEセクションに配置することができます。

POST /ProcessMessage HTTP/1.1
MIME-Version: 1.0
Content-Type: multipart/related; type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:501aa27d-9dd1-4f8a-b56d-3fbf327e7be6+id=1";start-info="application/soap+xml"
VsDebuggerCausalityData: uIDPoysDMCv023ZIjK0Cpp504ooAAAAA//jfaCaohkab2Zx/EU7gpLZDcUldWtlGr1j4ZnrfKl4ACQAA
Host: localhost:84
Content-Length: 55125
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive


--uuid:501aa27d-9dd1-4f8a-b56d-3fbf327e7be6+id=1
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage/v1_01/ProcessAttachment</a:Action>
    <a:MessageID>urn:uuid:a85374e6-c8ca-4328-ad32-6e8b88a5ca59</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand="1">http://localhost:84/ProcessMessage</a:To>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ProcessMessage xmlns="http://www.starstandards.org/webservices/2005/10/transport">
      <payload xsi:type="gwm:WarrantyClaimExtended">
        <OEMClaimNumber>12345</OEMClaimNumber>
        <Attachment xmlns="http://www.gm.com/2006/GWM">
          <File>
            <xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634618782531246992" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
          </File>
          <Filename>sample.gif</Filename>
        </Attachment>
      </payload>
    </ProcessMessage>
  </s:Body>
</s:Envelope>
--uuid:501aa27d-9dd1-4f8a-b56d-3fbf327e7be6+id=1
Content-ID: <http://tempuri.org/1/634618782531246992>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream

GIF89a<BinaryStuff>

前に述べたように、まだいくつかの問題があります。石鹸ヘッダーから欠落しているタグがいくつかあります...しかし、私たちはそれらを理解することができると思います。本当の問題は、Content-IDがパートナーが受け入れることができる形式ではないことです-彼らは<1.a33c2d7e84634122705ebc71e53d95d4c2683d726ba54e14@apache.org>のようなものを期待しており、.netはそれらをhttp://tempuri.org/1/634618782531246992としてフォーマットしています。これにより、SOAPメッセージ内のエスケープされたcontent-idの読み取り方法がわからないため、Webサービスハンドラーがクラッシュします。

于 2012-01-07T00:23:54.987 に答える
1

SoapUIを介して機能するようになったと言うように、送信されたXMLをSoapUIに要求するだけで、どのように表示されるかがわかり、それを模倣するようにコードを変更できます。

更新:コメントの後、他の回答をより詳細に読んだ後:解決策は、ktsiolisの回答のようにHttpWebRequestを使用して、バイトを直接送信するだけのように見えます。詳細に:

  • SOAP XML(あなたが与えた例)を作成し、これをUTF8のバイトにエンコードします(1)
  • 最初のmimeboundary(「BeforeXML」の一部)を使用して文字列を作成し、UTF8でバイトにエンコードします(2)
  • 2番目のmimeboundary(「XMLの後」の部分)のバイトを作成します。したがって、「-MIMEBOUNDARY」などを含む文字列を作成し、UTF8バイトにエンコードして、test.gifファイルのすべてのバイトを追加します(3)
  • すべてのバイトを(2)、(1)、(3)の順序で追加し、それをネットワーク経由で送信します。

これでうまくいかないのですか?

于 2012-01-04T07:57:30.093 に答える
0

私はまったく同じプロジェクトに携わっており、このスレッドで議論されているのと同じ問題を抱えています! 私は vb 2005 と WSE 3.0 の拡張機能を使用しています。ファイル プロパティに直接ファイルの内容を書き込むと、添付ファイルはパートナーによって受け入れられます。私の場合、これは PRA 以外のほぼすべてのトランザクションで機能します。ここでは、応答は肯定的で、AttachmentID が配信されますが、添付ファイルはトランザクションに表示されません。

添付ファイル セクションの例を次に示します。

                <gwm:Attachment>
                  <gwm:File>/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ...</gwm:File>
                  <gwm:Filename>intro2.jpg</gwm:Filename>
                </gwm:Attachment>

Service の RequireMtom を True に設定すると、次のエラーが発生します。

Das Präfix '' kann nicht von '' in 'http://www.starstandards.org/webservices/2005/10/transport' innerhalb desselben Startelementtags neu definiert werden.

一方では機能しますが、他方では、XOP 要素と共に送信されるかどうかはわかりません。

于 2012-01-17T12:46:35.423 に答える
0

わかりましたので、<gwm:File>要素内のファイルからデータを受け入れるようにしました。これは XOP を使用しないため、リクエストは次のようになります。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">  <soap:Header>  <payloadManifest xmlns="http://<examplePayload>">  <manifest contentID="Content0" namespaceURI="http://<exampleManifest>" element="ProcessRepairOrder" version="2.01" />  </payloadManifest>  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsu:Created>2011-12-19T15:25:13Z</wsu:Created>  <wsu:Expires>2011-12-19T15:30:00Z</wsu:Expires>  </wsu:Timestamp>  <wsse:UsernameToken><wsse:Username>username</wsse:Username><wsse:Password>password</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ProcessMessage xmlns="<examplePayload"><payload><content id="Content0">    <s:ProcessRepairOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.xsd" xmlns:s="http://<exampleManifest>" xmlns:gwm="http://example"> 
    <s:ApplicationArea> 
        <s:Sender> 
            <s:Component>Test</s:Component> 
            <s:Task>ProcessAttachment</s:Task> 
            <s:CreatorNameCode>Test</s:CreatorNameCode> 
            <s:SenderNameCode>XX</s:SenderNameCode> 
            <s:DealerNumber>111111</s:DealerNumber> 
            <s:DealerCountry>GB</s:DealerCountry> 
        </s:Sender> 
        <s:CreationDateTime>2010-03-26T13:37:05Z</s:CreationDateTime> 
        <s:Destination> 
            <s:DestinationNameCode>GM</s:DestinationNameCode> 
            <s:DestinationURI/> 
            <s:DestinationSoftwareCode>GWM</s:DestinationSoftwareCode> 
        </s:Destination> 
    </s:ApplicationArea> 
    <s:DataArea xsi:type="gwm:DataAreaExtended"> 
        <s:Process/> 
        <s:RepairOrder> 
            <s:Header xsi:type="gwm:RepairOrderHeaderExtended"> 
                <s:DocumentId/> 
            </s:Header> 
            <s:Job xsi:type="gwm:JobExtended"> 
                <s:JobNumber/> 
                <s:OperationId>Test</s:OperationId> 
                <s:OperationName/> 
                <s:CodesAndComments/> 
                <s:Diagnostics/> 
                <s:WarrantyClaim xsi:type="gwm:WarrantyClaimExtended"> 
                    <s:OEMClaimNumber>00112233445566778899</s:OEMClaimNumber> 
                    <gwm:Attachment> 
                        <gwm:File>GIF89a@�&lt;/gwm:File> 
                        <gwm:Filename>test.gif</gwm:Filename> 
                    </gwm:Attachment> 
                </s:WarrantyClaim> 
                <s:LaborActualHours>0.0</s:LaborActualHours> 
                <s:Technician/> 
            </s:Job> 
        </s:RepairOrder> 
    </s:DataArea>  </s:ProcessRepairOrder>  </content></payload></ProcessMessage></soap:Body></soap:Envelope>

SoapUI に渡されると、これは完全に機能しますが、コードでは応答が返されますが、次Response is not well-formed XML.の内部例外でエラーがスローされます。WSE1608: No XOP parts were located in the stream for the specified content-id: <rootpart*36875c60-630c-4e23-9e74-f9a9c7547fc7@example.jaxws.sun.com>

技術的には別の問題であるため、これに関する新しい質問を開きます。

もう 1 つの質問は、WSE を使用した Soap response, not wellformed XML, no XOP parts located にあります。

于 2012-01-10T13:01:17.603 に答える