(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Silverlight and Sharepoint working together: event receivers in Silverlight

(1 votes)
Walter Ferrari
>
Walter Ferrari
Joined Dec 17, 2009
Articles:   19
Comments:   12
More Articles
0 comments   /   posted on Mar 13, 2012
Categories:   Line-of-Business
Tweet

In the previous articles of this series (see the panel From this series on the right) we dealt with some introductory aspects such as how to integrate Silverlight into Sharepoint, then we built a Silverlight menu capable of interacting with a Sharepoint site as an example. Throughout this journey we have introduced some basic concepts of Sharepoint useful for Silverlight developers.

Now it's time to dig into it at full throttle facing more advanced concepts. In this article we will become familiar with the Sharepoint event receivers, a cool feature which allows the user to be notified about various events occurring inside a Sharepoint environment. An example is the possibility to receive the notification of an item added to a list. Unfortunately, the mechanism works at server side and that means that there is no “out of the box” possibility to use the feature directly in a Silverlight application.

Nevertheless, we will find a way to make the event receivers available in a Silverlight web part in order to give a new dimension of interactivity to a Sharepoint solution.

As an example we will create a small application to invite our colleagues to a coffee break and get a close to real time answer. This will involve the creation of a wcf service with a service contract for a Sharepoint solution and a service contract for a Silverlight web part. Both contracts are duplex service contracts. Now you may be like “all this mess for a silly application to get someone together for a coffee break?” In fact, it may sound useless but it is not. Event receivers are a great feature of Sharepoint and exporting them into a Silverlight web part opens a very interesting perspective.

The “Coffee break” application

Let’s suppose we want to create a small application running in a Sharepoint site (a kind of widget) to quickly organize a coffee break with colleagues. We want to be able to select a time and send an invitation to our user’s group. The other users should be notified quite immediately and they should be able to accept or turn down the invitation. Eventually we should be notified about all the confirmations received from our colleagues. All this without the need to refresh any page.

The images below sum it all up:

applicationsdr

 

A video showing the application in action is available here.

The source code of the application is available here.

 

The big picture

In the introduction I gave some clues. I mentioned Sharepoint event receivers, a wcf service with duplex service contracts, a Sharepoint solution and a Silverlight web part. Let me put together the pieces of the mosaic starting with the event receivers. (As usual Sharepoint developers can skip this part)

 

sharepoint_2010_icon Event receivers are a convenient way to get notifications about Sharepoint events. The trappable events most used are synthesized in the tables below:

ListEventsTable

ListItemsTable

WorkflowTable

The nice thing is that you can create these event receivers from Visual Studio 2010 selecting the “Event receiver” template for a “new project” or for a “new item” of an existing project.

NewProjectEV

The template lets you choose the type of event you want to trap and then creates the skeleton code for you.

NewProjectEV1

 

Once clarified what the event receivers are, let’s move on and suppose you want to trap the events related to the built-in Sharepoint Calendar list. In fact, this list seems the ideal candidate where to store the “coffee break appointments”. So the idea is that when someone (user A) proposes a coffee break, he/she inserts a new item in this list. Then, “an item was added” event is fired and caught by the event receiver that we previously created in a web part. From here the web part should be able to redirect the notification to a Silverlight application.

Obviously the Silverlight application must be hosted in a Silverlight web part in order to be available in a Sharepoint page.

When the Silverlight app received the notification it should be able to display the information to the user B and allow him to express a positive feedback. If a positive feedback is given, the item in the Calendar list is updated causing the firing of a “an item was updated” event. Another event receiver pointed on this event should redirect the feedback to the client Silverlight app of user A.

So the key point is: who is in charge of transferring the signalling of events from the server code in the web part to the client code in the Silverlight application?

The answer is : a wcf Service that serves as a bridge.

Hopefully the following images will help to clarify this.

BigPicture1

Figure 1: How the “new coffee break event” is passed from the Silverlight of the user A to the Silverlight app of the user B

 

BigPicture2

Figure 2: How the “coffee break event confirmation” is passed from the Silverlight app of the user B to the Silverlight app of the user A

 

Note that the built-in Calendar list does not contain any field specifically dedicated to storing the participants of an event or their confirmations. So for this purpose I used the “Description” field of the Calendar. Basically, when user B in figure 2 confirms his will to take a coffee break with user A, he updates the “coffee break” item in the Calendar list by adding his confirmation in the Description field.

 

A wcf service as a bridge

In the previous paragraph we learned that the idea (behind the possibility to extend the event receivers to a client application) is to use an “ad hoch” wcf service. Furthermore, this wcf service should be able to manage a one-to-many relation when a new item in the Calendar is created and when an item is updated. The image below shows both cases:

wcfService1

Figure 3: the wcf service manages a one-to-many relation

 

In this way all the users of a group will receive a notification about a new coffee break proposal and a notification about the confirmations of one or more of them.

Previously we have also stated that all these notifications should appear without the need to refresh the Sharepoint page containing the Silverlight application. This means that the Silverlight application should implement some kind of polling to the wcf service or better, the wcf service should be able to “push” the data into the Silverlight application. You as Silverlight developers surely know that there are several ways to accomplish this. For the “coffee break” application I used HTTP Polling Duplex following the details explained in this excellent article. Without going too much in detail (for further explanations you can download and look at the source code linked to this article), I added the following interfaces to the service: the first defines the methods that the client can call on the service:

[ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(ISPDataServiceCallback))]
public interface ISPDataService
{
[OperationContract(IsOneWay = true)]
void DataFromClient(SPData value);

[OperationContract(IsOneWay = true)]
void DataFromSP(SPData value);
}

