Calling The Web Services

Calling HTTP Web Services

All of the HTTP web services can be invoked using an HTTP POST with the POST request body containing a request XML as described in the section above. The request document should be POSTed to the .aspx page that implements the operation. The requester should check the status and content of the HTTP response received. A 200 OK status code indicates that the request was successfully processed.

Example 2. Calling HTTP Web Services From C#

The listing below shows an example of invoking a web serivce over HTTP from within a C# program. Note that the GetResponse() method has been written to be generic and can be used to access any of the NetworkedPlanet web service operations. A complete working program based on this example code can be found in the examples/CS directory of your installation.

private void ProcessRequest(string serviceApplicationUrl, string topicmapName, string searchString)
{
  // First construct the URL. We start with the path to the application
  // directory provided by the user. Expand this by adding the operation
  // ASPX page address (with a slash separator if needed).
  string requestUrl = serviceApplicationUrl;
  if (!requestUrl.EndsWith("/")) 
  {
    requestUrl += "/";
  }
  requestUrl += "GetTopicsByName.aspx";

  Hashtable parameters = new Hashtable();
  parameters["topicmap"] = topicmapName;
  parameters["name"] = searchString;

  XmlDocument responseDoc = new XmlDocument();

  try 
  {
    HttpStatusCode statusCode = GetResponse(requestUrl, parameters, responseDoc);
    if (statusCode == HttpStatusCode.OK) 
    {
      System.Console.WriteLine("Search request was processed successfully. Results follow.");
    } 
    else 
    {
      System.Console.WriteLine("Search request failed: " + statusCode.ToString() + ". Details follow.");
    }
    XmlTextWriter writer = new XmlTextWriter(System.Console.Out);
    writer.Formatting = Formatting.Indented;
    responseDoc.WriteTo(writer);
  } 
  catch (System.Net.WebException webex) 
  {
    System.Console.Error.WriteLine("Error encountered in sending request. Please check the service application URL and try again.");
    System.Console.Error.WriteLine("  Error detail: " + webex.Message);
  }
}

/// <summary>
/// Attempts to contact a NetworkedPlanet webservice, passing in the specified parameters.
/// </summary>
/// <param name="requestUrl">The URL of the service to contact</param>
/// <param name="parameters">The parameters to pass to the service.</param>
/// <param name="responseDoc">The response XML received from the web service</param>
/// <returns>The HTTP status code of the response</returns>
/// <exception cref="System.Net.WebException">Raised if the service could not be reached.</exception>
/// <remarks>The <c>parameters</c> hashtable must use string keys and the value for each key must be either
/// a string or an IList of string.</remarks>
private HttpStatusCode GetResponse(string requestUrl, Hashtable parameters, XmlDocument responseDoc)
{
  // Construct the request XML
  XmlDocument requestDoc = new XmlDocument();
  XmlElement requestEl = requestDoc.CreateElement("request");
  requestDoc.AppendChild(requestEl);
  // Parameters should be either strings or lists of strings
  foreach(string key in parameters.Keys) 
  {
    if (parameters[key] is string) 
    {
      XmlElement param = requestDoc.CreateElement("param");
      param.SetAttribute("name", key);
      param.InnerXml = parameters[key] as string;
      requestEl.AppendChild(param);
    } 
    else if (parameters[key] is IList)
    {
      // If the parameter is a list of strings, write a separate
      // param element for each item in the list.
      foreach(string item in (parameters[key] as IList)) 
      {
        XmlElement param = requestDoc.CreateElement("param");
        param.SetAttribute("name", "key");
        param.InnerXml = item;
        requestEl.AppendChild(param);
      }
    }
  }

  // Perform an ASCII encoding of the request xml
  ASCIIEncoding encoding = new ASCIIEncoding();
  byte[] encodedBody = encoding.GetBytes(requestDoc.OuterXml);

  // Construct the request object
  HttpWebRequest webRequest = HttpWebRequest.Create(requestUrl) as HttpWebRequest;
  webRequest.ContentType = "text/xml";
  webRequest.ContentLength = encodedBody.Length;
  webRequest.Method = "POST";
  Stream bodyStream = webRequest.GetRequestStream();
  bodyStream.Write(encodedBody, 0, encodedBody.Length);
  bodyStream.Close();

  HttpWebResponse webResponse = null;
  try 
  {
    webResponse = webRequest.GetResponse() as HttpWebResponse;
  } 
  catch (System.Net.WebException webEx)
  {
    webResponse = webEx.Response as HttpWebResponse;
  }
  // NOTE: this will throw an exception out to the caller if the
  // response is not an XML document.
  responseDoc.Load(webResponse.GetResponseStream());
  return webResponse.StatusCode;
}

