1
votes

I am getting the error:

An error was found while parsing the multipart request. Boundary terminator '--BOUNDARY--' was not found in the request.

I have tried debugging with Firefox and chrome with same results. Any help would be greatly appreciated.

Here is the code I am using:

Public Sub configureMultiPartFormDataRequest(ByVal request As HttpWebRequest, _
                                                 ByVal xmlBody As String, _
                                                 ByVal docName As String)

        'Overwrite the default content-type header and set a boundary marker
        request.ContentType = "multipart/form-data; boundary=BOUNDARY"

        'Start building the multipart request body
        Dim requestBodyStart As String = "\r\n\r\n--BOUNDARY\r\n" + _
            "Content-Type: application/xml\r\n" + _
            "Content-Disposition: form-data\r\n" + _
            "\r\n" + _
            xmlBody + "\r\n\r\n--BOUNDARY\r\n" + _
            "Content-Type: application/pdf\r\n" + _
            "Content-Disposition: file; filename=\" + docName + " \  documentId=1\r\n" + _
            "\r\n"
        Dim requestBodyEnd As String = "\r\n--BOUNDARY--\r\n\r\n"

        'Read the contents of provided document into the request stream
        Dim fileStream As FileStream = File.OpenRead(docName)

        'Write the body of the request
        Dim bodyStart() As Byte = System.Text.Encoding.UTF8.GetBytes(requestBodyStart.ToString())
        Dim bodyEnd() As Byte = System.Text.Encoding.UTF8.GetBytes(requestBodyEnd.ToString())
        Dim dataStream As Stream = request.GetRequestStream()
        dataStream.Write(bodyStart, 0, requestBodyStart.ToString().Length)

        'Read the file contents and write them to the request stream. (4096 Byte Blocks)
        Dim buf(4096) As Byte
        'Dim len As Integer
        'While ((len = fileStream.Read(buf, 0, 4096)) > 0)
        '    dataStream.Write(buf, 0, len)
        'End While
        Dim bytesRead As Integer
        Do
            bytesRead = fileStream.Read(buf, 0, buf.Length)
            If bytesRead > 0 Then
                dataStream.Write(buf, 0, bytesRead)
            End If
        Loop While bytesRead > 0


        dataStream.Write(bodyEnd, 0, requestBodyEnd.ToString().Length)


        dataStream.Close()

    End Sub

Added 05/09/2014 Here is the actual request text from Fiddler2. It appears that the bodyEnd is being set to "PDF-1.7". I have searched the code for this string without success. Thanks for your help: \r\n\r\n--BOUNDARY\r\nContent-Type: application/xml\r\nContent-Disposition: form-data\r\n\r\nsentDocuSign API - Embedded Signing example1\10.1.11.100\SecureDocs\EnrollmentForms\[email protected] Adams10010011\r\n\r\n--BOUNDARY\r\nContent-Type: application/pdf\r\nContent-Disposition: file; filename=\XXX\; documentId=1\r\n\r\n%PDF-1.7

David Thanks for your fix for the BOUNDARY error. I implemented your xml example and now get an error: "The document element did not contain the encoded document, or there is a problem with the encoding." Here is the request: --BOUNDARY Content-Type: application/xml Content-Disposition: form-data

sentDocuSign API - Embedded Signing example1C:\Hold\[email protected] Adams10010011

--BOUNDARY Content-Type: application/pdf Content-Disposition: file; filename=\C:\Hold\myXML.xml \ documentId=1

    <nameValue>
        <name>canManageAccount</name>
        <value>false</value>
    </nameValue>

--BOUNDARY--

Thanks for your help!!!

2
shouldn't your Content-Disposition: form-data be Content-Disposition: application/xml? can you post the data that dataStream.Write is compiling? - Andrew
I think the content-disposition is set correctly, however as Andrew has asked it would be most helpful if you post the actual request text that this code creates and sends out... - Ergin
Ergin's right. I need to drink Coffee before answering Stack Overflow :) - Andrew
Ah, I see this issues. 1. Add back your JSON/XML body and your PDF. Don't try and escape the file name, you don't need to the path in the multipart file aka filename=\C:\Hold\myXML.xml \ should be yourfilename.pdf my files where just to make the sample simple to understand and the code change for the New Line and Carriage returns can't be escaped that way in VB.NET - David W Grigsby
Also, please start new questions about new problems, instead of follow ons on this question so that it is clearer for others in the community about what the original question was and what the answer was, so thanks for your help in following this best practice. Happy Coding! - David W Grigsby

2 Answers

1
votes

Your code snippet above is missing the calling method so I made my own as shown below to demonstrate how to leverage WebHookapp endpoint to capture what is being sent. So I think you will see that the body is not formatted correctly due to the fact you tried to "escape" the line breaks and carriage return values vs using the chr with the correct value.

Code I added to call you above method

Imports System.IO
Imports System.Net

Public Class Form1

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

    Dim myHTTPRequest As System.Net.HttpWebRequest = WebRequest.Create("http://webhookapp.com/1037371688646089664")
    Dim myXML As String = "{SomeXMLorJason: sampleNotFormatedcorrectly}"
    Dim myDocName As String = "c:\myXML.xml"
    myHTTPRequest.Method = "POST"

    configureMultiPartFormDataRequest(myHTTPRequest, myXML, myDocName)


    myHTTPRequest.GetResponse()

