jlweatherly | Posts: 3

Bad Request 400 eslClient.CreatePackage() after upgrade from 10.3 to 10.13

0 votes
Hello, I recently updated the api version for Silanis.ESL.dll from 10.3 to 10.13, after doing so the code that I'm using to dynamically build the packages for getting signed no longer works. The test code that I use with hard coded values still works, but I keep getting Bad Request 400 errors when I use my dynamic code in a real test from our web application and I can't seem to find any further details as to what is causing the 400 Bad Request. Here is the "test" code that is working just fine:
    Public Function GenerateTestSession(cFilePath As String, cReturnURL As String) As String
        Dim eslClient = New EslClient(API_KEY, SDK_URL)

        Dim signer = createSignerDynamic("[email protected]", "John", "Smith", "My Co.", "JSmith")

        Dim settings As New DocumentPackageSettings
        With settings
            .CeremonyLayoutSettings = New CeremonyLayoutSettings
            .CeremonyLayoutSettings.ProgressBar = False
            .CeremonyLayoutSettings.BreadCrumbs = False
            .CeremonyLayoutSettings.IFrame = True
            .CeremonyLayoutSettings.SessionBar = False
            .CeremonyLayoutSettings.GlobalNavigation = False
            .CeremonyLayoutSettings.ShowTitle = False
            .CeremonyLayoutSettings.Navigator = False

            .EnableDecline = True
            .EnableOptOut = True

            .LinkHref = cReturnURL
            .LinkText = "Click here when done!"
            .ShowDialogOnComplete = True
        End With

        Dim db As DocumentBuilder
        Dim file As New FileInfo(cFilePath)
        db = NewDocumentNamed("My Document").FromFile(file.FullName)
        Dim sb As SignatureBuilder = SignatureBuilder.CaptureFor(signer.Email).OnPage(1).AtPosition(450, 380)

        Dim fb As FieldBuilder = FieldBuilder.CheckBox.OnPage(1).AtPosition(345, 372)
        fb.WithSize(15, 15).WithName("OKResident").WithId("OKResident")
        sb.WithField(fb)

        Dim fb_radio As FieldBuilder = FieldBuilder.RadioButton("group1").OnPage(1).AtPosition(345, 472)
        fb_radio.WithId("radio label")
        fb_radio.WithValue(False) ' default to not selected

        ' not yet fully supported and tested...
        sb.WithField(fb_radio)

        ' do nothing for now so we don't get an error...

        Dim fb_drop As FieldBuilder = FieldBuilder.DropList.OnPage(1).AtPosition(345, 572)
        fb_drop.WithSize(300, 300)
        fb_drop.WithName("dorp label")
        fb_drop.WithId("drop id")
        fb_drop.WithValue("DropList Option 2") 'default to 2nd option

        Dim fvb As FieldValidatorBuilder = FieldValidatorBuilder.Basic _
            .WithOption("DropList Option 1") _
            .WithOption("DropList Option 2") _
            .WithOption("DropList Option 3")
        fb_drop.WithValidation(fvb)

        sb.WithField(fb_drop)

        db.WithSignature(sb)

        Dim documentPackage = PackageBuilder.NewPackageNamed("Sample Document") _
            .WithSigner(signer).WithDocument(db).WithSettings(settings).Build()

        Dim packageId = eslClient.CreatePackage(documentPackage)
        eslClient.SendPackage(packageId)

        Dim SessionToken = eslClient.SessionService.CreateSessionToken(packageId, signer.Id)
        Return SessionToken.Token
    End Function
And here's the dynamically built package code that is generating the 400 error (that WAS working just fine before upgrading to 10.13):
    Public Function GenerateSession(iTransID As Guid) As String
        Dim eslClient = New EslClient(API_KEY, SDK_URL)

        Dim esr As New eSignRequest(iTransID, sqlMan) ' eSignRequest is my special class for handling the requests
        Dim eSignUser As eSignUser = esr.ESignUser ' eSignUser is also my class
        Dim settings As DocumentPackageSettings = createSettings(esr.ReturnURL) ' function included down below

        Dim signer As Signer = createSignerDynamic(eSignUser.Email, eSignUser.FirstName,
                                                   eSignUser.LastName, eSignUser.Company,
                                                   eSignUser.ID) ' function included down below

        Dim pkgBuilder = PackageBuilder.NewPackageNamed(esr.PackageName)
        pkgBuilder.WithSigner(signer)
        pkgBuilder.WithSettings(settings)

        createDocumentsDynamic(pkgBuilder, esr.Documents, signer) ' function included down below
        Dim docPackage As DocumentPackage = pkgBuilder.Build()
        Dim packageId As PackageId = eslClient.CreatePackage(docPackage)
        eslClient.SendPackage(packageId)

        Dim sessionToken As SessionToken = eslClient.SessionService.CreateSessionToken(packageId, signer.Id)

        'Save the eSign Package ID (GUID) to our database
        sqlMan.saveAWSGuid(iTransID, packageId.ToString)

        Return sessionToken.Token
    End Function

    Private Function createSettings(cReturnURL As String) As DocumentPackageSettings
        Dim settings As New DocumentPackageSettings
        With settings
            .CeremonyLayoutSettings = New CeremonyLayoutSettings
            .CeremonyLayoutSettings.ProgressBar = False
            .CeremonyLayoutSettings.BreadCrumbs = False
            .CeremonyLayoutSettings.IFrame = True
            .CeremonyLayoutSettings.SessionBar = False
            .CeremonyLayoutSettings.GlobalNavigation = False
            .CeremonyLayoutSettings.ShowTitle = False
            .CeremonyLayoutSettings.Navigator = False

            .EnableDecline = True
            .EnableOptOut = True
            '.EnableInPerson = True ' brings up "In Person" dialog, not used right now...

            .LinkHref = cReturnURL
            .LinkText = "Click here when done!"
            .ShowDialogOnComplete = True
        End With

        Return settings
    End Function

   Private Function createSignerDynamic(cEmail As String, cFirst As String, cLast As String, cCompany As String, cID As String) As Signer
        Dim s As Signer
        s = SignerBuilder.NewSignerWithEmail(cEmail) _
            .WithFirstName(cFirst) _
            .WithLastName(cLast) _
            .Build()
        'We do not want to have any emails going out to the users
        s.DeliverSignedDocumentsByEmail = False
        If Not String.IsNullOrEmpty(cCompany) Then
            s.Company = cCompany
        End If
        If Not String.IsNullOrEmpty(cID) Then
            s.Id = cID
        End If
        Return s
    End Function

    Private Sub createDocumentsDynamic(ByRef pb As PackageBuilder, ByVal Docs As List(Of Document), ByVal signer As Signer)
        For Each doc As Document In Docs
            pb.WithDocument(createDoc(doc, signer))
        Next
        pb.Build()
    End Sub

    Private Function createDoc(dr As DataRow, drSigs() As DataRow, drFields() As DataRow, signer As Signer) As DocumentBuilder

        'Create a Document Object for signing from the transaction data for this ceremony
        Dim myDoc As New Document(dr, drSigs, drFields)

        'Initialize the document, ie read in the PDF whether it is from a file or print job..
        Dim db As DocumentBuilder = createDoc_InitDocument(myDoc, signer)

        'Create the signatures for the page, this will also place any datafields on as well
        createDoc_AddSignatures(db, myDoc, signer)

        Return db
    End Function

    Private Function createDoc(myDoc As Document, signer As Signer) As DocumentBuilder
        'Initialize the document, ie read in the PDF whether it is from a file or print job..
        Dim db As DocumentBuilder = createDoc_InitDocument(myDoc, signer)

        'Create the signatures for the page, this will also place any datafields on as well
        createDoc_AddSignatures(db, myDoc, signer)

        Return db
    End Function

 Private Function createDoc_InitDocument(myDoc As Document, signer As Signer) As DocumentBuilder
        Dim cID As String = myDoc.DocId
        Dim cDisplayName As String = myDoc.DisplayName
        Dim cDescription As String = myDoc.Description
        Dim cInput As String = myDoc.Input
        Dim cDocLocation As String = myDoc.DocLocation
        Dim db As DocumentBuilder

        Dim cDocDirectory As String = ""

        If Not IsNothing(WebContext) Then
            cDocDirectory = WebContext.Server.MapPath("~/Documents/" & cDocLocation)
        End If

        db = NewDocumentNamed(cDisplayName).WithId(cID)

        If cInput = "" Then
            ' If input is blank, cDocLocation will point to a file that's within the project's
            ' Documents folder.
            Dim cPhysicalLocation As String = cDocDirectory & cDocLocation
            db.FromFile(cPhysicalLocation)
        ElseIf cInput.StartsWith("http") Then

            ' if it starts with http, then it's going to be a PDF that was generated via 
            ' the Printing Service, so we must go out and download it in order to 
            ' insert it into our package
            Dim request As System.Net.WebRequest = System.Net.WebRequest.Create(cInput)
            request.Credentials = New System.Net.NetworkCredential("username", "password_haha")
            Dim response As System.Net.WebResponse = request.GetResponse()

            Dim s As Stream = response.GetResponseStream()
            Dim nRemaining As Integer = response.ContentLength
            Dim nOffset As Integer = 0

            Dim buffer(nRemaining) As Byte

            While (nRemaining > 0)
                Dim nRead As Integer = s.Read(buffer, nOffset, nRemaining)

                If nRead  0 Then
                    Throw New Exception("Error Reading PDF")
                End If
                nRemaining = nRemaining - nRead
                nOffset = nOffset + nRead
            End While

            Dim ms As New MemoryStream(buffer)
            db.FromStream(ms, DocumentType.PDF)
        Else
            'Otherwise read in the file from the project directory "Documents"
            Dim cPhysicalLocation As String = cDocDirectory & cInput
            db.FromFile(cPhysicalLocation)
        End If

        ' if this is an eSign Consent form, we need to add the accept 
        ' button that will be shown at the bottom of the page..
        If cID.ToLower = "esignconsent" Then
            db.WithSignature(SignatureBuilder.AcceptanceFor(signer.Email))
        End If

        Return db
    End Function

    Private Sub createDoc_AddSignatures(ByRef db As DocumentBuilder, myDoc As Document, signer As Signer)
        For Each sig As DocumentSignature In myDoc.Signatures
            Dim lInitials As Boolean = sig.Initial
            Dim nLocX As Integer = sig.Locaction_X
            Dim nLocY As Integer = sig.Locaction_Y
            Dim nPage As Integer = 0

            'Find out on which page the signature should be placed
            If Not IsDBNull(sig.Locaction_Page) Then
                nPage = sig.Locaction_Page
            Else
                nPage = 0
            End If

            If String.IsNullOrEmpty(signer.Email) Then
                Throw New ArgumentException("Signer Email Address must be provided.")
            End If

            Dim sb As SignatureBuilder

            If lInitials Then
                sb = SignatureBuilder.InitialsFor(signer.Email).OnPage(nPage).AtPosition(nLocX, nLocY)
            Else
                sb = SignatureBuilder.CaptureFor(signer.Email).OnPage(nPage).AtPosition(nLocX, nLocY)
            End If

            'create any data fields for the signature...
            createDoc_AddDataFields(sb, myDoc.Fields)

            db.WithSignature(sb)

        Next
    End Sub

    Private Sub createDoc_AddDataFields(ByRef sb As SignatureBuilder, myFields As List(Of DocumentDataField))
        For Each fld As DocumentDataField In myFields
            Dim cLabel As String = fld.Label
            Dim cFieldType As String = fld.Type
            Dim nSize As Integer = fld.Size
            Dim lShowLabel As Boolean = fld.ShowLabel
            Dim cContentFormat As String = If(fld.ContentFormat, "")
            Dim cGroupName As String = If(fld.GroupName, "")

            Dim nLocX As Integer = fld.Locaction_X
            Dim nLocY As Integer = fld.Locaction_Y
            Dim nWidth As Integer = fld.Locaction_W
            Dim nHeight As Integer = fld.Locaction_H
            Dim nPage As Integer = fld.Locaction_Page

            Select Case cFieldType
                Case "TextBox"
                    Dim fb = FieldBuilder.TextField.OnPage(nPage).AtPosition(nLocX, nLocY).WithName(cLabel).WithId(cLabel)

                    Select Case cContentFormat
                        Case "numeric"
                            fb.WithValidation(FieldValidatorBuilder.Numeric)
                        Case "email"
                            fb.WithValidation(FieldValidatorBuilder.Email)
                        Case Else
                            ' no validation needed..
                    End Select

                    sb.WithField(fb)

                Case "CheckBox"
                    Dim fb As FieldBuilder = FieldBuilder.CheckBox.OnPage(nPage).AtPosition(nLocX, nLocY)
                    fb.WithSize(nWidth, nHeight)
                    fb.WithName(cLabel)
                    fb.WithId(cLabel)

                    sb.WithField(fb)

                Case "RadioButton"
                    Dim fb As FieldBuilder = FieldBuilder.RadioButton(cGroupName).OnPage(nPage).AtPosition(nLocX, nLocY)
                    fb.WithId(cLabel)
                    fb.WithSize(nWidth, nHeight)
                    fb.WithValue(False) ' default to not selected

                    ' not yet fully supported and tested...
                    'sb.WithField(fb)
                    ' do nothing for now so we don't get an error...
                Case "Select"
                    Dim fb As FieldBuilder = FieldBuilder.DropList.OnPage(nPage).AtPosition(nLocX, nLocY)
                    fb.WithSize(nWidth, nHeight)
                    fb.WithName(cLabel)
                    fb.WithId(cLabel)
                    fb.WithValue("DropList Option 2") 'default to 2nd option

                    Dim fvb As FieldValidatorBuilder = FieldValidatorBuilder.Basic _
                        .WithOption("DropList Option 1") _
                        .WithOption("DropList Option 2") _
                        .WithOption("DropList Option 3")
                    fb.WithValidation(fvb)

                    ' not yet fully supported and tested...
                    'sb.WithField(fb)
                    ' do nothing for now so we don't get an error...
                Case Else
                    Throw New ApplicationException("Invalid DataField: " & cFieldType)
            End Select
        Next
    End Sub
