This article was imported from codelync.com
Creating the WCF Service
As I discovered in my previous post, we can’t directly use the Lync API from a Metro style app, so to create a Metro style UI for Lync we’re going to build a WCF wrapper around the Lync API.
The requirements for the app are to get a list of the users Lync contacts, and to keep their presence updated correctly. To achieve this, the WCF Service needs a simple interface:
[ServiceContract(
Namespace="http://www.codelync.com/prototype/lyncmetro",
SessionMode = SessionMode.Required,
CallbackContract = typeof(ILyncMetroCallback))]
public interface ILyncMetro
{
[OperationContract]
List<LyncGroup> GetContacts();
}
public interface ILyncMetroCallback
{
[OperationContract(IsOneWay = true)]
void AvailabilityChanged(string sipUri, AvailabilityEnum availability);
}
Supported by the following data contract:
[DataContract]
public class LyncContact
{
[DataMember]
public string SipUri { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Byte[] Image { get; set; }
[DataMember]
public AvailabilityEnum Availability { get; set; }
}
[DataContract]
public class LyncGroup
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<LyncContact> Contacts { get; set; }
}
[DataContract(Name = "Availability")]
public enum AvailabilityEnum
{
[EnumMember]
Offline,
[EnumMember]
Away,
[EnumMember]
Busy,
[EnumMember]
Online
}
With the following implementation:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class LyncMetro : ILyncMetro
{
ILyncMetroCallback _callback = null;
LyncMetro()
{
_callback = OperationContext.Current
.GetCallbackChannel<ILyncMetroCallback>();
Lync.AvailabilityChanged += Lync_AvailabilityChanged;
}
public List<LyncGroup> GetContacts()
{
return Lync.GetContacts();
}
void Lync_AvailabilityChanged(
object sender, AvailabilityChangedEventArgs e)
{
_callback.AvailabilityChanged(e.SipUri, e.Availability);
}
}
Note that I’m wiring up an event handler to the AvailabilityChanged
event on a static class called Lync
. The event handler calls the AvailabilityChanged
method in the ILyncMetroCallback
WCF interface – this will ultimately call a method in the client application that handles a contact’s availability changes.
The Lync
static class encapsulates interaction with the Lync client. As well as logic to sign in and out of Lync in UI Suppression mode (not shown, for brevity), it contains a public method for retrieving contacts:
internal static List<LyncGroup> GetContacts()
{
List<LyncGroup> lyncGroups = new List<LyncGroup>();
foreach (var group in _client.ContactManager.Groups)
{
var lyncGroup = new LyncGroup()
{
Name = group.Name,
Contacts = new List<LyncContact>()
};
lyncGroups.Add(lyncGroup);
foreach (var contact in group)
{
lyncGroup.Contacts.Add(GetLyncContact(contact));
contact.ContactInformationChanged += contact_ContactInformationChanged;
}
}
return lyncGroups;
}
The _client
variable is a member variable of type Microsoft.Lync.Model.LyncClient
, found in the Lync Client API. It has a ContactManager
property, which encapsulates functionality for managing contacts. The Groups
property used here returns all contact groups that the user has defined in the Lync client.
Note that I’m wiring up an event handler to capture any availability changes. The event handler looks like this:
static void contact_ContactInformationChanged(object sender, ContactInformationChangedEventArgs e)
{
if (e.ChangedContactInformation.Contains(ContactInformationType.Availability))
{
Contact contact = (Contact)sender;
var availability = GetAvailability((ContactAvailability)contact.GetContactInformation(ContactInformationType.Availability));
OnAvailabilityChanged(contact.Uri, availability);
}
}
The OnAvailabilityChanged
method isn’t shown here. This method just raises the AvailabilityChanged
event that is defined on the Lync class.
The class also contains 3 helper methods. GetAvailability
converts from a Lync ContactAvailability
enumeration to the AvailabilityEnum
enumeration defined in our WCF data contract:
static AvailabilityEnum GetAvailability(ContactAvailability contactAvailability)
{
AvailabilityEnum availability = AvailabilityEnum.Offline;
switch (contactAvailability)
{
case ContactAvailability.Away:
case ContactAvailability.BusyIdle:
case ContactAvailability.FreeIdle:
case ContactAvailability.TemporarilyAway:
availability = AvailabilityEnum.Away;
break;
case ContactAvailability.Busy:
case ContactAvailability.DoNotDisturb:
availability = AvailabilityEnum.Busy;
break;
case ContactAvailability.Free:
availability = AvailabilityEnum.Online;
break;
default: // Invalid, None, Offline
availability = AvailabilityEnum.Offline;
break;
}
return availability;
}
GetLyncContact
takes a Lync API Contact
object and returns it as a LyncContact
object:
static LyncContact GetLyncContact(Contact contact)
{
var lyncContact = new LyncContact();
lyncContact.Name = contact.GetContactInformation(ContactInformationType.DisplayName) as string;
lyncContact.SipUri = contact.Uri;
lyncContact.Availability = GetAvailability((ContactAvailability)contact.GetContactInformation(ContactInformationType.Availability));
try
{
lyncContact.Image = GetImageBytesFromStream(contact.GetContactInformation(ContactInformationType.Photo) as Stream);
}
catch(Exception)
{
lyncContact.Image = File.ReadAllBytes(Path.Combine(Application.StartupPath, "NoPhoto.png"));
}
return lyncContact;
}
GetImageBytesFromStream
converts a stream representing a contacts image into a byte array:
static Byte[] GetImageBytesFromStream(Stream stream)
{
byte[] bytes;
using (BinaryReader br = new BinaryReader(stream))
bytes = br.ReadBytes((int)stream.Length);
return bytes;
}
Next: Creating the Metro style app
This is part 4 in a series of 5:
- Part 1 – Testing Lync on the Developer Preview tablet
- Part 2 – Testing a custom Lync application on the Developer Preview tablet
- Part 3 – Calling the Lync API from a Metro style app
- Part 4 – Creating the WCF Service
- Part 5 – Creating the Metro style app