Skip to content

Integration Example: C#


IdM Global Services Integration Example Account

Ensure you have an account setup. You will need the Username, Password and WSDL location.

If you are unsure of any of the details you can contact the helpdesk for more information on: 01244 657321

Importing the Webservice in Visual Studio

Adding a web reference to visual studio which will create all the webservice objects. It will also set the endpoint so it doesn't have to be set manually (it is possible to set this manually if required).

Visual Studio 2013 Professional Edition (C#)

Creating a basic Windows Forms Application (called IdMGlobalServicesIntegration in the examples below).

Right-click the project and select Add Service Reference.

Click Advanced.

Click Add Web Reference...

Enter the WSDL url into the URL box and click the green arrow. The WSDL url is:

idmp.gb.co.uk/idm-globalservices-ws/globalservices21a.wsdl

Because the IdM service is secured (SSL encrypted) and has an https:// address, then security warnings may appear. The Visual Studio wizard will normally allow the web reference to be created if insecure (http://) content is blocked.

The webservice will be found, type a name for it in the box. The default name (uk.co.gb.idmp) is used in the following examples, but any other name can be used instead.

Click on Add Reference. If successful the service can be seen in the Web Reference folder as shown below:

Code C#

Once the webservice has been added to Visual Studio it is now possible to start integrating. The user interface for the final application can be seen below:

On the right there is a tabControl with three tabPages - the first tabPage is for simple address lookups. On the left are the credentials and connection information. At the bottom is an area where exception messages are displayed.

Creating a basic UI

Within the Address tab page, add the following components to your form:

Component Type Component Name
TextBox txtAddressPostcode
Button btnPostcodeAddressLookup
ListBox lstPostcodeAddressResults

Creating the Service Layer

The service layer will contain the logic for managing the authentication and calling the web service.

Start by creating an interface as shown below:

namespace idmglobalservicesintegration.services
{
    public interface iglobalservicesws
    {
        executecaptureresponse postcodeaddresslookup(
            string postcode);
    }
}

To create a structure make a folder called impl in the service folder and create a new Class that implements the interface created above.

namespace idmglobalservicesintegration.services.impl
{
    public class globalservicesws : iglobalservicesws
    {
    }
}

This is the file/folder hierarchy:

It is now possible to implement the lookup method defined in the interface created beforehand.

Variables Service Layer Implementation

The following variables are required for configuration.

It is good practice to move these configuration variables to an external source instead of hard coding them.

// username for the webservice
private string m_username = string.empty;
// password for the webservice
private string m_password = string.empty;
// profile guid to use for the webservice
private string m_profileguid = string.empty;
// the webservice url
private string m_webserviceendpoint = string.empty;
// the authenticated user.
private iauthenticationdetails m_authenticationdetails = null;
// instance of the webservice.
private idmglobalservicesservice m_globalserviceswebservice = new idmglobalservicesservice();
// valid flag
private bool m_valid = true;

Change the username, password and profileGuid to the ones supplied, or they can be updated programmatically (as in the complete project attached at the end of these notes).

See here for an explanation of the AuthenticationDetails object.

Implementing the Postcode Lookup Method

The following function takes a string argument which is the postcode (which is taken from the postcode TextBox added to the form previously).

/**
 * executes the alu request and returns the response.
 *
 * executecaptureresponse contains the addresses returned from the webservice.
 */
public executecaptureresponse postcodeaddresslookup(
    string postcode)
{
    // create the options
    var requestoptions = new idmrequestoptions
    {
        addresssearchlevel = enumaddresslevel.premise,
        casing = enumcasing.mixed,
        maxreturn = 100,
        offset = 0,
        addressenvelopeformat = "a3tcp"
    };
 
    // create the request
    var request = new executecapturerequest
    {
        profilerequest = new profilerequestcapture()
        {
            requestdata = new profilerequestcapturedata()
            {
                    address = new idmdatasearchaddress() 
                    { 
                        postcode = postcode 
                    },
                    options = requestoptions,
                },
            customerreference = "samplecode",
            profileguid = this.profileguid
 
        },
        securityheader = getsecurityheader(),
    };
 
    // perform the search
    executecaptureresponse executecaptureresponse = this.globalserviceswebservice.executecapture(request);
 
    // recycle the authentication token from the response.
    this.authenticationdetails.refreshauthenticationdetails(executecaptureresponse.securityheader);
 
    // return
    return executecaptureresponse;
}

As seen from the comments, the Request is being created then the getSecurityHeader() method is being called and added to the request.

Getting a valid security header

The below functions will authenticate against the web service and setup a valid security header:

/**
 * authenticate against the webservice and set the authenticationtoken.
 * authenticateuserresponse contains the authentication token and other details.
 */
private void authenticateuser()
{
    if (!this.authenticationdetails.isvalid)
    {
        // create an authenticate user request.
        authenticateuserrequest request = new authenticateuserrequest()
        {
            // set the username and password.
            username = this.username,
            password = this.password
        };
        // create response and call the webservice.
        authenticateuserresponse response = this.globalserviceswebservice.authenticateuser(request);
        // save for next time
        this.authenticationdetails = new authenticationdetails(response);
    }
}
 
/**
 * returns a security header for authentication purposes.
 * securityheader contains the authentication details.
 */
private securityheader getsecurityheader()
{
    // ensure we have a valid authentication token.
    this.authenticateuser();
    // create a new securityheader
    securityheader header = new securityheader()
    {
        username = this.authenticationdetails.username,
        authenticationtoken = this.authenticationdetails.authenticationtoken
    };
    return header;
}

The getSecurity function calls AuthenticateUser first. AuthenticateUser() will check to see if a valid authenticationToken already exists by calling the user.isValid() method. If it does it will not authenticate it will use the valid authenticationToken currently in place. Otherwise it will do an authentication and update the AuthenticationDetails with a new username, authenticationToken and expiry time.

Then getSecurityHeader will create the SecurityHeader object and add the required authentication details (username, authenticationToken) and then return the header.

Postcode Lookup button event

The below method uses the globalService class variable, this needs to be added add GlobalSerivcesWSImpl globalService = new GlobalServicesWSImpl(); to the top of the class.

Double clicking the Lookup button on the UI designer will automatically create the Click event for that control. The following code will attempt to execute the lookup() function and catch any errors that may occur (in any subsequent methods).

private void btnpostcodeaddresslookup_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        // clear any old messages
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofilematchcodeaddress.text;
            executecaptureresponse response = this.globalservicesws.postcodeaddresslookup(txtaddresspostcode.text);
            this.addressdisplaypostcodeaddresses(response, this.lstpostcodeaddressresults);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
    }
}

