Sunday, July 31, 2016

Calling WCF web services from PowerBuilder Native through a proxy web service

One of the issues with PowerBuilder Native's support for web services is that it is based on ASP.Net Web Services.  That technology, introduced with .Net 1.0, doesn't provide support for anything other than simple XML over HTTP SOAP services.  Microsoft introduced WCF web services in .Net 3.0 to provide support for a much creater variety of SOAP services.  In particular, WCF web services:

  • Can be accessed through protocols other than HTTP, such as TCP or named pipes.
  • Added support for web services standards such as WS-Security, WS-Addressing, WS-ReliableMessaging, WS-Coordination and WS-AtomicTransaction.
So what can you do if you need to consume a web service that requires support for alternate protocols, those latter web services standards or both?

One option, which I included in a PBDJ article from January of 2012, is to create a WCF client using PowerBuilder.Net or Visual Studio.Net, packaging that up in a .Net assembly, and then exposing the assembly to PowerBuilder Native as a COM object via COM Callable Wrappers.

That technique works, but it requires either:
  • configuration of the desktop (adding the assembly to the GAC and creation of registry entries) or 
  • a side-by-side assembly deploy and creation of manifest files to support registry free COM
In some workplaces the first isn't allowed, and the second is rather complicated.

What we're going to look at today is another approach for consuming more advanced web services from PowerBuilder Native, but one which won't require desktop configuration or complicated manifest creation.  What is will require is a web server inside your firewall that you can deploy a proxy WCF service on.

For this example, we're going to use the Amazon Web Services Product Advertising API as the more complicated web service that we can't access directly from PowerBuilder Native.  That's largely because Amazon requires custom headers -- including signing of the request.  That's the same example that I used in that article from 2012.  We're going to use very similar code, so I won't explain what all of it does.  You can refer back to the 2012 article for that explanation.  What I will explain though are the differences between the code we're going to use for this example and the code from 2012.

Once again for this example we're going to use PowerBuilder.Net to create the WCF client.  The same technique will work if you decide to use Visual Studio.Net instead, the main differences are in the way that you'll configure the WCF service you create with that IDE.

The first thing we'll need to do is create a WCF service.

Figure 1 - New WCF Service

When you get to the page in the wizard that asks you for the object to create, select Custom Nonvisual and give it a name:

Figure 2 = WCF Service Object

Although the "Finish" button on the wizard is enabled at this point I would recommend clicking "Next" instead until you get to the Hosting Options page.  On that page, select "Console ("Self-Hosted") application rather than the default of IIS.  Now click "Finish".

Figure 3 - WCF Service Hosting Options

We'll come back to the WCF Service in a bit.  The next thing we want to do is create a WCF client proxy in the WCF Service target.

Figure 4 - New WCF Client

When you get to the page that asks for the service URL, we (at least at the time of the writing of this article) need to do a bit of a hack.  What you would normally do here is enter the URL that the Amazon Web Services WSDL is located:

Figure 5 - WCF Client URL

The problem isn't with PowerBuilder.  It's actually with the Amazon Web Services.  The bug that was filed on the problem back in 2011 is available here, and it also discusses the solution.  I'm not quite sure why Amazon hasn't fixed it yet.  The problem is that what Amazon says it's going to return int the WSDL for the ImageSets property of an Item and what it actually does return are two different things.  Perhaps Java or other web service clients handle that gracefully, but C# doesn't.  If you create a proxy directly off Amazon's WSDL and call the ItemSearch method, what you'll get is a .Net exception of:

error CS0030: Cannot convert type 'AmazonService.AWSECommerceServiceAPI.ImageSet[]' to 'AmazonService.AWSECommerceServiceAPI.ImageSet'

The solution is to download the WSDL to your workstation, open it in an editor (I recommend Notepad++) and then change line 584 from:

<xs:element name="ImageSets" minOccurs="0" maxOccurs="unbounded">
<xs:element name="ImageSets" minOccurs="0" maxOccurs="1">

Now reference that file on your workstation rather than the original Amazon WSDL in the web service client proxy wizard.  Once you've created the proxy project, run it to create the WCF client.  The project will end up generating something like 11 different non-visual user objects.  That's because the Amazon WSDL contains 11 different service binding, one for each of the country websites ( CA, CN, DE, ES, FR, IN, IT, JP, UK and US ).  There is also a default one set to US.  If you're in the US, keep the first one and delete the rest.  If you're in a different country use the one that is for your country and delete the others.

Figure 6 - Amazon Web Service Bindings

We need a data type to use to return the data from the proxy service.  I created a custom non-visual user object called n_item and added the following as instance variables on that object:

string Title
string Author
string Publisher
string ISBN
string PublicationDate
string Price

I defined them all as strings because that's the data type that Amazon uses to return them.  Note that I'm using a non-visual object rather than a structure here.  That's because for purposes of returning data from a web service, non-visual object handle representations of nulls better than structures do.

Now go back to the non-visual object that was created by the WCF Service wizard.  We want to create a function on that object that uses the WCF client to talk to Amazon and then returns the data to PowerBuilder Native.  I've called the method of_search.  For this example, I'm not passing any arguments.  For the return, I've indicated that it will return an array of the n_item non-visual object I just defined.  (One nice feature of PowerBuilder.Net is that is does support returning arrays from functions).

Now for some code.  You'll need to adjust the following based on what namespace you used for your WCF proxy and WCF service.  I used "wcfclient" for the client and "TeamSybase" for the service.  I also renamed the non visual object created by the WCF client project to just "awsecommerceservice".  The original name generated by the WCF client project was quite long.

string _accessKeyId = "XXXXXXXXXXXXXXXX"
string _secretKey = "YYYYYYYYYYYYYYY"
string _associatetag = "ZZZZZZZZZZZZZZZ"

string _responseGroup[]
wcfclient.ItemSearch _itemsearch
wcfclient.ItemSearchRequest _itemsearchrequest
wcfclient.ItemSearchRequest _isr[]
wcfclient.ItemSearchResponse _itemsearchresponse
TeamSybase.awsecommerceservice _client
System.Collections.IEnumerator _itemsenum
System.Collections.IEnumerator _itemenum
wcfclient.Item _item
wcfclient.Items _items
TeamSybase.n_item items[]
integer index = 1

// create a WCF Amazon ECS client
_client = create TeamSybase.awsecommerceservice

// Configure the client
_client.wcfConnectionObject.EndpointAddress.URL = ""
_client.wcfConnectionObject.BasicHttpBinding.Security.SecurityMode = PBWCF.BasicHttpSecurityMode.TRANSPORT!
_client.wcfConnectionObject.BasicHttpBinding.MaxReceivedMessageSize = 1000000

// prepare an ItemSearch request
_itemsearchrequest = create wcfclient.ItemSearchRequest
_responseGroup[1] = "Medium"
_itemsearchrequest.SearchIndex = "Books"
_itemsearchrequest.Title = "PowerBuilder"
_itemsearchrequest.ResponseGroup = _responseGroup
_itemsearch = create wcfclient.ItemSearch
_isr[1] = _itemsearchrequest
_itemSearch.Request = _isr
_itemSearch.AWSAccessKeyId  = _accessKeyId
_itemsearch.AssociateTag = _associatetag



SetPointer ( HourGlass! )

  // issue the ItemSearch request
  _itemsearchresponse = _client.ItemSearch(_itemsearch);
  // write out the results
  _itemsenum = _itemsearchresponse.Items.GetEnumerator()
  do while _itemsenum.MoveNext()
    _items = _itemsenum.Current
    _itemenum = _items.Item.GetEnumerator()
    do while _itemenum.MoveNext()
       _item = _itemenum.Current
  items[index] = create TeamSybase.n_item
  items[index].Title = _item.ItemAttributes.Title
  items[index].Author = _item.ItemAttributes.Author[1]
  items[index].Publisher = _item.ItemAttributes.Publisher
  items[index].ISBN = _item.ItemAttributes.ISBN
  items[index].PublicationDate = _item.ItemAttributes.PublicationDate
  if not IsNull ( _item.ItemAttributes.ListPrice ) then
  items[index].Price = _item.ItemAttributes.ListPrice.FormattedPrice
  end if
  index = index + 1
catch ( System.Exception e )
  items[1] = create TeamSybase.n_item
  items[1].Title = e.Message
end try

return items

Note that I'm not providing you with an access key, secret key or associate tag for Amazon.  You'll need to sign up with their web services program for the first two items and their associates program for the third.  Once you've signed up with their web services program, you'll find the access key and secret key under Security Credentials:

Figure 7 - Amazon Web Services Management Console

Figure 8 - Amazon Web Services Security Credentials

You get the secret key when you generate the access key.

Your associate tag is located in the upper right hand corner of your Amazon Associates account page.

Figure 9 - Amazon Associates Account Page

Ok, now to cover some of the differences between the code I used in 2012 and the code above.

_client.wcfConnectionObject.BasicHttpBinding.MaxReceivedMessageSize = 1000000

As will be noted a bit later, I changed the ResponseGroup for the request form "Small" (2012) to "Medium" (today). That's because in 2012 I was just returning titles and today I want more information ( authors, publisher, publication date, etc) that required getting more data back in the service response. So much data in fact, that it exceeds the default size that WCF allows for the size of the message (65,536 bytes).  I've increased the size significantly to allow for the additional data.