Example 3. Calling HTTP Web Services From VB.NET

    ' Contains the logic for issuing a search request and processing
    ' the results.
    Sub DoRequest(ByVal serviceUrl As String, ByVal topicmapName As String, ByVal searchString As String)
        Dim requestUrl As String
        requestUrl = serviceUrl
        If Not (requestUrl.EndsWith("/")) Then
            requestUrl = requestUrl + "/"
        End If
        requestUrl = requestUrl + "GetTopicsByName.aspx"
        System.Console.WriteLine(requestUrl)
        Dim params As New Hashtable
        params("topicmap") = topicmapName
        params("name") = searchString

        Dim responseDoc As New Xml.XmlDocument
        Dim responseCode As HttpStatusCode
        Try
            responseCode = GetResponse(requestUrl, params, responseDoc)
            If (responseCode.Equals(HttpStatusCode.OK)) Then
                System.Console.WriteLine("Search process successfully. Results follow:")
            Else
                System.Console.WriteLine("Search request failed. Error details follow:")
            End If
            Dim writer As XmlTextWriter
            writer = New XmlTextWriter(System.Console.Out)
            writer.Formatting = Formatting.Indented
        responseDoc.WriteTo(writer)
        Catch ex As WebException
            System.Console.Error.WriteLine("Error processing request: " + ex.Message)
            System.Console.Error.WriteLine("  Please check the service URL and try again.")
        End Try
    End Sub

    ' Performs the "heavy lifing" of the application. This function posts 
    ' a set of parameters (defined in the params Hashtable) to the
    ' URL specified by requestUrl and parses the response into
    ' responseDoc. Because all of the NetworkedPlanet web service
    ' operations use the same request format, this method can
    ' be reused to invoke any of the operations we support.
    ' The keys in the params Hashtable must be strings and the
    ' values must be either strings or ILists of strings.
    Function GetResponse(ByVal requestUrl As String, ByVal params As Hashtable, ByVal responseDoc As XmlDocument) As HttpStatusCode

        Dim requestDoc As XmlDocument
        Dim requestEl As XmlElement
        Dim paramEl As XmlElement
        Dim key As String
        requestDoc = New XmlDocument
        requestEl = requestDoc.CreateElement("request")
        requestDoc.AppendChild(requestEl)
        For Each key In params.Keys
            If (TypeOf params(key) Is IList) Then
                ' Extract each item in the list in turn add add
                ' a separate param element for it
                Dim paramValue As String
                For Each paramValue In params(key)
                    paramEl = requestDoc.CreateElement("param")
                    paramEl.SetAttribute("name", key)
                    paramEl.InnerXml = paramValue
                    requestEl.AppendChild(paramEl)
                Next
            Else
                ' Create a single param element for the item value
                paramEl = requestDoc.CreateElement("param")
                paramEl.SetAttribute("name", key)
                paramEl.InnerXml = params(key)
                requestEl.AppendChild(paramEl)
            End If
        Next
        System.Console.WriteLine(requestDoc.OuterXml)

        Dim encodedBody As Byte()
        Dim asciiEncoding As New ASCIIEncoding
        encodedBody = asciiEncoding.GetBytes(requestDoc.OuterXml)

        Dim httpRequest As HttpWebRequest
        httpRequest = HttpWebRequest.Create(requestUrl)
        httpRequest.Method = "POST"
        httpRequest.ContentLength = encodedBody.Length
        httpRequest.ContentType = "text/xml"
        Dim requestStream As Stream
        requestStream = httpRequest.GetRequestStream()
        requestStream.Write(encodedBody, 0, encodedBody.Length)
        requestStream.Close()

        Dim httpResponse As HttpWebResponse
        Try
            httpResponse = httpRequest.GetResponse()
        Catch ex As WebException
            httpResponse = ex.Response
        End Try

        If httpResponse.ContentType = "text/xml" Then
            Dim reader As New XmlTextReader(httpResponse.GetResponseStream())
            responseDoc.Load(reader)
        Else
            ' We shouldn't get non XML content return from NetworkedPlanet
            ' requests, but this handles the case that the server returns s
            ' some default error page (e.g. if access is denied) by embedding
            ' the response text inside a wrapper element
            responseDoc.AppendChild(responseDoc.CreateElement("NonXmlResponse"))
            Dim rdr As New StreamReader(httpResponse.GetResponseStream())
            responseDoc.InnerText = rdr.ReadToEnd()
            rdr.Close()
        End If
        Return httpResponse.StatusCode

    End Function

Example 4. Calling HTTP Web Services From Javascript

The following example shows the use of the XmlHttpRequest object provided by some browsers. There are a number of cross-browser libraries that help you avoid browser issues in using Javascript.

 /**
  * Construct and post the request and handle the response
  */
