Printer Friendly View
 


Calling and Hosting FoxPro Web Services through .NET

by Rick Strahl
Updated: 10/10/2011


Web Services with Visual FoxPro have never been easy. The most common Web Service tool for FoxPro is the SOAP Toolkit, which has been discontinued and which had a host of problems when dealing with complex types passed over Web Services. In this article I’ll show how you can leverage the powerful Web Service features of .NET and the new Windows Communication Foundation in your FoxPro application through COM Interop.



What's covered: Download the Code Samples for this article
Discuss this article

 

 


 

 

Today more and more applications interact and communicate via Web Services either as clients or as publishers. It’s becoming quite common for many application development scenarios to include Web Service functionality as an integral part of the development process. The good news is that Web Service technology has stabilized and today interoperability is much better. It’s much easier to call a Java Web Service from .NET or Visual FoxPro (VFP) than it was in the early days of constantly moving standards and incompatible Web Service platform implementations. Over time Web Services have also become more complex, especially in regards to the data that is sent over the wire. It’s very common today to have Web Services that send complex messages that contain many nested types of information in single messages.

 

The State of FoxPro Web Services

For Visual FoxPro developers dealing with complex Web Services has always been difficult because the stock tool that is natively available through COM – the SOAP Toolkit – is limited when dealing with complex Web Services.

 

Whether you’re building or consuming Web Services in Visual FoxPro, your first stop likely takes you to the Soap Toolkit. Visual FoxPro ships and installs the COM based SOAP Toolkit and FoxPro’s internal Web Service client and server Wizards both rely on it to publish and consume Web Services. The SOAP Toolkit is a pretty crude tool by today’s standards – it’s COM based and provides only the bare basics of Web Service interoperability and can’t easily deal with Web Services that need to consume complex types or need to use extended Web Service protocols like the very WS-* Web Service standards that provide security, encryption or state management. If you’re using the SOAP Toolkit to consume Web Services that are returning anything but simple type values you will quickly find that it’s pretty tedious to deal with the data that is returned, as you will end up having to parse the XML messages on your own. Alternately you can also resort to implementing convoluted type interfaces using some of the toolkit’s extension interfaces that allow mapping of classes, but this process is almost more work than parsing the XML data. In my experience this lack of support for complex types is a major stumbling block as almost all Web Services that are published by providers commercially are based on complex types using objects, arrays or collections, and enumerations none of which are handled natively by the SOAP Toolkit.

 

For publishing Web Services the SOAP Toolkit fares no better – it provides the ability to use either an ASP or ISAPI listener to publish COM objects as Web Services. Although Visual FoxPro’s Web Service Wizard does a decent job of publishing simple Web services, the services published are limited in that you can’t easily publish anything but simple types from your exposed service methods. Add to that some limitations in Visual FoxPro to expose nested types to COM and it becomes very difficult to publish any content that requires anything but single hierarchy objects.

 

This may be workable in simple scenarios or in FoxPro to FoxPro calling scenarios where you can often use raw XML strings to pass data across applications, but for many Web Service and Service Oriented Architecture (SOA) scenarios that need to interact with non-FoxPro applications this limited functionality is not adequate.

 

The last straw for the SOAP Toolkit however is the fact that is no longer officially updated or supported by Microsoft. All new development on it has stopped so there won’t be any future improvements or bug fixes (other than critical hotfixes for security), so it won’t keep up with the latest standards should they change.

 

This makes the SOAP Toolkit a somewhat volatile solution especially if you are interoperating with Web Services from the Java and .NET platforms which are constantly changing and updating to the latest standards. Currently the SOAP toolkit is still in line with the latest SOAP 1.2 spec, but it doesn’t deal with any of the WS-* protocols or any of the upcoming SOAP 2.0 specifications.

 

 



Using .NET to provide a Web Service Bridge

Microsoft’s official recommendation for Web Services is to use .NET to access and publish Web Services. .NET is Microsoft’s preferred Web Services platform where all future development and support for new technologies is implemented and so Microsoft is recommending to use .NET in combination with COM for non .NET technologies like Visual FoxPro. While this may seem arrogant at first it makes sense in that the .NET 2.0 Web Services stack and Windows Communications Foundation (WCF) are .NET only technologies.

Web Service Client

For FoxPro developers creating a .NET Web Services client means that you can create a .NET Web Service client and use COM Interop to interact with this generated proxy object from FoxPro.

 

This process is not difficult and it actually makes the experience of consuming Web Services easier because .NET can deal much better with complex Web services and provide a strongly typed interface to them, including automatic message type (parameters and return values) creation and full Intellisense support. In many cases the complex result messages can simply be passed back to Visual FoxPro to access directly over COM.

 

You can drive the Web Service proxy either directly from FoxPro by passing the proxy back to FoxPro over COM, or by creating a small shim class that acts as a front end to the Web Service with .NET code. The latter is more work, but provides more flexibility and ensures that you think about your Web Service as a separate entity from your business objects or whatever you are exposing to the Web Service.

Web Service Publishing

.NET also supports easy publishing of Web Services through the ASP.NET ASMX framework. ASMX Web Services – named for the file extension that is used – are a special ASP.NET handler that can execute Web Service classes and expose these services to the Web. Like ASP.NET you can use COM Interop to access FoxPro code from these ASMX Web Services.

 

The process to do this is straight forward as you simply create a FoxPro COM object(s) and call it from the Web Service methods. The actual Web Service class uses .NET code and it only uses a little bit of code typically to call the FoxPro business logic to generate the result for the Web Service methods. .NET manages all the type serialization as well as automatic generation of the service meta data which is the WSDL definition for the service.

 

It’s easy to create the objects and access them in .NET, but the administrative aspects of COM Interop from ASP.NET are tricky as you have to ensure proper permissions are set for COM components and any files that need to be accessed. Debugging is also difficult as FoxPro COM component run inside of IIS and can’t be easily debugged or shut down. If you’re new to COM and dealing with COM in a Web Server environment this process can be daunting to work with at first, but in the end it’s just a mechanical process that has to be remembered and followed– there’s nothing difficult about, it’s only tedious.

 

The big benefit is that you get a mature, efficient and powerful Web Service framework through this mechanism that makes it fairly easy to create complex Web services.

Windows Communication Foundation

In addition to native .NET Web Services, Microsoft recently released the .NET Framework 3.0 which includes the Windows Communication Foundation (WCF). WCF provides a service based architecture (SOA) for .NET that among other things provides both Web Service client and server support. WCF expands on the base Web Service functionality by providing extended support for WS-* protocols that provide encryption, authentication, transaction management, binary transports and attachments and much, much more.

 

For plain HTTP based Web Services ASMX services and the .NET 2.0 Web Service client are easier to use than WCF, but WCF provides a unified architecture for creating service for inter-application communication. The same service architecture that can publish and access plain HTTP based Web Services can also work for more high performance protocols like raw TCP/IP, Named Pipes and Message Queues among others. Essentially by building a service once you can expose the service to a variety of different protocols with a single code base and even have all of the protocols be accessible at the same time.

 

One of the really nice things about WCF is that can be hosted in a variety of different applications. WCF services can be hosted in IIS using a mechanism similar to ASMX services through ASP.NET. But there’s also a new Windows Activation Service (WAS) that is a service that can publish services without having to have IIS running. WCF services can also be self hosted in any application that can run .NET code including Visual FoxPro applications that can use COM Interop to host a WCF service.

WCF is very powerful and given what it accomplishes it’s actually relatively easy to use especially compared with what was involved previously to publish multi-protocol services consistently. But for pure Web Services WCF is more complex and requires more configuration than ASMX style services do. It also requires a more formal service based architecture approach to creating services that requires explicitly defining of contracts via .NET Interfaces. Given that WCF is brand new technology that just released, it’s bound to get easier with better tool integration as the technology matures and comes into more common use.



Calling Web Services through .NET

For the following examples you should be familiar with the basics of .NET COM Interop. If you’re new to creating and calling .NET COM components and calling them from Visual FoxPro I recommend you read through the following documents:

 

http://tinyurl.com/ycn4bl
http://tinyurl.com/yfxa95

 

In this first example, let’s use a .NET Web Service client to call a Web Service that provides a front end to a standard SOAP based Web Service that returns some complex types. This Web Service is a partial public front end to an e-Commerce application that provides access to items and pricing information. The service can be found here:

 

http://www.west-wind.com/webstoresandbox/service/WebStoreConsumerService.asmx

 

The service has a few methods that manage inventory information: One method DownloadInventoryItem returns a single inventory object while DownloadInventoryItems returns a list of items for a given category and UploadInventoryItem allows uploading and echoing back an inventory item created on the client. These three methods use complex types as parameters and return values to demonstrate functionality that isn’t easily accomplished with the SOAP Toolkit.

 

So let’s create a Web Service client project in .NET that allows us to access the Web Service directly from Visual FoxPro. Let’s start by creating a new .NET Class Library Project:

 

·         Create a new Class Library Project in C#

·         Remove the Class.cs file from the project

·         Instead add a new class called WebStoreClient.cs

·         Right-click on the References Node in the project

·         Select Add Web  Reference (see Figure 1)

·         Type http://www.west-wind.com/webstoresandbox/service/WebStoreConsumerService.asmx?WSDL for the service URL.

·         Type in WebStoreService for the name of the service reference used on the client

 

Figure 1

Figure 1 – Add a Web Service Reference by specifying the WSDL file

 

At this point you have class file that contains a client proxy of the Web Service from the Web server. It basically has mapped all the methods to a set of client objects and interfaces and has created mapping classes for any types that are returned as part of the Web Service. Although I’m calling a .NET Web Service in this case, keep in mind that this process works the same with any Web Service whether it’s .NET, Java, PHP or FoxPro.

 

Behind the scenes WSDL.exe (also available from the command line with many options) is used to parses the service and any dependent message types. It creates a source code file that contains this class that compiles into the .NET client assembly. To use this generated proxy we can now create  small .NET wrapper class that you can then call from FoxPro via COM Interop as shown in Listing 1.

 

Listing 1: Wrapper class that calls the Web Service and is accessible through COM

namespace WebServiceClient

{

    [ClassInterface(ClassInterfaceType.AutoDual)]

    [ProgId("WebServiceClient.WebStoreClient")]

    public class WebStoreClient

    {

        public string ErrorMessage

        {

            get { return _ErrorMessage; }

            set { _ErrorMessage = value; }

        }

        private string _ErrorMessage = "";

 

        public WebStoreService.WebStoreService Proxy

        {

            get

            {

                if (this._Proxy == null)

                {

                    this._Proxy = new

                          WebServiceClient.WebStoreService.WebStoreService();

                    this._Proxy.Timeout = 10000;

                }

               

                return _Proxy;

            }

            set { _Proxy = value; }

        }

        private WebStoreService.WebStoreService _Proxy = null;

 

        public wws_itemsRow GetInventoryItem(string Sku)

        {

            wws_itemsRow Item = null;

            try

            {

                Item = this.Proxy.DownloadInventoryItem(Sku);

            }

            catch (Exception ex)

            {

                this.ErrorMessage = ex.Message;

            }

            return Item; 

        }

 

        public wws_itemsRow[] GetInventoryItems(string Category)

        {

            wws_itemsRow[] Items = null;

            try

            {

                Items = this.Proxy.DownloadInventoryItems(Category);

            }

            catch (Exception ex)

            {

                this.ErrorMessage = ex.Message;

            }

 

            return Items;

        }

 

    }

}

 

The code is a very thin wrapper around the WebStoreService proxy class which was generated for us by WSDL.exe. The class exposes a Proxy property which is a reference to the actual WebService proxy. This reference is directly accessible over COM, and while you can directly call service methods off this property, I recommend you create explicit wrapper methods as shown in Listing 1 as this gives you more control to handle errors and return them in a more meaningful way than through COM exceptions. It also shields you from possible future proxy implementation changes. Sometimes simple changes in the service can result the format or naming of proxy classes to change – using a wrapper method allows you to abstract the Web Service related logic in one place.

 