(hopefully this all formatted correctly...)

mwilliams | Posts: 957

Reply to: Bad Request 400 eslClient.CreatePackage() after upgrade from 10.3 to 10.13

0 votes
I don't have a copy of the 10.3 SDK to do any testing, unfortunately. I started in the 10.9 timeframe. :) I'll see if I can get a copy of the 10.3 SDK, tomorrow. Do you think you could comment out everything in Generate session except the necessary items and then start uncommenting from the top down and running to see when the issue happens? This way we can narrow it down a bit. Something like below to start, then, uncomment the necessary lines for settings, then for signers, then documents...or whatever way makes sense. If nothing breaks it down to creating the package. Go ahead and send the package to make sure that works fine. If so, then we'd know it's in the get session part. If it ends up being in the documents area, you can do something similar to narrow down within the fields/signatures.
Public Function GenerateSession(iTransID As Guid) As String
        Dim eslClient = New EslClient(API_KEY, SDK_URL)

        'Dim esr As New eSignRequest(iTransID, sqlMan) ' eSignRequest is my special class for handling the requests
       ' Dim eSignUser As eSignUser = esr.ESignUser ' eSignUser is also my class
        'Dim settings As DocumentPackageSettings = createSettings(esr.ReturnURL) ' function included down below

        'Dim signer As Signer = createSignerDynamic(eSignUser.Email, eSignUser.FirstName,
        '                                           eSignUser.LastName, eSignUser.Company,
       '                                            eSignUser.ID) ' function included down below

        'Dim pkgBuilder = PackageBuilder.NewPackageNamed(esr.PackageName)
       ' pkgBuilder.WithSigner(signer)
        'pkgBuilder.WithSettings(settings)

        'createDocumentsDynamic(pkgBuilder, esr.Documents, signer) ' function included down below
        Dim docPackage As DocumentPackage = pkgBuilder.Build()
        Dim packageId As PackageId = eslClient.CreatePackage(docPackage)
       ' eslClient.SendPackage(packageId)

       ' Dim sessionToken As SessionToken = eslClient.SessionService.CreateSessionToken(packageId, signer.Id)

        'Save the eSign Package ID (GUID) to our database
        'sqlMan.saveAWSGuid(iTransID, packageId.ToString)

        Return "blah"
    End Function

jlweatherly | Posts: 3

Reply to: Bad Request 400 eslClient.CreatePackage() after upgrade from 10.3 to 10.13

0 votes
Good idea on commenting out various chunks of code. I was under the impression that leaving any of those bits out would automatically generate an error on CreatePackage(), however the required parts are only actually required during SendPackage(), I still would get errors, but easily understood errors that happened a line later... Anyways, I was able to narrow it down to being an issue with the Signer (leaving signer in the package would always fail at CreatePackage, removing it would then error during SendPackage), which is generated with the following code:
    Private Function createSignerDynamic(cEmail As String, cFirst As String, cLast As String, cCompany As String, cID As String) As Signer
        Dim s As Signer

        s = SignerBuilder.NewSignerWithEmail(cEmail) _
            .WithFirstName(cFirst) _
            .WithLastName(cLast) _
            .Build()

        'We do not want to have any emails going out to the users
        s.DeliverSignedDocumentsByEmail = False

        If Not String.IsNullOrEmpty(cCompany) Then
            s.Company = cCompany
        End If
        If Not String.IsNullOrEmpty(cID) Then
            s.Id = cID
        End If

        Return s
    End Function
Now I'll begin looking into what changes might have been made that cause this code to no longer work...

jlweatherly | Posts: 3

Reply to: Bad Request 400 eslClient.CreatePackage() after upgrade from 10.3 to 10.13

