WFC-Web Servies From Appeon Power Builder
WFC-Web Servies From Appeon Power Builder
WFC-Web Servies From Appeon Power Builder
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.
PowerBuilder Classic and WCF
One option for accessing WCF from PowerBuilder Classic, 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 (requiresadding 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 (rather complicated)
PowerBuilder Classic and WCF
string _responseGroup[]
I used "wcfclient" for the client and
wcfclient.ItemSearch _itemsearch "TeamSybase" for the service.
wcfclient.ItemSearchRequest _itemsearchrequest
wcfclient.ItemSearchRequest _isr[] I also renamed the non visual object
created by the WCF client project to just
wcfclient.ItemSearchResponse _itemsearchresponse
TeamSybase.awsecommerceservice _client
"awsecommerceservice". The original
name generated by the WCF client
System.Collections.IEnumerator _itemsenum
System.Collections.IEnumerator _itemenum
wcfclient.Item _item project was quite long.
wcfclient.Items _items
_client.wcfConnectionObject.SoapMessageHeader.AddMessageHeaderItem(&
"Signature",&
"http://security.amazonaws.com/doc/2007-01-01/",&
_secretKey,&
PBWCF.WCFHMAC.HMACSHA256!,&
"")
SetPointer ( HourGlass! ) Once again I'm returning more data in
Try
// issue the ItemSearch request
this example than I did in 2012, so
_itemsearchresponse = _client.ItemSearch(_itemsearch); we're using a type to collect the data
// write out the results
_itemsenum = _itemsearchresponse.Items.GetEnumerator()
and accessing more attributes.
do while _itemsenum.MoveNext() Because I'm trying to keep this simple,
_items = _itemsenum.Current I'm only pulling the first author for a
_itemenum = _items.Item.GetEnumerator()
do while _itemenum.MoveNext() book if there are multiple authors.
_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
The ListPrice may be null.
Not checking for the null that and
if not IsNull ( _item.ItemAttributes.ListPrice ) then trying to assign the value directly will
items[index].Price = _item.ItemAttributes.ListPrice.FormattedPrice
end if cause a runtime exception
index = index + 1
loop
loop
catch ( System.Exception e )
items[1] = create TeamSybase.n_item
items[1].Title = e.Message
end try
return items
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
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.
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
For changes to the 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 IncludeExceptionDetailInFaul
ts.
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.
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.
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
The calling thread must be STA, because web service proxy.
many UI components require this. Since WPF is UI technology, if you don't
select this options you'll get a .Net
exception
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.
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.
Test the service
We’re 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
SOAPUI will create a sample request
for you automatically.
Run that, and you should get data
back
If not, resolve the errors shown from
the returned exception.
Assuming all is good, it's time to use
this from PowerBuilder Classic.
Calling the
service from
PowerBuilder
Classic
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.
We’re going to a Grid Datawindow
that uses our new proxy web service.
Select New -> DataWindow -> Grid
For source, select Web Service
On the next page in the wizard, enter
the same value for the WSDL that you
gave SOAPUI earlier.
On the next page, there should only
be one service, select it.
Now you need to select the method
you want to call.
Choose the Search method (or
whatever you called it).
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.
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:
dw_1.Retrieve()
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.
Questions?