Setting Up Data Channels

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

The following is a member of an example C# class named UserAgent. The implementation illustrates the general work flow that a client can follow to set up Communicator Web Access Server events from a server. Typically, this member method should run in a dedicate thread that should be started after a session is initiated. The thread should be cancelled when the session is closed. For more information about how to create, start, and cancel a dedicated thread, see Receiving Events from a Communicator Web Access Server.

The DataChannelUrl property (listed below) illustrates how to set up the event channel URL to include the appropriate session ID (sessionId), and server update sequence ID (ackId). The string is composed of the Url location to poll plus three additional parameters:

  • Sid: Session ID. The value is supplied by the Communicator Web Access Server synchronously on initiation of a session. A user can run more than one client processes on a single device. Each process is identified by a session ID. To ensure that a client process receives its own events, the session ID is required.

  • AckId: Acknowledgement Id. This value is supplied by the Communicator Web Access Server in the event received by the client immediately preceding the new polling request.

  • UA: User Activity. The possible values are true | false. This is the mechanism that allows a client to report machine activity to a Communicator Web Access Server. The server uses this value and the last published user state to determine an aggregate state of the user. This is particularly important in Multi-Point-of-Presence (MPOP) scenarios where a single user has logged on to a Communicator Web Access Server from multiple devices. The server uses the UA parameter sent by each device to determine which device the user is actively using. With that information, the Communicator Web Access Server can direct incoming request events such as IM invitations to the active device. A client should set the UA value with each polling request. Using a stale value can result in IM invitations sent to an inactive device.

The ProcessCwaEventsResponse method (listed below) illustrates how to obtain the session ID and update sequence ID (ackId) as well as the server-requested wait period (pollWaitTime) before the client should make the next event poll.

Notice that an attempt is also made (by calling the ProcessAuthTicket, see listing in Setting Up Sign-in and Command Channels) to parse the CWA-Ticket header and cache any new ticket the server might return.

It is highly recommended that the client code call a method like ProcessAuthTicket from within both the data channel and the command channel processing code. This ensures that the current authentication ticket is retrieved and cached with each POST or GET request to the Communicator Web Access Server.

The authentication ticket is attached to the request in the CreateRequest method, which is also listed in Setting Up Sign-in and Command Channels.

public void DataChannel(object sender, DoWorkEventArgs e)
{
    UserAgent userAgent = (UserAgent)e.Argument;

    while (userAgent.connected && !userAgent.dataChannelCancelled)
    {
        HttpWebRequest request = userAgent.(
                     userAgent., "GET");
        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
            if (response != null)
            {
                // Server could recreate the ticket if a
                // session remains open for too long.
                userAgent.(response.Headers);
                if (response.ContentLength > 0)
                {
                    (response);
                }
            }
}
        catch (Exception ex)
        {
            ProcessDebugEvents("DataChannel Error:" , ex);
        }
        finally
        {
            if (response != null)
                response.Close();
        }
        // Follow the server-requested wait period.
        Thread.Sleep(userAgent.pollWaitTime);
    }

    if (userAgent.ConnectionTerminatedEvent!=null)
        userAgent.ConnectionTerminatedEvent(this, null); // DateTime.Now);

    if (userAgent.dataChannelCancelled)
        userAgent.dataChannel.Dispose();

}

string 
{
   get
   {
       //the returned string includes the UA (user activity) parameter
       //that indicates current user activity. CWA server uses the
       //value to determine machineState to publish for remote subscribers
       return this.serverUrl +
            "/cwa/asyncdatachannel.ashx?Sid=" + this.sessionId +
            "&AckID=" + this.ackId +
            "&UA=true";
   }
}

//
// Process the CwaEvents element to extract session ID (sessionID),
// the server-requested poll waiting time (pollWaitTime), update
// sequence ID (ackId). These data are needed for the next HTTP
// request.
//
bool (HttpWebResponse response)
{
    bool succeeded = false;
    XmlDocument xmldoc = new XmlDocument();
    xmldoc.Load(response.GetResponseStream());
    if (xmldoc.DocumentElement.Name == "CwaEvents")
    {
        string str = XmlUtils.GetAttributeValue(
                  xmldoc.DocumentElement, "pollWaitTime");
       if (str != null && str != string.Empty)
          pollWaitTime = int.Parse(str);

       str = XmlUtils.GetAttributeValue(
          xmldoc.DocumentElement, "sessionTimeout");

       str = XmlUtils.GetAttributeValue(
          xmldoc.DocumentElement, "ackId");
       if (str != null && str != string.Empty)
          ackId = int.Parse(str);

       str = XmlUtils.GetAttributeValue(xmldoc.DocumentElement, "sid");
       if (str != null && str != string.Empty)
          sessionId = int.Parse(str);
       succeeded = true;
    }

    // Process parse the Event child elements: (listing omitted)
    ProcessDataEvents(xmldoc.DocumentElement);

    return succeeded;
}

See Also

Concepts

Setting Up Sign-in and Command Channels