0 votes

Ok, after more trial and error using the same technique, I narrowed it down to the following bit of code inside createSignerDynamic:

        If Not String.IsNullOrEmpty(cID) Then
            s.Id = cID
        End If

I was passing in eSignUser.ID with the value of their email address as I didn't have anything else to use for the signer.Id value. After commenting out this code it was now erroring at:

        Dim sessionToken As SessionToken = eslClient.SessionService.CreateSessionToken(packageId, signer.Id)

Which was being caused by signer.Id being Nothing, so I changed that line to the following

        Dim sessionToken As SessionToken = eslClient.SessionService.CreateSessionToken(packageId, eSignUser.Email)

And all seems to be well again. So there appears to be an issue with using an email address (SignerBuilder.NewSignerWithEmail()) and then setting the Id to the same email address. However something I found on CreateSessionToken() via google is that starting in API version 10.6 you do not need to set the Custom Id and can just use the email address directly in the call to CreateSessionToken (See here), that's effectively what I'm doing now by commenting out my offending code and changing the one line later on. So now that that's all taken care of, does anyone know of a better way to get error messages out of the ESLClient in .NET in this situation? I feel this could have easily been tracked down had I known more information about what it was complaining about instead of resorting to playing whack-a-mole with commenting out chunks of code..


mwilliams | Posts: 957

Reply to: Bad Request 400 eslClient.CreatePackage() after upgrade from 10.3 to 10.13

0 votes
Great! Glad it's working, now. As for error messaging, the best way this could be handled as the SDK is, now would probably be to not build out the entire document package in one call. Instead, create the package with nothing in it, then, add your signers and documents in individual calls before sending. This way, you'd be able to determine your fail point without playing "whack-a-mole". :) You could request an enhancement in the enhancement ideas forum to be more granular in the error message about what caused the issue when creating the entire transaction in one step.

Hello! Looks like you're enjoying the discussion, but haven't signed up for an account.

When you create an account, we remember exactly what you've read, so you always come right back where you left off