Creating a Client

Creating a client for Web services is greatly simplified in WWSAPI by the Service Model API and the WsUtil.exe tool. The Service Model provides an API that enables the client to send and receive messages over a channel as C method calls. The WsUtil tool generates headers and helpers for implementing the client. These headers include the types and function prototypes for C functions representing the services offered by the target Web service. The helpers are used to create the service proxy, which contains the binding information and endpoint address for the service.

Using WsUtil to Generate Headers and Helpers

To generate the headers and helpers, WsUtil opens and reads the metadata files for the target service — wsdl and xsd files— and converts them into headers; therefore, it is necessary to retrieve the metadata files for the target service in advance, for example by using SvcUtil, a part of the Windows Communication Foundation. For security reasons, it is imperative that your copies of these files are trustworthy. (For more information, see the "Security" section of the WsUtil Compiler Tool topic.)

To run WsUtil, use the following command-line syntax if the WSDL and XSD files for the service are in their own directory: WsUtil.exe *.wsdl *.xsd. Alternatively, you can specify the files by full name.

WsUtil generally generates two files for each metadata file: a header and a C file. Add these files to your coding project, and use #include statements to include them in the code for your client. (The XSD files represent types, and the WSDL files represent operations.)

Creating the Service Proxy

The header generated by WsUtil contains a helper routine for creating the service proxy with the required binding. This routine is included in the "Policy helper routines" section of the generated header file. For example, the generated header for the calculator service illustrated in the httpcalculatorclientexample example will contain the following function prototype.

HRESULT BasicHttpBinding_ICalculator_CreateServiceProxy(
    __in_opt WS_HTTP_BINDING_TEMPLATE* templateValue,
    __in_ecount_opt(proxyPropertyCount) const WS_PROXY_PROPERTY* proxyProperties,
    __in const ULONG proxyPropertyCount,
    __deref_out_opt WS_SERVICE_PROXY** _serviceProxy,
    __in_opt WS_ERROR* error);

Incorporate this helper in your code and pass a WS_SERVICE_PROXY handle to receive the handle to the created service proxy. In the simplest scenario, in which only a service proxy handle and an error object are passed to the function, the call looks like the following.

hr = BasicHttpBinding_ICalculator_CreateServiceProxy(
            NULL,
            NULL,
            0,
            &serviceProxy,
            error);

To create the address portion of the service proxy, call WsOpenServiceProxy with a handle to the service proxy and a pointer to a WS_ENDPOINT_ADDRESS containing the service endpoint address to which you wish to connect.

Implementing the Client with Function Prototypes

The headers generated from the service WSDL files also contain C function prototypes representing the services available from the Web service and specific to the binding required. For example, a header generated for the calculator service illustrated in HttpCalculatorServiceExample will contain the following prototype for that service's multiplication operation.

HRESULT BasicHttpBinding_ICalculator_Multiply(
    __in WS_SERVICE_PROXY* _serviceProxy,
    __in double n1,
    __in double n2,
    __out double* MultiplyResult,
    __in WS_HEAP* _heap,
    __in_ecount_opt(_callPropertyCount) const WS_CALL_PROPERTY* _callProperties,
    __in const ULONG _callPropertyCount,
    __in_opt const WS_ASYNC_CONTEXT* _asyncContext,
    __in_opt WS_ERROR* _error);

You can copy the prototypes and use them as templates for coding the function calls in your client, in each case passing the handle to service proxy. When you are finished with the service proxy, call WsCloseServiceProxy.