Before class can be called over COM you still need to compile the project and then register the generated assembly to COM by setting the Register for COM Interop Project project option as shown in Figure 2.

Figure 2

Figure 2 – The Interop assembly must be registered for COM Interop. This option is set in the Project options under the Build tab.

 

You also need to add a couple of assembly level attribute in the AssemblyInfo.cs file:

 

[assembly: ComVisible(true)]

[assembly: ClassInterface(ClassInterfaceType.AutoDual)]

 

This ensures that types are published to COM and publish with Dual interfaces so you get Intellisense on most objects returned from this assembly. Finally compile the project. To  instantiate the .NET COM object  and access any of the proxy methods you can use the following FoxPro code:

 

loService = CREATEOBJECT("WebServiceClient.WebStoreClient")

loItem = loService.GetInventoryItem("WWHELP40")

? loItem.Descript

? loItem.Price

 

 

You can also retrieve the item by using the proxy directly:

loItem = loService.Proxy.DownloadInventoryItem("WWSTORE20")

 

which gives you direct access to any of the methods available on the proxy. As you can see in Figure 3 you even get Intellisense on the service and even most of the result objects like the loItem result object.

 Figure 3

Figure 3 – Accessing the Web Service COM Client in Visual FoxPro provides Intellisense to service methods and returned result objects.

 

Reading from the service is easy, because unlike the SOAP Toolkit that requires XML parsing for this sort of thing, you simply get a COM object returned that you can reference and access properties on. This works even for more complex objects like the GetInventoryItems method which returns an array of Inventory items.

 

loService = CREATEOBJECT("WebServiceClient.WebStoreClient")

loItems = loService.DownloadInventoryItems("")

? loItems[1].Descript

? loItems[1].Price

loItem = loItems[1] 

? loItem.Abstract  && shows Intellisense

 

Most types returned from .NET will just work in FoxPro and you can access objects and arrays as shown here easily. There are some exceptions – specifically complex .NET value types (structures) and some collections can’t be marshaled properly over COM but those are relatively rare. When you do run into result types that aren’t directly accessible in FoxPro you can create wrapper classes in .NET and pull out the values from the incompatible types, store them into the wrapper class and return the wrapper class instead.

 

The examples above return complex values which is pretty straight forward because FoxPro can access the COM objects directly. It gets a little more complicated if you need to pass data to a Web Service because the .NET interface is strongly typed. Take the following .NET method that posts an item to the Web Service as an example:

 

public string UploadInventoryItem(wws_itemsRow Item)

{

    string Result = null;

    try

    {

        Result = this.Proxy.UploadInventoryItemAndReturnDescript(Item);

    }

    catch (Exception ex)

    {

        this.ErrorMessage = ex.Message;

    }

 

    return Result;

}

 

The COM object takes a strongly typed inventory Item object as a parameter and you can’t just create  FoxPro object to map the signature of that object and pass it. Instead the object you pass has to be of the EXACT type, which means the object has to originate from the .NET COM object.  There are several ways you can do this. The easiest is to simply instantiate the target type via COM if the type is available through COM in FoxPro:

 

*** Create the Item Object through COM

oItem=CREATEOBJECT("WebServiceClient.WebStoreService.wws_ItemsRow")

oItem.Descript = "My New Item"

oItem.Sku="New Item"

oItem.Price=405.00

 

*** Pass the Item to the Service Wrapper

loService = CREATEOBJECT("WebServiceClient.WebStoreServiceClient")

? loService.UploadInventoryItem(oItem) && echo back Descript

 

The Item is created as a COM object which is then assigned and passed back to the COM wrapper, which in turn calls the Web Service and submits the object. If the type in question is not COM accessible you can use a factory approach instead by creating a method that returns an instance of the class you need to work with such as GetEmptyInventoryItem() for example.

 

Although it is possible for FoxPro to pass generic FoxPro objects to .NET via COM, .NET will only be able to access these objects by using late binding via Reflection which is inefficient and difficult to code. Since Web Service clients will always generate proxy objects for each of the message types you should always be able to instantiate the message types directly.

Automating Web Service Proxies from .NET with West Wind Web Service Proxy Generator

The last examples demonstrate how to create a .NET proxy class and call it from Visual FoxPro. There are a number of steps involved to make this happen as well as a few limitations in accessing some of the .NET data types, especially arrays and value types as well as any generic types the Web Service might be exposing.

 

We publish a tool that automates the entire process of creating a .NET proxy class, creating a FoxPro wrapper class to instantiate and call the server based on a WSDL URL through a friendly UI. In addition the tool provides a wwDotNetBridge helper class that allows .NET components to load with COM registration as well as providing support for many otherwise unsupported .NET features like support for arrays, structures, and enums, access to static methods and properties and generic types. wwDotNetBridge opens up most .NET types for use in FoxPro, not just those registered through COM interop.

 

You can find out more about our tool here:

http://www.west-wind.com/wsdlgenerator/


Publishing a Web Service through .NET

Next let’s publish an ASMX Web Service that calls FoxPro code through COM Interop. Although this is a bit more work than using the FoxPro Web Service Wizard, this process actually gives you a lot more control over how the Web Services are published. First ASMX Web Services have much richer type support for Web Service responses. In addition by using ASMX Web Services you get a more customizable platform for building your service logic and you can actually debug your code. The SOAP Toolkit uses bunch of black box code to publish COM objects as Web Service – if something goes wrong in the configuration it’s notoriously difficult to figure out exactly what the problem is because no detailed error messages are returned. By using ASMX Web Services you are responsible for creating each of the service methods on your own, but because of this you also are dealing with code that you can run a debugger against, so you can actually see what’s happening inside of your service and detect any errors and the server status. It’s much easier to troubleshoot this environment. Finally ASP.NET is much richer in providing error reporting, diagnostics and dynamic generation of Web Service metadata (the WSDL for the service) automatically. There are no more generation steps involved in updating the WSDL instead it’s dynamically generated as needed and directly tied to the service. No more changing host addresses in generated WSDL files to switch between local development and live environments for example.

 

