How to: Create a managed SIP application

Lync 2013

Learn how to create a managed SIP application in a Microsoft Lync Server 2013 deployment.

Last modified: August 16, 2013

Applies to: Lync Server 2013

Creating a managed SIP application involves the following tasks:

  • Create and compile an application manifest.

  • Initialize a ServerAgent object.

  • Catch message dispatching events in an event loop.

  • Implement an event handler that processes the SIP messages that are dispatched from the Microsoft SIP Processing Language (MSPL) script that is embedded in the application manifest.

Creating and compiling an application manifest

The first step in creating a managed Lync Server 2013 SIP application is to create an application manifest and compile it within your application. The application manifest contains a message filter script that runs on the server and dispatches only the SIP messages that your application is interested in receiving. This action is usually performed in the Main method of the managed code application, as follows.

using System.Threading;
using System.Resources;
using Microsoft.Rtc.Sip;
...

// Obtain an XML string that contains your application manifest.
// In the sample below, the XML string is contained with the
// application assembly as a resource, and retrieved using the
// ResourceManager.GetString(resourceName) method.

ResourceManager myResourceManager = new ResourceManager(myApplicationClass);

// The "appManifest" string should be the name you gave your application
// manifest XML file when you added it as a resource to your application's
// assembly.

string myAppManifestXmlString = myResourceManager.GetString("appManifest");

ApplicationManifest myAppManifest = new ApplicationManifest(myAppManifestXmlString);

try {
myAppManifest.Compile();
}
catch (CompilerErrorException cee) {
Console.WriteLine("The following errors occurred during compilation:");
foreach (string errorMessage in cee.ErrorMessages) {
   Console.WriteLine("--- {0}", errorMessage);
}
}

Initializing a ServerAgent object

The common point of communication between the Lync Server 2013 computer and your application is a ServerAgent object. This object sends and receives messages through Lync Server 2013 on behalf of your application.

The ServerAgent object must bind to the ApplicationManifest object that is created in the previous section. As shown in the following example, this binding process is established when the ServerAgent is created.

try {
ServerAgent myAppServerAgent = new ServerAgent(myAppManifest);
}
catch (NullReferenceException nre) {
Console.WriteLine("The application manifest is uncompiled and ServerAgent cannot be instantiated.");
}
catch (ServerNotFoundException snfe) {
Console.WriteLine("The Lync Server computer is not available.");
}

The invocation of the previous ServerAgent constructor fails if the supplied application manifest does not compile with the MSPL compiler. In this case, a NullReferenceException is thrown. Therefore, your code should ensure that the application manifest compiles successfully before instantiating a ServerAgent instance.

Calling the previous constructor is applicable in a script-only application where the MSPL script is used to filter and process SIP messages and no messages are dispatched from the MSPL script to the managed code.

If the managed application handles messages that are dispatched from the MSPL message filter, the managed application must implement a message handler that is used to process the SIP messages that are dispatched from the MSPL message filter. For example, if the message filter calls the Dispatch function as shown in the following example, the managed application must have a message handler named OnInviteReceived.

Dispatch("OnInviteReceived");

In addition, the class implementing this method must also bind to the newly created ServerAgent object as shown in the next example.

ServerAgent myServerAgent = new ServerAgent(myClassWithDispatchMethods, myAppManifest);

Catching message dispatching events in an event loop

When Dispatch is called from the MSPL script, a server event is raised. The managed application must catch this event to process the dispatched messages. To catch the event, the application can leverage the signaling capability of the WaitHandle property that is exposed by the ServerAgent object in a loop. When the Lync Server instance receives a dispatched message, it raises a signal on the WaitHandle object. The application can wait for the signal by calling WaitOne (or WaitAny if other application signals are being handled) on the ServerAgent object. If this method returns true (or a positive integer containing the index to the signaled callback in your handle array, in the case of WaitAny), the ProcessEvent(Object) method must be called on the ServerAgent instance. The ProcessEvent passes the dispatched message to the event handler specified in the call to Dispatch.

Each application has its own process and is responsible for creating its own threads. The Microsoft Lync Server 2013 SIP Application Managed API does not require a specific threading model. However, the .NET Framework provides a ThreadPool class that can be used for this particular purpose. You can use ThreadPool to create a queue for events as shown in the following code example, which services a single input from the Lync Server 2013 computer.

ManualResetEvent autoResetEvent = new ManualResetEvent(false);
WaitHandle[] handleArray = new WaitHandle[] {
                              myAppServerAgent.WaitHandle,
                              manualResetEvent
                           };

WaitCallback waitCallback = new WaitCallback(myAppServerAgent.ProcessEvent);

while (true)
{
   int signaledEvent = WaitHandle.WaitAny(handleArray);

   if (signaledEvent == 0)  // The server event wait handle (index = 0) in handleArray was signaled
   {

       // Schedule a worker thread to process the server event.
       try
       {
          if (!ThreadPool.QueueUserWorkItem(waitCallBack))
          {
              Console.WriteLine("QueueUserWorkItem fails, quitting.");
              return;
          }

       }
       catch (Exception e)
       {
          Console.WriteLine("Unexpected exception: {0}\n{1}",
                            e.Message,
                            e.StackTrace);
       }
    }
    else // Manual reset event handle (index = 1) in handle array was signaled
    {
       Console.WriteLine("Quit handle signaled, worker will quit now\n");
       break;
    }
}
NoteNote

The ServerAgent class includes the ServerAgent.ProcessEvent callback property that is used specifically for event signaling. Passing this callback to a WaitCallback delegate adds each Lync Server 2013 generated event (calls to Dispatch in the message filter) to a work queue that is obtained from the thread pool.

Implementing the message event handler

To receive messages from the Lync Server 2013 computer, your application manifest must dispatch them to the application. Within the application manifest, the MSPL built-in Dispatch function is used to send the current message to a supplied handler in your application, as shown in the following example.

if (sipRequest.Method == "MESSAGE")
Dispatch("OnMessageReceived");
Respond(200);
}

The previous script causes Lync Server 2013 to dispatch any message with a SIP method type of "MESSAGE" to the "OnMessageReceived" event handler in your application, passing the request as a RequestReceivedEventArgs object. The following example shows how to define the handler.

public void OnMessageReceived(object sender, RequestReceivedEventArgs requestEventArgs) {

// Obtain the Request object to process from RequestReceivedEventArgs.
Request request = requestEventArgs.Request;

// Obtain the new server transaction for this request.
ServerTransaction myServerTransaction = requestEventArgs.ServerTransaction;

// Processing logic here.
// ...

// Create a branch on the server transaction to forward the request.
try
{
   // Attempt to send the request.
   requestEventArgs.ServerTransaction.CreateBranch();
   requestEventArgs.SendRequest(request);
}
catch (Exception e)
{
   Console.WriteLine("Unexpected exception: {0}\n{1}",
                            e.Message,
                            e.StackTrace);
}
}
NoteNote

The method signature of your message handler must match that of the RequestReceivedEventHandler delegate, which takes an object as the first parameter, and a RequestReceivedEventArgs reference as the second parameter.

To dispatch the methods, ServerAgent.ProcessEvent must be called if a server event is signaled with ServerAgent.WaitHandle. This method passes the dispatched message to the event handler that is registered with the corresponding MSPL Dispatch call.

Show: