无法使用BinaryReader从WebRequest正确读取数据

3

嗨!

我正在开发一个C# SOAP服务,与我们政府服务中的一个进行通信。他们也使用SOAP进行通信,但现在引入了两个处理请求非常不同的新端点。我注意到的第一件事是,当我从客户端应用程序的PHP代码中调用$SoapClient->Request(...)时,它失败并显示错误Looks like we got no XML document。获取实际响应的唯一方法是使用try-catch SoapFault,然后调用$response = $SoapClient->__getLastResponse()来读取它。它确实不是XML格式,而是一种二进制格式,类似于电子邮件附件的源代码。

在我找到问题后,下载PDF文件时,它仍然是格式错误的。起初我认为是PHP弄错了什么,但后来我查看了WebService的日志,发现它已经是格式错误的。我尝试了许多不同的编码方式,使用StreamReader,但没有成功。然后我改用BinaryReader来处理这两个端点。现在它离我想要的响应更近了,但仍然包含看似随机的垃圾字符,就像这张截图所示:

左边是我要找的内容,右边是我得到的内容。 enter image description here

我的代码:

string soapResult;
try
{
    using (HttpWebResponse webResponse = (HttpWebResponse)httpRequest.EndGetResponse(asyncResult))
    {
        if (request == "edoc/getDocument" || request == "edoc/downloadFile")
        {
            using (BinaryReader rd = new BinaryReader(webResponse.GetResponseStream()))
            {
                soapResult = Encoding.Default.GetString(rd.ReadBytes(10000000));
            }
        }
        else
        {
            using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
            {
                soapResult = rd.ReadToEnd();
            }
        }
    }
}
...

我该如何克服这个问题?我已经苦苦挣扎了好几天,但是无法找出问题所在...

编辑: 实际响应看起来就像这样:

--MIME_Boundary
Content-ID: <c907fb5b-7aa7-4556-88fd-5074f43aafbb>
Content-Type: application/xop+xml; type="text/xml"; charset=UTF-8
Content-Transfer-Encoding: 8bit

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><env:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp wsu:Id="Timestamp-JAuOpC673QOitIDD7tlAuA22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsu:Created>2021-08-19T12:00:14Z</wsu:Created><wsu:Expires>2021-08-19T12:05:14Z</wsu:Expires></wsu:Timestamp></wsse:Security></env:Header><env:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><ns10:getDocument xmlns="http://eeszt.gov.hu/ns/common/ws/messageHeaderTypes/v3" xmlns:ns2="http://eeszt.gov.hu/ns/common/cdm/v3" xmlns:ns3="http://eeszt.gov.hu/ns/common/ws/messageTypes/v3" xmlns:ns4="http://eeszt.gov.hu/ns/eDoc/ws/eDocService/v1" xmlns:ns5="http://eeszt.gov.hu/ns/eDoc/ws/eDocService/messages/v1" xmlns:ns6="http://eeszt.gov.hu/ns/eDoc/ws/eDocService/Request/v1" xmlns:ns7="http://eeszt.gov.hu/ns/documentrenderer/ws/common/messages/v1" xmlns:ns8="http://eeszt.gov.hu/ns/common/ws/queryTypes/v3" xmlns:ns9="http://eeszt.gov.hu/ns/common/ws/errorTypes/v3" xmlns:ns10="http://eeszt.gov.hu/ns/eDoc/ws/eDocService/Response/v1" xmlns:ns11="http://eeszt.gov.hu/ns/common/ws/versionInfoTypes/v3" xmlns:ns12="http://eeszt.gov.hu/ns/documentrenderer/ws/DocumentRendererService"><ns10:getDocumentResponse><ns3:businessMessageHeader><initiator><userId>O60547</userId><userName>Dr. Psyklon</userName><clientUserId>O60547</clientUserId><applicationId>DokiRex.NET:v1.57</applicationId><applicationName>DokiRex.NET</applicationName><applicationFunction>edoc_get_document</applicationFunction><organizationId>E200158</organizationId><organizationName>Asd</organizationName><organizationUnitId>002001581</organizationUnitId><organizationUnitName>Eeszt Dev</organizationUnitName></initiator><representedUser><userId>O60547</userId><userName>Orvos 1 DEV69</userName><clientUserId>O60547</clientUserId></representedUser><initiatorCitizen><ns2:citizenIDs><ns2:citizenID><ns2:type>1</ns2:type><ns2:id>900200018</ns2:id></ns2:citizenID></ns2:citizenIDs></initiatorCitizen><representedCitizen><ns2:citizenIDs><ns2:citizenID><ns2:type>1</ns2:type><ns2:id>900200018</ns2:id></ns2:citizenID></ns2:citizenIDs></representedCitizen><logging><submittedAt>2021-08-19T14:00:14.156+02:00</submittedAt><EESZTLogging><receivedAt>2021-08-19T14:00:14.147+02:00</receivedAt><processedAt>2021-08-19T14:00:14.234+02:00</processedAt><EESZTtransactionId>0aa47ec3-ad01-4a37-b75b-121c2f645a1c</EESZTtransactionId></EESZTLogging></logging></ns3:businessMessageHeader><ns3:status>OK</ns3:status><ns5:businessMessageContent><ns5:eDoc><ns4:id>11953</ns4:id><ns4:docType>ack</ns4:docType><ns4:docTypeName>Kézbesítés igazolás</ns4:docTypeName><ns4:docNev>Kézbesítés igazolás</ns4:docNev><ns4:docStatusz>REND</ns4:docStatusz><ns4:docStatuszName>Renderelt</ns4:docStatuszName><ns4:docFeltoltoIntezmeny>E200006</ns4:docFeltoltoIntezmeny><ns4:docFeltoltoSzervezetiEgyseg>002000061</ns4:docFeltoltoSzervezetiEgyseg><ns4:docFeltoltoUser>O60017</ns4:docFeltoltoUser><ns4:docFelelosUser>O60017</ns4:docFelelosUser><ns4:allampolgar><ns2:type>1</ns2:type><ns2:id>900200018</ns2:id></ns4:allampolgar><ns4:feltoltesIdeje>2021-06-23T19:12:52.308+02:00</ns4:feltoltesIdeje><ns4:tarolasiIdo>2021-10-01T19:12:52.000+02:00</ns4:tarolasiIdo><ns4:forrasDocId>11952</ns4:forrasDocId><ns4:parentDocId>11952</ns4:parentDocId><ns4:attachments><ns4:attachmentResponse><ns4:id>29625</ns4:id><ns4:name>kezbesitesi_jelentes.pdf</ns4:name><ns4:mimeType>application/pdf</ns4:mimeType><ns4:file><inc:Include href="cid:5bed3685-037d-438e-a306-b96d1c1ac435-1158030@eeszt.gov.hu" xmlns:inc="http://www.w3.org/2004/08/xop/include"/></ns4:file></ns4:attachmentResponse></ns4:attachments><ns4:recipients/><ns4:linkedDocuments/></ns5:eDoc></ns5:businessMessageContent></ns10:getDocumentResponse></ns10:getDocument></env:Body></soapenv:Envelope>
--MIME_Boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <5bed3685-037d-438e-a306-b96d1c1ac435-1158030@eeszt.gov.hu>

%PDF-1.4
%ª«¬­
1 0 obj
<<
/Creator (Apache FOP Version 2.3)
/Producer (Apache FOP Version 2.3)
/CreationDate (D:20210623191252+02'00')
>>
endobj
2 0 obj
<<
  /N 3
  /Length 3 0 R
  /Filter /FlateDecode
>>
stream
xœí™gPTY€ï{
ÝM“¡ÉI¢„$ç$A²¨@w“i¡ÉAQdpFIŠ ¢€ŽAFQÅ€(( ¢N#ƒ€2Ž"**KãÙ­
...

3
Encoding.Default非常可疑。你知道下游系统使用的是哪种编码吗?我的意思是SOAP响应是否定义了编码方式? - Peter Csala
2
我几乎试过所有的编码(Unicode,UTF8,UTF7,ASCII),但它们看起来更糟。 - Balázs Varga
2
不是因为它不是XML。它包含多个文件,用--MIME_Boundary分隔。我感兴趣的PDF文件的以下标头是:--MIME_Boundary Content-Type: application/octet-stream Content-Transfer-Encoding: binary - Balázs Varga
4
也许你需要使用MultipartMemoryStreamProvider。参见此主题讨论 - John
2
你可以把原始响应写入文件吗?然后,你可以使用十六进制编辑器比较这些文件并查看区别。 - PEK
显示剩余3条评论
2个回答

2
您正在获取一个多部分响应,因此需要解析它以获取各个部分。我将提供一个示例解决方案,使用包含扩展方法以更轻松处理此类内容的Microsoft.AspNet.WebApi.Client NuGet包。由于您使用旧的现在已过时的HttpWebRequest,因此需要先将您获得的流转换为HttpContent对象,然后可以使用扩展方法ReadAsMultipartAsync从中获取MultipartMemoryStreamProvider对象。该对象具有一系列内容,因此您可以读取每个部分。

以下是更改后的代码,用于将PDF部分读取为字符串。

string soapResult;
using (HttpWebResponse webResponse = (HttpWebResponse)httpRequest.EndGetResponse(asyncResult))
{
   StreamContent streamContent = new StreamContent(webResponse.GetResponseStream());
   streamContent.Headers.Add("Content-Type", webResponse.ContentType);

   MultipartMemoryStreamProvider? multipart = await streamContent.ReadAsMultipartAsync();

   soapResult = await multipart.Contents[1].ReadAsStringAsync(); // read second content that has index 1
}

我建议您更改代码,使用更新的HttpClient执行Web请求,这样代码会变得更加简单。

string soapResult;
using (HttpClient httpClient = new HttpClient()) // For best performance you should create one HttpClinet for all the application and reuse it for all calls not create new for each call.
{
   using (HttpResponseMessage? httpResponseMessage = await httpClient.GetAsync("https://localhost:5001/api/multipart"))
   {
      MultipartMemoryStreamProvider? multipart = await httpResponseMessage.Content.ReadAsMultipartAsync();

      soapResult = await multipart.Contents[1].ReadAsStringAsync();
   }
}


  

谢谢,你的解决方案指引了我正确的方向。我只是将ReadAsStringAsync()更改为ReadAsByteArrayAsync()并将其包装在Convert.ToBase64String中,现在我能够在另一端获得有效的XML响应,并使用base64_decode显示pdf。 - Balázs Varga

2
不要通过任何编码将二进制内容读取为字符串。原始的 PDF 内容不符合任何编码,因此您的字符串结果肯定会损坏。
如果您需要在 SOAP 消息中返回二进制内容作为文本,则应改用 base64 编码:
// binary content: as base64
if (webResponse.ContentType == "application/octet-stream")
    soapResult = Convert.ToBase64String(br.ReadBytes((int)webResponse.ContentLength));

您的SOAP消息的接收者可以通过Convert.FromBase64String将原始二进制内容恢复。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接