So, let’s start by creating a .NET Web Service.

 

·         Create a new ASP.NET Web Site in a directory of your choice called FoxWebService

·         Create a virtual directory called FoxWebService

·         You can use the _WebConfiguration.exe file provided in the FoxWebService folder

·         Alternately use the IIS Management Console to create the virtual directory

 

I prefer to create my projects for use with IIS rather than the built in Web Server because the built in server switches ports which makes it hard to keep the Web Service address consistent. Make sure your site is accessible before continuing on. Once the site works lets go into FoxPro and create a new COM Server.

 

If you’re unfamiliar with COM Interop from .NET I recommend reading the following article which covers creating COM objects for use with ASP.NET which is almost exactly the same as using them from a Web Service. The article can be found here: http://tinyurl.com/ykd7jc.

 

So let’s create a FoxPro class that will be exposed to COM and includes a few housekeeping features as shown in Figure 2.

 

Listing 2: A sample FoxPro COM server to be accessed from a Web Service

#DEFINE CRLF CHR(13) + CHR(10)

 

DEFINE CLASS FoxServer as SESSION OLEPUBLIC

cAppStartPath = ""

lError = .F.

cErrorMsg = ""

 

***********************************************************

* FoxServer :: Init

***********************************************************

FUNCTION INIT

 

SET RESOURCE OFF   && Best to compile into a CONFIG.FPW

SET EXCLUSIVE OFF

SET REPROCESS TO 2 SECONDS

 

SET CPDIALOG OFF

SET DELETED ON

SET EXACT OFF

SET SAFETY OFF

 

*** IMPORTANT: Figure out your DLL startup path

IF application.Startmode = 3 OR Application.StartMode = 5

   THIS.cAppStartPath = ADDBS(JUSTPATH(Application.ServerName))

ELSE

   THIS.cAppStartPath = SYS(5) + ADDBS(CURDIR())

ENDIF

 

SET PATH TO (THIS.cAppStartpath) ADDITIVE

 

ENDFUNC

 

***********************************************************

* FoxServer :: GetRequestInfo

***********************************************************

Function GetRequestInfo() as String

 

DECLARE Integer GetUserName ;

   IN WIN32API AS GUserName ;

   STRING @nBuffer, ;

   INTEGER @nBufferSize

 

lcUserName=space(255)

lnLength=len(lcUserName)

 

lnError=GUserName(@lcUserName,@lnLength)

 

lcUserName = SUBSTR(lcUsername,1,lnLength-1)

lcPath = SYS(5) + CURDIR()

 

lcOutput = "Current Path: " + lcPath + CRLF +;

"    DLL Path: " + this.cAppStartPath + CRLF +;

"Current User: " + lcUserName + " - " + SYS(0) + CRLF + ;

"Current Thread: " + TRANSFORM( Application.ThreadId)+CRLF

 

RETURN lcOutput

 

ENDDEFINE

 

The server is created as Session class to limit the public properties exposed to COM, and it includes some initialization code to determine the startup path and set the environment.

 

For testing the GetRequestInfo() method returns some status information about the COM server which is quite useful for debugging purposes. To create the server, create a project called FoxService and compile it into a COM object with:

 

BUILD MTDLL foxservice FROM foxservice recompile

 

Test it from the FoxPro Command Window with:

 

o = CREATEOBJECT("FoxService.FoxServer")

? o.GetRequestInfo()

 

If all of that works, go back into Visual Studio. The next step is to import the COM object into .NET:

 

·         Go into the Web project

·         Right click on the BIN directory and select Add Reference

·         In the dialog select the COM tab and find the FoxService object (Figure 4)

·         Click OK to add a reference to the COM object

 

Figure 4

Figure 4 – Adding a reference to the FoxPro COM server creates a .NET Interop assembly that wraps the COM object with a .NET class.

 

This creates a .NET wrapper object for the FoxService COM object that can be accessed in .NET code and which allows us to access the object in the Web Service. Visual Studio creates a separate assembly Interop.FoxService.dll that contains .NET types for each of the COM types exposed in the type library. Next, lets create our actual Web Service class in .NET.

 

·         Right click on the FoxWebService project and select Add New Item

·         Add a Web Service and name it FoxService.asmx

 

Open the generated Web Service class and replace the code in the service with the code shown in Listing 3.

Listing 3: A basic C# Web Service that calls our FoxPro COM object