End Sub

'Your Code goes here ---> from above:

End Class

What is in the file c:\myXML.xml

        <nameValue>
            <name>canManageAccount</name>
            <value>false</value>
        </nameValue>

What was sent:

POST /1037371688646089664
content-type    multipart/form-data; boundary=BOUNDARY
host    webhookapp.com
content-length  439
expect  100-continue
connection  Keep-Alive
\r\n\r\n--BOUNDARY\r\nContent-Type: application/xml\r\nContent-Disposition: form-data\r\n\r\n{SomeXMLorJason: sampleNotFormatedcorrectly}\r\n\r\n--BOUNDARY\r\nContent-Type: application/pdf\r\nContent-Disposition: file; filename=\c:\myXML.xml \  documentId=1\r\n\r\n                <nameValue>
                    <name>canManageAccount</name>
                    <value>false</value>
                </nameValue>\r\n--BOUNDARY--\r\n\r\n

What to do to fix your code:

 'Start building the multipart request body
        ' http://www.asciitable.com/

        Dim asciLN As String = Chr(10)
        Dim asciCR As String = Chr(13)

        Dim requestBodyStart As String = asciCR + asciLN + asciCR + asciLN + "--BOUNDARY" + asciCR + asciLN + _
            "Content-Type: application/xml" + asciCR + asciLN + _
            "Content-Disposition: form-data" + asciCR + asciLN + _
            asciCR + asciLN + _
            xmlBody + asciCR + asciLN + asciCR + asciLN + "--BOUNDARY" + asciCR + asciLN + _
            "Content-Type: application/pdf" + asciCR + asciLN + _
            "Content-Disposition: file; filename=\" + docName + " \  documentId=1" + asciCR + asciLN + _
            asciCR + asciLN
        Dim requestBodyEnd As String = asciCR + asciLN + "--BOUNDARY--" + asciCR + asciLN + asciCR + asciLN

Which will yield:

POST /1037371688646089664
content-type    multipart/form-data; boundary=BOUNDARY
host    webhookapp.com
content-length  409
expect  100-continue
connection  Keep-Alive

--BOUNDARY
Content-Type: application/xml
Content-Disposition: form-data

{SomeXMLorJason: sampleNotFormatedcorrectly}

--BOUNDARY
Content-Type: application/pdf
Content-Disposition: file; filename=\c:\myXML.xml \  documentId=1

                <nameValue>
                    <name>canManageAccount</name>
                    <value>false</value>
                </nameValue>
--BOUNDARY--

And a general envelope in JSON as Multipart should look like below:

POST http://{server}/restapi/{apiVersion}/accounts/{accountId}/envelopes

X-DocuSign-Authentication: <DocuSignCredentials><Username>{name}</Username><Password>{password}</Password><IntegratorKey>{integrator_key}</IntegratorKey></DocuSignCredentials>
Accept: application/json
Content-Type: multipart/form-data; boundary=AAA

--AAA
Content-Type: application/json
Content-Disposition: form-data
{
  "status":"sent",
  "emailBlurb":"Test Email Body",
  "emailSubject": "Test Email Subject - EnvelopeDefFull",
  "documents": [{
      "name": "test1.pdf",
      "documentId":"1"
      "order":"1"
  }],
  "recipients": {
    "signers" : [{
      "email": "[email protected]",
      "name": "Sally Doe",
      "recipientId":"1",
    }]
  }
}
--AAA
Content-Type: application/pdf
Content-Disposition: file; filename="test1.pdf";documentid=1

<document bytes removed>

--AAA--
-1
votes

Generally speaking your request should look like the following. The only difference is that this example used JSON format instead of XML. Only change you need to make is changing application/json to application/xml for the Content-Type, then change the JSON data to XML format instead.

POST http://{server}/restapi/{apiVersion}/accounts/{accountId}/envelopes

X-DocuSign-Authentication: <DocuSignCredentials><Username>{name}</Username><Password>{password}</Password><IntegratorKey>{integrator_key}</IntegratorKey></DocuSignCredentials>
Accept: application/json
Content-Type: multipart/form-data; boundary=AAA

--AAA
Content-Type: application/json
Content-Disposition: form-data
{
  "status":"sent",
  "emailBlurb":"Test Email Body",
  "emailSubject": "Test Email Subject - EnvelopeDefFull",
  "documents": [{
      "name": "test1.pdf",
      "documentId":"1"
      "order":"1"
  }],
  "recipients": {
    "signers" : [{
      "email": "[email protected]",
      "name": "Sally Doe",
      "recipientId":"1",
    }]
  }
}
--AAA
Content-Type: application/pdf
Content-Disposition: file; filename="test1.pdf";documentid=1

<document bytes removed>

--AAA--

Without seeing the actual request that your code is constructing and sending I can only assume something is wrong with the formatting. Ensure that you have extra newlines (CRLF) where needed and that the document bytes are correctly being written to the request. If you're still stuck you might want to run through a tool such as Fiddler to check the request data...