_responseGroup[1] = "Medium"

As just noted, in 2012 I used "Small" because I only wanted the titles.  I'm using "Medium" now to get more data.

_itemsearch.AssociateTag = _associatetag

This is a result of changes that Amazon made since 2012.  They now require that you provide them with an associates tag in every Product Advertising API web service request.

    do while _itemenum.MoveNext()
       _item = _itemenum.Current
  items[index] = create TeamSybase.n_item
  items[index].Title = _item.ItemAttributes.Title
  items[index].Author = _item.ItemAttributes.Author[1]
  items[index].Publisher = _item.ItemAttributes.Publisher
  items[index].ISBN = _item.ItemAttributes.ISBN
  items[index].PublicationDate = _item.ItemAttributes.PublicationDate
  if not IsNull ( _item.ItemAttributes.ListPrice ) then
  items[index].Price = _item.ItemAttributes.ListPrice.FormattedPrice
  end if
  index = index + 1

Once again I'm returning more data in this example than I did in 2012, so we're using a type to collect the data and accessing more attributes.  Because I'm trying to keep this simple, I'm only pulling the first author for a book if there are multiple authors.

Now that we've defined the method for our web service we need to go back to the web service project object that was created by the wizard.  When the wizard was first run, there were no methods on the non-visual object and so there was nothing to expose in the service.  Now we have a method to expose.

Figure 10 - WCF Service Options

So we need to check the checkbox in front of our new method so the project knows what to expose.  I've also give the service an alias of "Search" that is a bit more web service friendly than "of_search".  I should probably also alias the web service name as well, but haven't done so for this example.  Nor have I changed the target namespace, which you should do for a production web service.

There's a few other things I've customized here, and you'll need to do the same.   I'll explain what each of them is.  Note for changes to the service attributes (that apply to all of the operations) you'll use the Service Attribute button to bring up that dialog to select those options, whereas for operations attributes (which only apply to specific methods of the service) you'll use the Operations Attribute button and it's resulting dialog.

Under Service Behavior attributes, I've enabled IncludeExceptionDetailInFaults.  I've done that primarily for debugging purposes.  Once you've got the web service working and want to move it to production you'll want to turn that off.

Figure 11 - WCF Service Behavior Attributes Dialog

I've also checked the XmlSerializerFormat option.  By default, WCF services use the DataContractSerializer.  ASP.Net web services (what PowerBuilder Native uses for web services) uses the XmlSerializerFormat and can't properly handle the response from the DataContractSerializer.  The XMLSerializerFormat option in WCF allows us to create a WCF service that uses a serializer that older technology clients like PowerBuilder Native can understand.

Under Operation Attributes, the OperationContract Name attribute is set for us by the project when we alias the name of the method.  What I've done in addition to that is set the STAOperationalBehavior attribute.  That forces the method to be invoked under a single threaded apartment (STA) threads.  By default, WCF uses multi-threaded apartment (MTA) threads.

Figure 12 - WCF Operations Behavior Attributes Dialog

The only reason we need to do this is that, for reasons I'm not clear on, PowerBuilder.Net includes references to WPF classes when you create a web service proxy.  Since WPF is UI technology, if you don't select this options you'll get a .Net exception that indicates:

The calling thread must be STA, because many UI components require this.

That's because .Net notices the references to WPF classes in the project.  It may be possible to remove those references, but I haven't attempted that yet.  Of course, if you're using Visual Studio.Net to create the proxy WCF web service you shouldn't have this issue because Visual Studio .Net won't create such references.

Do a full build on the WCF Service.  Once you've done that, you can go back into the WCF Service project, go to the Run tab, and point the "Application" property to the wcfservice_host.exe file that got deployed with the build.

Figure 13 - WCF Service Run Options

Once you've done that you can then right click on the WCF Service project and select "Run" whenever you want to run the service.  It will run in a command prompt window.

Figure 14 - WCF Service Running Self Hosted

We're now ready to test the service.  I'm going to use SOAPUI (the open source version) for that, both because it makes generating a "client" for the new service very easy and because it will show us any exceptions being thrown by the service.

Create a new project in SOAPUI, select Add WSDL, and then copy the WSDL information from the WCF service project into the WSDL Location prompt in SOAPUI:

Figure 15 - WCF Service WSDL Location

Figure 16 - SOAPUI Add WSDL Dialog

SOAPUI will create a sample request for you automatically.  Run that, and you should get data back:

Figure 17 - SOAPUI Calling WCF Service

If not, resolve the errors shown from the returned exception.  Assuming all is good, it's time to use this from PowerBuilder Native.

Create a new workspace and a new target of type application in PowerBuilder Native.  Create a new window (lets say w_main).  Add the following to the open event of the application:

Open ( w_main )

That's the bare minimum of a PowerBuilder Native application.  Now lets create a Grid Datawindow that uses our new proxy web service.

After you've selected New -> DataWindow -> Grid, select web service as the source.

Figure 18 - New Web Service Based DataWindow

On the next page in the wizard, enter the same value for the WSDL that you gave SOAPUI earlier.

Figure 19 - Web Service DataWindow Service URL Dialog

On the next page, there should only be one service, select it.

Figure 20 - Web Service DataWindow Service Selection

Now you need to select the method you want to call.  Choose the Search method (or whatever you called it).

Figure 21 - Web Service DataWindow Method Selection

On the next page you'll need to select what data the datawindow is going to show.  In this case there's only one option, the result set from the service.  Select it and hit Next.

Figure 22 - Web Service DataWindow Data Selection

Continue through the remainder of the wizard and PowerBuilder will create the DataWindow for you.  You can preview it and it should display the data we saw in SOAPUI.

Drop that new datawindow onto the w_main window.  Just to make things simple we're only going to add two more lines of code.  In the open event of the window add this:


And in the resize event of the window add this:

dw_1.Resize ( newwidth - 100, newheight - 100 )

We're done.  Run the app and you should see the data being returned from the Amazon web services into our PowerBuilder Native application.

Figure 23 - PowerBuilder Native Consuming Amazon Web Service

Wednesday, July 27, 2016

PowerBuilder TV Webcast: PowerGen 2016

Automating the PowerBuilder Build Process with PowerGen 2016
Presenter: Phil Wallingford
Tuesday, October 11, 2016 at 8:00 AM PST (Los Angeles) / 17H00 PM CET (Paris).

An essential tool to automate the building of PowerBuilder applications, it lets you use command line functions to automate the entire build, create libraries from object source. With PowerGen, you can control your builds with predictability and reliability.

PowerBuilder TV Webcast: Bootstrap for PowerBuilder

Bootstrap for PowerBuilder
Presenter: Roland Smith
Tuesday, October 4, 2016 at 8:00 AM PDT (Los Angeles) / 17H00 CEST (Paris)

Download the source files of a PBT from your source control system and import the objects into empty library files that it creates for you. Follow that up with any rebuilds and regenerates that are needed to get all objects to compile successfully. With PowerBuilder Bootstrap:

  • Extract all source code files for a target from a source control system
  • Create new library files for a target and import all the object source code files
  • Generate a new PBC file for a workspace
  • Optimize all libraries for a target
  • Compile the executable files for a target and copy to a deployment folder

PowerBuilder TV Webcast: PowerVCS

PowerBuilder Version and Source Control with PowerVCS
Presenter: Phil Wallingford
Tuesday, September 20, 2016 at 8:00 AM PDT (Los Angeles) / 17H00 CEST (Paris)

A web-based solution where repository data resides on a secure Web server and source control functions are accessible with a browser. For those of you who have reached the limits of “PBNative”, who miss Object Cycle, or who have yet to implement a source control system of any description. See how PowerVCS is an ideal solution for locally and geographically distributed development teams.

Future of PowerBuilder webcast - Part 5 - Low Level Roadmap

Part 5 of the Future of #PowerBuilder webcast (Low Level Roadmap) starts at 9:00 AM PST tomorrow (July 28th). If you have not already signed up, you can still do so at

Monday, July 25, 2016


I created a 12.6 build of PBNISMTP back in April of 2015 but never updated the downloads or source code.  That's been corrected.

More recently, I moved the project to VS2015.  It has also been updated to the most recent version of CPJNSMTPConnection (3.17). The VS2008 code is still available but will no longer be maintained.

Since CPJNSMTPConnection is dependant on CWSocket I updated that to the latest version as well (3.17),  The new version on CPJNSMTPConnection also no longer references OpenSSL, but instead uses SSLWrappers  and CryptoWrappers

I did have to make one minor change to CWSocket. For some reason, CPJNSMTPConnection was still calling a Delete method on CWSocket that had been removed in the latest version. I added a noop Delete method so that the code would continue to compile.

The only PowerBuilder sample provided is for PowerBuilder 12.6. If you want to use the utility with an earlier version of PowerBuilder you will need to download the C++ source and compile it referencing the PBNI/SDK files for that release.

Note that the PBX files are significantly larger than they were when VS2008 was used to compile them. That's because of a change that Microsoft made in the way files that dynamically link to MFC are compiled starting in VS2010.