function DoSearch()
{
  // Assumes that our page has three text fields for providing the request parameters
  oServiceUrl = document.getElementById("serviceUrl")
  oTopicmap = document.getElementById("topicmap")
  oSearchString = document.getElementById("searchString")
  // A placeholder element on our page for progress / result messages
  oMessage = document.getElementById("message");
  szRequestUrl = oServiceUrl.value
  if (szRequestUrl.charAt(szRequestUrl.length - 1) != "/") {
    szRequestUrl = szRequestUrl + "/"
  }
  szRequestUrl = szRequestUrl + "GetTopicsByName.aspx"
  szRequestBody = "<request><param name='topicmap'>" + oTopicmap.value + 
    "</param><param name='name'>" + oSearchString.value + "</param></request>"
  oMessage.innerText = "Sending request. Please wait...";
  oMessage.className = "pending";
  DoPost(szRequestUrl, szRequestBody);
}

/**
 * Posts the specified content to the specified URL using 
 * the global asynchronous request object 'req'. When the
 * request status changes, the ProcessRequestChange function
 * will be invoked
 */
function DoPost(url, content)
{
  if (window.XMLHttpRequest) {
    req = new XMLHttpRequest();
    req.onreadystatechange = ProcessRequestChange;
    req.open("POST", url, true);
    req.send(content);
  } else if (window.ActiveXObject) {
    req = new ActiveXObject("Microsoft.XMLHTTP");
    if (req) {
      req.onreadystatechange = ProcessRequestChange;
      req.open("POST", url, true);
      req.send(content);
    }
  }
}

function ProcessRequestChange()
{
  if (req.readyState == 4) {
    if (req.status == 200) {
      // Handle successful response.
      // Response XML can be found in req.responseXML
    } else {
      // Handle error reponse.
      // Error XML document can be found in req.responseXML
    }
  }
}

Note

Although the HTTP interface also accepts HTTP GET requests, these are restricted by the limitations imposed on URL lenght and URL parameter structures. We therefore recommend that you always use POST requests for consistency.

Calling SOAP Web Services

The SOAP service implementation endpoints are provided by the .asmx files contained in the service web applications. This is TMService.asmx for the Topic Maps Web Service and NpclSchemaService.asmx for the NPCL Web Service. These endpoints provide a WSDL description if you invoke an HTTP GET on them with a single parameter "wsdl" - e.g. http://localhost/tmws/TMService.asmx?wsdl.

From the WSDL file you can generate the client-side proxy for accessing the web service. In .NET this is done using the wsdl.exe tool. For your convenience we have provided a .NET assembly, serviceclient.dll. This assembly contains client stubs for the Topic Maps Web Service and NPCL Web Service as well as classes for creating and serializing / de-serializing the XML structures that are used as parameters and return values for the web service operations.

Calling SOAP Web Services From C#

The following code shows a method that invokes the GetTopicsByName operation on the Topic Maps Web Service and processes the response. The sample code shown here uses the utilities provided by the serviceclient.dll assembly. The full code for this example can be found in examples/CS/WebServices/TopicsByNameSOAP. As the code below shows, the response from the web service can be deserialized into the appropriate class from the NetworkedPlanet.WebServiceClient.Tmws namespace (for TMWS operations) or NetworkedPlanet.WebServiceClient.Npcl namespace (for NPCL Web Service operations) - there are also a set of common structures for reporting lists of results and/or errors in the NetworkedPlanet.WebServiceClient.Common namespace.

Example 5. Calling SOAP Web Services From C#

using System;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;
using NetworkedPlanet.WebServiceClient;
using NetworkedPlanet.WebServiceClient.Tmws;
using NetworkedPlanet.WebServiceClient.Common;