See here for an explanation on error handling.

Populating the Addresses ListBox

AddressDisplayPostcodeAddresses() will populate the address listbox with a formatted string for each address. See the following code:

private void addressdisplaypostcodeaddresses(executecaptureresponse response, listbox lstresults)
{
    // clear the listbox (addresses) so we can add new items.
    lstresults.items.clear();
    // check and make sure the response is not null.
    if ((response != null) &&
        (response.profileresponse != null) &&
        (response.profileresponse.profileresponsedetails != null) &&
        (response.profileresponse.profileresponsedetails.length > 0))
    {
        // for each address returned from the webservice.
        foreach (profileresponsedetails profileresponsedetails in response.profileresponse.profileresponsedetails)
        {
            if (profileresponsedetails.captureresponse != null && profileresponsedetails.captureresponse.response != null)
            {
                foreach (captureresponsedata responsedata in profileresponsedetails.captureresponse.response)
                {
                    if (responsedata.address != null)
                    {
                        foreach (idmdataaddress address in responsedata.address)
                        {
                            displayaddressinlistbox(address, lstresults);
                        }
                    }
                }
            }
        }
    }
}

Note the addressString is a StringBuilder object which makes it easier to concatenate strings with the Append() method;

The first part clears the address box as it might have already done a lookup. The second part will check to see if the response has any addresses.

The for each loop will take each address and format it with the following method:

// formats a string appending a line separator.
private string stringconcat(string text)
{
    if (string.isnullorempty(text))
    {
        return null;
    }
    else
    {
        return text + ", ";
    }
}

The returned string is appended to addressString and then added to the list box as an item.

Authentication Token Recycling

The above example can be improved by recycling the authentication token. Once authenticated every request afterwards will return a valid authentication token. It is strongly recommended you create a method of using that returned token as to prevent unnecessary calls to the web service.

The following interface will handle the refreshing of the authentication token, checking if the authentication is expired (the isValid() method) and holding the current username.

using system;
 
using idmglobalservicesintegration.uk.co.gb.idmp;
 
namespace idmglobalservicesintegration.services
{
    /**
     ** interface for handling the idm authentication process
     */
    interface iauthenticationdetails
    {
        datetime authenticationtime { get; }
        datetime sessionexpirytime { get; }
        string authenticationtoken { get; }
        string username { get; }
        bool isvalid { get; }
        void refreshauthenticationdetails(securityheaderresponse securityheader);
        void invalidate();
    }
}

This interface is implemented by the class below.

using system;
 
using idmglobalservicesintegration.uk.co.gb.idmp;
 
namespace idmglobalservicesintegration.services.impl
{
    /**
     ** class for handling the idm authentication process
     */
    public class authenticationdetails : iauthenticationdetails
    {
        #region data
        private string m_username;
        private string m_authenticationtoken;
        private datetime m_authenticationtime;
        private datetime m_sessionexpirytime;
        private bool m_valid;
        #endregion
 
        #region constructor
        public authenticationdetails()
        {
            this.m_username = string.empty;
            this.m_authenticationtoken = string.empty;
            this.m_authenticationtime = datetime.minvalue;
            this.m_sessionexpirytime = datetime.minvalue;
            this.m_valid = false;
        }
        public authenticationdetails(authenticateuserresponse response)
        {
            this.m_username = response.fullusername;
            this.m_authenticationtoken = response.authenticationtoken;
            this.m_authenticationtime = response.authenticationtime.value;
            this.m_sessionexpirytime = response.sessionexpirytime.value;
            this.m_valid = true;
        }
        #endregion
 
        #region properties
        public string username
        {
            get { return this.m_username; }
        }
        public string authenticationtoken
        {
            get { return this.m_authenticationtoken; }
        }
        public datetime authenticationtime
        {
            get { return this.m_authenticationtime; }
        }
        public datetime sessionexpirytime
        {
            get { return this.m_sessionexpirytime; }
        }
        public boolean isvalid
        {
            get
            {
                datetime now = datetime.now;
                if (this.m_sessionexpirytime == null || now > this.m_sessionexpirytime)
                {
                    this.m_valid = false;
                }
                return this.m_valid;
            }
        }
        #endregion
 
        #region public methods
        public void refreshauthenticationdetails(securityheaderresponse securityheader)
        {
            this.m_authenticationtoken = securityheader.authenticationtoken;
            this.m_authenticationtime = securityheader.authenticationtime.value;
            this.m_sessionexpirytime = securityheader.sessionexpirytime.value;
            this.m_valid = true;
        }
        public void invalidate()
        {
            this.m_valid = false;
        }
        #endregion
    }
}

See the next section on Managing Credentials for authentication improvements.

Managing Credentials

We can allow the user to set the Username, Password and ProfileGuid by adding more components to the UI. We do not really want to be hard coding the Password into the application for security reasons. We can now add a method to set the security details and re-authenticate when a lookup is executed.

We can add another clause to the isValid() method in the AuthenticationDetails so we can change the username and password and invalidate the session forcing the lookup call to re-authenticate with a new username and password.

The following properties will allow the Username, Password and ProfileGuid to be updated safely. Whenever the appropriate setter is used, it also calls

m_authenticationdetails.invalidate();

which will trigger the application to re-authenticate on the next address lookup.

public string username
    {
        get { return m_username; }
        set { m_username = value; m_authenticationdetails.invalidate(); }
    }
    public string password
    {
        private get { return m_password; }
        set { m_password = value; m_authenticationdetails.invalidate(); }
    }
    public string profileguid
    {
        get { return m_profileguid; }
        set { this.m_profileguid = value; m_authenticationdetails.invalidate(); }
    }
}

The passwords getter has been made private for security purposes. The isValid() method now checks the boolean valid is false as shown below:

if (this.authenticationtime == null || now > this.authenticationtime || !this.valid)
{
    m_valid = false;
}

There is a new class variable valid as shown below, it has a default value of true as when this class is constructed a successful authentication has occurred so it will always be true unless the invalidate() method is called:

private boolean m_valid = true;

The invalidate method just simply sets valid to false:

public void invalidate()
{
    this.m_valid = false;
}

Error Handling

There are many ways of handling errors. This example has a text box it uses primarily for showing errors (which we don't really cover).

You could if you wanted you could just use:

messagebox.show(exception.stacktrace);

This would populate and show a message box with the exception included.

The code can throw different types of exceptions for example:

catch (soapexception exception)
{
    txtmessages.text = exception.detail.value;
}
// fill the errors text box with any error messages.
catch (exception exception)
{
    txtmessages.text = exception.message;
    txtmessages.text += "\r\n" + exception.source;
}

The bonus to doing this is SoapException has a different method (exception.Detail.Value) if the exception is a validation exception this will allow us to get the actual cause and display it back to the user.

We use Exception when we want to catch anything that has not been handled by our previous catch statements.

Handling a Proxy

Most businesses operate behind a proxy server which in some cases can stop a program from being able to send SOAP requests. This example briefly covers a basic way of handling proxy server authentication you will need some extra components on the UI (unless you want to hard code the proxy details).

Component Name
TextBox txtProxyUsername
TextBox txtProxyPassword
TextBox txtProxyServer
TextBox txtProxyPort
Button btnProxyApply


First off we can attempt to detect the proxy server automatically in the forms constructor as demonstrated below:

// get the system proxy.
iwebproxy proxy = webrequest.getsystemwebproxy();
// if the system proxy exists.
if (proxy != null)
{
    // get the proxy server details.
    webrequest.defaultwebproxy = proxy;
    txtproxyserver.text = proxy.getproxy(new uri(globalservice.endpoint)).host;
    txtproxyport.text = proxy.getproxy(new uri(globalservice.endpoint)).port.tostring();
}

If a proxy exists the code will automatically fill out the server address and port number.

Now we add the code to the apply button as shown:

/**
 * calls the set proxy method and handles any errors.
 */
private void btnproxyapply_click(object sender, eventargs e)
{
    txtmessages.text = string.empty;
    try
    {
        this.setproxysettings();
    }
    catch (exception exception)
    {
        txtmessages.text = exception.message;
    }
}

Which in turn calls the setProxySettings() method as shown below:

// this will attempt to set the proxy details.
private void setproxysettings()
{
    /**
     * a possible exception could be thrown here if the user supplies text in the port number.
     * the above method is in a try catch so the message will be caught and presented in the error textbox.
     * providing no errors are thrown this will set the address and port of the proxy server.
     */
    webproxy proxy = new webproxy(txtproxyserver.text, convert.toint32(txtproxyport.text));
    // set the username and password.
    proxy.credentials = new networkcredential(txtproxyusername.text, txtproxypassword.text);
    // set the default proxy.
    webrequest.defaultwebproxy = proxy;
}

The proxy server is created and then overwrites the default system proxy.

Calling ExecuteCapture

The code snippet method highlights the main tasks to be performed to call the web service. Firstly the code retrieves the security header for the request with a valid authentication token. The code will then call the web service with the request passed into the method. Before passing back the response it will refresh the users authenticationToken for use on the next request.

/**
 * performs a capture seach
 * executecaptureresponse contains the response
 */
private executecaptureresponse executecapture(executecapturerequest request)
{
    // object containing security information - i.e. access token / username
    request.securityheader = this.getsecurityheader();
 
    // call the web service
    executecaptureresponse response = this.globalserviceswebservice.executecapture(request);
 
 
    // recycle the authentication token from the response.
    this.authenticationdetails.refreshauthenticationdetails(response.securityheader);
 
    return response;
}

Integrating Telephone

The following sample code shows the additional integration of the Global Telephone service.

A second tabPage has been added to the tabControl to organise the simple Telephone lookup.

You can get the latest source from the zip file at the bottom of this document.

In order to call the Web Service the ExecuteCaptureRequest request object must be created containing the input data for a Mobile and Landline lookup. The table below summarises the objects required:

Object Description
ExecuteCaptureRequest The top level request object containing the data for the web service method
ProfileRequestCapture Contains the IdM profile data
ProfileRequestCaptureData Contains the input data for both address and telephone data
List<IdmDataCaptureTelephone> Contains a list of telephone numbers and their type (LANDLINE, MOBILE, UNKNOWN)
IdmRequestOptions Contains options required for the ALU


The following code demonstrates setting up the request data that is passed into the code above:

public executecaptureresponse telephonevalidation(
    string mobile, string landline)
{
    // create the options
    var requestoptions = new idmrequestoptions
    {
        addresssearchlevel = enumaddresslevel.premise,
        casing = enumcasing.mixed,
        maxreturn = 100,
        offset = 0,
        addressenvelopeformat = "a3tcp"
    };
 
    // create a place holder for the telephone numbers
    list<idmdatacapturetelephone> listoftelephones = new list<idmdatacapturetelephone>();
 
// add the mobile telephone number to the list
if (!string.isnullorempty(mobile))
{
    idmdatacapturetelephone mobileidm = new idmdatacapturetelephone()
    {
        number = mobile,
        // where possible specify the telephone type (default = unknown)
        type = enumtelephone.mobile
    };
    listoftelephones.add(mobileidm);
}
 
// add the landline telephone number to the list
if (!string.isnullorempty(landline))
{
    idmdatacapturetelephone landlineidm = new idmdatacapturetelephone()
    {
        number = landline,
        type = enumtelephone.landline
    };
listoftelephones.add(landlineidm);
}
 
// create the profile request capture data
var profilerequestcapturedata = new profilerequestcapturedata()
{
    telephone = listoftelephones.toarray(),
    options = requestoptions
};
 
// create the profile request capture
var profilerequestcapture = new profilerequestcapture()
{
    // set the profile you wish to call (the profile dictates which services are used)
    profileguid = this.profileguid,
    configurationid = 1,
    // customer reference is stamped on the audit trail for each query
    customerreference = "samplecode",
    requestdata = profilerequestcapturedata
};
 
 
// create the top level request object
var request = new executecapturerequest()
{
    profilerequest = profilerequestcapture
};
 
 
// call the service and return the web service response
executecaptureresponse executecaptureresponse = this.executecapture(request);
 
// return
return executecaptureresponse;
}

The method above checks to see if the landline or mobile are null before adding a new IdmDataCaptureTelephone to the request. In this case we are specifying the type of number entered by adding the EnumTelephone.MOBILE to the IdmDataCaptureTelephone object. There is an extra option which is EnumTelephone.UNKNOWN. in this case the service will attempt to work out whether the number is landline or telephone and check the appropriate service.

The last part of the method assigns the objects we created at the start to there respective relations. Note that listOfTelephones.ToArray() automatically converts our list to an array which is what is required by the webservice.

Handling the Web Service Return (ExecuteCaptureResponse) for Telephone lookup

Once you have successfully called the web service and retrieve a valid response you can start to handle the results. The following code provides a high level overview of processing the results:

private void btnglobaltelephonevalidate_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        executecaptureresponse response = null;
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofilematchcodeglobaltelephone.text;
            response = this.globalservicesws.telephonevalidation(txtgtmobile.text, txtgtlandline.text);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
        this.displayvalidateresponse(response, this.tvgtresults);
    }
}
 
private void displayvalidateresponse(executecaptureresponse response, treeview tvresults)
{
    // clear the treeview so we can add new items.
    tvresults.nodes.clear();
    // check and make sure the response is not null.
    if ((response != null) &&
        (response.profileresponse != null) &&
        (response.profileresponse.profileresponsedetails != null) &&
        (response.profileresponse.profileresponsedetails.length > 0))
    {
        // for each address returned from the webservice.
        foreach (profileresponsedetails profileresponsedetails in response.profileresponse.profileresponsedetails)
        {
            if ((null != profileresponsedetails.validateresponse) &&
                (null != profileresponsedetails.validateresponse.response) &&
                (profileresponsedetails.validateresponse.response.length > 0))
            {
                foreach (validateresponsedata validateresponsedata in profileresponsedetails.validateresponse.response)
                {
                    treenode tnresponse = new treenode(validateresponsedata.input);
                    tvresults.nodes.add(tnresponse);
                    treenode tnstatus = new treenode(validateresponsedata.status.tostring());
                    tnresponse.nodes.add(tnstatus);
                    if ((null != validateresponsedata.validationcodes) &&
                        (null != validateresponsedata.validationcodes.item) &&
                        (validateresponsedata.validationcodes.item.length > 0))
                    {
                        foreach (idmdataitem idmdataitem in validateresponsedata.validationcodes.item)
                        {
                            treenode tnitem = new treenode(idmdataitem.key + "=" + idmdataitem.value);
                            tnresponse.nodes.add(tnitem);
                        }
                    }
                }
            }
        }
    }
}

Integrating Bank Account

The following sample code shows the additional integration of the Bank Account validation service.

A tab control has been added to the page to organise the simple Bank Account lookup.

You can get the latest source from the zip file at the bottom of this document.

In order to call the Web Service the ExecuteCaptureRequest request object must be created containing the input data for a Sortcode and Account number lookup. The table below summarises the objects required:

Object Description
ExecuteCaptureRequest The top level request object containing the data for the web service method
ProfileRequestCapture Contains the IdM profile data
ProfileRequestCaptureData Contains the input data for both address and telephone data
List<IdMDataCaptureBank> Contains an array of bank sortcode and account number
IdmRequestOptions Contains options required for the ALU

The following code demonstrates setting up the request data that is passed into the code above:

public executecaptureresponse bankaccountvalidation(
    string sortcode,
    string accountnumber)
{
    // create the options
    var requestoptions = new idmrequestoptions
    {
        addresssearchlevel = enumaddresslevel.premise,
        casing = enumcasing.mixed,
        maxreturn = 100,
        offset = 0,
        addressenvelopeformat = "a3tcp"
    };
 
    list<idmdatacapturebank> listofidmdatacapturebank = new list<idmdatacapturebank>();
    var bankdata = new idmdatacapturebank()
    {
        sortcode = sortcode,
        accountnumber = accountnumber
    };
    listofidmdatacapturebank.add(bankdata);
 
    // create the profile request capture data
    var profilerequestcapturedata = new profilerequestcapturedata()
    {
        bank = listofidmdatacapturebank.toarray(),
        options = requestoptions
    };
 
    // create the profile request capture
    var profilerequestcapture = new profilerequestcapture()
    {
        // set the profile you wish to call (the profile dictates which services are used)
        profileguid = this.profileguid,
        configurationid = 1,
        // customer reference is stamped on the audit trail for each query
        customerreference = "samplecode",
        requestdata = profilerequestcapturedata
    };
 
 
    // create the top level request object
    var request = new executecapturerequest()
    {
        profilerequest = profilerequestcapture
    };
 
 
    // call the service and return the web service response
    executecaptureresponse executecaptureresponse = this.executecapture(request);
 
    // return
    return executecaptureresponse;
    }
}
Handling the Web Service Return (ExecuteCaptureResponse) for Bank Account lookup

Once you have successfully called the web service and retrieve a valid response you can start to handle the results. The following code provides a high level overview of processing the results:

private void btnbankaccountvalidate_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        executecaptureresponse response = null;
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofilebankvalidation.text;
            response = this.globalservicesws.bankaccountvalidation(txtbanksortcode.text, txtbankaccountnumber.text);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
 
        this.displayvalidateresponse(response, this.tvbankresults);
    }
}

Integrating Matchcode Premium

The following sample code shows the additional integration of the MatchcodePremium service.

A tab control has been added to the page to organise the MatchcodePremium lookup.

You can get the latest source from the zip file at the bottom of this document.

In order to call the Web Service the ExecuteCaptureRequest request object must be created containing the input data for MatchcodePremium lookup. The table below summarises the objects required:

Object Description
ExecuteCaptureRequest The top level request object containing the data for the web service method
ProfileRequestCapture Contains the IdM profile data
ProfileRequestCaptureData Contains the input data for name, address and email
IdmDataCapturePerson Contains names for a person
idmDataArrayOfCapturePerson Contains an array for persons at an address
IdmDataSearchAddress Contains address (building and postcode)
List<IdmDataItem> Contains an array of key/value data items number
IdmRequestOptions Contains options required for the request

The following code demonstrates setting up the request data that is passed into the code above:

public executecaptureresponse lookupmatchcodepremium(
    string firstname, string lastname, string building, string postcode,
    string emailaddress,
    bool requestconsented, bool flowtypeappend, int consentedtotal, string consentedtype,
    int socialtotal, string socialtype)
{
    // create the options
    var requestoptions = new idmrequestoptions
    {
        addresssearchlevel = enumaddresslevel.premise,
        casing = enumcasing.mixed,
        maxreturn = 100,
        offset = 0,
        addressenvelopeformat = "a3tcp"
    };
 
    // create the person
    list<idmdatacaptureperson> listofperson = new list<idmdatacaptureperson>();
    var person = new idmdatacaptureperson()
    {
        firstname = firstname,
        lastname = lastname
    };
    listofperson.add(person);
    // convert to idm array type
    var idmdataarrayofcaptureperson = new idmdataarrayofcaptureperson() {
        person = listofperson.toarray()
    };
 
 
    // create the address
    var searchaddress = new idmdatasearchaddress() {
        persons = idmdataarrayofcaptureperson,
        building = building,
        postcode = postcode,
    };
 
    // create the additional items
    list<idmdataitem> listofadditionalitem = new list<idmdataitem>();
    listofadditionalitem.add(new idmdataitem()
    {
        key = "consented",
        value = (requestconsented ? "yes" : "no")
    });
    listofadditionalitem.add(new idmdataitem()
    {
        key = "flow_type",
        value = (flowtypeappend ? "append" : "social")
    });
    listofadditionalitem.add(new idmdataitem()
    {
        key = "consented_total",
        value = consentedtotal.tostring()
    });
    listofadditionalitem.add(new idmdataitem()
    {
        key = "consented_type",
        value = consentedtype
    });
    listofadditionalitem.add(new idmdataitem()
    {
        key = "social_request_action",
        value = socialtype
    });
    idmdataitem socialtotalitem = new idmdataitem()
    {
        key = "social_email_total",
        value = socialtotal.tostring()
    };
 
    // create emails
    list<string> listofemail = new list<string>();
    if(!string.isnullorempty(emailaddress))
    {
        listofemail.add(emailaddress);
    }
 
    // create the profile request capture data
    var profilerequestcapturedata = new profilerequestcapturedata()
    {
        address = searchaddress,
        options = requestoptions,
        email = listofemail.toarray(),
        additionaldata = new idmdataarrayadditionaldata()
        {
            item = listofadditionalitem.toarray()
        },
    };
    // create the profile request capture
    var profilerequestcapture = new profilerequestcapture()
    {
        // set the profile you wish to call (the profile dictates which services are used)
        profileguid = this.profileguid,
        configurationid = 1,
        // customer reference is stamped on the audit trail for each query
        customerreference = "samplecode",
        requestdata = profilerequestcapturedata
    };
 
 
    // create the top level request object
    executecapturerequest request = new executecapturerequest()
    {
        profilerequest = profilerequestcapture
    };
 
 
    // call the service and return the web service response
    executecaptureresponse executecaptureresponse = this.executecapture(request);
 
    // return
    return executecaptureresponse;
}
Handling the Web Service Return (ExecuteCaptureResponse) for MatchcodePremium lookup

Once you have successfully called the web service and retrieve a valid response you can start to handle the results. The following code provides a high level overview of processing the results:

private void btnpremiumlookup_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        executecaptureresponse response = null;
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofilematchcodepremium.text;
            response = this.globalservicesws.lookupmatchcodepremium(
                txtpremfirstname.text, txtpremlastname.text,
                txtprembuilding.text, txtprempostcode.text,
                txtprememail.text,
                chkpremconsented.checked, rbpremflowappend.checked,
                convert.toint32(nudpremconsentedtotal.value), cmbpremconsentedtype.text,
                convert.toint32(nudpremsocialtotal.value), cmbpremsocialtype.text);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
        this.displaycaptureresponse(response, tvpremresults);
    }
}
 
 
private void displaycaptureresponse(executecaptureresponse response, treeview tvresults)
{
    // clear the treeview so we can add new items.
    tvresults.nodes.clear();
    // check and make sure the response is not null.
    if ((response != null) &&
        (response.profileresponse != null) &&
        (response.profileresponse.profileresponsedetails != null) &&
        (response.profileresponse.profileresponsedetails.length > 0))
    {
        // for each address returned from the webservice.
        foreach (profileresponsedetails profileresponsedetails
            in response.profileresponse.profileresponsedetails)
        {
            if ((null != profileresponsedetails.captureresponse) &&
                (null != profileresponsedetails.captureresponse.response) &&
                (profileresponsedetails.captureresponse.response.length > 0))
            {
                int responseindex = 0;
                foreach (captureresponsedata captureresponsedata
                    in profileresponsedetails.captureresponse.response)
                {
                    responseindex++;
                    string caption = (!string.isnullorempty(captureresponsedata.input)
                        ? captureresponsedata.input : response.tostring());
                    treenode tnresponse = new treenode(caption);
                    tvresults.nodes.add(tnresponse);
 
                    if (null != captureresponsedata.address)
                    {
                        foreach (idmdataaddress idmdataaddress in captureresponsedata.address)
                        {
                            string formattedaddress = idmdataaddress.formattedaddress;
                            treenode tnaddress = new treenode(formattedaddress);
                            tnresponse.nodes.add(tnaddress);
                            if ((null != idmdataaddress.persons) &&
                                (null != idmdataaddress.persons.person) &&
                                (idmdataaddress.persons.person.length > 0))
                            {
                                foreach (idmdatacaptureperson idmdatacaptureperson
                                    in idmdataaddress.persons.person)
                                {
                                    string personname = idmdatacaptureperson.firstname +
                                        " " + idmdatacaptureperson.middlename +
                                        " " + idmdatacaptureperson.lastname;
                                    treenode tnperson = new treenode(personname);
                                    tnaddress.nodes.add(tnperson);
                                    if ((null != idmdatacaptureperson.consentedemails) &&
                                        (0 < idmdatacaptureperson.consentedemails.length))
                                    {
                                        foreach(idmdatasourcedvalue idmdatasourcedvalue
                                            in idmdatacaptureperson.consentedemails)
                                        {
                                            string email = idmdatasourcedvalue.value;
                                            treenode tnemail = new treenode(email);
                                            tnperson.nodes.add(tnemail);
                                        }
                                    }
                                    if ((null != idmdatacaptureperson.consentedlandlines) &&
                                        (0 < idmdatacaptureperson.consentedlandlines.length))
                                    {
                                        foreach (idmdatasourcedvalue idmdatasourcedvalue
                                            in idmdatacaptureperson.consentedlandlines)
                                        {
                                            string landline = idmdatasourcedvalue.value;
                                            treenode tnlandline = new treenode(landline);
                                            tnperson.nodes.add(tnlandline);
                                        }
                                    }
                                    if ((null != idmdatacaptureperson.consentedmobiles) &&
                                        (0 < idmdatacaptureperson.consentedmobiles.length))
                                    {
                                        foreach (idmdatasourcedvalue idmdatasourcedvalue
                                            in idmdatacaptureperson.consentedmobiles)
                                        {
                                            string mobile = idmdatasourcedvalue.value;
                                            treenode tnmobile = new treenode(mobile);
                                            tnperson.nodes.add(tnmobile);
                                        }
                                    }
                                }
                            }
                        }
                    }
 
                    if (null != captureresponsedata.groupedrelateddata)
                    {
                        foreach (idmdataadditionaldatagroup idmdataadditionaldatagroup
                                in captureresponsedata.groupedrelateddata)
                        {
                            string name = idmdataadditionaldatagroup.name;
                            treenode tndatagroup = new treenode(name);
                            tnresponse.nodes.add(tndatagroup);
                            foreach (idmdataitem idmdataitem in idmdataadditionaldatagroup.item)
                            {
                                treenode tnitem = new treenode(idmdataitem.key + "=" + idmdataitem.value);
                                tndatagroup.nodes.add(tnitem);
                            }
                        }
                    }
                }
            }
        }
    }
}

Parsing Web Service Response

ProfileResponseDisplay is a helper class given as an example as to how to parse the web service response. The class parses the response and returns a set of key value for display in the UI:

class profileresponsedisplay
{
    public string componentname { get; set; }
    public string componentstatus { get; set; }
    public string action { get; set; }
    public string notes { get; set; }
    public profileresponsedetails profileresponsedetails { get; set; }
 
    private static string seperator = " | ";
 
    public profileresponsedisplay(profileresponsedetails profileresponsedetails)
    {
        this.componentname = profileresponsedetails.componentname;
        this.componentstatus = profileresponsedetails.componentstatus.tostring();
        this.action = profileresponsedetails.componentaction;
        this.notes = profileresponsedetails.notes;
        this.profileresponsedetails = profileresponsedetails;
    }
 
    public string displayvalue
    {
        get { return this.componentname + seperator + this.action + seperator + this.componentstatus; }
    }
 
    public profileresponsedisplay value
    {
        get { return this; }
    }
 
    /**
    * gets the lookup results from the executecaptureresponse.
    */
    public list<validateresponsedatadisplay> getvalidateresponse()
    {
        list<validateresponsedatadisplay> validateresponsedata = new list<validateresponsedatadisplay>();
        if (this.profileresponsedetails != null
            && this.profileresponsedetails.validateresponse != null
            && this.profileresponsedetails.validateresponse.response != null)
        {
            foreach(validateresponsedata responsedata in
                   this.profileresponsedetails.validateresponse.response.tolist<validateresponsedata>())
            {
                // adds an object that combines the key and value separated by " = "
                validateresponsedata.add(new validateresponsedatadisplay(responsedata));
            }
        }
        return validateresponsedata;
    }
 
    /**
    * gets the addresses from the executecaptureresponse.
    */
    public list<idmdataaddress> getaddresses()
    {
        list<idmdataaddress> addresses = new list<idmdataaddress>();
 
        if (this.profileresponsedetails != null
                && this.profileresponsedetails.captureresponse != null
                && this.profileresponsedetails.captureresponse.response != null)
        {
            foreach (captureresponsedata data in this.profileresponsedetails.captureresponse.response)
            {
                addresses = data.addresses.address.tolist<idmdataaddress>();
            }
        }
 
        return addresses;
    }
}

The two methods to note here are the getValidationResponse() and the getAddresses() they safely return the telephone results and the addresses matched.

Integrating AddressBase Premium

The following sample code shows the additional integration of the AddressBase Premium capture service.

A tab control has been added to the page to run the simple AddressBase Premium lookup.

You can get the latest source from the zip file at the bottom of this document.

In order to call the Web Service the ExecuteCaptureRequest request object must be created containing the input data for address lookup. The table below summarises the objects required:

Object Description
ExecuteCaptureRequest The top level request object containing the data for the web service method
ProfileRequestCapture Contains the IdM profile data
ProfileRequestCaptureData Contains the input data
IdmDataSearchAddress Contains the search address
IdmRequestOptions Contains options required for the request


The following code demonstrates setting up the request data that is passed into the code above:

public executecaptureresponse addressbasepremiumlookup(
    string postcode,
    string building)
{
    var requestoptions = new idmrequestoptions
    {
        addresssearchlevel = enumaddresslevel.premise,
        casing = enumcasing.mixed,
        maxreturn = 100,
        offset = 0,
        addressenvelopeformat = "a3tcp"
    };
 
    // create the address
    var searchaddress = new idmdatasearchaddress()
    {
        building = building,
        postcode = postcode,
    };
 
    // create the profile request capture data
    var profilerequestcapturedata = new profilerequestcapturedata()
    {
        address = searchaddress,
        options = requestoptions,
    };
    // create the profile request capture
    var profilerequestcapture = new profilerequestcapture()
    {
        // set the profile you wish to call (the profile dictates which services are used)
        profileguid = this.profileguid,
        configurationid = 1,
        // customer reference is stamped on the audit trail for each query
        customerreference = "samplecode",
        requestdata = profilerequestcapturedata
    };
Handling the Web Service Return (ExecuteCaptureResponse) for AddressBase Premium lookup

Once you have successfully called the web service and retrieve a valid response you can start to handle the results. The following code provides a high level overview of processing the results:

private void btnabprlookup_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        executecaptureresponse response = null;
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofileabpr.text;
            response = this.globalservicesws.addressbasepremiumlookup(
                txtabprpostcode.text,txtabprbuilding.text);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
        this.displaycaptureresponse(response, tvabprresults);
    }
}

The display method can be updated to show specific AddressBase Premium data. i.e.

foreach (idmdataaddress idmdataaddress in captureresponsedata.address)
{
    string formattedaddress = idmdataaddress.formattedaddress;
    treenode tnaddress = new treenode(formattedaddress);
    tnresponse.nodes.add(tnaddress);
 
    // addressbasepremium data
    if (!string.isnullorempty(idmdataaddress.aposapr))
        tnaddress.nodes.add(new treenode("osapr=" + idmdataaddress.aposapr));
    if (!string.isnullorempty(idmdataaddress.osal2toid))
        tnaddress.nodes.add(new treenode("al2toid=" + idmdataaddress.osal2toid));
    if (!string.isnullorempty(idmdataaddress.ositntoid))
        tnaddress.nodes.add(new treenode("itntoid=" + idmdataaddress.ositntoid));
    if (!string.isnullorempty(idmdataaddress.ostopotoid))
        tnaddress.nodes.add(new treenode("topotoid=" + idmdataaddress.ostopotoid));
 
    idmdatablpu blpu = idmdataaddress.blpu;
    if (null != blpu)
    {
        treenode tnblpu = new treenode("blpu");
        tnaddress.nodes.add(tnblpu);
        tnblpu.nodes.add(new treenode("state=" + blpu.blpustate.tostring()));
        if (null != blpu.blpustartdate)
            tnblpu.nodes.add(new treenode("startdate=" + blpu.blpustartdate.tostring()));
        tnblpu.nodes.add(new treenode("logicalstatus=" + blpu.blpulogicalstatus.tostring()));
        tnblpu.nodes.add(new treenode("easting=" + blpu.easting.tostring()));
        tnblpu.nodes.add(new treenode("northing=" + blpu.northing.tostring()));
    }
 
    idmdatalpi lpi = idmdataaddress.lpi;
    if (null != lpi)
    {
        treenode tnlpi = new treenode("lpi");
        tnaddress.nodes.add(tnlpi);
        if (!string.isnullorempty(lpi.lpikey))
            tnlpi.nodes.add(new treenode("key=" + lpi.lpikey));
        if (!string.isnullorempty(lpi.level))
            tnlpi.nodes.add(new treenode("level=" + lpi.level));
        if (!string.isnullorempty(lpi.lpilanguage))
            tnlpi.nodes.add(new treenode("language=" + lpi.lpilanguage));
        tnlpi.nodes.add(new treenode("logicalstatus=" + lpi.lpilogicalstatus.tostring()));
    }
}

Integrating Matchcode Names

The following sample code shows the additional integration of the Matchcode Names capture service.

A tab control has been added to the page to run the simple Matchcode Names lookup.

You can get the latest source from the zip file at the bottom of this document.

In order to call the Web Service the ExecuteCaptureRequest request object must be created containing the input data for Names lookup. The table below summarises the objects required:

Object Description
ExecuteCaptureRequest The top level request object containing the data for the web service method
ProfileRequestCapture Contains the IdM profile data
ProfileRequestCaptureData Contains the input data
IdmDataSearchAddress Contains the search address
IdmDataCapturePerson Contains ther person information
IdmDataArrayOfCapturePerson Contains the IdmDataCapturePerson
IdmRequestOptions Contains options required for the request


Within the address contains a list of people this is where the IdmDataArrayOfCapturePerson can be found.

Code for the search button:

private void btnnameslookup_click(object sender, eventargs e)
{
    using (waiter hourglass = new waiter(this))
    {
        executecaptureresponse response = null;
        txtmessages.text = string.empty;
 
        // attempt to do a lookup.
        try
        {
            this.globalservicesws.profileguid = txtprofilematchcodenames.text;
            response = this.globalservicesws.lookupmatchcodenames(
                txtnamesfirstname.text, txtnameslastname.text,
                txtnamesbuilding.text, txtnamespostcode.text);
        }
        catch (soapexception exception)
        {
            txtmessages.text = exception.detail.value;
        }
        // fill the errors text box with any error messages.
        catch (exception exception)
        {
            txtmessages.text = exception.message;
            txtmessages.text += "\r\n" + exception.source;
        }
 
        this.displaycaptureresponse(response, tvnamesresults, "matchcodenames");
    }
}

The following method shows the construction of the request:

public executecaptureresponse lookupmatchcodenames(
        string firstname, string lastname, string building, string postcode)
    {
        // create the options
        var requestoptions = new idmrequestoptions
        {
            addresssearchlevel = enumaddresslevel.premise,
            casing = enumcasing.mixed,
            maxreturn = 100,
            offset = 0,
            addressenvelopeformat = "a3tcp"
        };
 
        // create the person
        list<idmdatacaptureperson> listofperson = new list<idmdatacaptureperson>();
        var person = new idmdatacaptureperson()
        {
            firstname = firstname,
            lastname = lastname
        };
        listofperson.add(person);
        // convert to idm array type
        var idmdataarrayofcaptureperson = new idmdataarrayofcaptureperson()
        {
            person = listofperson.toarray()
        };
 
 
    // create the address
    var searchaddress = new idmdatasearchaddress()
    {
        persons = idmdataarrayofcaptureperson,
        building = building,
        postcode = postcode,
    };
 
    // create the profile request capture data
    var profilerequestcapturedata = new profilerequestcapturedata()
    {
        address = searchaddress,
        options = requestoptions,
    };
 
    // create the profile request capture
    var profilerequestcapture = new profilerequestcapture()
    {
        // set the profile you wish to call (the profile dictates which services are used)
        profileguid = this.profileguid,
        configurationid = 1,
        // customer reference is stamped on the audit trail for each query
        customerreference = "samplecode",
        requestdata = profilerequestcapturedata
    };
 
 
    // create the top level request object
    executecapturerequest request = new executecapturerequest()
    {
        profilerequest = profilerequestcapture
    };
 
 
    // call the service and return the web service response
    executecaptureresponse executecaptureresponse = this.executecapture(request);
 
    // return
    return executecaptureresponse;
}

For a better understanding of the request/response see the Integration Guide which will contain an address search with returned people.

Exception Handling

The following exception handling code will be able to handle business exceptions and service exceptions. The BusinessExceptions can contain things like: Invalid Authentication Token, Locked account and Invalid profile. They are useful for determining what is wrong with the executing account. You can see the Integration Guide for a list of some of the common BusinessExceptions.

try
{
// put here handling of the web service return (executecaptureresponse),
    i.e. for telephone or bank account lookup
}
catch (soapexception exception)
{
    // soapexception caught use idmexceptionhandler to see if it is a business or service exception.
    soapexception convertedexception = util.idmexceptionhandler.getexception(exception);
 
    // check to see if the exception is a businessexception
    if (convertedexception.gettype() == typeof(util.businessexception))
    {
        // we know it is a businessexception so cast the convertedexception to businessexception
        // so codes can be retrieved.
        util.businessexception businessexception = (util.businessexception)convertedexception;
 
        // display a different message for invalid credentials
        if (businessexception.errorcode.equals("be010009"))
        {
            txtmessages.text = "incorrect credentials: check username and password";
        }
        // otherwise use a more general message.
        else
        {
            txtmessages.text = "business exception caught: "
                + businessexception.errorcode + ": " + businessexception.message;
        }
    }
    // check to see if the exception is a serviceexception
    else if (convertedexception.gettype() == typeof(util.serviceexception))
    {
        // we know it is a serviceexception so cast the convertedexception to serviceexception
        // so codes and transactionguid can be retrieved.
        util.serviceexception serviceexception = (util.serviceexception)convertedexception;
        // this method for the serviceexception returns an error message with the transactionguid
        // so the error can be identified by helpdesk or the idm team.
        txtmessages.text = serviceexception.geterrormessage();
    }
    // if the exception is not a business or service exception then handle the soapexception here.
    else
    {
        // just show the error message.
        txtmessages.text = "soapexception caught: "+ convertedexception.detail;
    }

This demonstrates how to catch exceptions and handle them with user friendly messages. The BusinessException, ServiceException and IdmExceptionHandler can be found in the sample code attached.

Project Source Code

Download the source code here: IdMGlobalServicesIntegration

Powersearch Sample Code

A simple UI Global PowerSearch client has been proposed with the aim of providing a suggestion on how to consume this web service by a C# .net application. The application has two distinctive components: the main ui form and the PowerSearchSampleCode.Service package. The former is a trivial gui and no further details are going to be described in this document. The latter encapsulates all the http connection logic and just exposes a regular C# static method with a PowerSearchRequest class as an argument and a PowerSearchResponse as the returned value so the service can be used seamlessly with other .Net code. This component is explained below.

Building the request

Global Powersearch is a REST web service and requires an authenticathed and authorised user. There is not an ad-hoc authentication service, therefore this is done in each Global Powersearch call.

Only two elements are needed to build a request, the authentication header and the parameters. The authentication header is the only mandatory HTTP header of the request.

Authentication is done under basic access authentication protocol RFC2045-MIME so this is not secured by default, therefore the service runs under HTTPS to protect user's credentials as well as the content.

There is not a specific authenticate web service call, instead, all requests should be contained in the header field "Authentication". This field should follow the RFC2045-MIME specification.

The next method in the sample code is responsible for generating that header:

/// 
/// generates the basic access authentication header based on
/// rfc2045-mime. notice this protocol does not provide security.
/// to provide a security layer service should be running under https.
/// 
///idm username
///password belonging to the username
/// 
private static authenticationheadervalue createbasicheader(string username, string password)
{
    return new authenticationheadervalue("basic", convert.tobase64string(encoding.utf8.getbytes(username + ":" + password)));
}

The algorithm concatenates the strings username, ":" and password. The result is encoded in base64 and the header is created under the scheme "basic". The client uses the HttpClient provided by the .Net Framework to encapsulate the network complexities, so the authentication header must be built as an AuthenticationHeaderValue object.

The last step will be generating the request parameters. In order to make the data manipulation easier, the parameters are encapsulated in the class PowerSearchRequest. The lookup method will read the request in order to reconstruct the final URL.

country + geocode + address + format (where country and address are mandatory and geocode and format optional).

Once we have the authentication header and URL, eventually, the web service call can be executed.

Building the response

The response can be retrieved as a stream. Since the response is formatted in XML, this can be easily de-serialised onto a C# object to facilitate the access to the information from the C# code.

// xml parse
var data = await response.content.readasstreamasync();
var serializer = new xmlserializer(typeof(response));
var reader = xmlreader.create(data);
 
// use the deserialize method to restore the object's state.
var response = (response)serializer.deserialize(reader);

Inside the response object, the field 'matches' contain a list of strings of free formatted addresses and a field 'address' which encapsulates the free formatted address and the geolocation information.

Project Source Code

Download the source code here: PowerSearchSampleCode

Get started for free today

  • No credit card required
  • Cancel any time
  • 24/5 support
Get started