向SOAP请求添加附件



我不知道如何在SOAP请求中添加附件。我们必须使用用java构建的第三方web服务,这是我遇到过的最复杂的事情。我们使用过的任何其他需要附件的web服务都有一个方法或属性来添加附件。简单。但是,这个没有提供这样的方法。

我们已经得到了SOAP消息的一个版本,它与我们想要的XML完全一致,但是我们不能添加的是文件的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文档,但似乎无法在我们的代码中找到方法。

我已经加了赏金来尝试找到这个问题的解决方案。如果有人有任何其他的想法,请告诉我。

再次编辑:我知道自从我能够检查这里的回复已经有一个星期了,但是虽然有些人给了我一个好主意去哪里看,我仍然一片空白。围绕XopDocument及其方法的糟糕文档是一个很大的症结,如果有人有任何使用SaveToXopPackage的例子,请提供,因为这已经开始令人恼火了!

我面临着同样的问题,我发现的最终解决方案是通过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是包含SOAP请求的文件的绝对路径,该文件还包含以MIME边界分隔的要附加的文件的原始二进制数据

我认为您可能有几个选项:

1)使用MTOM。这似乎自动将传出的消息包装在MIME块中。

2)微软实际上通过XopDocument类提供了用mime生成和读取XOP的支持,SoapEnvelope就是从这个类继承的。

保存方法为SaveToXopPackage,读取方法为LoadFromXopPackage。

然而,我认为这种方法可能需要你自己通过HttpWebRequest执行消息的发送。这个博客有一个如何实现它的例子。缺点是需要大量额外的代码和配置才能正常工作。

理想的解决方案是拦截执行信封传输的代码,但我一直无法在管道中找到它的正确位置。

我有90%的信心和你们在做同样的项目。这个soap请求有点太熟悉了:-)

通过切换到WCF并基本上手工编码请求对象(创建与soap格式匹配的类,然后使用xmlelement属性对其进行修饰,使其看起来像soap请求),我们已经获得了大部分方法。文件本身在Attachment类上声明为Byte(),并使用xmlelement进行装饰。

下面是WCF契约和部分数据模型的样子。实际的数据模型有一堆额外的类(Application Area, data Area, Job等),但这足以让您了解它的结构。重要的部分是作为Byte()的File。这是在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替换它。请注意,现在我只是通过localhost发送它,所以我可以使用tcpTrace看到请求。你可以谷歌那个应用,但它基本上会捕获请求,所以我们能看到它的样子。我设置tcpTrace监听端口84。

<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得到的trace。它的基本结构是正确的,并且它设法将二进制数据从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>

就像我之前提到的,我们仍然有一些问题。有一些标签从Soap报头丢失…但我想我们能算出来。真正的问题是Content-ID不是我们的合作伙伴可以接受的格式——他们期望是<1.a33c2d7e84634122705ebc71e53d95d4c2683d726ba54e14@apache.org>之类的格式,而。net将它们格式化为http://tempuri.org/1/634618782531246992。这将导致他们的Web服务处理程序崩溃,因为它不知道如何读取soap消息中的转义内容id。

正如您所说,您通过SoapUI获得了它的工作,我认为您可以向SoapUI询问它发送的生成的XML,以便您知道它应该是什么样子,然后修改您的代码来模仿。

更新:在您的评论和更详细地阅读其他答案之后:解决方案看起来我只是直接发送字节,使用HttpWebRequest,就像ktsiolis的答案一样。详细:

  • 创建您的SOAP XML(您给出的示例),用UTF8(1)将其编码为字节
  • 创建一个带有初始mime边界的字符串("Before XML"中的部分),以UTF8(2)编码为字节
  • 为第二个mime边界("after XML"中的部分)创建字节。因此,创建包含"——MIMEBOUNDARY"等的字符串,编码为UTF8字节,并添加test.gif文件的所有字节 (3)
  • 按顺序(2),(1)和(3)附加所有字节,并将其发送过线。

这难道不应该起作用吗?

好的,所以我让它接受来自<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@�</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>的内部异常

我将就此打开一个新问题,因为它在技术上是一个不同的问题。

另一个问题可以在Soap响应中找到,不是格式良好的XML,没有XOP部分位于,使用WSE

我参与了完全相同的项目,我在这个线程中讨论了相同的问题!我正在使用vb 2005和WSE 3.0增强功能,我让它工作,即使它现在是一个痛苦。当直接在file属性中写入文件内容时,该附件将被合作伙伴接受。在我的例子中,这适用于除PRA之外的几乎所有交易。这里,响应是肯定的,并且将传递AttachmentID,但是附件没有出现在事务中。

下面是附件部分的一个示例:

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

如果我将服务的RequireMtom设置为True,我会得到以下错误:

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

一方面,它可以工作,另一方面,我不确定它是否会与XOP元素一起发送。

相关内容

  • 没有找到相关文章

最新更新