Event receivers in earlier versions of SharePoint primarily ran on the
SharePoint Server to handle events that occurred on SharePoint objects such as
list, libraries, site etc.
In SharePoint 2013, a new concept, Remote Event Receivers, has been introduced, where the event generated by a SharePoint app could be listened to and handled by the SharePoint Server.
In other words, we could create SharePoint Apps (that is a standalone module of code that is complete in itself and can be installed / uninstalled independently on a Client) that can act as event generators. The handlers can be written using web services. These are very similar to the event receivers in the earlier version - except that these work in remote clients. This provides substantially more scope for including useful functionality in our SharePoint Apps.
In SharePoint 2013, a new concept, Remote Event Receivers, has been introduced, where the event generated by a SharePoint app could be listened to and handled by the SharePoint Server.
In other words, we could create SharePoint Apps (that is a standalone module of code that is complete in itself and can be installed / uninstalled independently on a Client) that can act as event generators. The handlers can be written using web services. These are very similar to the event receivers in the earlier version - except that these work in remote clients. This provides substantially more scope for including useful functionality in our SharePoint Apps.
Remote event receivers are done by means of Web services, that listen
for events to occur. Instead of running code on the SP server, the app fires an
event that is handled by this web service. By registering a remote end-point we
can invoke either a one-way or two-way event receiver. Visual Studio 2013
provides templates to create a Remote Event Receiver, that creates the skeleton
for this set up, that we can build on, to meet our requirements. By default, when
we use Visual Studio 2013 to create the remote event receiver, there are 2
methods in the WCF service; they are:
- ProcessEvent()
that handles events that occur before an action occurs, such as when a
user adds or deletes a list item. This is a synchronous event (2-way that
can handle "-ing" (current) events) that can call-back to
SharePoint, for example cancelling an addition to a list
- ProcessOneWayEvent()
that handles events that occur after an action occurs, such as after a
user adds an item to a list or deletes an item from a list. This is an
asynchronous event (1-way that can handle "-ed" (past) events,
fire and forget type)
Remote event receivers handles events in an item in
the app such as list item, library item or web. In remote event
receivers, app responds, when ever item added, updated or deleted in a
list/library. When ever creating new remote event receiver you can select the
type of event receiver. for Eg. you select ListItemEvent, that fires whenever
user add/updates/deletes the list item.
Remote event receivers follow the typical three patterns for
authentication that are used for Auto hosted and SharePoint-hosted Apps for
SharePoint: on-premises only, in the cloud only, and hybrid where part is
on-premises and part is in the cloud. Remote event receivers only need to be
concerned about authentication if they need to call back into SharePoint to
perform some action on SharePoint. If your remote event receiver is of the
fire-and-forget model, or if you are simply performing a validation and optionally
cancelling an event, you do not need to be concerned with authentication in
your code, but the manifest does need to have the correct designation. Figure 1
shows the on-premises-only and cloud-only configurations as well as the
appropriate authentication used by the remote event receiver if your code needs
to call back into SharePoint.
FIGURE 1:
Some enterprises that have
their SharePoint site on-premises will choose to be configured for a hybrid
environment where their remote event receivers may reside either on internal
servers or in the cloud. In this case the enterprise might want a single
authentication method and programming model for its remote event receivers that
will work equally well regardless of where the remote event receiver is hosted.
To accommodate this, the enterprise must follow the Microsoft-provided guidance
to configure SharePoint to use Windows Azure Access Control Services (ACS) as
the authorization service and expose the appropriate endpoints for SharePoint
and any internally hosted remote event receivers to the public Internet. ACS
must be able to access these endpoints to provide the needed authentication via
OAuth. Figure 2 shows this hybrid pattern.
FIGURE 2
Although you have the
opportunity to call back into SharePoint to do additional work within the app
web, host web, or elsewhere depending on your app’s permissions, sometimes you
might simply want to make some alterations on the list item and its properties
that are currently being processed in the ProcessEvent method. You
can do this by evaluating any value passed in on the properties object
and then use the SPRemoteEventResult object and its ChangedItemProperties object
to pass your alterations back to SharePoint.
For instance, you can use the properties.ItemEventProperties.AfterProperties object
in your validation logic to assess whether the incoming values are as you
expected them to be. Once you make any changes to your result object
this will be passed back to SharePoint. SharePoint will update the list columns
accordingly.
The following Try It Out walks you through using the SPRemoteEventResult object.
Additionally, you will see in this example that because your app does not
explicitly need to call back into SharePoint to read/write data, there is no
need to use the TokenHelper class in your code.
Below are the The Code Base examples of two methods:
ProcessEvent method:
which handles the app installed/uninstalling event.
After the app gets installed, it attaches the Remote Event Receiver with the Product
list. During the uninstalling event, it deletes the Remote Event Receiver from
the list
public class AppEventReceiver : IRemoteEventService
{
public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
SPRemoteEventResult result = new SPRemoteEventResult();
if (properties.EventType == SPRemoteEventType.AppInstalled)
{
using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
{
if (clientContext != null)
{
//Get reference to the host web list with name Products
var documentsList = clientContext.Web.Lists.GetByTitle(“Products”);
clientContext.Load(documentsList);
clientContext.ExecuteQuery();
string remoteUrl = “https://ur cloud host web url”;
{
public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
SPRemoteEventResult result = new SPRemoteEventResult();
if (properties.EventType == SPRemoteEventType.AppInstalled)
{
using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
{
if (clientContext != null)
{
//Get reference to the host web list with name Products
var documentsList = clientContext.Web.Lists.GetByTitle(“Products”);
clientContext.Load(documentsList);
clientContext.ExecuteQuery();
string remoteUrl = “https://ur cloud host web url”;
//Create the remote event receiver
definition
EventReceiverDefinitionCreationInformation newEventReceiver =new EventReceiverDefinitionCreationInformation()
{
EventType = EventReceiverType.ItemAdded,
ReceiverAssembly = Assembly.GetExecutingAssembly().FullName,
ReceiverName = “ProductRemoteEventReceiver”,
ReceiverClass = “ProductRemoteEventReceiver”,
ReceiverUrl = remoteUrl,
SequenceNumber = 15000
};
EventReceiverDefinitionCreationInformation newEventReceiver =new EventReceiverDefinitionCreationInformation()
{
EventType = EventReceiverType.ItemAdded,
ReceiverAssembly = Assembly.GetExecutingAssembly().FullName,
ReceiverName = “ProductRemoteEventReceiver”,
ReceiverClass = “ProductRemoteEventReceiver”,
ReceiverUrl = remoteUrl,
SequenceNumber = 15000
};
//Add the
remote event receiver to the host web list
documentsList.EventReceivers.Add(newEventReceiver);
clientContext.ExecuteQuery();
}
}
}
else if (properties.EventType == SPRemoteEventType.AppUninstalling)
{
using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
{
var list = clientContext.Web.Lists.GetByTitle(“Products”);
clientContext.Load(list);
clientContext.ExecuteQuery();
EventReceiverDefinitionCollection erdc = list.EventReceivers;
clientContext.Load(erdc);
clientContext.ExecuteQuery();
List<EventReceiverDefinition> toDelete = newList<EventReceiverDefinition>();
foreach (EventReceiverDefinition erd in erdc)
{
if (erd.ReceiverName == “ProductRemoteEventReceiver”)
{
toDelete.Add(erd);
}
}
//Delete the remote event receiver from the list, when the app gets uninstalled
foreach (EventReceiverDefinition item in toDelete)
{
item.DeleteObject();
clientContext.ExecuteQuery();
}
}
}
documentsList.EventReceivers.Add(newEventReceiver);
clientContext.ExecuteQuery();
}
}
}
else if (properties.EventType == SPRemoteEventType.AppUninstalling)
{
using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
{
var list = clientContext.Web.Lists.GetByTitle(“Products”);
clientContext.Load(list);
clientContext.ExecuteQuery();
EventReceiverDefinitionCollection erdc = list.EventReceivers;
clientContext.Load(erdc);
clientContext.ExecuteQuery();
List<EventReceiverDefinition> toDelete = newList<EventReceiverDefinition>();
foreach (EventReceiverDefinition erd in erdc)
{
if (erd.ReceiverName == “ProductRemoteEventReceiver”)
{
toDelete.Add(erd);
}
}
//Delete the remote event receiver from the list, when the app gets uninstalled
foreach (EventReceiverDefinition item in toDelete)
{
item.DeleteObject();
clientContext.ExecuteQuery();
}
}
}
return result;
}
}
}
}
ProcessOneWayEvent method:
ProcessEvent is a
synchronous event handler and is used to call code when a “before” event occurs
. ProcessOneWayEvent is
an asynchronous event handler and is used to call code when an “after” event
occurs . My
code exists in ProcessOneWayEvent method as I am handling ItemAdded event here.
publicclassRemoteEventReceiver1 : IRemoteEventService
{
publicSPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
SPRemoteEventResult result = newSPRemoteEventResult();
using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
{
if (clientContext != null)
{
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
}
}
{
publicSPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
SPRemoteEventResult result = newSPRemoteEventResult();
using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
{
if (clientContext != null)
{
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
}
}
return result;
}
}
publicvoid ProcessOneWayEvent(SPRemoteEventProperties properties)
{
// On Item Added event, the list item creation executes
if(properties.EventType == SPRemoteEventType.ItemAdded){
using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
{
if (clientContext != null)
{
try
{
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
List imageLibrary = clientContext.Web.Lists.GetByTitle(“Products”);
ListItemCreationInformation itemCreateInfo = newListItemCreationInformation();
ListItem oListItem = imageLibrary.AddItem(itemCreateInfo);
oListItem[“Title”] = “TITLE CHANGED BY RER”;
oListItem.Update();
clientContext.ExecuteQuery();
}
catch (Exception ex){ }
}
}
}
}
{
// On Item Added event, the list item creation executes
if(properties.EventType == SPRemoteEventType.ItemAdded){
using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
{
if (clientContext != null)
{
try
{
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
List imageLibrary = clientContext.Web.Lists.GetByTitle(“Products”);
ListItemCreationInformation itemCreateInfo = newListItemCreationInformation();
ListItem oListItem = imageLibrary.AddItem(itemCreateInfo);
oListItem[“Title”] = “TITLE CHANGED BY RER”;
oListItem.Update();
clientContext.ExecuteQuery();
}
catch (Exception ex){ }
}
}
}
}
}
}
How It Works:
The SPRemoteEventResult object
that is returned to SharePoint. SharePoint honors any modification you made to
the object and updates the document list columns appropriately. It’s important
to note that although you must choose Trust It when your app is installed, when
using the SPRemoteEventResult object only, if your code is not
explicitly calling back into SharePoint using CSOM or REST to read/write data,
then you do not need to write code that uses the TokenHelper class.
This example shows the pattern where your remote event receiver can impact data
being written to SharePoint by modifying the SPRemoteEventResult object
directly.
Hope this post was helpful! Millions of thanks for reading this blog.....happy sharepoint....happy coding...