Lync Asynchronous Programming
[This is preliminary documentation and is subject to change.]
Microsoft Lync 2013 Preview API features you add to your client application depend on a reliable network connection to send and receive the SIP messages that are the basis of collaboration between two Microsoft Lync Server 2013 Preview clients. Virtually every method you call on a Lync 2013 Preview API class results in a SIP request being sent from your client over a network to Lync Server 2013 Preview. Even the best network topology occasionally exhibits a latency that prevents an instantaneous response to a client’s SIP request. To avoid blocking code execution during an asynchronous network operation, Lync 2013 Preview API supports the standard .NET asynchronous programming pattern. For information about the asynchronous programming pattern used with Lync 2013 Preview API, see Calling Synchronous Methods Asynchronously
The Lync 2013 Preview API asynchronous programming pattern has three elements.
The IAsyncResult interface. You must obtain an instance of this interface as a return value of a call into a Lync 2013 Preview API method if you intend to block execution on your UI thread until an asynchronous operation completes. Otherwise, you obtain this interface as the parameter of a callback method conforming to the System.AsyncCallback signature.
The asynchronous callback method. This type of callback method requires that you instantiate a System.AsyncCallback Delegate with a method that you define.
The state change event handler. This is an asynchronous event callback method whose Lync 2013 Preview API delegate defines the method signature. Unlike a System.AsyncCallback method that is called only when an operation completes, a state changed event handler is called whenever the state of a Lync 2013 Preview API class changes.
You must implement event handlers in order to respond to events that can be raised when the state of an Lync 2013 Preview API object changes. A callback method is called whenever you define and pass your callback method to a Lync 2013 Preview API asynchronous method as a delegate.
Callback logic is required to check on the status of an asynchronous operation initiated by your application. Callback logic is invoked when the operation is finished.
The logic called by the Lync platform does not provide you with the new state of an object at the completion of an operation. To obtain the new state of an object, you must handle the event associated with the class instance whose method you call.
In most cases, your callback logic calls the EndXXX() method on the object which began the asynchronous operation and then catches any exceptions raised by the operation. For these cases, it is a good idea to simply created a lambda expression for the invoked callback logic and pass the expression in the callback argument position of the BeginXXX() operation call. In cases where you want to add more complex logic, you should create a method of the AsyncCallback type.
The three elements of a callback method are:
A Lync 2013 Preview API delegate type.
A client defined callback method to be called by Lync 2013 Preview API.
A state object defined on your client and passed by Lync 2013 Preview API to your callback method.
You pass the callback method you have created with the signature of a specified callback delegate as a parameter of the asynchronous Lync 2013 Preview API method you call. You can also declare an object that will hold any state value you choose to assign to the asynchronous operation. If you do not declare and pass an asynchronous state object, then you must pass a null value. The asynchronous state object is useful when you have declared a single System.AsyncCallback method to be called upon completion of different kinds of operations. The state of the operation including the nature of the operation is available to the callback method upon execution.
IAsyncResult is passed into the EndXXX() method call that corresponds to the BeginXXX() call that started an asynchronous operation. If you intend to simulate a synchronous operation call and block your UI thread until an asynchronous operation completes, you must call EndXXX() on the same code path used for the BeginXXX() call. For example, you can connect a modality synchronously by calling the connect operation like this: csm.EndConnect(csm.BeginConnect(null, null)); It is not advised that you code the operation this way. If there is any significant network latency, your application appears to hang. More importantly, you cannot catch any exceptions that may result from an attempt to connect a modality. There are some asynchronous Lync 2013 Preview API operations that fail when called in this way.
Otherwise, you call EndXXX() within your callback method. Where an asynchronous operation returns results such as a conversation window (Automation.EndStartConversation) or contact search results (ContactManager.EndSearch), you call EndXXX() to get the results.
If you are developing an application using Silverlight, you cannot use the IAsyncResult.AsyncWaitHandle property to signal your code that an asynchronous operation has completed. In this scenario, AsyncWaitHandle returns null.
Lync API Events
Events are raised any time state changes on an object. State change on an object is not always the result of a local operation. Instead, the state change can be the result of an action by a remote user.
An event handler returns event source and data classes to your application logic as parameters. A source class instance is the object raising an event while a data class instance gives you related source state change values. You examine the data instance to see the original and new state of an object.
For example, Microsoft.Lync.Model.Conversation.ConversationManager undergoes a state change when a conversation invitation comes from a remote user. The incoming invitation invokes the ConversationManager.ConversationAdded event.
A Microsoft.Lync.Model.Contact instance undergoes a state change when notified that a remote user has published new or updated presence information. The notification of updated presence information invokes a Contact.ContactInformationChanged event on the Microsoft.Lync.Model.Contact instance.
It is essential that your client listens for invitations by registering for appropriate events and listens for notifications from Lync Server 2013 Preview by registering for appropriate notification-related events. To listen for Lync 2013 Preview API events, your application must:
Create a set of callback method to act as event handlers for the events that will be raised by Lync 2013 Preview API classes.
Register for a set of events on Lync 2013 Preview API before calling methods on the interface that can raise events.
Handle events to get the state of the SIP request generated by the original asynchronous Lync 2013 Preview API method call. Be prepared to handle both a successful or failed request. Most events raised should be handled. In many cases, you can update your user interface to inform the user of the status of a SIP request. For example, you should inform a user of the progress of a request to sign in to Lync Server 2013 Preview.
When your application has finished using an object such as a Microsoft.Lync.Model.Conversation.Conversation, be sure to remove any event callback registration you added to the object. You should also remove event callback registrations on conversation Microsoft.Lync.Model.Conversation.Participant objects and the Microsoft.Lync.Model.Conversation.Modality objects exposed by a conversation participant.
Because of the private nature of a real conversation, it is important that your application encapsulates each individual conversation it starts within its own wrapping class. An instance of a conversation wrapping class should encapsulate a single conversation. In this class, you handle all events related to the conversation, modalities, and participants. Conversation state such as IM text and media streams should be private to the wrapping class so that when the class is instantiated by a calling library, the calling library cannot access the content of the conversation.
Another benefit of encapsulating conversations is that you cannot create a conversation event handler that is inadvertently registered to handle events from different conversations. For example, you may want to connect the audio/video modality automatically in specific conversation context – but not for all conversations. If you connect this modality in the Conversation.ParticipantAdded event handler, you must be sure to add this logic only to the event handler you add to a wrapping class for this kind of conversation.