Web Services Connectivity and Programming Guide

Transcription

Web Services Connectivity and Programming Guide
finPOWER Connect 2
Web Services Connectivity and Programming
Guide
Version 1.12
30th March 2015
N:\DATA\Development\finPOWER Connect\Version 2\Web Services\finPOWER Connect Web
Services Connectivity and Programming Guide.doc
Table of Contents
Disclaimer.................................................................................................................... 5
Version History ............................................................................................................. 7
Introduction ................................................................................................................. 8
Limitations ................................................................................................................ 8
System Requirements and Prerequisites .......................................................................... 9
Help Resources ........................................................................................................... 10
Web Services ............................................................................................................. 11
Connectivity and Security ............................................................................................ 12
Encryption .............................................................................................................. 12
Authentication ......................................................................................................... 12
Setting up a Test Environment ..................................................................................... 13
Setup and Connection .............................................................................................. 13
Web Administrator ................................................................................................ 15
User .................................................................................................................... 16
Client................................................................................................................... 17
Signing In ............................................................................................................ 18
Using the Web Services Test Form ............................................................................. 19
Programming Languages ............................................................................................. 21
Microsoft .NET ......................................................................................................... 21
Parsing using the XmlDocument .............................................................................. 21
Deserialisation into a .NET Object............................................................................ 21
Authenticating (Signing In) .......................................................................................... 23
Web Roles ............................................................................................................... 23
Web Subscribers ...................................................................................................... 23
The Authentication Process ....................................................................................... 23
hashSalt .............................................................................................................. 23
hash .................................................................................................................... 24
Authentication Code Sample ................................................................................... 24
Authentication Response ........................................................................................ 27
Supplying the Session Token with a Request ............................................................ 28
When to Re-Authenticate ....................................................................................... 28
Dates ........................................................................................................................ 30
Custom Web Services .................................................................................................. 31
Overview ................................................................................................................ 31
Creating a Custom Web Service Script ........................................................................ 32
Calling the Custom Web Service ................................................................................ 33
Accepting Parameters ............................................................................................... 34
Controlling the Response .......................................................................................... 36
HTML Response..................................................................................................... 36
JSON Response ..................................................................................................... 36
Page 2 of 72
Text Response ...................................................................................................... 36
XML Response ...................................................................................................... 36
PDF Response ....................................................................................................... 36
Accepting Posted Data .............................................................................................. 38
Serialising the Response ........................................................................................... 40
Nullable Types ...................................................................................................... 41
Dates .................................................................................................................. 43
Enums ................................................................................................................. 45
Using Attributes to Tweak Serialisation .................................................................... 46
Preventing Properties From Being Serialised ............................................................. 47
Serialising Collections ............................................................................................ 49
Deserialising the Request .......................................................................................... 51
Testing Posted XML ............................................................................................... 53
Enums ................................................................................................................. 54
Using Attributes to Tweak Deserialisation ................................................................. 55
Deserialising Collections ......................................................................................... 56
Troubleshooting Deserialisation Issues ..................................................................... 58
Parsing Posted XML Request ...................................................................................... 59
Serialising and Deserialising XML .................................................................................. 61
Serialisation ............................................................................................................ 61
Visual Basic .......................................................................................................... 62
C# ...................................................................................................................... 63
Deserialisation ......................................................................................................... 64
Visual Basic .......................................................................................................... 65
C# ...................................................................................................................... 66
PDF Documents .......................................................................................................... 67
Returning a PDF Document from a Custom Web Service ............................................... 67
Returning a Response Containing a PDF Document Data from a Custom Web Service ....... 68
Formatting PDF Documents ....................................................................................... 69
Visual Basic Code Examples ......................................................................................... 70
Troubleshooting .......................................................................................................... 72
Timeout when Authenticating Client ........................................................................... 72
Misconfigured Address Database ............................................................................. 72
Page 3 of 72
Page 4 of 72
Disclaimer
This document contains information that may be subject to change at any stage.
All code examples are provided "as is".
Copyright Intersoft Systems Ltd, 2014.
Page 5 of 72
Page 6 of 72
Version History
Date
Version
Name
Changes
07/03/2014
1.00
PH
Created.
17/03/2014
1.01
PH
Clarified that Web Services cannot currently be used for accessing external
resources.
20/03/2014
1.02
PH
Added serialisation/ deserialisation section and samples.
09/04/2014
1.03
PH
Added dates section.
02/05/2014
1.04
PH
Updated information regarding session tokens and when to re-authenticate.
06/05/2014
1.05
PH
Clarified section detailing session token in Authorization header.
06/06/2014
1.06
PH
Added troubleshooting guide for address database issues and PDF sections.
21/07/2014
1.07
PH
Updated ExecuteRequest sample.
21/07/2014
1.08
PH
Support for external Web Services detailed in Limitations section.
12/08/2014
1.09
PH
Custom Web Services section enhanced.
13/08/2014
1.10
PH
Custom Web Service Enum deserialisation.
01/10/2014
1.11
PH
Custom Web Service section used to note new "Execute (Parameters)"
option from Test Web Service form.
30/03/2015
1.12
PH
Added link to Microsoft article in Introduction, Web Services
section.
Page 7 of 72
Introduction
This document is intended for software developers who would like to connect to the finPOWER
Connect Web Services over HTTP.
This document provides all of the necessary information needed to connect to and perform
requests against the Web Services.
For information on installing and configuring the finPOWER Connect Web Services on a Web
Server, see the finPOWER Connect 2 Web Services Installation and Configuration
document.
Limitations
Where access to a resource external to the finPOWER Connect database is required and a builtin Web Service does not exist to achieve this, it should be assumed that such access cannot
currently be achieved and therefore any Custom Web Services or Scripts that run within
finPOWER Connect as part of a Web Service call cannot access these resources.
This includes the following:
 Document Manager
o Accessing of the Document Manager folder structure is not possible in the usual manner
from a Web Service.
 Any form of document publishing, E.g., using a Word VBA template to create a document.
o Microsoft Office should never be run on a Web Server and therefore no form of document
publishing is available from a Web Service.
 Access to external Web Services, E.g.:
o PPSR G2B
o Credit Bureau (Centrix, Veda, DecisionLogic etc)
o MotorWeb
WARNING: Any Custom Web Services or Scripts that attempt to access external resources
cannot be supported and cannot be guaranteed to work in future releases of finPOWER
Connect and the finPOWER Connect Web Services.
Unless listed in the table below, assume the external resource is not supported.
The following external Web Services are supported. The Web Services version at which support
was added is detailed below:
Service
Version
Details
Credit Sense
2.01.01.00
Comprehensive Web Service support.
Veda (Australia)
2.01.01.00
Limited Web Services since it is anticipated most
functionality will be performed from Custom Web
Services.
Page 8 of 72
System Requirements and Prerequisites
 Since the finPOWER Connect Web Services use HTTP, the only programming requirement is
a development environment that allows HTTP and secure HTTP (HTTPS) requests to be
made.
o The application being developed can use any programming language and exist on any
platform providing the above is supported.
 A connection to a Web Server running the finPOWER Connect Web Services is required.
o This Web Server might be:
 Accessible over the Internet.
 Accessible over a private LAN.
 Running on the development PC (for testing purposes).
 The finPOWER Connect 2 Web Services Installation and Configuration
document details installation of the Web Services for testing purposes.
 From a development point-of-view, a solid knowledge of the following is recommended:
o HTTP connectivity.
o XML and/ or JSON.
 Most code samples are currently limited to Visual Basic (VB.NET).
Page 9 of 72
Help Resources
The finPOWER Connect Web Services have online help detailing all Web Services. This help is
available from:
 The finPOWER Connect Web Services Web Server via the API reference link on the Sign In
page:
 From within the finPOWER Connect Windows User Interface via the Test Web Services
form (Tools, Web, Test Web Services).
o The help is available by selecting a Web Service on the Web Services tab, providing a
valid URL has been entered on the Connect page.
 This help is constantly evolving and is updated for every new Web Service that is added.
Page 10 of 72
Web Services
 All Web Services are based on the Microsoft Web API framework meaning:
o They use HTTP/ HTTPS as a transport protocol.
o They do not use SOAP and therefore no WSDL is available.
 XML (or JSON) can be parsed manually or, if using a language that supports it (e.g.,
VB.NET), deserialised into a simple object.
o They use a RESTful, RPC based approach meaning:
 Most services are fully URL-based, E.g., to retrieve a list of Accounts for a finPOWER
Connect Client, you would simply request a URL such as:
 /Api/Client/GetAccounts?clientId=C10000&includeQuote=true
o Unless otherwise specified, both XML and JSON are supported.
 Generally, only the HTTP response will contain XML/ JSON data but services that
require more than just simple URL parameters can POST either XML or JSON.
 The finPOWER Connect Web Services consist of many individual services.
o These services are organised into 'Controllers' which is simply a way of grouping related
services, e.g., the above URL example calls the GetAccounts service which is located in
the Client controller.
 NOTE: The Web Services help and the Test Web Services form within finPOWER
Connect organise their table of contents with a higher level of grouping for readability,
e.g., both Client and ClientWebMail controllers are grouped within a Client folder.
The following are useful articles for understanding Microsoft's Web API and REST services:
http://blogs.msdn.com/b/martinkearn/archive/2015/01/05/introduction-to-rest-and-net-webapi.aspx
Page 11 of 72
Connectivity and Security
 Connectivity to the Web Services is via HTTP/ HTTPS.
o HTTP is fine for testing but secure HTTP (HTTPS) MUST be used in a production
environment.
o The HTTP link to Web Services may be over a private network or the Internet (public) or,
to an installation of the Web Services running on the same PC (usually for development
purposes only, using localhost).
Encryption
 All communication (in a production environment) takes place over a secure, encrypted HTTP
channel using SSL/ TLS.
o This is enabled by a certificate installed on the Web Server hosting the Web Services and
is outside of the scope of this document.
Authentication
 Most Web Services require authentication.
 Any application wishing to access the Web Services must have a Web Subscriber record
defined in the finPOWER Connect database.
o This record has an Id and a Secret key, both of which are required for authentication.
 Authenticated services must be passed a special Session Token as an HTTP header. This is
returned from the initial authentication request.
o The Session Token is valid for up to 24 hours.
Page 12 of 72
Setting up a Test Environment
When programming against the finPOWER Connect Web Services, it is useful to be able to test
the Web Services without having to write any code.
finPOWER Connect provides a Test Web Services form for this purpose.
The following steps are required to set up a test environment.
NOTE: This assumes you can connect to a Web Server running the finPOWER Connect Web
Services. Installation and configuration of the Web Services is detailed in the finPOWER
Connect 2 Web Services Installation and Configuration document.
Setup and Connection
 Install the latest version of finPOWER Connect.
 Open finPOWER Connect.