private static void ProcessRequest(string endpointUrl, string tmName, string queryString)
{
  // Create a new TMWS SOAP client bound to the specified endpoint.
  TMSClient tmwsClient = new TMSClient(endpointUrl);
  try 
  {
    XmlNode results = tmwsClient.GetTopicsByName(tmName, queryString);
    XmlSerializer ser = new XmlSerializer(typeof(TopicMapFragment));
    TopicMapFragment resultsFragment = ser.Deserialize(new XmlNodeReader(results)) as TopicMapFragment;
    foreach(Topic t in resultsFragment.topiclist) 
    {
      if (!t.stub) 
      {
        System.Console.WriteLine("Topic {0}: {1}", t.oid, t.names[0].namestring);
      }
    }
  } 
  catch (SoapException ex) 
  {
    if (ex.Detail != null) 
    {
      // SoapExceptions from TMWS will usually contain an XML fragment with a detailed description of the error 
      // If the SoapException was raised due to a TMWS error, the SOAP detail element will contain
      // results structure which can be deserialized to extract information.
      XmlNamespaceManager nsmgr = new XmlNamespaceManager(ex.Detail.OwnerDocument.NameTable);
      nsmgr.AddNamespace("res", "http://www.networkedplanet.com/schema/ws-results");
      XmlElement resultsEl = ex.Detail.SelectSingleNode("res:results", nsmgr) as XmlElement;
      if (resultsEl != null) 
      {
        // We have a results element which can be deserialized to an
        // instance of the NetworkedPlanet.WebServiceClient.Common.ResultListType class
        XmlSerializer ser = new XmlSerializer(typeof(ResultListType));
        ResultListType resultList = ser.Deserialize(new XmlNodeReader(resultsEl)) as ResultListType;
        foreach(ResultType result in resultList.result) 
        {
          if (result.isError && result.error != null)
          {
            System.Console.Error.WriteLine("\nError: {0}\n  {1}", result.error.code, result.error.message);
            if (result.error.cause != null) 
            {
              foreach(CSharpException cause in result.error.cause) 
              {
                System.Console.WriteLine("  Cause: {0}", cause.message);
              }
            }
            if (result.error.action != null) 
            {
              foreach(Action action in result.error.action) 
              {
                System.Console.Error.WriteLine("  Corrective Action: {0}", action.Value);
              }
            }
          }
        }
      } 
      else 
      {
        // Just display the contents of the SOAP fault details element.
        System.Console.Error.WriteLine("Error detail:\r\n" + ex.Detail.OuterXml);
      }
    }
  }
}
Calling SOAP Web Services From VB.NET

The following code shows a method that invokes the GetTopicsByName operation on the Topic Maps Web Service and processes the response. The sample code shown here uses the utilities provided by the serviceclient.dll assembly. The full code for this example can be found in examples/VB/WebServices/TopicsByNameSOAP. As the code below shows, the response from the web service can be deserialized into the appropriate class from the NetworkedPlanet.WebServiceClient.Tmws namespace (for TMWS operations) or NetworkedPlanet.WebServiceClient.Npcl namespace (for NPCL Web Service operations) - there are also a set of common structures for reporting lists of results and/or errors in the NetworkedPlanet.WebServiceClient.Common namespace.

Example 6. Calling SOAP Web Services from VB

Imports System.Xml
Imports System.Web.Services.Protocols
Imports NetworkedPlanet.WebServiceClient
Imports NetworkedPlanet.WebServiceClient.Tmws
Imports NetworkedPlanet.WebServiceClient.Common

...

    Sub DoRequest(ByVal endpointUrl As String, ByVal tmName As String, ByVal queryString As String)
        Dim tmwsClient As New TMSClient(endpointUrl)
        Try
            Dim responseXml As XmlNode
            responseXml = tmwsClient.GetTopicsByName(tmName, queryString)
            Dim ser As System.Xml.Serialization.XmlSerializer
            ser = New System.Xml.Serialization.XmlSerializer(GetType(TopicMapFragment))
            Dim results As TopicMapFragment
            results = ser.Deserialize(New XmlNodeReader(responseXml))
            Dim t As Topic
            For Each t In results.topiclist
                If (Not t.stub) Then
                    System.Console.WriteLine("Topic {0} : {1}", t.oid, t.names(0).namestring)
                End If
            Next
        Catch ex As SoapException
            If Not (ex.Detail Is Nothing) Then
                Dim nsmgr As XmlNamespaceManager = New XmlNamespaceManager(ex.Detail.OwnerDocument.NameTable)
                nsmgr.AddNamespace("res", "http://www.networkedplanet.com/schema/ws-results")
                Dim resultsEl As XmlElement = ex.Detail.SelectSingleNode("res:results", nsmgr)
                If Not (resultsEl Is Nothing) Then
                    Dim ser As System.Xml.Serialization.XmlSerializer = New System.Xml.Serialization.XmlSerializer(GetType(ResultListType))
                    Dim results As ResultListType = ser.Deserialize(New XmlNodeReader(resultsEl))
                    Dim result As ResultType
                    For Each result In results.result
                        If result.isError Then
                            System.Console.Error.WriteLine("ERROR: {0}", result.error.code)
                            System.Console.Error.WriteLine("  {0}", result.error.message)
                            If Not (result.error.cause Is Nothing) Then
                                Dim cause As CSharpException
                                For Each cause In result.error.cause
                                    System.Console.Error.WriteLine("  Cause: {0}", cause.message)
                                Next
                            End If
                            If Not (result.error.action Is Nothing) Then
                                Dim action As Action
                                For Each action In result.error.action
                                    System.Console.Error.WriteLine("  Corrective Action: {0}", action.Value)
                                Next
                            End If
                        End If
                    Next
                    Return
                End If
            End If
            System.Console.Error.WriteLine("Error Detail: {0}", ex.Detail.OuterXml)
        End Try
    End Sub