Welcome!

PowerBuilder Authors: Chris Pollach, Avi Rosenthal, Yakov Fain, RealWire News Distribution, Al Soucy

Related Topics: PowerBuilder, SOA & WOA, .NET

PowerBuilder: Article

Creation and Consumption of Web Services with PowerBuilder

Web services support has been significantly enhanced in PowerBuilder.NET

Creating a WCF Service Target in PowerBuilder.NET
Now let's see how to create a WCF Service. The first thing we'll do is select the WCF Service target type from the New dialog (see Figure 5).

Figure 5

The first step of the wizard will ask you if you want to create a new WCF Service, or if you want to migrate over an existing PowerBuilder Classic .NET Web Service target. We'll select the new client option. The second step will ask you for the project name, the library name, and the target name. The third step will allow you to modify the library search path to include other libraries. In the fourth step, you'll assign a name to the .NET assembly that the target will eventually create.

In the fifth step of the wizard, you'll choose the type of object that will initially be created with the target and will give it a name. You can specify "(None)" if you want to skip this step. We're going to select what probably makes the most sense, "Custom Nonvisual," and give it a name (see Figure 6).

Figure 6

Note that the Finish button has been enabled since the second step of the wizard. We're going to keep going for a while because there's one more option we want to customize. In the sixth step, we can include additional resources or resource folders. The seventh step allows you to add references to Win32 dynamic link libraries. The eighth step is the one we're looking for though. Here we get to choose whether the application will be deployed to our local IIS server or generated as a console "self-hosted" application. We want the second option (see Figure 7).

Figure 7

Having selected that option, there is a ninth step in the wizard that allows us to specify the name of the executable that will run the self-hosted application as well as the base address and the service URL. At this point, we can hit the Finish button to complete the project.

Now we want to open the nonvisual object that was automatically created and code a method on it (see Listing 2). For this sample, I'm connecting to the Xtreme Sample Database 2008 database that appears to have been installed on my system as part of Visual Studio 2008. You might want to use the sample database provided with the SQL Anywhere 12 install as part of PowerBuilder 12.5. Note that, like a .NET Web Service application in PowerBuilder Classic, I can use the global SQLCA transaction object in my custom nonvisual. I don't have to create a local copy of a transaction object like I needed to do for some of the earlier EAServer-based methods of deploying web services. Also note that I'm connecting and disconnecting from the database within the method. In a "real" application, you would typically use an ADO.NET connection to the database with connection pooling enabled, so that the connect and disconnect would simple acquire and return a connection from the connection pool rather than making and breaking an actual connection to the database.

I've created a ‘d_grid' DataWindow that retrieves the list of employees from the sample database. What I then do is transfer that data to an array of structure using the Object.Data property. To facilitate that, I've created a ‘DW2STRUCT' utility that reads a DataWindow and creates a structure that matches the result set definition. The sample code for this article, as well as a number of other PowerBuilder code examples are available at: https://docs.google.com/#folders/0B7FWlsMaOo12NWIyODU4ZjktMWYwZS00MT-I3L.... There is a PB11 version of that utility available on Sybase's CodeXchange, and a 12.5 version that I've updated to support PowerBuilder.NET that I will make available shortly. What the function is returning is an array of that structure. Note that one of the recent enhancements in PowerBuilder, at least in PowerBuilder.NET, that made this possible is the ability to directly return arrays from methods.

Figure 8

At this point we need to open the deployment project that was initially created because we need to update it so that it knows to expose the method we just created (see Figure 8).

Figure 9

Note that we can also give the web service method a more conventional CamelCase method name when we generate the service. One other change I'll make to the project is to add a reference to the executable that launches the web service in a console to the Run tab (see Figure 9).

Figure 10

As a result, when we select the Run option for this target, the web service hosting environment will be launched (see Figure 10) and referencing the WSDL location in a browser will return the WSDL from the running service (see Figure 11).

Figure 11

Creating a REST Client in PowerBuilder.NET
What we'll look at next is creating a REST Client in PowerBuilder.NET. For this sample, we're going to use some of the services from Flickr.com.[3] Once again, as with the Amazon web services, you'll need to create an account with Flickr and obtain and apiKey before the samples will work for you. What we're going to use specifically is the photo search method, which takes two arguments: our apiKey and the text we want to use to search for photos.

Once again, we open the New dialog and this time select REST Client Proxy (see Figure 12).

Figure 12

The first step of the wizard will have us give the project a name and pick a library to store the project in. The second step is where things get interesting. It requests a service method URL and a service method type (GET, PUT, POST or DELETE). With regard to the service method type, think of the four basic methods of CRUD operations (create, read, update and delete). By convention, the four service method types correspond to those four CRUD operations:

  • GET = Read
  • PUT = Create
  • POST = Update
  • DELETE = Delete

