Integrating Lync Status into an ASP.Net Gridview

This post describes integrating Lync status into an ASP.Net Gridview. I had a bit of a nightmare trying to achieve this so that it worked on IE8 all the way up to IE11 . First I had it working on IE8 but for IE9+ the status always showed as offline. I finally made it work using the example below (using Lync 2010):

First create the Gridview – in this example we’re binding ‘analysts’ :

<asp:GridView ID="analystGV" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField AccessibleHeaderText="ApplicationTrackerAssignedTo" HeaderText="Analyst">
<ItemTemplate>
<asp:Label ID="lyncStatus" data-id='<%# Eval("AnalystEmail") %>' runat="server" Text='<%# Eval("AnalystName") %>' onmouseover='<%# Eval("AnalystEmail", "javascript:ShowOOUI(this.id,&#39;{0}&#39;);") %>' onmouseout='HideOOUI()'></asp:Label>
</ItemTemplate>
<HeaderTemplate>
Analyst
</HeaderTemplate>  
</asp:TemplateField>
</Columns>
</asp:GridView>

You’ll notice that the ID of the label is called lyncStatus, which will obviously generate a unique ID (for example ‘analystGV_ctl01_lyncStatus’, ‘analystGV_ctl02_lyncStatus’ etc) for each label when the Gridview renders. We also use a data-id attribute to store the email address of the analyst. I’ve seen examples in the internet where people have used the SIP URI as the ID on fields, but this won’t work in a Gridview if we’re expecting multiple instances of the same SIP (the same user, for example) and as the ID would suggest, it would not be unique!

The Text of the label displays the analyst’s name.

Now paste the following into the <head> section:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<style type="text/css">
.available {
background: url('images/lyncStatusIcons/lync_available.png') no-repeat left center;
padding-left: 20px;
}
.offline {
background: url('images/lyncStatusIcons/lync_offline.png') no-repeat left center;
padding-left: 20px;
}
.away {
background: url('images/lyncStatusIcons/lync_away.png') no-repeat left center;
padding-left: 20px;
}
.busy, .inacall {
background: url('images/lyncStatusIcons/lync_busy.png') no-repeat left center;
padding-left: 20px;
}
.donotdisturb {
background: url('images/lyncStatusIcons/lync_dnd.png') no-repeat left center;
padding-left: 20px;
}      
</style>

Above we include the JQuery library and specify some styles for the status of each user.

Here are the icons I use:

 

Finally, just before the </body> tag, paste this:

 <script type="text/javascript">
var nameCtrl;
function onStatusChange(name, status, id) {
// This function is fired when the contacts presence status changes.
// In a real world solution, you would want to update an image to reflect the users presence
var sipClassName = getLyncPresenceString(status);
document.getElementById(id).className = "";
document.getElementById(id).className = sipClassName;
//since it doesnt get the status correctly for duplicate users (GetStaus return code is incorrect and this function isn't called)
//we get the first instance and search for other duplicate users and set the class
$('span[data-id="' + name + '"]').each(function () {
analystID = $(this).attr('id');
if (analystID != id) { //if it's not the current ID we're processing, set the class
document.getElementById(analystID).className = sipClassName;
}
});
}
function ShowOOUI(id, sipUri) {
if (nameCtrl && nameCtrl.PresenceEnabled) {
var rect = document.getElementById(id).getBoundingClientRect();
x = rect.left;
y = rect.top;
nameCtrl.ShowOOUI(sipUri, 0, x, y);
}
}
function HideOOUI() {
if (nameCtrl && nameCtrl.PresenceEnabled) {
nameCtrl.HideOOUI();
}
}
function getLyncPresenceString(status) {
switch (status) {
case 0:
return 'available';
break;
case 1:
case 8:
return 'offline';
break;
case 2:
case 4:
case 16:
return 'away';
break;
case 3:
case 5:
return 'inacall';
break;
case 6:
case 7:
case 10:
return 'busy';
break;
case 9:
case 15:
return 'donotdisturb';
break;
default:
return '';
}
}
//try and create NameCtrl object
try {
nameCtrl = new ActiveXObject('Name.NameCtrl.1');
nameCtrl.OnStatusChange = onStatusChange;
}
catch (err) {
//cannot create object, so don't show status
//in later versions of Lync we could try and create the object without using ActiveX, but since we're
//using 2010 we wont.
}
$(document).ready(function () {
//loop through every span element with an ID ending with 'lyncStatus' and get the status for that user
$('span[id$="lyncStatus"]').each(function () {
sipUri = $(this).attr('data-id');
analystID = $(this).attr('id');
if (nameCtrl && nameCtrl.PresenceEnabled) {
//GetStatus doesn't work when calling for a SIP that GetStatus has already been called for!
nameCtrl.GetStatus(sipUri, analystID);
}
});
});
</script>

When the document has loaded, this piece of JQuery iterates through all elements with an ID ending with ‘lyncStatus’. it retrieves the id and the data-id attributes (the id so it knows what element to set the Lync status on, and the data-id which stores the SIP URI (email address in my case)). If an instance of the nameCtrl object was successfully created, and presence is enabled, it attempts to get the status for that SIP.

**Note**

I experienced intermittent issues where duplicate users would not always be rendered correctly. That is, when GetStatus was called for a duplicate user (let’s say the same user joe.bloggs@alkanesolutions.co.uk appears twice) it would not return the correct value and OnStatusChange would never be called. To circumvent this issue, when the first instance of each user is ‘rendered’, I then use JQuery to find all other users with the same SIP URI and to give them the same status css class. Not ideal, but it works!

**Another Note**

If you’re testing this on an x64 platform, you must launch the x86 version of Internet Explorer. Otherwise it appears we cannot instantiate the Name.NameCtrl object, and we will get the ‘Automation server can’t create object’ error in our ‘catch’ block.

Also if you have Lync 2013 (and not 2010 like me) you may be able to get the integration working in Chrome/Firefox too by following instructions on how to instantiate the object here.

Create a custom debug log file in an ASP.Net Class

This is a quick example of how to create a custom debug log file in an ASP.Net class which you can use in your website. If the file doesn’t exist, it creates it. It names the file today’s date. And records a date/time at the start of each log entry

.aspx.cs page

...
CustomDebug.WriteToLog("Blah Blah Blah...");
....

 

.cs class

using System;
using System.Web;
using System.IO;
using System.Globalization;
public class CustomDebug
{
public CustomDebug()
{
//
// TODO: Add constructor logic here
//
}
public static void WriteToLog(string errorMessage)
{
try
{
string path = "E:\\Logs\\CustomDebug\\" + DateTime.Today.ToString("dd-MM-yy") + ".txt";
if (!File.Exists(path))
{
File.Create(path).Close();
}
using (StreamWriter w = File.AppendText(path))
{             
w.WriteLine(DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss") + ": Debug Message: " + errorMessage);
w.Flush();
w.Close();
}
}
catch (Exception ex)
{ //handle exception
}
}
}