o If available, open the finPOWER Connect database to which the Web Services connect.
 This is not necessary but does make the connection and testing process easier, E.g., if
you call a Web Service to add an Account, you can then view the Account directly from
within finPOWER Connect.
o If unavailable, open any finPOWER Connect database, E.g., the demonstration database.
 Ensure you are logged in as an administrator User.
 From the Tools menu, select Web, Test Web Services.
 On the Connect page, enter the URL of the Web Services to access, E.g.
NOTE: The Web Services URL will always end with /Api/.
 Click the Ping button to test that the Web Services are available.
 All going well, you should see a message like this:
Page 13 of 72
o NOTE: Ping is one of the few Web Services that do not require authentication.
 Now you can connect to the Web Services by specifying details of the user to connect as.
The User Type determines how you connect.
o Note that connecting as a finPOWER Connect User or a Client requires the Id and Secret
Key of a Web Subscriber to connect as.
o If you have the finPOWER Connect Web Services database loaded, you can add a new
Web Subscriber record (if required) as follows:
 From the Tools menu, select Web, Web Subscribers.
 Click the Add button and enter the following:
 Code: TEST
 Name: Test Web Services
 Click the Save button.
 Close the Web Subscribers form.
o If you do not have the finPOWER Connect Web Services database, you will need to
contact the database administrator and ask them to set up a Web Subscriber record for
you to use and to supply you with the Web Subscriber Id and Secret Key.
Page 14 of 72
Web Administrator
 Connecting as a Web Administrator requires only the Web Administration User Id and
Password. By default these are:
o User Id: webadmin
o Password: password
 NOTE: The Web Administrator role is for use in the Web Services Administration facility and
would not generally be used by external applications.
Page 15 of 72
User
 Connecting as a finPOWER Connect User requires both the User Id and Password and also
the Id and Secret Key of a Web Subscriber to connect as.
 If you have the Web Services database open, you can select the Subscriber from the
dropdown. If not, you will need to be enter the details manually in the Subscriber
dropdown and Secret Key fields.
 Enter the credentials of a finPOWER Connect User, E.g.
o User Id: admin
o Password: admin
 NOTE: The User must have been granted Web Access. This is configured via the Web
Access page on the Users form (Tools, User Security, Users).
Page 16 of 72
Client
 Connecting as a finPOWER Connect Client requires both the Client Id and Password and also
the Id and Secret Key of a Web Subscriber to connect as.
 If you have the Web Services database open, you can select the Subscriber from the
dropdown. If not, you will need to be enter the details manually in the Subscriber
dropdown and Secret Key fields.
 Enter the credentials of a finPOWER Connect Client, E.g.
o Client Id: C10000
o Password: Password1
 NOTE: The Client must have been granted Web Access. This is configured via the Web
Access page on the Clients form (Client, Clients).
Page 17 of 72
Signing In
 After entering the Web Administrator/ User/ Client details, click the Connect button to sign
in.
 You should see a message similar to this:
And a green box will appear in the top-right corner of the form to show that you have
connected successfully:
o
If signing in was unsuccessful, you will see a message such as:
 Click OK and switch to the Web Services tab.
 Click the Response tab.
 The response should contain an XML error message which should help you determine
why signing in failed. The following example has removed attributes on the Error tag
for clarity):
Page 18 of 72
Using the Web Services Test Form
Now that you have successfully connected to the Web Services, you can test any Web Service
or view online help as follows.
 Switch to the Web Services tab.
 Locate and select the Web Service to test in the explorer.
o You can use the Quick Search box above the explorer to filter Web Services.
 The Help tab allows you to view the selected Web Service's help.
 The Request and Response pages allows you to view the information sent to and received
from the Web Services.
 For example:
o Type Client Accounts into the Quick Search box.
o Select the Client, GetAccounts Web Service.
o A list of parameters that this Web Service accepts is displayed along with help for the
Web Service, E.g.
o Enter any parameters, E.g.
 Client Id: C10000
 Include Quote: checked
o Click the Test button.
o The Response tab will automatically be selected and the results of the test will be
displayed, E.g.
Page 19 of 72
 By default, the response will be retrieved as XML. This can be changed from the Connect