[WebService(Namespace = "http://www.west-wind.com/demos/foxwebservice")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class FoxWebService : System.Web.Services.WebService

{

    [WebMethod]

    public string FoxServerStatus()

    {

        foxservice.FoxServer Service = new foxservice.FoxServer();

        string Result = Service.GetRequestInfo(false);

        return Result;       

    }

 

    [WebMethod]

    public DateTime GetServerTime()

    {

        return DateTime.Now;

    }

 

    [WebMethod]

    public string ThreadingMode()

    {

        return Thread.CurrentThread.ApartmentState.ToString();

    }

}

 

A .NET Web Service is basically a class that is marked up with a few attributes that identify the class and methods that are to be exposed through the Web Service. For now the FoxServerStatus method is the only one that accesses the FoxPro COM object. Notice that I can simply create an instance of the FoxServer class and then use that class like a stock .NET class. I get strong typing based on the types I specified in the FoxPro server and Intellisense shows the methods available on the server. In this case I simply return the result from the GetRequestInfo() method call.

 

Next, let’s test the server. Right click on the ASMX file in the Solution Explorer and select View in Browser. You’ll see a Web Service sample page that looks like Figure 5.

 

Figure 5

Figure 5 – ASMX Web Services let you test Web Services interactively through a Web page.

 

You can click on any of the links of the test page and check to see if the service works. The test page runs your service method and displays the result as an XML document. It ain’t pretty, but it’s quite useful for quickly checking operation of the service.

Calling the Web Service

Let’s call the service using the same mechanism we used earlier in the article – by adding a new wrapper COM class to the WebServiceClient project we created earlier. We’ll simply add another Web Reference and then create another COM wrapper class for this service. We’ll start by importing the Web Service with this Url through Add Web Reference:

 

http://localhost/foxWebService/FoxWebService.asmx?WSDL

 

This URL points at the dynamically generated WSDL for the Web Service and we can import and generate the new reference from it. Once the Web Reference exists we can then use to build a wrapper class that is exposed to COM as shown in Listing 4.

 

Listing 4: The client wrapper for the FoxWebService for COM Interop

[ClassInterface(ClassInterfaceType.AutoDual)]

[ProgId("WebServiceClient.FoxWebServiceClient")]

public class FoxWebServiceClient {

    public string ErrorMessage

    {

        get { return _ErrorMessage; }

        set { _ErrorMessage = value; }

    }

    private string _ErrorMessage = "";

 

    public FoxWebService.FoxWebService Proxy

    {

        get

        {

            if (this._Proxy == null)

            {

                this._Proxy = new FoxWebService.FoxWebService();

                this._Proxy.Timeout = 10000;

            }           

            return _Proxy;

        }

        set { _Proxy = value; }

    }

    private FoxWebService.FoxWebService _Proxy = null;

 

    public string FoxServerStatus()

    {

        string Result = "";

        try

        {

            Result = this.Proxy.FoxServerStatus();

        }

        catch (Exception ex)

        {

            this.ErrorMessage = ex.Message;

        }

 

        return Result;

    }

 

    public DateTime GetServerTime()

    {

        return this.Proxy.GetServerTime();

    }

}

 

All that’s left to do is compile the code and then go into Visual FoxPro and try it out with this code:

 

o = CREATEOBJECT("WebServiceCLient.FoxWebServiceClient")

? o.FoxServerStatus()

? o.GetServerTime()

? o.Proxy.ThreadingMode()

 

This code now goes out and uses FoxPro code to call a .NET COM Interop component, which in turn calls a .NET Web Service, which in turn calls a FoxPro COM component, and returns this result back to the caller. We’ve come full circle creating a Web Service and calling with Visual FoxPro on both ends.

Complex Objects and COM Interop

The .NET Web Service is quite capable of returning complex objects. To return a complex object is as simple as returning the type as a result of the method. As long as the type is XML serializable in .NET the type will be automatically serialized into XML and the ASMX service automatically provides the appropriate schema metadata required to generate an appropriate WSDL file.

 

You can also publish the FoxPro COM objects to the Web Service to some degree. There are some limitations but let’s start with an example that works. We’ll create a class in the FoxService.prg file and publish it through COM as shown in Listing 5.

 

Listing 5: A complex, nested FoxPro type

DEFINE CLASS Customer as Session OlePublic

 

cName = "Rick Strahl"

cCompany = "West Wind Technologies"

cAddress = "32 Kaiea Place"

tEntered = DATETIME()

DIMENSION cName_COMATTRIB[4]

cName_COMATTRIB[1] = 0  && Full Access

cName_COMATTRIB[2] = "Customer Name"

cName_COMATTRIB[3] = "cName"  && Proper capitalization.

cName_COMATTRIB[4] = "string" && Data type


… more COMATTRIB definitions for each prop

 

ENDDEFINE


Rebuild the COM object (BUILD MTDLL FoxService from FoxService RECOMPILE after you’ve stopped and restarted the IIS service). Then let’s create a method in the Web Service to expose this object:

 

[WebMethod]

public foxservice.CustomerClass GetCustomer()

{

    foxservice.CustomerClass Customer =

                new foxservice.CustomerClass();

    return Customer;

}

 

Now that you’ve made a change to the COM type library you’ll need to reload the COM reference – remove the reference then add it back into the project (note this has changed in Visual Studio 2005 which no longer auto-refreshes COM references – see sidebar). You can now use the Web Service test page to hit this method and you should see the object returned.

 

Go back into the .NET WebServiceClient project now and Update Web Reference on the FoxWebService and then rebuild the project. I’m going to cheat here and not create a wrapper method but use the Proxy directly from FoxPro so I have nothing else to do but to instantiate the object:

 

loService = CREATEOBJECT("WebServiceClient.FoxWebServiceClient")

loCust = loService.Proxy.GetCustomer()

? loCust.cCompany

? loCust.tEntered

 

And we’ve just accessed a Web Service that’s published a FoxPro object. That’s cool, but unfortunately this only works as long as your object is a single hierarchy deep. As soon as you have nested objects on the published object, serialization in .NET no longer works because .NET knows nothing about the generic types. For example add an object property like the following to the FoxPro  Customer class in the FoxService.prg file:

 

oPhoneNumbers = null

 

FUNCTION INIT

*** Note: Create as COM object so we can cast in .NET

This.oPhoneNumbers = CREATEOBJECT("FoxService.PhoneNumbers")

ENDFUNC

 

then add the PhoneNumbers class:

 

DEFINE CLASS PhoneNumbers as Session OlePublic

 

cTelephone = "808 123-1231"

cFax = "808 332-1231"

cMobile = "808 312-1231"

 

… COMAttrib definitions
ENDDEFINE

 

Stop and restart IIS, recompile the COM object and reimport the COM reference in the .NET Web Service project. If you now return this class as a result type (FoxService.Customer) the Web Service will actually fail and complain about not being able to serialize an object – the Web Service actually fails to compile as .NET is trying to create a serialization assembly for the Web Service class.

 

So what’s the alternative if you need to publish complex types as part for your Web Service? You can create a .NET wrapper type and use that type as a return value and then take your COM object values and assign them to this wrapper type. While this is still a lot of extra work, it’s still a lot easier than doing XML parsing and type conversion. Start by creating a wrapper type that matches the FoxPro type:

[Serializable]

public class cCustomer

{

    public string cName = "";

    public string cCompany = "";

    public string cAddress = "";

    public DateTime tEntered = DateTime.Now;

    public cPhoneNumbers oPhoneNumbers = new cPhoneNumbers();

}

 

[Serializable]

public class cPhoneNumbers

{

    public string cTelephone = "";

    public string cMobile = "";

    public string cFax = "";

}

 

I’m using the same names as the FoxPro type but that’s not really required – for example it might be nice to use non-hungarian naming (which is standard for .NET code) for the properties here. This type can now be used for parameters or return values and be returned from a method like this:

 

[WebMethod]

public cCustomer GetCustomer()

{

    foxservice.CustomerClass Customer =

               new foxservice.CustomerClass();

 

    cCustomer Cust = new cCustomer();

    Cust.cName = Customer.cName;

    Cust.cCompany = Customer.cCompany;

    Cust.cAddress = Customer.cAddress;

    Cust.tEntered = (DateTime) Customer.tEntered;

 

    // *** Cast the PhoneNumber to the COM type

    foxservice.PhoneNumbers PhoneNumbers =

      Customer.oPhoneNumbers as foxservice.PhoneNumbers;

 

    cPhoneNumbers Phone = Cust.oPhoneNumbers;

    Phone.cTelephone = PhoneNumbers.cTelephone;

    Phone.cMobile = PhoneNumbers.cMobile;

    Phone.cFax = PhoneNumbers.cFax;

 

    return Cust;

}

 

ASMX Web Service Threading Models

If you look back on the code in Listing 3 I included a method in the Web Service class to return the threading mode of the Web Service:

 

return Thread.CurrentThread.ApartmentState.ToString();

 

If you run this method in a Web Service you will get a value of MTA returned which stands for MultiThreaded Apartment. This means the Web Service running in true free threaded mode. This is a problem for Visual FoxPro COM objects which require Single Thread Apartment (STA)  threads in order to run reliably. Unlike ASP.NET pages, ASMX Web Services do not support an ASPCOMPAT mode which can automatically switch the service into STA mode. This can cause big performance and stability issues for FoxPro COM objects called off ASMX pages.

 

There are two ways to work around this issue. One is to use COM+ to host your COM components. COM+ manages the thread marshalling and makes it possible to handle VFP COM objects in an MTA environment, but COM+ can be a little inconvenient to deal with during development and it incurs significant overhead for COM object access.

 

The other mechanism is to use the ASP.NET page handler to provide the ASPCOMPAT compatibility for your ASMX Web Services. This can be accomplished by creating a custom HTTP Handler which I have provided in the WebServiceStaHandler.cs class in the Web project. The handler needs to be hooked up in the web.config file like this:

 

<configuration>

      <httpHandlers>       

        <add verb="*" path="FoxWebService.asmx"
                     
type="WebServiceStaHandler" />       

      </httpHandlers>

    </system.web>

</configuration>

 

The handler is hooked specifically the FoxWebService.asmx page but you can also use wildcards in the name to handle multiple files.

 

With this handler enabled the ThreadingMode Web Service method now returns STA mode which is compatible with FoxPro COM objects. For more info on this issue see http://tinyurl.com/y9vq32.

 



Web Services through Windows Communication Foundation

Above I’ve detailed how to create Web Services with ASMX and call Web Serivces using the standard .NET 2.0 Web Service client proxy framework. The .NET Framework 3.0 was recently released and WCF is a key component of this release.

 

So let’s take a very brief tour of doing the two things I showed above with WCF – calling a generic Web Service and implementing a Web Service in ASP.NET with WCF. Let’s start with creating the same Web Service I created for ASMX in WCF.

 

In order to follow along her make sure that you have the .NET Framework 3.0 installed and you install the Visual Studio 2005 Extensions for the .NET 3.0 Framework.

Creating a WCF Web Service in ASP.NET

The process of creating a WCF Web Service is not very different from the process with ASMX – you can simply add a Web Service to an ASP.NET application. To do so start with the FoxWebService project we used earlier and follow these steps:

 

·         Go to the FoxWebService Project

·         Right click and Add New Item

·         Select New WCF Service and name it FoxWcfService

 

This creates a .SVC file in your Web project with a code behind link to a source file that contains a service contract interface and class. The SVC file looks like this:

 

<%@ ServiceHost Language="C#" Debug="true" Service="FoxWcfService"  

    CodeBehind="~/App_Code/FoxWcfService.cs" %>

 

The SVC extension is mapped in IIS and routes the call to the code behind class file. This file implements an interface that acts as a Service Contract and an implementation class that provides the logic. I’m going to use the same service logic used in the ASMX server we used to call the FoxPro COM server we created earlier. Listing 6 shows the ServiceContract interface and implementation class.

 

Listing 6: A WCF based Web Service calling a Fox Server in ASP.NET

[ServiceContract]

public interface IFoxWcfService

{

    [OperationContract]

    string FoxServerStatus();

 

    [OperationContract]

    cCustomer GetCustomer();

}

 

public class FoxWcfService : IFoxWcfService

{

    public string FoxServerStatus()

    {

        foxservice.FoxServer Service = new foxservice.FoxServer();

        return Service.GetRequestInfo(false);

    }

 

    public cCustomer GetCustomer()

    {

        foxservice.CustomerClass Customer = new foxservice.CustomerClass();

 

        cCustomer Cust = new cCustomer();

        Cust.cName = Customer.cName;

        Cust.cCompany = Customer.cCompany;

        Cust.cAddress = Customer.cAddress;

        Cust.tEntered = (DateTime)Customer.tEntered;

 

        foxservice.PhoneNumbers PhoneNumbers =

                Customer.oPhoneNumbers as foxservice.PhoneNumbers;

 

        cPhoneNumbers Phone = Cust.oPhoneNumbers;

        Phone.cTelephone = PhoneNumbers.cTelephone;

        Phone.cMobile = PhoneNumbers.cMobile;

        Phone.cFax = PhoneNumbers.cFax;

 

        return Cust;

    }

}

 

The main difference in the WCF implementation from the ASMX one is that the Service Contract and implementation are separated. WCF uses ServiceContracts to map service endpoints and looks in a compiled assembly for the interface implementation. In this case there’s little benefit to this separation but the separation is a more formal SOA approach where the interface should be modeled before any implementation is done. In addition, WCF also allows setting up of explicit DataContract objects which can be used to define how messages are formatted and are mapped to underlying objects. DataContracts are optional though and it’s not required here since we can use WCF’s default serialization semantics to return our results.

 

The class above use the same code the we used previously and the GetCustomer() method returns a complex object that is mapped from a FoxPro object returned over COM. If you recall we created a couple .NET wrapper types for this FoxPro object so it can be properly serialized. The same approach works here.

 

In addition to the service implementation WCF also requires some configuration setting in a .config file (actually it can also be done programmatically, but only if you self host, not inside of ASP.NET). These settings tell WCF which endpoints to listen on and what protocols to serve on those endpoints as shown in Listing 7.

 

Listing 7: WCF web.config Settings are required to configure a Service Endpoint

<configuration>

    <system.serviceModel>

      <services>

        <service name="FoxWcfService"

                 behaviorConfiguration="FoxWcfServiceBehaviors">

          <endpoint contract="IFoxWcfService"
                   
binding="basicHttpBinding"/>

          <!--<endpoint contract="IFoxWcfService"

                        binding="wsHttpBinding"/>-->

          <endpoint address="mex" binding="mexHttpBinding"

                    contract="IMetadataExchange" />

        </service>

      </services>

      <behaviors>

        <serviceBehaviors>

          <behavior name="FoxWcfServiceBehaviors" >

            <serviceDebug includeExceptionDetailInFaults="true" />

            <serviceMetadata  httpGetEnabled="true"/>

          </behavior>

        </serviceBehaviors>

      </behaviors>

    </system.serviceModel>

</configuration>

 

A service is mapped by its typename (FoxWcfService – if we’d used a namespace the namespace would be required here). Each service has one or more endpoints and the endpoint is mapped to a specific service contract interface (IFoxWcfService) and it is associated with a binding that determines the protocol and other connection related settings. Here I’m using the BasicHttp binding which is the SOAP 1.1/1.2 format over HTTP or HTTPS. The beauty of WCF is that you can also use other bindings. For example, I could switch the service to use the WsHttpBinding instead in which case the service would service requests using WS-* related SOAP protocols. IIS is limited to serving HTTP protocols, but a WCF service in other host containers can also service plain Tcp/Ip, Named Pipes and MSMQ using the same service interface.

 

There’s also a ‘Mex’ endpoint – this endpoint provides the MetaDataExchange, which is required in order for the service to publish its WSDL for discovery. WCF always uses the SOAP and WSDL regardless of connection protocol but the Mex endpoint must be explicitly specified in order to access the WSDL.

 

At this point the service is configured and you can navigate to http://localhost/FoxWebService/foxwcfservice.svc to see if the service is active. Like ASMX a WCF service has a service HTML page that describes the service along with a link to the WSDL. There’s no test page though so you can’t test the service as easily as an ASMX service.  The service is published using standard SOAP 1.2 and WSDL so this service is directly accessible from any Web Service client.

Calling a Web Service with WCF

Next let’s call this newly created service with WCF. To do this let’s add another class to the our client .NET project, add a WCF Service Proxy and then expose that object via COM to FoxPro. First lets add a new Service Reference to the project WebServiceClient project:

 

·         Select the WebServiceCLient project

·         Right click and select Add Service Reference

·         The familiar Web Service Reference dialog from Figure 1 pops up

·         Type http://localhost/FoxWebService/foxwcfservice.svc for the service address

·         Select the service and name it FoxWcfService

 

Visual Studio creates a service reference for you which consists of a generated source file that contains a generated service contract, a proxy class and all the message objects. It also creates app.config file with client configuration settings. I’m going to skip over the config file here (see sidebar) and configure the client completely via code. With the generated proxy in place we can now create a wrapper class for COM Interop which is shown in Listing 8.

 

Listing 8: A WCF Client wrapper class for use with COM Interop

[ClassInterface(ClassInterfaceType.AutoDual)]

[ProgId("WebServiceClient.FoxWcfServiceClient")]

public class FoxWcfServiceClient

{

    public string ErrorMessage

    {

        get { return _ErrorMessage; }

        set { _ErrorMessage = value; }

    }

    private string _ErrorMessage = "";

 

    public FoxWcfService.FoxWcfServiceClient Proxy

    {

        get

        {

            if (this._Proxy == null)

                this.SetProxy(null);

            return _Proxy;

        }

        set { _Proxy = value; }

    }

    private FoxWcfService.FoxWcfServiceClient _Proxy = null;

 

    public void SetProxy(string EndPointUrl)

    {

        if (string.IsNullOrEmpty( EndPointUrl) )

          EndPointUrl="http://localhost/FoxWebService/foxwcfservice.svc";

 

        BasicHttpBinding binding = new BasicHttpBinding();

        binding.ReceiveTimeout = TimeSpan.FromSeconds(30F);

        //binding.ProxyAddress = "localhost:8080";       

 

        this._Proxy = new FoxWcfService.FoxWcfServiceClient(

                            binding,

                            new EndpointAddress(EndPointUrl) );

 

        //this._Proxy.ClientCredentials = new NetworkCredential();

    }

 

    public string FoxServerStatus()

    {

        string Result = "";

        try

        {

            Result = this.Proxy.FoxServerStatus();

        }

        catch (Exception ex)

        {

            this.ErrorMessage = ex.Message;

        }

 

        return Result;

    }

 

    public WebServiceClient.FoxWcfService.cCustomer GetCustomer()

    {

        WebServiceClient.FoxWcfService.cCustomer Customer = null;

        try

        {

            Customer = this.Proxy.GetCustomer();

        }

        catch (Exception ex)

        {

            this.ErrorMessage = ex.Message;

        }

 

        return Customer;

    }

}

 

This code is similar to the ASMX client code we wrote earlier. What’s different is the client proxy configuration which is a little more complex as you have to specify the endpoint and binding to use explicitly. WCF provides much more configurability than the ASMX client did with most of the settings on the Binding object. Authentication security can be configured with the Proxy.ClientCredential property. Although I won’t show this here most of these settings can also be set in a .config file for the application.

 

Since we previously configured the WebServiceClient project all we have to do is compile to generate the COM Interop assembly that includes this class. We can now use the following code in Visual FoxPro:

 

loService=CREATEOBJECT("WebServiceClient.FoxWcfServiceClient")

Cust = loService.GetCustomer()

? Cust.cCompany

? Cust.tEntered

? Cust.oPhoneNumbers

? Cust.oPhoneNumbers.cFax

 

It looks identical to the ASMX client code we used previously and it work roughly the same. Functionally there’s very little difference between this service and the ASMX service, although from my limited tests with WCF services so far it feels like WCF is much faster accessing Web Services – especially for the first time.

 

The real value of WCF on the server and client though is that you can with very little effort switch protocols. For example, if we decided we want to support the WS-* SOAP stack and be able to use binary messaging over wsHttpBinding, all I have to do is create another endpoint entry in web.config and give a unique address and different HTTP compatible binding. We can then add the endpoint into the web.config service configuration (shown previously in Listing 7) like this:

 

<service name="FoxWcfService"

         behaviorConfiguration="FoxWcfServiceBehaviors">

  <endpoint contract="IFoxWcfService" binding="wsHttpBinding"                 

            address="ws" />

  <endpoint contract="IFoxWcfService" binding="basicHttpBinding" />

  <endpoint address="mex" binding="mexHttpBinding"

            contract="IMetadataExchange" />

</service>

 

And that’s all it takes – we now have a service that can communicate with multiple protocols – all that changes is the endpoint address for the Web Service call with a relative path of “ws”. Both bindings are listed in the WSDL so the WSDL URL stays the same and you can switch between them at will. On the client the change is even easier – all that needs to change is the use of the binding from BasicHttpBinding to WsHttpBinding() and the endpoint Url:

 

public void SetProxy(string EndPointUrl,bool UseWs)

{

    Binding binding = null;

    if (!UseWs)

    {

        if (string.IsNullOrEmpty(EndPointUrl))

           EndPointUrl =

              "http://localhost/FoxWebService/FoxWcfService.svc";

        binding = new BasicHttpBinding();

    }

    else

    {

        if (string.IsNullOrEmpty(EndPointUrl))

           EndPointUrl =

           "http://localhost/FoxWebService/FoxWcfService.svc/ws";

        binding = new WSHttpBinding();

        //binding.MessageEncoding = WSMessageEncoding.Mtom;

    }

 

    binding.ReceiveTimeout = TimeSpan.FromSeconds(30F);

 

    this._Proxy = new FoxWcfService.FoxWcfServiceClient(

                        binding,

                        new EndpointAddress(EndPointUrl) );

}

 

With this code you can switch between the two protocols with a simple logical parameter change. Now that’s pretty powerful.

Choosing between ASMX and WCF

There’s a lot of overlap between ASMX and the stock .NET 2.0 Web Service client, and WCF based Web services and clients. It’s a valid question to ask which of the two approaches to use when using Web Services in .NET and when using COM Interop from Visual FoxPro.

 

If your goal is to use pure HTTP based standard SOAP 1.x Web Services and you don’t foresee a need to support WS-* style service then I recommend you stick with ASMX Web Services and the stock .NET 2.0 proxy. These “old” mechanisms are easier to use and even if you use them now and you later decide to move to WCF it’s relatively straightforward to upgrade existing services and clients.

 

WCF is more powerful, more flexible and more configurable than ASMX/stock Web Service Proxies, but it requires more configuration and because of it is more complex to build and use. WCF exposes a lot of extra power for that extra complexity though and while it is only slightly more difficult to use for basic functionality, it takes some time to get familiar with the multitude of configuration settings you can tweak.

 

The real value of WCF services comes in non Web based applications. Today we often think of anything that requires a distributed architecture as requiring Web/HTTP based connectivity. Other mechanisms exist but they have been notoriously more difficult to implement. WCF changes all that by bringing the Web Service model to various different protocols. If you need to build two or more applications that need communicate with each other and that can use WCF, then WCF offers many advantages such as the ability to utilize optimized binary data which performs much better than the more verbose XML text data. You can use complex authentication and session and transaction management, which allow creating complex distributed applications with relative ease. WCF solves many very complex problems in a consistent and resusable fashion. Not all of this technology is easy to use, but at least this functionality is now available in a consistent environment. Before WCF you had to build these sort of architectures and protocols on your own from scratch.

 

Because WCF is an abstraction layer technology it is also forward looking technology. The framework is open and extensible and is capable of growing as new protocols and technologies become available as they likely are going to be in the future. Moving forward I’m sure we’ll be moving away from ASMX Web Services and .NET 2.0 Web Service clients towards using WCF exclusively and the tools to do this are likely to get more user friendly as well.

 

I think WCF strikes a great balance between complexity, ease of use and configurability. You get a lot of functionality for very little additional complexity over stock .NET Web Service functionality.

Summary

Web Services communication with FoxPro has never been easy and this article probably hasn’t dispelled that notion for you. What I’ve shown here involves multiple technologies that must be bridged and interoperate with each other in order to utilize .NET’s Web Service functionality. If you’re not familiar with .NET and doing FoxPro to .NET COM Interop, much of this content may seem very complex.

 

But running on a non-.NET platform FoxPro developers don’t have much of a choice for a quality Web Services platform. The SOAP Toolkit works fine for simple Web Services, but for any service that returns complex data it unfortunately falls short. By interoperating with .NET FoxPro developers gain access to a truly full featured Web Services platform that the SOAP Toolkit never really provided. Both plain and WCF based Web Services are available allow access to a full featured and fully supported Web Services and SOA platform for FoxPro developers to take advantage of.

 

Resources

If you have any questions, comments, or just would like to discuss the content of this article please visit: http://www.west-wind.com/wwThreads/default.asp?Forum=White+Papers and post your questions there.

 

Discuss this article:

http://www.west-wind.com/wwThreads/default.asp?Forum=White+Papers

 

West Wind Web Service Proxy Generator for Visual FoxPro:

http://www.west-wind.com/wsdlgenerator/