Since we're doing a read operation, we'll use GET for our service method type. For the service method URL, we need to ensure that we include argument names in {} brackets in the URL at the location where we want to provide arguments at runtime. If we neglect this step, the proxy will end up creating a method with no arguments that is fixed for the one call we used to create the proxy.

http://api.flickr.com/services/rest/?method=flickr.photos. search&api_key={apikey}&text={text}&format=rest

The third step is interesting as well. Remember earlier I mentioned that few REST services actually provide a machine-readable method of describing themselves. To compensate for that, PowerBuilder gives you three different methods of defining the data structure that will be returned by the service:

  • Skip the step and use primitive types
  • Provide a schema or sample data that PowerBuilder will parse to determine the data structure
  • Provide an existing .NET assembly that contains the data types to expect

Unfortunately, PowerBuilder doesn't provide an explicit option to handle a WSDL 2.0 or WADL URL to describe the result data set for those methods that do provide one. In any event, we're going to use the second option and provide some sample data from calling the method. The way we get that data is to simply use the URL referenced above with appropriate arguments. This particular method will return XML to our browser, which we can then cut and paste into the appropriate location on the wizard (see Figure 13). In this step in the wizard, we also provide the name of the assembly where PowerBuilder will generate the .NET classes it will use to handle the response from the service.

Figure 13

In the fourth step of the wizard, we'll tell PowerBuilder what format to expect the data in, since REST services can provide it in a number of different formats. Since this particular method returns XML, we'll choose that option. We also need to indicate which of the classes that PowerBuilder generated from the sample data we consider to be the overall response data type. For this example, PowerBuilder found the following data types in the sample data:

  • restclient.rsp: The overall response type
  • restclient.rspPhotos: The array of photos matching our query with the overall response type
  • restclient.rspPhotosPhoto: An individual photo within the above array

The class names are taken from the tag names used in the XML response. Select the restclient.rsp class as the response data type.

The fifth step of the wizard allows us to specify the namespace for the proxy, give the proxy a name, and indicate whicch library it will be stored in. While the wizard has additional steps, we've provided enough for it to get started and can hit the Finish button so the proxy project is generated.