page by changing the Format to JSON.
Page 20 of 72
Programming Languages
You may develop your application in the programming language of your choice, on the
platform of your choice. The majority of the code samples throughout this document however
use Visual Basic (VB.NET).
Most finPOWER Connect Web Services allow you to use either XML or JSON for transferring
data.
NOTE: No formal XML or JSON schemas are defined and the XML/ JSON responses may be
extended over time hence any parsing code should assume that the response may contain
additional nodes/ properties in the future.
Microsoft .NET
Microsoft .NET programming languages (Visual Basic and C#) allow the response returned
from a Web Service to be parsed in different ways, E.g., you may wish to parse an XML
response using an XmlDocument object or you could use .NET's built-in deserialisation to
automatically convert the XML (or JSON) into a simple .NET object.
The following are Visual Basic code examples of parsing an XML error response of:
Parsing using the XmlDocument
Private Sub ParseXml(xml As String)
Dim Document As System.Xml.XmlDocument
Dim Node1 As System.Xml.XmlNode
Dim Node2 As System.Xml.XmlNode
Dim Message As String
Dim Code As String
Dim InternalMessage As String
' Load XML Document
Document = New System.Xml.XmlDocument()
Document.LoadXml(xml)
' Get Root <Error> node
Node1 = Document.SelectSingleNode("//Error")
' Get properties
Node2 = Node1.SelectSingleNode("Message")
If Node2 IsNot Nothing Then Message = Node2.InnerText
Node2 = Node1.SelectSingleNode("Code")
If Node2 IsNot Nothing Then Code = Node2.InnerText
Node2 = Node1.SelectSingleNode("InternalMessage")
If Node2 IsNot Nothing Then InternalMessage = Node2.InnerText
End Sub
Deserialisation into a .NET Object
Private Sub ParseXml(xml As String)
Dim
Dim
Dim
Dim
ErrorDetails As WSErrorDetails
ms As System.IO.MemoryStream
Obj As Object
XmlSerializer As Serialization.XmlSerializer
Page 21 of 72
' Deserialise
Try
' Create Serialiser
XmlSerializer = New Serialization.XmlSerializer(GetType(WSErrorDetails))
' Deserialise
ms = New System.IO.MemoryStream(Encoding.UTF8.GetBytes(xml))
ErrorDetails = DirectCast(XmlSerializer.Deserialize(ms), WSErrorDetails)
Catch ex As Exception
' Failed
Finally
If ms IsNot Nothing Then ms.Close(): ms.Dispose()
End Try
End Sub
<Xml.Serialization.XmlType("Error")>
Public Class WSErrorDetails
Public Message As String
Public Code As String
Public InternalMessage As String
End Class
A more comprehensive example of deserialisation is given in the Deserialisation section.
Page 22 of 72
Authenticating (Signing In)
This section details the authentication process.
Most Web Service require that a special 'Session Token' is included in an HTTP header. This
Session Token is generated during the authentication process, itself a Web Service, and is valid
for 24 hours.
Web Roles
A different authentication service is used depending on the type of user that you are signing in
as. The type of user defines a 'Web Role' which determines which services can be used.
The Web Roles are:
 User (a finPOWER Connect User)
 Client (a finPOWER Connect Client)
 WebAdmin (the Web Services Administrator)
You will only ever use User or Client since WebAdmin is used internally for administering Web
Services.
Web Subscribers
For an application to use Web Services, that application must first have a Web Subscriber
record defined in finPOWER Connect.
Web Subscribers are maintained in finPOWER Connect from the Tools menu, Web, Web
Subscribers.
Each Subscriber is given a unique Subscriber Id and also a Secret Key which are used
during the authentication process.
If successful, the authentication service returns a Session Token. This is tied to the Web
Subscriber's Secret Key therefore, if the Web Subscriber's Secret Key is changed (via the Web
Subscribers form), the Session Token will immediately become invalid.
The Authentication Process
When authenticating, the Subscriber's Secret Key is never sent across the network. It is used
to produce a Hash which is sent with the authentication request.
An example URL to authenticate a finPOWER Connect User is shown below:
/Api/Authentication/AuthenticateUser?subscriberId=CC&userId=Admin&password=admin&hash=Faawwodidux5zIuG
%2Fe1vR8wpCVxV0aoKijjyucKbo14%3D&hashSalt=YXBIGIMHKJ
The subscriberId, userId and password parameters are self-explanatory. The hash and
hashSalt are explained in the next section.
hashSalt
The hashSalt parameter is simply a string of 10 random letters. The following Visual Basic code
sample forms a random string.
Rnd = New Random(CInt(Now.Ticks Mod Int32.MaxValue))
hashSalt = ""
For i = 1 To 10
hashSalt &= Chr(65 + Rnd.Next(0, 25))
Next
Page 23 of 72
hash
The hash parameter is an SHA256 hash produced by concatenating the Hash Salt, User Id,
Password and the Web Subscriber's Secret Key. The following pseudo code shows the process
of creating the hash:
s = hashSalt & userId & password & secretKey
hash = Sha256(s)
hash = Base64Encode(hash)
Authentication Code Sample
The following is a Visual Basic code example of signing in as a finPOWER Connect User. It
demonstrates how to create the Hash required by the authentication service and how to send a
request to the Web Services.
The resultant Session Token can then be used for performing authenticated requests.
The ExecuteRequest and CreateHash functions are taken directly from the Web Forms
examples in the /Samples folder of the Web Services application.
' Connection Constants
Const WEB_SERVICES_URL As String = "http://localhost/finPOWERConnectWS2/Api/"
Const WEB_SUBSCRIBER_ID As String = "CC"
Const WEB_SUBSCRIBER_SECRET_KEY As String = "1F673CE613414"
Const USER_ID As String = "admin"
Const USER_PASSWORD As String = "admin"
Public Sub Test()
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Document As System.Xml.XmlDocument
ErrorMessage As String
Hash As String
HashSalt As String
Node1 As System.Xml.XmlNode
Nodes As System.Xml.XmlNodeList
Ok As Boolean
RequestUrl As String
ResponseText As String
SessionToken As String
StatusCode As Integer
' Assume Success
Ok = True
' Initialise
Document = New System.Xml.XmlDocument()
' -------------------------------------------------' Connect to Web Services as a finPOWER Connect User
' -------------------------------------------------If Ok Then
' Produce a hash (and a random hash salt) of the User Id and Password
Hash = HashSha256(USER_ID & USER_PASSWORD, WEB_SUBSCRIBER_SECRET_KEY, HashSalt)
' Build Request URL
RequestUrl = WEB_SERVICES_URL
RequestUrl &= String.Format("Authentication/AuthenticateUser?subscriberId={0}&userId={1}&passwor
d={2}&hash={3}&hashSalt={4}", Server.UrlEncode(WEB_SUBSCRIBER_ID), Server.UrlEncode(USER_ID), Server
.UrlEncode(USER_PASSWORD), Server.UrlEncode(Hash), Server.UrlEncode(HashSalt))
' Execute Request
Ok = ExecuteRequest(RequestUrl, "GET", "XML", "",
Nothing, "", ResponseText, StatusCode, ErrorMessage, Nothing) AndAlso StatusCode = HttpStatusCode.OK
' Parse Response
If Ok Then
' Parse Response to retrieve Session Token
Document.LoadXml(ResponseText)
SessionToken = Document.SelectSingleNode("//SessionDetails/SessionToken").InnerText
End If
End If
' Error
If Not Ok Then
Page 24 of 72
' If ResponseText contains <Error>, this can be parsed as an XML document
End If
End Sub
''' <summary>
''' Execute a Request (sending either nothing, text or binary data in the form of a Byte array) to
retrieve either a text or binary (Byte array) Response.
''' </summary>
''' <param name="requestUrl">
''' The Request URL.
''' </param>
''' <param name="httpMethod">
''' The HTTP Method, E.g., GET or POST.
''' </param>
''' <param name="contentType">
''' The Content Type for the HTTP Content-Type header or just 'XML' or 'JSON'.
''' </param>
''' <param name="requestText">
''' The Request Text or a blank String if not sending any text in the body of the request or if
sending binary data using the requestBytes parameter.
''' </param>
''' <param name="requestBytes">
''' The Request Bytes or Nothing if not sending binary data to the request.
''' </param>
''' <param name="sessionToken">
''' The Session Token or a blank String is using a unauthenticated Web Service.
''' </param>
''' <param name="responseText">
''' The Response Text. This will be Nothing if the content type of the Response did not indicate
that this was a text response, i.e., it did not begin 'text'.
''' </param>
''' <param name="responseBytes">
''' The binary Response. This will be Nothing if the content type of the Response indicates a text
response.
''' </param>
''' <param name="statusCode">
''' The HTTP Status Code received.
''' </param>
''' <param name="errorMessage">
''' An Error Message. This will only by populated if this function returns False.
''' </param>
''' <param name="response">
''' The Response object. May be useful for debugging purposes.
''' </param>
''' <returns>
''' A Boolean value indicating success.
''' </returns>
''' <remarks>
''' NOTE: This is a sample only and matches the function used in the Web Services Test form within
finPOWER Connect. This sample may be subject to updating at any time.
''' </remarks>
Private Function ExecuteRequest(requestUrl As String,
httpMethod As String,
contentType As String,
requestText As String,
requestBytes() As Byte,
sessionToken As String,
ByRef responseText As String,
ByRef responseBytes() As Byte,
ByRef statusCode As Integer,
ByRef errorMessage As String,
ByRef response As System.Net.HttpWebResponse) As Boolean
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Buffer(1023) As Byte
Bytes As Integer
Encoding As System.Text.UTF8Encoding
Ok As Boolean
MemoryStream As System.IO.MemoryStream
Request As System.Net.HttpWebRequest
Stream As System.IO.Stream
srText As System.IO.StreamReader
' Assume Success
Ok = True
' Initialise ByRef Parameters
responseText = ""
responseBytes = Nothing
statusCode = 0
errorMessage = ""
Page 25 of 72
response = Nothing
' Initialise
Select Case UCase(contentType)
Case "JSON" : contentType = "application/json"
Case "XML" : contentType = "text/xml"
End Select
' Create Web Request
Try
Request = DirectCast(System.Net.WebRequest.Create(requestUrl), System.Net.HttpWebRequest)
With Request
' General
.Method = httpMethod
.ContentType = contentType
.Timeout = 20000 ' 20 Seconds
' Add authorisation header
If Len(sessionToken) <> 0 Then
.Headers.Add("Authorization", String.Format("AuthFinWs token=""{0}""", sessionToken))
End If
' Write Request Body
If Len(requestText) = 0 AndAlso requestBytes Is Nothing Then
' None
.ContentLength = 0
Else
' Text/ Binary
Try
' Encode Text as UTF8
If Len(requestText) <> 0 Then
.ContentType &= "; charset=UTF-8"
Encoding = New System.Text.UTF8Encoding()
requestBytes = Encoding.GetBytes(requestText)
End If
' Content Length
.ContentLength = requestBytes.Length
' Content
Stream = .GetRequestStream()
Stream.Write(requestBytes, 0, requestBytes.Length)
Catch ex As Exception
Ok = False
errorMessage = ex.Message
Finally
If Stream IsNot Nothing Then
Stream.Close()
Stream.Dispose()
End If
End Try
End If
End With
Catch ex As Exception
Ok = False
errorMessage = ex.Message
End Try
' Send Request and get Response
Try
Response = DirectCast(Request.GetResponse(), System.Net.HttpWebResponse)
Catch ex As System.Net.WebException
' Not all exceptions should be treated as errors
If ex.Response Is Nothing OrElse Not (TypeOf ex.Response Is System.Net.HttpWebResponse) Then
Ok = False
errorMessage = ex.Message
Else
' Valid Response received
response = DirectCast(ex.Response, System.Net.HttpWebResponse)
End If
Catch ex As Exception
Ok = False
errorMessage = ex.Message
End Try
' Get Response details
If Ok AndAlso response IsNot Nothing Then
' Response (as both a Byte array and Text to cater for both situations)
If response.ContentLength = 0 Then
' No Response Content
responseText = ""
Page 26 of 72
ReDim responseBytes(0)
Else
' Get either Text or Binary Response
If response.ContentType.StartsWith("text", StringComparison.OrdinalIgnoreCase) OrElse
InStr(response.ContentType, "/json", CompareMethod.Text) <> 0 Then
' Text
srText = New System.IO.StreamReader(response.GetResponseStream())
responseText = srText.ReadToEnd()
srText.Close()
Else
' Binary
MemoryStream = New System.IO.MemoryStream()
Stream = response.GetResponseStream()
Do
Bytes = Stream.Read(Buffer, 0, 1023)
If Bytes > 0 Then MemoryStream.Write(Buffer, 0, Bytes)
Loop While Bytes > 0
responseBytes = MemoryStream.ToArray()
End If
End If
' Status Code
statusCode = CInt(response.StatusCode)
End If
Return Ok
End Function
Public Function HashSha256(value As String,
key As String,
ByRef salt As String) As String
Dim
Dim
Dim
Dim
Dim
HashBytes As Byte()
i As Integer
rnd As Random
SaltValueKeyBytes As Byte()
Sha256 As System.Security.Cryptography.SHA256
' Generate Salt (could just as easily be passed in but this will generate a random one regardless)
rnd = New Random(CInt(Now.Ticks Mod Int32.MaxValue))
salt = ""
For i = 1 To 10
salt &= Chr(65 + rnd.Next(0, 25))
Next
' Convert Salt+Value+Key into a byte array
SaltValueKeyBytes = System.Text.Encoding.UTF8.GetBytes(salt & value & key)
' Hash
Sha256 = New System.Security.Cryptography.SHA256Managed()
HashBytes = Sha256.ComputeHash(SaltValueKeyBytes)
' Base-64 encode
Return System.Convert.ToBase64String(HashBytes)
End Function
Authentication Response
Both the Authentication/AuthenticateClient and Authentication/AuthenticateUser services
return a Session Details response, both of which include a Session Token, E.g.
Page 27 of 72
Supplying the Session Token with a Request
The Session Token returned when authenticating (signing in) must be supplied with all
authenticated requests (i.e., just about anything other than Ping).
In a typical Web application, the Session Token might be stored in Session state.
The Authentication Code Sample above demonstrated issuing an authenticated request to
retrieve a list of a Client's Accounts. The authenticated request included a special HTTP
Authorization header, E.g.:
GET http://localhost/finPOWERConnectWS2/Api/Client/GetAccounts?clientId=C10000
Content-Type: text/xml
Authorization: AuthFinWs token="0fb1121adfPi6BcHo48oIgTWMo9+ZA==:rW5lqC5"
The token= portion of the header specifies the Session Token (this has been truncated for
clarity).
When to Re-Authenticate
As mentioned above, authenticating (signing in), returns a Session Token that must be sent
with any request that requires authentication.
The Session Token is valid for 24 hours, after which, supplying it with a request will fail.
Therefore, you may wish to consider the following scenarios and solutions:
 Never re-authenticate
o When the User (or Client) first signs in, store the Session Token in Session State.
Typically, for financial applications, Session State on a Web Server is set to a short
period, E.g., 20 minutes of inactivity.
o Therefore, if you are sure that a User is never going to be continuously connected to your
Web application for more than 24 hours, this approach is suitable.
o This is the method the Client Connect sample uses.
 Re-authenticate a User/ Client after a set period
o If a User (or Client) is likely to remain signed in to your Web application for more than 24
hours, you may wish to re-authenticate after a set period, E.g., every 12 hours.
o When the User (or Client) first signs in, store the Session Token together with the
authentication time and the User (or Client's) Id and Password in Session State.
 NOTE: If using out-of-process Session State, you may wish to encrypt this information
as a precaution.
o Prior to performing a Web Service request, check if the Session Token is more than 12
hours old and, if so, re-authenticate using the Id and Password stored in Session State.
Update the Session Token and authentication time held in Session State.
 Ad-hoc access, i.e., no User or Client is signed in
o If your Web application has no concept of a User (or Client) signing in, E.g., an
application that provides a loan application form on a public Website, you will need to
store the credentials of a finPOWER Connect User somewhere in your application. You will
then need to do one of the following:
Page 28 of 72
 Re-authenticate prior to performing a Web Service request. This provides a new
Session Token that you never need to store.
 NOTE: This approach may bloat the finPOWER Connect audit log.
 When first performing a Web Service request, authenticate and store the Session
Token together with the authentication time in Application State.
 Prior to performing a Web Service request, check if the Session Token is more than
12 hours old and, if so, re-authenticate and update the Session Token and
authentication time held in Application State.
Page 29 of 72
Dates
Web Service dates use the ISO 8601 standard regardless of whether the date is passed as part
of a request URL or is included in an XML or JSON response.
Web Services return dates in UTC (Coordinated Universal Time) regardless of how they are
stored within the finPOWER Connect database or displayed in the finPOWER Connect Windows
interface.
WARNING: Any dates provided as parameters to Web Services will be parsed according to the
time zone on the Web Server. Therefore, it is advisable to always provide dates in UTC format.
Dates are covered in detail in the Dates topic of the Web Services API reference.
Page 30 of 72
Custom Web Services
Custom Web Services are implemented via finPOWER Connect Scripts.
Although General, Summary Page (version 2) and Web Summary Page type Scripts can all be
used as custom Web Services, this section will concentrate on Web Service (Web API) type
Scripts.
This section is a basic tutorial on how to create and use a custom Web Service.
Overview
Custom Web Services can be written where either there is no Web Service currently available
to perform a specific task or, a totally custom task is required, E.g., creating a Quote Account
using custom information entered on a Web page (as per the CustomLoanQuote1VB.aspx
sample detailed in the Visual Basic Code Examples section).
NOTE: Always check with Intersoft Systems before choosing to write a custom Web Service if
the task you want to perform could be considered standard finPOWER Connect functionality.
Page 31 of 72
Creating a Custom Web Service Script
This section outlines the steps required to create a simple custom Web Service Script.
 Open finPOWER Connect.
 Open the database being used by the Web Services.
 From the Admin menu, select Scripts.
 Click the Add button.
 Give the Script an Code and Description, E.g.:
o Code: TESTWS
 NOTE: By default, the Script's code is the name of the custom Web Service and
should therefore contain only alphanumeric characters (this can be overridden on the
Web page of the Scripts form).
o Description: Custom Web Service Test
 Specify a Script Type of Web Service (Web API).
 On the Script Code page, click the Paste template Script code button.
 Click the Save button to save the Script.
Page 32 of 72
Calling the Custom Web Service
The custom Web Service created above can now be called just like any other Web Service
using the special Custom controller, E.g.:
http://localhost/finPOWERConnectWS2/Api/Custom/TESTWS
In this case, a Script named TESTWS will be called or, if a Script has a Web Service Name of
'TESTWS' defined on the Web page of the Scripts form in finPOWER Connect, this Script will be
called (i.e., the Script's code is used by default but can be overridden by specifying a Web
Service Name).
By default, you must have already authenticated and therefore include the Authorization HTTP
header as detailed in The Authentication Process section.
WARNING: The Web page of the Scripts form has a checkbox to 'Allow Anonymous access'.
Use this option with extreme caution since it allows your custom Web Service to be called
without having first authenticated.
You can test your custom Web Service from the Test Web Services form in finPOWER
Connect as follows:
 Connect to the Web Services from the Connect page as detailed in the Setting up a Test
Environment section.
 Switch to the Web Services page.
 Select the Custom, ExecuteGet node in the Web Services explorer.
 Enter the Id of your Script, E.g., TESTWS
 Click the Test button.
o You should see a Response of:
 Switch to the Connect page and change the Format to JSON.
 Switch to the Web Services page and click the Test button again.
o You should now see a Response of:
NOTE: Custom Web Services can be called using either the 'GET' or 'POST' HTTP methods via
the ExecuteGet and ExecutePost nodes in the Web Services explorer.
GET-based Web Services receive all of their parameters from the URL; POST-based services
can receive parameters from the URL and also from the 'Posted' RequestText, E.g., the
RequestText might be XML formatted Client information.
Page 33 of 72
Accepting Parameters
We will now update the custom Web Service to accept parameters.
The Script will be updated to accept a ClientId parameter and will return the Client's name
together with a list of all their aliases (Akas).
Update your custom Web Service Script code to the following:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim ErrorCode As String
Dim ErrorStatusCode As HttpStatusCode
Dim Ok As Boolean
Dim
Dim
Dim
Dim
Client As finClient
ClientAka As finClientAka
ClientDetails As clsClientDetails
ClientId As String
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Get Parameters
ClientId = request.Parameters.GetString("ClientId")
' Load Client
Client = finBL.CreateClient()
If Client.Load(ClientId) Then
' Create and update Client Details
ClientDetails = New clsClientDetails()
ClientDetails.Name = Client.Name
' List AKAs
For Each ClientAka In Client.Akas
ClientDetails.Akas.Add(ClientAka.NameFull)
Next
Else
Ok = False
End If
' Response
If Ok Then
Return request.CreateResponse(HttpStatusCode.OK, ClientDetails)
End If
' Error
If Not Ok Then
Return request.CreateErrorResponse(ErrorStatusCode, "Failed to get Client name details.",
ErrorCode, finBL.Error.Message(True, True))
End If
End Function
<System.Xml.Serialization.XmlType("ClientDetails")>
Public Class clsClientDetails
Public Name As String
Public Akas As New List(Of String)
End Class
We will now test the updated service using the Test Web Service form.
 Select the Custom, Execute (GET) node in the Web Services explorer.
 Enter the Id of your Script, E.g., TESTWS
 In the Parameters field, enter clientId=C10000.
o Parameters must be URL encoded and separated by a '&', E.g., if you had two
parameters, you would specify them as param1=value1&param2=value2
 Click the Test button.
Page 34 of 72
o You should see a Response similar to:
 Switch to the Connect page and change the Format to JSON.
 Switch to the Web Services page and click the Test button again.
o You should now see a Response similar to:
NOTE: As of version 2.02.01 of finPOWER Connect, Custom Web Service Scripts can define
Parameters which are then used by the Test Web Service form when selecting the Custom,
Execute (Parameters) node in the Web Services explorer.
This provides a more user-friendly way of testing Custom Web Services that use Parameters.
In the above example, adding a Text or Range parameter named 'ClientId' to the Script would
allow the Custom Web Service to be tested in this way.
Page 35 of 72
Controlling the Response
Note that in the above example, the XML response has a root node of <ClientDetails>. This
is because we applied an XmlType attribute to the clsClientDetails class. Without this, the
root node will have been named <clsClientDetails>.
Also, because we have declared the Akas property as a List(Of String), we do not have any
control over how this is serialised. Using a custom collection would allow more control.
Our custom Web Service switches automatically between XML and JSON serialisation due to
the way we are returning the response as an object, i.e.:
Return request.CreateResponse(HttpStatusCode.OK, ClientDetails)
Alternatively, to return an error response:
Return request.CreateErrorResponse(ErrorStatusCode, "Failed to add Client.", ErrorCode,
finBL.Error.Message(True, True))
For most services, this is probably desirable but, using the various 'Create' methods of the
request object we can force the response to be a particular format as follows:
HTML Response
CreateHtmlResponse allows us to force the response to be HTML, E.g.
Return request.CreateHtmlResponse(HttpStatusCode.OK, "<h1>This is HTML</h1>")
This simply sets the HTTP Content-Type header to text/html.
JSON Response
CreateJsonResponse allows us to force the response to be JSON, E.g.
Return request.CreateJsonResponse(HttpStatusCode.OK, "{FirstName: "John", LastName: "Smith"}")
This simply sets the HTTP Content-Type header to application/json.
Text Response
CreateTextResponse allows us to force the response to be plain text, E.g.
Return request.CreateTextResponse(HttpStatusCode.OK, Account.AccountId)
This simply sets the HTTP Content-Type header to text/plain.
NOTE: If a Web Service is designed to return only a very simple value, E.g., the Id of an
Account, returning it as plain text means that any calling applications do not need to parse
XML or JSON and therefore simplifies the code.
XML Response
CreateXmlResponse allows us to force the response to be XML, E.g.
Return request.CreateXmlResponse(HttpStatusCode.OK, Branch.ToXmlString())
This simply sets the HTTP Content-Type header to text/xml.
PDF Response
CreatePdfResponse and CreatePdfResponseFromHtml allows us to force the response to be PDF
document, E.g.
Page 36 of 72
Return request.CreatePdfResponseFromHtml(HttpStatusCode.OK, "<h1>My PDF document</h1>")
Or:
Dim PdfData() As Byte
If finBL.PdfUtilities.CreatePdfByteArrayFromHtml("<h1>My PDF document</h1>", PdfData) Then
Return request.CreatePdfResponse(HttpStatusCode.Ok, PdfData)
Else
' Error
End If
This sets the HTTP content to the binary PDF data and sets the Content-Type header to
application/pdf.
See the PDF Documents section for more information.
Page 37 of 72
Accepting Posted Data
Sometimes, you may wish to simply POST data directly to a custom Web Service, E.g., an XML
document created from an external application.
The following Script will accept a POSTed piece of XML in the following format and create a
Transaction for an Account. It will not return anything, just an HTTP Status code of 200 if
successful:
<AccountPayment>
<AccountId>L10035</AccountId>
<Amount>35.00</Amount>
<Reference>REF</Reference>
</AccountPayment>
Update your custom Web Service's Script code to the following:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim ErrorCode As String
Dim ErrorStatusCode As HttpStatusCode
Dim Ok As Boolean
Dim AccountPayment As finAccountPayment
Dim AccountPaymentDetails As clsAccountPaymentDetails
Dim Obj As Object
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Parse XML (use business layer helper Function)
If finBL.Runtime.WebUtilities.DeserialiseXmlStringToObject(request.RequestText,
GetType(clsAccountPaymentDetails), Obj) Then
AccountPaymentDetails = DirectCast(Obj, clsAccountPaymentDetails)
Else
Ok = False
End If
' Add Account Payment
If Ok Then
AccountPayment = finBL.CreateAccountPayment()
With AccountPayment
' Load Account
Ok = .AccountLoad(AccountPaymentDetails.AccountId)
' Update
If Ok Then
.TransactionTypeId = "PAY"
.PaymentMethodId = "CASHR"
.PaymentValue = AccountPaymentDetails.Amount
.TransactionReference = AccountPaymentDetails.Reference
End If
' Commit
If Ok Then
Ok = .ExecuteCommit()
End If
End With
End If
' Response
If Ok Then
Return request.CreateResponse(HttpStatusCode.OK)
End If
' Error
If Not Ok Then
Return request.CreateErrorResponse(ErrorStatusCode, "Failed to make Account payment.",
ErrorCode, finBL.Error.Message(True, True))
End If
End Function
<System.Xml.Serialization.XmlType("AccountPayment")>
Page 38 of 72
Public Class clsAccountPaymentDetails
Public AccountId As String
Public Amount As Decimal
Public Reference As String
End Class
We will now test the updated service using the Test Web Service form.
 Select the Custom, Execute (POST) node in the Web Services explorer.
 Enter the Id of your Script, E.g., TESTWS
 In the Request Text field, past the XML shown at the start of this section.
 Click the Test button.
o You should receive a Response that contains nothing, just an HTTP Status code of 200.
The Deserialising the Request and Parsing Posted XML Request sections cover handling Posted
data in more detail.
Page 39 of 72
Serialising the Response
As shown in some of the previous samples in this section, serialisation to either XML or JSON is
handled automatically by the Web API and the .NET framework.
This section has examples of automatic serialisation of the Response from Script objects.
WARNING: Never attempt to return built-in finPOWER Connect business layer objects from a
Custom Web Service. These objects are not designed for serialisation.
NOTE: Many of the examples in this section remove the following attributes from the
response's root XML node for clarity:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Page 40 of 72
Nullable Types
.NET nullable types are not used within the finPOWER Connect business layer however, they
can, and often should, be used when returning the results of a Web Service.
For instance if you attempt to return an object that has a Date property, E.g., DateOfBirth,
and this does not have a value, it will be returned as 0001-01-01T00:00:00 since the .NET
Date type cannot have no value (within .NET, the Date = Nothing assignment and comparison
is actually assigning and comparing the date with 0001-01-01T00:00:00).
For example, the following Script:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim ClientDetails As ClientDetails
' Create Object
ClientDetails = New ClientDetails()
With ClientDetails
.Name = "Paul"
End With
' Return
Return request.CreateResponse(HttpStatusCode.OK, ClientDetails)
End Function
Public Class ClientDetails
Public Name As String
Public DateOfBirth As Date
End Class
Returns:
<ClientDetails>
<Name>Paul</Name>
<DateOfBirth>0001-01-01T00:00:00</DateOfBirth>
</ClientDetails>
If this is modified to use a nullable data type, E.g.:
Public Class ClientDetails
Public Name As String
Public DateOfBirth As Date?
End Class
The response is much more intuitive:
<ClientDetails>
<Name>Paul</Name>
<DateOfBirth xsi:nil="true" />
</ClientDetails>
Nullable types would typically be used for the following:
 Dates
o Only where the date is optional, E.g., a Date of Birth.
 Numeric types, E.g., Decimal, Double and Integer
o Only where returning zero does not make sense.
 Boolean values
o Only where returning True or False does not make sense.
Page 41 of 72
NOTE: Strings cannot be nullable since the String data type in the .NET framework is an object
and only value types can be nullable.
WARNING: Returning nullable types does add an extra level of complexity to the application
having to parse the XML and you should consider not including the elements in the response at
all as described in the Preventing Properties From Being Serialised section.
Page 42 of 72
Dates
Dates are serialised using the ISO 8601 standard as detailed in the Dates section.
All built-in Web Services return dates containing a time portion in UTC format, regardless of
how they are stored within finPOWER Connect.
Unless you have a requirement to explicitly ignore this rule, all dates containing a time portion
that are returned from a Custom Web Service, E.g., Log dates, should be returned as UTC
dates.
WARNING: .NET Dates have a Kind property which may affect how the date is serialised.
Therefore, when setting dates on objects that are to be serialised, it is important to bear this in
mind, E.g., if Kind is DateTimeKind.Local, serialising a date containing a time portion may
not produce the result you expect, E.g., the date may be converted to a UTC date when this is
not expected.
When testing a Custom Web Service, if dates and times are involved, ensure that you test the
service on a Web Server running in the time zone that the production server will be using to
ensure there are no unforeseen issues.
finPOWER Connect contains business layer functionality to convert a dates to nullable, UTC
format dates, E.g.:
' Create Object
ClientDetails = New ClientDetails()
With ClientDetails
.Name = Client.Name
.DateOfBirth = finBL.Runtime.DateUtilities.CastToNullableUtcDate(Client.DateOfBirth)
If LastLog IsNot Nothing Then
.LastLogDate = finBL.ToUniversalTime(LastLog.Date)
End If
End With
Produces the following response:
<ClientDetails>
<Name>Smith, John</Name>
<DateOfBirth>1978-02-04T00:00:00Z</DateOfBirth>
<LastLogDate>2014-08-07T03:26:11Z</LastLogDate>
</ClientDetails>
Note that both dates are returned as UTC dates even though the Date of Birth does not contain
a time portion.
The following helper functions are available in finPOWER Connect business layer:
 finBL.ToUniversalTime(value)
o Converts a date recorded in local time (as Log dates are in finPOWER Connect 2) to UTC
time.
o The time will be adjusted from local time to UTC time.
 finBL.Runtime.DateUtilities
o CastToNullableUtcDate(value)
 Casts a date containing no time portion (E.g., a Date of Birth) to a nullable UTC date.
 If the Date = Nothing then this will be handled correctly.
 Any time portion is removed.
o CastToNullableUtcDateTime(value)
 Casts a date, optionally containing a time portion to a nullable UTC date.
 If the Date = Nothing then this will be handled correctly.
Page 43 of 72
 Does not 'convert' the date to UTC, i.e., no time adjustment is made so this is not
suitable for converting local dates to UTC dates.
Page 44 of 72
Enums
Enums are serialised as String values, E.g., isefinAccountStatus.ClosedPending is
serialised to 'ClosedPending' using a method such as finAccount.Status.ToString().
finPOWER Connect generally has an Enum value, E.g., isefinAccountStatus.ClosedPending
and also a display value, E.g., 'Closed (Pending)'. This is not the same as the serialised
version of the Enum ('ClosedPending') although often the two are the same.
WARNING: Do not confuse the finPOWER Connect display value for the Enum which is
achieved via methods such as finBL.Enums.isefinAccountStatus_ToString() methods.
These methods are used for displaying Enum values in a user-readable form, E.g., including
spaces or varying the display value based upon the database country.
When returning an object that contains an Enum value, it may be desirable to return both the
Enum and the display value. Typically, the property holding the display value is named the
same as the Enum value property but with a 'Text' suffix, E.g.:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim Account As finAccount
Dim AccountDetails As AccountDetails
' Load (ignore errors for simplicity)
Account = finBL.CreateAccount()
Account.Load("L10000")
' Create Object
AccountDetails = New AccountDetails()
With AccountDetails
.Name = Account.Name
.Status = Account.Status
.StatusText = Account.StatusText
End With
' Return
Return request.CreateResponse(HttpStatusCode.OK, AccountDetails)
End Function
Public Class AccountDetails
Public Name As String
Public Status As isefinAccountStatus
Public StatusText As String
End Class
Produces the following response:
<AccountDetails>
<Name>Smith, John</Name>
<Status>ClosedPending</Status>
<StatusText>Closed (Pending)</StatusText>
</AccountDetails>
Page 45 of 72
Using Attributes to Tweak Serialisation
You may wish to serialise classes using an XML element named differently from the class
name.
This is achieved by applying the XmlType or XmlRoot attributes to the class, E.g.:
<System.Xml.Serialization.XmlType("Transaction")>
Public Class finwsAccountTransaction
' Properties
Public [Date] As Date
Public ElementId As String
Public Reference As String
Public Value As Decimal
End Class
< System.Xml.Serialization.XmlRoot("Transactions")>
Public Class finwsAccountTransactions : Inherits List(Of finwsAccountTransaction)
End Class
< System.Xml.Serialization.XmlType("AvailableCredit")>
Public Class finwsAccountAvailableCreditDetails
Public
Public
Public
Public
Public
Public
AvailableCredit1 As Decimal
AvailableCredit2 As Decimal
AvailableCredit3 As Decimal
CreditLimit1 As Decimal
CreditLimit2 As Decimal
CreditLimit3 As Decimal
End Class
NOTE: Both of these attributes work in a similar way in that they determine the name of the
XML element containing their properties.
Page 46 of 72
Preventing Properties From Being Serialised
Sometimes, you may wish to define properties on your object but not have them serialised
under certain circumstances.
For example, you may have a ClientDetails class that contains properties that should only
be serialised for 'Individual' type Clients, E.g., DateOfBirth.
NOTE: These ShouldSerialize methods are applied when serialising as XML or JSON and are
built-in to the .NET framework.
The method MUST be named after the property name, E.g., to control whether a DateOfBirth
property is serialised, you must have a method named ShouldSerializeDateOfBirth() that
returns a Boolean value.
Also note the U.S. spelling of the word 'serialize'.
The following example shows how to achieve this using special ShouldSerialize methods
which are used by the .NET serialisation process to decide whether or not to serialise a
property:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim Client As finClient
Dim ClientDetails As ClientDetails
' Load (ignore errors for simplicity)
Client = finBL.CreateClient()
Client.Load("C10000")
' Create Object
ClientDetails = New ClientDetails(Client)
With ClientDetails
.Name = Client.Name
.DateOfBirth = finBL.Runtime.DateUtilities.CastToNullableUtcDate(Client.DateOfBirth)
.OrganisationNumber = Client.OrganisationNumber
End With
' Return
Return request.CreateResponse(HttpStatusCode.OK, ClientDetails)
End Function
Public Class ClientDetails
' Properties
Public Name As String
Public DateOfBirth As Date?
Public OrganisationNumber As String
' Other
Private mClient As finClient
Public Sub New(client As finClient)
mClient = client
End Sub
Public Sub New()
End Sub
' Prevent Serialisation for Not Applicable Properties
Public Function ShouldSerializeDateOfBirth() As Boolean
Return mClient Is Nothing OrElse mClient.IsIndividual OrElse mClient.IsSoleTrader
End Function
Public Function ShouldSerializeOrganisationNumber() As Boolean
Return mClient Is Nothing OrElse mClient.IsOrganisation
End Function
End Class
Page 47 of 72
Produces the following response for an 'Individual' Client:
<ClientDetails>
<Name>Smith, John</Name>
<DateOfBirth>1978-02-04T00:00:00Z</DateOfBirth>
</ClientDetails>
And the following response for an 'Organisation' Client:
<ClientDetails>
<Name>Company Limited</Name>
<OrganisationNumber>1234567890</OrganisationNumber>
</ClientDetails>
WARNING: Serialisable classes must always have an empty, public constructor which is why
the above example has two constructors.
This is also why the test mClient Is Nothing is performed since theoretically, a
ClientDetails object could be created without passing in a finClient object.
Page 48 of 72
Serialising Collections
All of the above examples have dealt with serialising a single-level object.
The following example shows how to return a collection object:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim
Dim
Dim
Dim
Account As finAccount
AccountTransaction As finAccountTransaction
AccountDetails As AccountDetails
Transaction As Transaction
' Load (ignore errors for simplicity)
Account = finBL.CreateAccount()
Account.Load("L10000")
' Create Object
AccountDetails = New AccountDetails()
With AccountDetails
.AccountId = Account.AccountId
.Name = Account.Name
.Transactions = New List(Of Transaction)
End With
' Add Transactions
For Each AccountTransaction In Account.Transactions
' Create
Transaction = New Transaction()
' Update
With AccountTransaction
Transaction.Date = finBL.Runtime.DateUtilities.CastToUtcDate(.Date)
Transaction.ElementId = .ElementId
Transaction.Value = .Value
End With
' Add to Collection
AccountDetails.Transactions.Add(Transaction)
Next
' Return
Return request.CreateResponse(HttpStatusCode.OK, AccountDetails)
End Function
Public Class AccountDetails
Public AccountId As String
Public Name As String
Public Transactions As List(Of Transaction)
End Class
Public Class Transaction
Public [Date] As Date
Public ElementId As String
Public Value As Decimal
End Class
Produces the following response:
<AccountDetails>
<AccountId>L10000</AccountId>
<Name>Smith, John</Name>
<Transactions>
<Transaction>
<Date>2014-06-08T00:00:00Z</Date>
<ElementId>ADV</ElementId>
<Value>10000</Value>
</Transaction>
<Transaction>
<Date>2014-06-09T00:00:00Z</Date>
<ElementId>ACCF</ElementId>
<Value>123</Value>
</Transaction>
Page 49 of 72
<Transaction>
<Date>2014-07-09T00:00:00Z</Date>
<ElementId>ACCF</ElementId>
<Value>2.22</Value>
</Transaction>
<Transaction>
<Date>2014-07-09T00:00:00Z</Date>
<ElementId>PAY</ElementId>
<Value>-4.22</Value>
</Transaction>
</Transactions>
</AccountDetails>
Page 50 of 72
Deserialising the Request
As shown in the Accepting Posted Data section, it is often desirable to deserialise XML posted
to the Custom Web Service into an object that the Script can use.
WARNING: Deserialisation is useful for small, flat objects or simple collections. For complex
XML it may be more suitable to parse the posted XML directly.
The finPOWER Connect business layer provides functionality to deserialise XML into an object
as shown in the following example:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim ErrorCode As String
Dim ErrorStatusCode As HttpStatusCode
Dim Ok As Boolean
Dim Client As finClient
Dim ClientDetails As ClientDetails
Dim Obj As Object
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Parse XML (use business layer helper Function)
If finBL.Runtime.WebUtilities.DeserialiseXmlStringToObject(request.RequestText,
GetType(ClientDetails), Obj) Then
ClientDetails = DirectCast(Obj, ClientDetails)
Else
Ok = False
End If
' Add Client
If Ok Then
Client = finBL.CreateClient()
With Client
' Update
.FirstName = ClientDetails.FirstName
.LastName = ClientDetails.LastName
.DateOfBirth = ClientDetails.DateOfBirth
' Save
Ok = .Save()
End With
End If
' Return Response
If Ok Then
Return request.CreateResponse(HttpStatusCode.OK, Client.ClientId)
Else
Return request.CreateErrorResponse(ErrorStatusCode, "Failed to add Client.", ErrorCode,
finBL.Error.Message(True, True))
End If
End Function
Public Class ClientDetails
Public FirstName As String
Public LastName As String
Public DateOfBirth As Date
End Class
The following XML can be posted to the above Script:
<ClientDetails>
<FirstName>Paul</FirstName>
<LastName>Jones</LastName>
<DateOfBirth>1986-03-17</DateOfBirth>
</ClientDetails>
Page 51 of 72
Points of note in the above example are:
 Use of the DeserialiseXmlStringToObject() helper method.
o Internally, this uses the .NET framework's deserialisation functionality.
 ClientDetails.DateOfBirth is defined as a date.
o This means that if the XML omits this tag, the property will remain as the default value
for a Date which equals Nothing, therefore there is no special handling required.
o
o
This is a Date with no time portion hence there is no need to convert from a UTC date.
Supplying an empty DateOfBirth element in the XML, E.g.:
<DateOfBirth/>
Will cause a deserialisation error. Either omit the element completely or use the following
format:
<ClientDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FirstName>Paul</FirstName>
<LastName>Jones</LastName>
<DateOfBirth xsi:nil="true" />
</ClientDetails>
And change the DateOfBirth property to a nullable type:
Public Class ClientDetails
Public FirstName As String
Public LastName As String
Public DateOfBirth As Date?
End Class
And handle accordingly when updating the finClient object, E.g.:
If ClientDetails.DateOfBirth IsNot Nothing Then
.DateOfBirth = CDate(ClientDetails.DateOfBirth)
End If
Page 52 of 72
Testing Posted XML
Testing a Custom Web Service that accepts posted XML can be achieved from the Test Web
Services form.
Simply paste a sample of the XML into the 'Request Text' field, E.g.:
Page 53 of 72
Enums
Enums are included in XML using their String representation, E.g.,
isefinAccountStatus.ClosedPending would be serialised using a method such as
finAccount.Status.ToString(). This would produce a value of 'ClosedPending'.
WARNING: Do not confuse this with the finPOWER Connect display value for the Enum which
is achieved via methods such as finBL.Enums.isefinAccountStatus_ToString() methods.
These methods are used for displaying Enum values in a user-readable form, E.g., including
spaces or varying the display value based upon the database country.
Deserialisation of Enums is handed internally by the .NET framework however, it is not
recommended that you use nullable types for Enums since this complicates the deserialisation
process. Therefore, do not include an Enum tag in the XML if it is not required.
Page 54 of 72
Using Attributes to Tweak Deserialisation
By default, XML will be deserialised into properties that match the XML element names.
This can be tweaked using attributes, E.g.:
<System.Xml.Serialization.XmlType("TransactionBatch")>
Public Class clsTransactionBatch
Public BatchId As String
Public TransactionType As String
Public Transactions As List(Of clsTransaction)
End Class
<System.Xml.Serialization.XmlType("Transaction")>
Public Class clsTransaction
Public
Public
Public
Public
Public
AccountId As String
[Date] As Date
Reference As String
ElementId As String
Value As Decimal
End Class
Page 55 of 72
Deserialising Collections
Collections can also be deserialied as shown in the following example which creates a Batch of
Transactions and saves and then commits the Batch:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Batch As finBatch
BatchTransaction As finBatchTransaction
ErrorCode As String
ErrorStatusCode As HttpStatusCode
Obj As Object
Ok As Boolean
Transaction As clsTransaction
TransactionBatch As clsTransactionBatch
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Deserialise the XML to an Object
If finBL.Runtime.WebUtilities.DeserialiseXmlStringToObject(request.RequestText,
GetType(clsTransactionBatch), Obj) Then
TransactionBatch = DirectCast(Obj, clsTransactionBatch)
Else
Ok = False
End If
If Ok Then
' Initialise
Batch = finBL.CreateBatch()
' Setup Batch
With Batch
.BatchId = TransactionBatch.BatchId
.TransactionTypeId = TransactionBatch.TransactionType
.SourceSet(isefinTransactionSource.ExternalA)
End With
' Add Transactions
For Each Transaction In TransactionBatch.Transactions
' Create
BatchTransaction = Batch.Transactions.CreateBatchTransaction()
' Update (ignore errors for simplicity of sample)
With BatchTransaction
.AccountIdSet(Transaction.AccountId)
.ElementIdSet(Transaction.ElementId)
.Date = Transaction.Date
.Value = Transaction.Value
.Reference = Transaction.Reference
End With
' Add
Batch.Transactions.Add(BatchTransaction)
Next
' Save Batch
Ok = Batch.Save()
' Commit Batch
If Ok Then
Ok = Batch.ExecuteCommit(False)
End If
End If
' Return Response
If Ok Then
Return request.CreateResponse(HttpStatusCode.OK)
Else
Return request.CreateErrorResponse(ErrorStatusCode, String.Format("Failed to execute custom Web
Service Script '{0}'.", ScriptInfo.ScriptId), ErrorCode, finBL.Error.Message(True, True))
End If
End Function
<System.Xml.Serialization.XmlType("TransactionBatch")>
Page 56 of 72
Public Class clsTransactionBatch
Public BatchId As String
Public TransactionType As String
Public Transactions As List(Of clsTransaction)
End Class
<System.Xml.Serialization.XmlType("Transaction")>
Public Class clsTransaction
Public
Public
Public
Public
Public
AccountId As String
[Date] As Date
Reference As String
ElementId As String
Value As Decimal
End Class
The following XML can be posted to the above Script:
<TransactionBatch>
<BatchId>WSBatch001</BatchId>
<TransactionType>PAY</TransactionType>
<Transactions>
<Transaction>
<AccountId>L10000</AccountId>
<Date>2014-08-07</Date>
<Reference>Reference 1</Reference>
<ElementId>PAY</ElementId>
<Value>100.00</Value>
</Transaction>
<Transaction>
<AccountId>L10035</AccountId>
<Date>2014-08-08</Date>
<Reference>Reference 2</Reference>
<ElementId>PAY</ElementId>
<Value>42.50</Value>
</Transaction>
</Transactions>
</TransactionBatch>
Points of note in the above example are:
 Use of the DeserialiseXmlStringToObject() helper method.
o Internally, this uses the .NET framework's deserialisation functionality.
o This deserialises the <Transactions> block in to the Transactions property which is
defined as a List(Of clsTransaction).
 Attributes (E.g., <System.Xml.Serialization.XmlType("Transaction")>) are used to
map the class names, E.g., clsTrasaction to an XML element name, E.g., Transaction.
Page 57 of 72
Troubleshooting Deserialisation Issues
Problems can arise when attempting to deserialise XML into an object and these are often hard
to track.
The DeserialiseXmlStringToObject() method will return False if deserialisation failed. This
may be due to the following:
 The XML being deserialised was invalid.
 Dates or numbers within the XML are invalid.
o E.g., Date values are not in the ISO 8601 format.
 ISO 8601: 2014-08-16
 Non-standard format: 8/16/2014
 Dates or numbers elements in the XML are empty.
o Even if the property on the object that the element is being serialised into is a nullable
type, including an empty element will still produce an error unless the xsi:nil="true"
attribute is applied as described in the 'Date of Birth' example at the end of the
Deserialising the Request section.
Additionally, if the property name in the object does not exactly match the XML element name
(this is case-sensitive), the property will not be populated during the deserialisation process.
Page 58 of 72
Parsing Posted XML Request
Parsing the posted XML request manually may be a better option than deserialising it if:
 The XML is complex, E.g., many levels of nesting.
 You want more control than the deserialisation process can provide, E.g.:
o The XML has different versions, E.g., a 'version' attribute on the root node affects how
the XML should be parsed.
o The XML contains dates not formatted according to the ISO 8601 standard.
 This may be the case if the supplied XML is in a legacy format of comes from a source
that you do not have control over.
The finPOWER Connect business layer has helper methods to assist in the parsing of XML.
The following example shows how to manually parse the XML used in Deserialising Collections
sample:
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Batch As finBatch
BatchTransaction As finBatchTransaction
ErrorCode As String
ErrorStatusCode As HttpStatusCode
Ok As Boolean
XmlDocument As XmlDocument
Node As XmlNode
Nodes As XmlNodeList
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Parse XML
With finBL.Runtime.XmlUtilities
' Load XML Document
If .LoadXmlDocumentFromString(request.RequestText, XmlDocument) Then
' Initialise
Batch = finBL.CreateBatch()
' Get Root Node
Node = XmlDocument.SelectSingleNode("TransactionBatch")
If Node Is Nothing Then
Ok = False
finBL.Error.ErrorBegin("TransactionBatch node not found.")
End If
' Setup Batch
If Ok Then
Batch.BatchId = .GetSubNodeString(Node, "BatchId")
Batch.TransactionTypeId = .GetSubNodeString(Node, "TransactionType")
Batch.SourceSet(isefinTransactionSource.ExternalA)
End If
' Transactions
If Ok Then
Nodes = Node.SelectNodes("Transactions/Transaction")
For Each Node In Nodes
' Create
BatchTransaction = Batch.Transactions.CreateBatchTransaction()
' Update (ignore errors for simplicity of sample)
BatchTransaction.AccountIdSet(.GetSubNodeString(Node, "AccountId"))
BatchTransaction.ElementIdSet(.GetSubNodeString(Node, "ElementId"))
BatchTransaction.Date = .GetSubNodeDate(Node, "Date")
BatchTransaction.Value = .GetSubNodeDecimal(Node, "Value")
BatchTransaction.Reference = .GetSubNodeString(Node, "Reference")
' Add
Batch.Transactions.Add(BatchTransaction)
Next
Page 59 of 72
End If
' Save Batch
If Ok Then
Ok = Batch.Save()
End If
' Commit Batch
If Ok Then
Ok = Batch.ExecuteCommit(False)
End If
Else
Ok = False
End If
End With
' Return Response
If Ok Then
Return request.CreateResponse(HttpStatusCode.OK)
Else
Return request.CreateErrorResponse(ErrorStatusCode, String.Format("Failed to execute custom Web
Service Script '{0}'.", ScriptInfo.ScriptId), ErrorCode, finBL.Error.Message(True, True))
End If
End Function
Points of note in the above example are:
 Use of the finBL.Runtime.XmlUtilities helper methods to load and parse XML.
Page 60 of 72
Serialising and Deserialising XML
Some programming languages support serialisation and deserialisation of XML from and to an
object.
In many cases, this can make parsing a response (or forming a request) easier than dealing
directly with XML.
NOTE: This section is intended for external applications consuming the Web Services. For
Custom Web Service Scripts, see the Serialising the Response and Deserialising the Request
sections.
In the Custom Web Services section, the finPOWER Connect business layer was used to
serialise a response to XML (or JSON). This section gives code samples of both serialisation
and deserialisation.
Serialisation/ Deserialisation can be used with complex objects and collections (E.g., objects
that contain other objects). A Google search will provide many examples of how to achieve
this.
Serialisation
Serialisation is the process of taking an object and automatically creating an XML String that
represents that object.
The following examples will all serialise the simple ClientDetails object detailed below into XML:
ClientDetails
ClientId (String)
FirstName (String)
LastName (String)
DateOfBirth (Date)
Each of the code samples contains a SerialiseObjectToXmlString function which returns a
Boolean value based upon whether it was successful or not. If unsuccessful, an error message
is returned instead of the XML.
Page 61 of 72
Visual Basic
Public Sub Main()
Dim ClientDetails As clsClientDetails
Dim Xml As String
' Create Object
ClientDetails = New clsClientDetails()
With ClientDetails
.ClientId = "C10000"
.FirstName = "John"
.LastName = "Smith"
.DateOfBirth = New Date(1970, 9, 5)
End With
' Serialise
If SerialiseObjectToXmlString(ClientDetails, Xml) Then
MsgBox(Xml)
Else
MsgBox(Xml, MsgBoxStyle.Exclamation)
End If
End Sub
Public Function SerialiseObjectToXmlString(obj As Object, ByRef xml As String) As Boolean
Dim ms As System.IO.MemoryStream
Dim Ok As Boolean
Dim XmlSerializer As System.Xml.Serialization.XmlSerializer
' Assume Success
Ok = True
' Initialise ByRef Parameters
xml = ""
' Serialise
Try
XmlSerializer = New System.Xml.Serialization.XmlSerializer(obj.GetType())
ms = New System.IO.MemoryStream()
XmlSerializer.Serialize(ms, obj)
xml = System.Text.Encoding.UTF8.GetString(ms.GetBuffer(), 0, CInt(ms.Length))
ms.Close()
Catch ex As Exception
' Failed (return error message instead of XML)
Ok = False
xml = ex.Message
Finally
If ms IsNot Nothing Then ms.Dispose()
End Try
Return Ok
End Function
<System.Xml.Serialization.XmlType("ClientDetails")>
Public Class clsClientDetails
Public ClientId As String
Public FirstName As String
Public LastName As String
Public DateOfBirth As Date
End Class
Page 62 of 72
C#
public void Main()
{
clsClientDetails ClientDetails;
string Xml = "";
// Create Object
ClientDetails = new clsClientDetails {
ClientId = "C10000",
FirstName = "John",
LastName = "Smith",
DateOfBirth = new DateTime(1970, 9, 5)
};
// Serialise
if(SerialiseObjectToXmlString(ClientDetails, ref Xml)) {
System.Windows.Forms.MessageBox.Show(Xml);
}
else {
System.Windows.Forms.MessageBox.Show(Xml, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
public bool SerialiseObjectToXmlString(Object obj, ref string xml)
{
System.IO.MemoryStream ms = null;
bool Ok;
System.Xml.Serialization.XmlSerializer XmlSerializer;
// Assume Success
Ok = true;
// Initialise ByRef Parameters
xml = "";
// Serialise
try {
XmlSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
ms = new System.IO.MemoryStream();
XmlSerializer.Serialize(ms, obj);
xml = System.Text.Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
ms.Close();
}
catch(Exception ex) {
// Failed (return error message instead of XML)
Ok = false;
xml = ex.Message;
}
finally {
if(ms != null) ms.Dispose();
}
return Ok;
}
[System.Xml.Serialization.XmlType("ClientDetails")]
public class clsClientDetails {
public string ClientId;
public string FirstName;
public string LastName;
public DateTime DateOfBirth;
}
Page 63 of 72
Deserialisation
Deserialisation is the process of taking an XML String and automatically creating and
populating an object from the content of the XML.
The following examples will deserialise the following XML into the simple ClientDetails object
used in the previous section.
<ClientDetails>
<ClientId>C10000</ClientId>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
<DateOfBirth>1970-09-05T00:00:00</DateOfBirth>
</ClientDetails>
Each of the code samples contains a DeserialiseObjectFromXmlString function which
returns a Boolean value based upon whether it was successful or not. If unsuccessful, an error
message is returned instead of the deserialised object.
Page 64 of 72
Visual Basic
Public Sub Main()
Dim ClientDetails As clsClientDetails
Dim tempObject As Object
Dim Xml As String
' Define XML
Xml &= "<ClientDetails>"
Xml &= "<ClientId>C10000</ClientId>"
Xml &= "<FirstName>John</FirstName>"
Xml &= "<LastName>Smith</LastName>"
Xml &= "<DateOfBirth>1970-09-05T00:00:00</DateOfBirth>"
Xml &= "</ClientDetails>"
' Deserialise into Object
If DeserialiseXmlStringToObject(Xml, GetType(clsClientDetails), tempObject) Then
ClientDetails = DirectCast(tempObject, clsClientDetails)
MsgBox("Deserialised ClientId=" & ClientDetails.ClientId)
Else
MsgBox(CStr(tempObject), MsgBoxStyle.Exclamation)
End If
End Sub
Public Function DeserialiseXmlStringToObject(xml As String, objType As Type, ByRef obj As Object) As
Boolean
Dim ms As System.IO.MemoryStream
Dim Ok As Boolean
Dim XmlSerializer As System.Xml.Serialization.XmlSerializer
' Assume Success
Ok = True
' Initialise ByRef Parameters
obj = Nothing
' Deserialise
Try
' Create Serialiser
XmlSerializer = New System.Xml.Serialization.XmlSerializer(objType)
' Deserialise
ms = New System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml))
obj = XmlSerializer.Deserialize(ms)
ms.Close()
Catch ex As Exception
Ok = False
obj = ex.Message
Finally
If ms IsNot Nothing Then ms.Dispose()
End Try
Return Ok
End Function
<System.Xml.Serialization.XmlType("ClientDetails")>
Public Class clsClientDetails
Public ClientId As String
Public FirstName As String
Public LastName As String
Public DateOfBirth As Date
End Class
Page 65 of 72
C#
public void Main(object sender, EventArgs e)
{
clsClientDetails ClientDetails;
Object tempObject = null;
string Xml;
// Define XML
Xml = "";
Xml += "<ClientDetails>";
Xml += "<ClientId>C10000</ClientId>";
Xml += "<FirstName>John</FirstName>";
Xml += "<LastName>Smith</LastName>";
Xml += "<DateOfBirth>1970-09-05T00:00:00</DateOfBirth>";
Xml += "</ClientDetails>";
// Deserialise into Object
if(DeserialiseXmlStringToObject(Xml, typeof(clsClientDetails), ref tempObject))
{
ClientDetails = (clsClientDetails)tempObject;
System.Windows.Forms.MessageBox.Show("Deserialised ClientId=" + ClientDetails.ClientId);
}
else
{
System.Windows.Forms.MessageBox.Show((string)tempObject, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
bool DeserialiseXmlStringToObject(string xml, Type objType, ref Object obj)
{
System.IO.MemoryStream ms = null;
bool Ok;
System.Xml.Serialization.XmlSerializer XmlSerializer;
// Assume Success
Ok = true;
// Initialise ByRef Parameters
obj = null;
// Deserialise
try
{
// Create Serialiser
XmlSerializer = new System.Xml.Serialization.XmlSerializer(objType);
// Deserialise
ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml));
obj = XmlSerializer.Deserialize(ms);
ms.Close();
}
catch (Exception ex)
{
Ok = false;
obj = ex.Message;
}
finally
{
if (ms != null) ms.Dispose();
}
return Ok;
}
[System.Xml.Serialization.XmlType("ClientDetails")]
public class clsClientDetails {
public string ClientId;
public string FirstName;
public string LastName;
public DateTime DateOfBirth;
}
Page 66 of 72
PDF Documents
Web Service functionality exists to convert HTML to a PDF document.
NOTE: finPOWER Connect uses an external component to convert HTML to a PDF document
therefore the formatting is outside of the control of Intersoft Systems.
Returning a PDF Document from a Custom Web Service
Custom Web Services can return a Response representing a PDF document using either the
request.CreatePdfResponseFromHtml or request.CreatePdfResponse methods.
The following example returns a simple PDF document:
Option Explicit On
Option Strict On
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim ErrorCode As String
Dim ErrorStatusCode As HttpStatusCode
Dim Ok As Boolean
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Return Response
If Ok Then
Return request.CreatePdfResponseFromHtml(HttpStatusCode.OK, "<h1>My PDF document</h1>.")
Else
Return request.CreateErrorResponse(ErrorStatusCode, String.Format("Failed to execute custom Web
Service Script '{0}'.", ScriptInfo.ScriptId), ErrorCode, finBL.Error.Message())
End If
End Function
This returns the PDF file content as binary data. The following is a sample response with the
majority of the HTTP body stripped out since it is meaningless:
HTTP/1.1 200 OK
Content-Length: 2401
Content-Type: application/pdf
Date: Wed, 04 Jun 2014 00:29:48 GMT
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
%PDF-1.5
%����
%Created by EVO PDF Tools v3.5
Note that the Content Type header specifies application/pdf.
A consumer of this Web Service could then retrieve the response data as am array of bytes
and either write it to a file or stream it to the user's Web browser.
Page 67 of 72
Returning a Response Containing a PDF Document Data from
a Custom Web Service
In the previous section, a custom Web Service was used to return a PDF document. The
response from the custom Web Service was a complete PDF document and contained no other
information.
In certain situations, it may be desirable to return the PDF document as part of a more
complex response, E.g., an XML response containing a <PdfDocument> node.
The following example returns a resonse containing Base 64 encoded PDF data. This can then
be decoded by the Web Service consumer and written to a PDF file:
Option Explicit On
Option Strict On
Public Function Main(request As finwsHttpRequest) As finwsHttpResponse
Dim
Dim
Dim
Dim
Dim
ErrorCode As String
ErrorStatusCode As HttpStatusCode
Ok As Boolean
PdfDetails As PdfDetails
PdfDocumentBase64 As String
' Assume Success
Ok = True
' Initialise
ErrorStatusCode = HttpStatusCode.BadRequest
' Create PDF Document from HTML
Ok = finBL.PdfUtilities.CreatePdfBase64StringFromHtml("<h1>My PDF Document</h1>",
PdfDocumentBase64)
' Create PDF Details
If Ok Then
PdfDetails = New PdfDetails()
With PdfDetails
.Title = "PDF Title"
.PdfDocument = PdfDocumentBase64
End With
End If
' Return Response
If Ok Then
' Return PDF Details
Return request.CreateResponse(HttpStatusCode.OK, PdfDetails)
Else
' Error
Return request.CreateErrorResponse(ErrorStatusCode, String.Format("Failed to execute custom Web
Service Script '{0}'.", ScriptInfo.ScriptId), ErrorCode, finBL.Error.Message())
End If
End Function
Public Class PdfDetails
Public Title As String
Public PdfDocument As String
End Class
Since this Script returns an object (PdfDetails), it will automatically be serialised as either XML
or JSON as per the following (stripped down) responses:
<PdfDetails>
<Title>PDF Title</Title>
<PdfDocument>JVBERi0xLjUNCiWxsrO0DQolQ3JlYXRlZCBieSBFVk8gUERGIFRvb2xzIHYzLjUNCjEgMCBvYmoNCjw8DQovUGF
nZXMgMiAwIFINCi9QYWdlTGF5b3V0IC9PbmVDb2x1bW4NCi9QYWdlTW9kZSAvVXNlTm9uZQ0KL1ZpZXdlclByZWZlcmVuY2VzIDM
gMCBSDQovVHlwZSAvQ2F0YWxvZw0KPj4NCg0KZW5kb2JqDQo2IDAgb2JqDQo8PA0KL0ZpbHRlciAvRmxhdGVEZWNvZGUNCi9MZW5
ndGggMTMzDQo+Pg0Kc3RyZWFt</PdfDocument>
</PdfDetails>
Page 68 of 72
{"Title":"PDF Title",
"PdfDocument":"JVBERi0xLjUNCiWxsrO0DQolQ3JlYXRlZCBieSBFVk8gUERGIFRvb2xzIHYzLjUNCjEgMCBvYmoNCjw8DQovU
GFnZXMgMiAwIFINCi9QYWdlTGF5b3V0IC9PbmVDb2x1bW4NCi9QYWdlTW9kZSAvVXNlTm9uZQ0KL1ZpZXdlclByZWZlcmVuY2VzI
DMgMCBSDQovVHlwZSAvQ2F0YWxvZw0KPj4NCg0KZW5kb2JqDQo2IDAgb2JqDQo8PA0KL0ZpbHRlciAvRmxhdGVEZWNvZGUNCi9MZ
W5ndGggMTMyDQo+Pg0Kc3RyZWFt"}
Formatting PDF Documents
finPOWER Connect contains functionality to convert HTML into a PDF via the finBL.PdfUtilities
class.
When creating PDF documents from HTML, note the following:
 The PDF file is generated on the Web Server on which the Web Services are running and
can therefore only access any fonts available on this Server.
o You may wish to use safe fonts such as:
 Arial
 Times New Roman
 Verdana
 Any images you wish to include in the PDF, E.g., company logos should be referenced via a
URL that can be resolved by the Web Server.
 You do not have the same amount of control over the document that is produced as you
would using a Word processing package such as Microsoft Word.
 By default, the HTML is formatted as if displayed in a browser window that is 1024 pixels
wide.
o This can be changed via the ViewportWidth meta tag detailed below.
The following meta tags can be included at the top of the HTML to tweak that PDF file that is
produced:
<meta
<meta
<meta
<meta
<meta
<meta
<meta
name='pdf-PageSize' content='A4'/>
name='pdf-PageOrientation' content='Portrait'/>
name='pdf-LeftMargin' content='1.5cm'/>
name='pdf-RightMargin' content='1cm'/>
name='pdf-TopMargin' content='1.5cm'/>
name='pdf-BottomMargin' content='2.54cm'/>
name='pdf-ViewportWidth' content='1200'/>
 PageSize
o One of the following: A4, A5, Legal, Letter
 PageOrientation
o Either Portrait or Landscape
 LeftMargin, RightMargin, TopMargin, BottomMargin
o Can be specified in the following units: cm, inches (if omitted, points are assumed)
 ViewportWidth
o This defaults to 1024 but specifying a different value will vary how the PDF is generated,
E.g., how much information fits on a line.
 By changing this value, the HTML text may scale to a different size so for consistency,
it may be best to not set the ViewportWidth but to change the font size in the HTML
using CSS.
Page 69 of 72
Visual Basic Code Examples
Visual Basic code examples are included in the /Samples folder of the Web Services. All of
these samples are ASP.NET Web Forms and therefore contain a .aspx and a .aspx.vb file.
The following table lists these samples:
Sample
Description
Other Details
ConnectUser1VB.aspx
Connect as a finPOWER Connect
User and retrieve a list of Client
Accounts.
CustomLoanQuote1VB.aspx
Enter simple Loan and Client details
and use a custom Web Service to
create a Quote Account and a
Client.
Script CustomLoanQuote1VB.xml
must be imported into finPOWER
Connect.
To use get these samples up and running:
 Create a new empty Web Application in Visual Studio 2012 (or Visual Studio Express 2012
for Web).
o Keep the default project name of WebApplication1.
 The sample .aspx files reference a namespace of WebApplication1 so doing this saves
having to modify the samples' .aspx portion.
 Copy the entire contents of the Web Services /Samples folder into the new Web
Application.
o Include all files (except for any .xml files) in the Web Application project.
 Ensure you have a Web Subscriber record set up in finPOWER Connect.
o In finPOWER Connect, open the database that the Web Services are connected to.
o From the Tools menu, select Web and then Web Subscribers.
o Add a new Web Subscriber record with the following details:
 Code: TEST
 Description: Test Web Subscriber
 View the .vb portion of all sample pages and update the following constants to allow
connection to the Web Services:
o WEB_SERVICES_URL
o WEB_SUBSCRIBER_ID
o WEB_SUBSCRIBER_SECRET_KEY
 Run the Web Application and ensure that the ConnectUser1VB.aspx page runs correctly.
o This is the simplest example, therefore ensure this runs correctly before attempting to
run any other examples.
 Some samples may require a custom Web Service Script.
Page 70 of 72
o The following samples require that their corresponding .xml file is imported into the
finPOWER Connect Scripts library:
 CustomLoanQuote1VB.aspx
o To import the Script, do the following:
 In finPOWER Connect, open the database that the Web Services are connected to.
 From the Admin menu, select Scripts.
 Use the Import action to import the .xml file.
 Save the Script.
Page 71 of 72
Troubleshooting
Timeout when Authenticating Client
A timeout error when attempting to authenticate a Client via the
Authentication/AuthenticateClient service may be due to the following:
Misconfigured Address Database
If the Address database being used by the finPOWER Connect business layer is not available,
attempting to connect to it may cause a time out.
This may be an issue when attempting to authenticate as a Client since the response from this
service includes formatted Branch address details which involves accessing the Addressing
interface which will always attempt to initialise a connection to the Address database when first
accessed.
Page 72 of 72