As for the DataFromSP(SPData value) method we will come back on this in a while. Instead, the DataFromClient(SPData value) method is called by the Silverlight client application at the first start to be registered on the service. As you may remember, this is due to the fact that the service must ensure a relation “one to many” with the running clients. For this reason the service must keep track of each client available.

The registration is made by the client as follows:

// registration to the server
SPData regData = new SPData();
regData.Event = events.client_reg;
regData.User = currentUser;
_Proxy.DataFromClientAsync(regData);
}

void _Proxy_ReceiveSPDataReceived(object sender, ReceiveSPDataReceivedEventArgs e)
{
if (e.spData.Event == events.client_reg)
{
LogtxtBlock.Text = "Connection estabilished.";
AddBreakBtn.IsEnabled = true;
}

 

At the service level the DataFromClient(SPData value) method is implemented as follows:

public void DataFromClient(SPData value)
{
//Get client callback channel
var context = OperationContext.Current;
var sessionID = context.SessionId;
var currClient = context.GetCallbackChannel<ISPDataServiceCallback>();
context.Channel.Faulted += Disconnect;
context.Channel.Closed += Disconnect;

ISPDataServiceCallback client;
if (!_ClientCallbacks.TryGetValue(sessionID, out client))
{
lock (_Key)
{
_ClientCallbacks[sessionID] = currClient;
}
}

// Get SPData
if (value.Event == events.client_reg)
{
value.ItemValue = "acknowledgment";
currClient.ReceiveSPData(value);
}

}

 

For each new client a specific channel is reserved for future communications. Only in the event of a new registration an “acknowledgment” is sent back to the client as feedback that the communication channel has been established.

If you were careful you may have noticed that in the snippet of the code above there was a reference to a ISPDataServiceCallback interface. This interface defines the callback methods that the service can use to communicate with a client:

[ServiceContract]
public interface ISPDataServiceCallback
{
[OperationContract(IsOneWay = true)]
void ReceiveSPData(SPData spData);

[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginReceiveSPData(SPData spData, AsyncCallback callback, object state);
void EndReceiveSPData(IAsyncResult result);

[OperationContract(IsOneWay = true)]
void DataFromSPCallback(string message);
}

 

Here you may notice the definition of the ReceiveSPData(SPData spData) method used above to communicate to the client that the communication channel is ready.

Let's take a breath now and think: ok, we have seen how the client Silverlight app and the service can communicate but… one more piece is missing. In what way does the event receiver communicate with the service and instruct it to redirect the information gathered to the client?

You can add another service endpoint and a new binding to the wcf service. Using the Microsoft Configuration Editor” in the “coffee break” application I added a new endpoint called “wsdual” and a binding of type “wsDualHttpBinding”. So I was able to use the same contract type used by the Silverlight application.

The DataFromSP(SPData value) method included in the first interface (ISPDataService) that I put in a corner some paragraphs above is just the method used in the event receivers to transfer the notification about new/updated items in the Calendar list into the service.

The snippet below shows the method used by the event receivers:

public void SendSPDataToClient(events eventType, SPItemEventProperties properties, string userColumn)
{
InitConnectionToWCF();

DateTime eventDate = (DateTime)properties.ListItem["EventDate"];

SPData spdata = new SPData();
spdata.Event = eventType;
spdata.ItemValue = eventDate.ToShortTimeString();
spdata.listName = properties.List.Title;
spdata.ItemID = properties.ListItemId.ToString();

SPFieldLookupValue userValues = new SPFieldLookupValue(Convert.ToString(properties.ListItem[userColumn]));

spdata.User = userValues.LookupValue;
spdataService.DataFromSP(spdata);

}

 

Once the service receives the notification, it sends the information directly to the clients as follows:

public void DataFromSP(SPData spData)
{
SendSPDataToClient(spData);
}

public void SendSPDataToClient(SPData spData)
{
var cbs = _ClientCallbacks.Where(cb => ((IContextChannel)cb.Value).State == CommunicationState.Opened);
for (int i = 0; i < cbs.Count(); i++)
{
var cb = cbs.ElementAt(i).Value;
try
{
cb.BeginReceiveSPData(spData, _ReceiveSPDataCompleted, cb);
}
catch (TimeoutException texp)
{
//Log timeout error
}
catch (CommunicationException cexp)
{
//Log communication error
}
}

}

 

Insert/update items in the Sharepoint Calendar List from Silverlight

If you have read my previous articles on this topic you should be familiar with the use of the Silverlight client object model. In the “coffee break” application the insert/update is carried out in a secondary thread in order to be able to use the synchronous ExecuteQuery() method instead of the conventional ExecuteQueryAsync(). There is no particular reason behind that, it is just another way. Here below the snippet of code that creates a new item:

public void InsertEventThreadFunc(object objData)
{
ThreadData mthData = (ThreadData)objData;

List list = mthData.ThClientContext.Web.Lists.GetByTitle(mthData.ThSPData.listName);
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();

ListItem newEvent = list.AddItem(itemCreateInfo);
newEvent["Title"] = "Coffee break for " + mthData.ThSPData.User;
newEvent["EventDate"] = (DateTime)mthData.ThSPData.ItemValue;
newEvent["EndDate"] = (DateTime)mthData.ThSPData.ItemValue;
newEvent.Update();

mthData.ThClientContext.Load(list, i => i.Title);

mthData.ThClientContext.ExecuteQuery();
}

 

And below the snippet that updates the item:

public void UpdateEventThreadFunc(object objData)
{
ThreadData mthData = (ThreadData)objData;

List list = mthData.ThClientContext.Web.Lists.GetByTitle(mthData.ThSPData.listName);

CamlQuery camlQuery = new CamlQuery();

camlQuery.ViewXml =
@"<View>
<Query>
<Where>
<Eq>
<FieldRef Name='ID'/>
<Value Type='Counter'>"
+ mthData.ThSPData.ItemID + @"</Value>
</Eq>
</Where>
</Query>
</View>"
;


ListItemCollection listItems = list.GetItems(camlQuery);

mthData.ThClientContext.Load(listItems,
items => items.Include(item => item["Description"]));

mthData.ThClientContext.ExecuteQuery();

if (listItems[0] != null)
{
listItems[0]["Description"] = listItems[0]["Description"] + " " + mthData.CurrentUser.Substring(mthData.CurrentUser.LastIndexOf(@"\") + 1) + " will join the coffee break!";
listItems[0].Update();
mthData.ThClientContext.ExecuteQuery();
}

}

 

Summary

In this article we have introduced another interesting feature of Sharepoint: the event receivers. Although this feature seems to be reserved to server side applications like classic Sharepoint web parts, we have explored a way to make it available for a Silverlight application embedded in a Sharepoint web part. The simple application that we have created, i.e. a widget to quickly organize a coffee break with colleagues, is able to transfer to the client code the notification of an item added/updated to the built-in Calendar list. To do that it uses an external wcf service that exposes a HTTP Polling Duplex binding to communicate with the Silverlight part and a WSDualHttp binding to communicate with the server code of the event receiver. This example opens interesting perspectives of interaction between Silverlight and Sharepoint. In one of the next articles we will try to apply this strategy to another big chapter of the Sharepoint world: the workflows. But now, I definitely need a coffee break.


Subscribe

Comments

No comments

Add Comment

Login to comment:
  *      *       

From this series