After that, deploy the project so that the actual proxy is generated. Similar to the WCF Client Proxy mentioned earlier, PowerBuilder will create an assembly and automatically reference the one that contains the supporting classes (including the data type classes we'll work with) as well as a proxy object in our PowerBuilder library. Also, as with the WCF Client Proxy sample earlier, I've added this proxy to an existing WPF application, and will now create a window that uses that proxy. Listing 3 contains the code for this particular sample. One thing it references is a DataWindow called ‘d_grid' that I've created to display the results that contains two columns: title (a string of 256 characters) and URL (a string of 1024 characters). Only the title shows on the visible surface of the DataWindow; the URL is used internally later in the code sample to display the picture.

Once again, note that like the WCF Client proxy, the REST Client proxy is self-contained. Everything we need to use to call the service was generated by the proxy object. We just instantiate the proxy class and call methods on it.

Some parts of the sample code bear explanation. The REST service we call limits the amount of hits returned in order to keep the size of the response small. It operates in a "paging" fashion where we can call it subsequent to the first call to retrieve additional "pages" of responses. The service returns two important pieces of information in this regard in the message header: photos.total - the total number of photos that matched our search and photos.perpage - the maximum number of responses returned in single request. That means that the number of photos that was returned to our initial call is the smaller of those two values, which becomes important as we attempt to loop through the data and display it.

Once we know how many results we have, we loop through them and populate the DataWindow reference above with the title and the URL for the photo. Flickr stores its images in a URL schema as follows:

http://farm{farm number}.static.flickr.com/{server name}/{photo id}_{photo secret}.jpg

All of the information we need to construct that URL was returned by the service; we just need to assemble it together to get the actual URL.

Note that the service doesn't return actual photos to us; it just returns the data we need to construct a URL to reference the image. How do we display the photos now that we have the URL though? Since this is a WPF application, we can take advantage of the System.Windows.Controls.Image class from the.NET Framework. Its Source property takes a System.Windows.Media.ImageSource class as an argument, and the System.Windows.Media.Imaging.BitmapImage class (which is a descendant of ImageSource) accepts a URI as a constructor. As a result, we have Listing 4 that we add to the RowFocusChanging event of our DataWindow. It takes the URL from the row that just got focus, converts it to a URI, passes that to the BitmapImage class, and then assigns the result of that to the Image class, which then displays the photo in the window.

Using a PowerBuilder.NET WCF Client in a PowerBuilder Classic Application
All this is great for our PowerBuilder.NET applications, but what if we want to use some of this new functionality in our PowerBuilder Classic applications? Do we need to wait for the next major release to make that possible? Well, fortunately, the answer is no. Because PowerBuilder.NET can generate .NET assemblies, and because PowerBuilder Classic targets can access .NET assemblies either through conditional code blocks (.NET targets) or COM Callable Wrappers (Win32 targets), we can create assemblies in PowerBuilder.NET that take advantage of these new features and then reference them in our PowerBuilder Classic applications.

Because the use of .NET assemblies is fairly straightforward in PowerBuilder Classic .NET targets, for this example I'm going to focus on using a WCF Client generated in PowerBuilder.NET in a PowerBuilder Classic Win32 target. The technique involves five steps:

  1. Create a WFC client proxy
  2. Wrap that in a .NET assembly target
  3. Expose some methods of the WCF client proxy
  4. Expose the COM Callable Wrapper (CCW) of that .NET assembly
  5. Reference that CCW from the PowerBuilder Classic application

We already saw how to create a WFC Client proxy for the Amazon web services earlier in this article. I'm going to use that same proxy, but this time instead of adding it to a WPF target I'll be adding it to a .NET assembly target. In the nonvisual object in that .NET assembly target I'll add a method called of_productsearch and populate it with almost the exact same code we used in our WPF sample (see Listing 1). The primary difference is that the keyword it will search from will be changed to an argument, and instead of populating a listbox I'll populate an array of type String and return that from the method. Once I've done that, I can update the project object in the target so that it knows to expose that new method in the generated assembly (see Figure 14).

Figure 14

The way we're going to expose this assembly so that our PowerBuilder Classic Win32 application can see it is through a COM Callable Wrapper (CCW). For this sample, what we're going to do is add the assembly we're generating here to the Global Assembly Cache (GAC) using GACUTIL from the Windows SDK. We'll also use the REGASM utility from the .NET Framework to generate the COM entries the PowerBuilder Classic Win32 application will use and add them to the registry.

In order to add an assembly to the GAC, the assembly must be signed with a strong name. Therefore, we will also update the project in our .NET assembly target so that it signs our assembly with a strong name when it generates it (see Figure 15).

Figure 15

One problem we'll encounter when we attempt to add our assembly to the GAC is that it references the assembly that was created in support of the WCF Client. Not only must our assembly be signed, but so must every assembly it references and PowerBuilder doesn't provide us with an option to sign that assembly during creation. Fortunately, there is still a way we can sign it. The Windows SDK provides a utility called ILDASM that can be used to disassemble an assembly back into an Intermediate Language (IL) file. Another utility called ILASM from the Windows SDK can be used to recompile IL back into an assembly, and that utility has command line options that allow us to sign the assembly with a strong name during that recompilation. All we need to do is use the strong name file that PowerBuilder generated when we signed our assembly and feed it to the ILASM utility so that it will sign the proxy assembly with a strong name as well. In our sample, where our WCF proxy assembly is called amazonservice.dll and the strong name file that PowerBuilder created for our wrapper class is called amazonwrapper.snk, we can strong name sign the WCP proxy assembly as follows:

"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\x64\ildasm.exe" /all /out=amazonservice.il amazonservice.dll
ilasm /dll /key=amazonwrapper.snk amazonservice.il

Now we can add both our wrapper assembly and the WCF proxy assembly to the GAC using GACUTIL:

C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /i amazonservice.dll

We use REGASM to create the registry entries our PowerBuilder Classic Win32 target will use:

regasm amazonwrapper.dll /regfile:amazonwrapper.reg

I've taken the option here to create a registry entry file that we will run separately to add the entries to the target computer.

Once the assemblies have been loaded into the GAC and the registry entries created, our PowerBuilder Classic Win32 application can access them easily through OLE Automation (see Listing 5).

Conclusion
What we've seen in this article is how web services support has been significantly enhanced in PowerBuilder.NET through the support for WFC Client proxies, WCF Service targets and REST Client proxies. We've also seen how we can use PowerBuilder.NET's .NET Assembly target capability to make such functionality (particularly WCF and REST clients) available to PowerBuilder Classic targets.

References

  1. http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl
  2. http://aws.amazon.com/
  3. http://www.flickr.com/services/api/

More Stories By Bruce Armstrong

Bruce Armstrong is a development lead with Integrated Data Services (www.get-integrated.com). A charter member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON's PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs' PowerBuilder 9: Advanced Client/Server Development.

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
bruce.armstrong 08/12/12 12:44:00 AM EDT

The link for the sample code is wrong. Try this one instead.