How to extract a file out of an MTOM-Reader (XmlDictionaryReader)?

131 Views Asked by At

I have the following MTOM-Response with an MIME-Attachment:

MIME-Version:1.0
Content-Type:multipart/related;boundary=MIMEBoundary_dd50b80e-d2bc-4843-9b47-b22d83e3c51;type="application/xop+xml";start="<[email protected]>";start-info="text/xml"

--MIMEBoundary_dd50b80e-d2bc-4843-9b47-b22d83e3c51b
Content-Type:application/xop+xml;charset=utf-8;type="text/xml"
Content-ID:<[email protected]>

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp wsu:Id="6cb7c01e-372a-40f8-9ab3-ae5735d68a37" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsu:Created>2023-04-05T12:14:40Z</wsu:Created><wsu:Expires>2023-04-05T12:19:40Z</wsu:Expires></wsu:Timestamp><saml2:Assertion ID="155d9fa0-bd04-404f-bf12-b84d9347c02b" IssueInstant="2023-04-05T12:14:40Z" Version="2.0" xmlns:vwsu="http://xmldefs.volkswagenag.com/Technical/Security/UsernameToken/V1" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer>https://ws-gateway.volkswagenag.com</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" NameQualifier="http://xmldefs.volkswagenag.com/Technical/Security/NameQualifier/V1#Anonymous">UNKNOWN</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"/></saml2:Subject><saml2:Conditions NotBefore="2023-04-05T12:13:40Z" NotOnOrAfter="2023-04-05T12:19:40Z"/><saml2:Advice><saml2:Assertion ID="8ccded29-1327-419a-b51a-b84d93471792" IssueInstant="2023-04-05T12:14:40Z" Version="2.0"><saml2:Issuer>https://ws-gateway.volkswagenag.com</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" NameQualifier="http://xmldefs.volkswagenag.com/Technical/Security/NameQualifier/V1#UMSGlobalUserID">DUONZQM</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"/></saml2:Subject><saml2:Conditions NotBefore="2023-04-05T12:13:40Z" NotOnOrAfter="2023-04-05T12:19:40Z"/><saml2:AuthnStatement AuthnInstant="2023-04-05T12:14:40Z"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute Name="ValidationType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><saml2:AttributeValue>sc:no-credential-validation-type</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion></saml2:Advice></saml2:Assertion></wsse:Security><To wsu:Id="98eebfae-b071-4ad8-ba4f-ae5735d69f52" xmlns="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">ws://volkswagenag.com/PP/QM/GroupProblemManagementService/V3</To><Action wsu:Id="8ecd6f90-d506-4597-90e3-ae5735d68a80" xmlns="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">http://xmldefs.volkswagenag.com/PP/QM/GroupProblemManagementService/V3/KpmService/GetDocumentResponse</Action><MessageID wsu:Id="3b62de53-13fd-46be-a2b2-ae5735d6eefa" xmlns="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">${= "urn:uuid:" + UUID.randomUUID()}</MessageID><wsa:RelatesTo xmlns:wsa="http://www.w3.org/2005/08/addressing">${= "urn:uuid:" + UUID.randomUUID()}</wsa:RelatesTo></soap:Header><soap:Body><ns2:GetDocumentResponse xmlns:ns2="http://xmldefs.volkswagenag.com/PP/QM/GroupProblemManagementService/V3"><GetDocumentResponseInternal><ResponseMessage><MessageId>INFO_001</MessageId><MessageType>MT_INFO</MessageType><MessageText>Method completed successfully</MessageText><SessionKey>de.volkswagen.kpm.backend.command.KPMSessionImpl@806d9365</SessionKey><VersionId>release_17.3.2</VersionId><VersionDate>Fri Mar 17 11:33:58 CET 2023</VersionDate></ResponseMessage><Document><Name>Pound_layer_cake</Name><Suffix>jpg</Suffix><Description>Uploaded 20230216_10-13-37</Description><AccessRight>0</AccessRight><FileType>01</FileType><Data><xop:Include href="cid:[email protected]" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></Data></Document></GetDocumentResponseInternal></ns2:GetDocumentResponse></soap:Body></soap:Envelope>

--MIMEBoundary_dd50b80e-d2bc-4843-9b47-b22d83e3c51b
Content-Type:image/jpeg
Content-Transfer-Encoding:binary
Content-ID:<[email protected]>

[Enter binary Data here]

And I am trying to get the attachment and save it as a file using C# and .NET. After requesting the data from the server and saving the response as a byte array, I used XmlDictionaryReader.CreateMtomReader to read the MTOM formatted response.

byte[] postArray = Encoding.UTF8.GetBytes($"<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:v3='http://xmldefs.volkswagenag.com/PP/QM/GroupProblemManagementService/V3'><soapenv:Header><To xmlns='http://www.w3.org/2005/08/addressing'>ws://volkswagenag.com/PP/QM/GroupProblemManagementService/V3</To><Action xmlns='http://www.w3.org/2005/08/addressing'>http://xmldefs.volkswagenag.com/PP/QM/GroupProblemManagementService/V3/KpmService/GetDocumentRequest</Action><MessageID xmlns='http://www.w3.org/2005/08/addressing'>${{= \"urn:uuid:\" + UUID.randomUUID()}}</MessageID></soapenv:Header><soapenv:Body><v3:GetDocument><UserAuthentification><UserId>{aUsername}</UserId></UserAuthentification><ProblemNumber>{aDefectID}</ProblemNumber><DocumentId>{aAttachmentID}</DocumentId></v3:GetDocument></soapenv:Body></soapenv:Envelope>");
Console.WriteLine($"GetLocalFilename from URL {aURL} of Attachment {aAttachmentID} belonging to Defect {aDefectID}");
byte[] result = client.UploadData(aURL, postArray);
XmlDictionaryReader reader = XmlDictionaryReader.CreateMtomReader(result, 0, result.Length, Encoding.UTF8, XmlDictionaryReaderQuotas.Max);

This worked so far. However I am unsure how to move on from here. The data is still stored within the reader and unfortunately I couldn't find clear instructions on how to extract a file from it. So for my first attempt, I simply tried this:

string elementBytes = reader.ReadElementContentAsString();

But it gave me the following error message:

'Element' is an invalid XmlNodeType. Line 2, position 84.

I assumed that maybe trying to read the <Data> tag would do the job

string elementBytes = reader.ReadElementContentAsString("Data", "");

But I ran into another error message along the way:

'None' is an invalid XmlNodeType. Line 1, position 1.

I have no idea what I am doing wrong or if this is even the right way to access the file data properly. My main goal here is to save the data that the server sent as a properly built file. How can I achieve that?

1

There are 1 best solutions below

0
Vasily Golovin On

the main issue in approch to solve your problem is that Reader doesnt store whole data, but acts like pointer to some node in xml tree which it analyses from source, reading chars until it founds boundaries of currently analysing element: tag or value.

So all you need is iterate through elements that reader is founding and read content when it points on Data element

My straight forward solution is:

while (reader.Read())
{
    if (reader.Name != "Data")
        continue;
            
    var val = reader.ReadElementContentAs(typeof(byte[]), null) as byte[];
               
    break;
}