Wednesday, June 11, 2014

Remote Event Receivers in SharePoint 2013

 

A new concept of remote event receivers have been introduced in SharePoint 2013. 

These are similar to event receivers in 2010 except that they run remotely and not actually on server.  Hence we user CSOM in the handlers.

There can be two type of event receivers

1. App event receivers

2. Remote event receivers.

Now we need to be clear that app event receivers and Remote event receivers work in Cloud Hosted App i.e. auto hosted or provider hosted.  They do not work with SharePoint Hosted apps.  I have seen some examples on net having remote event receivers on SharePoint Hosted app but event receivers are not meant for SharePoint Hosted App.  There are some methods of these receivers to get client context and they dont work with SharePoint Hosted app.  I had a tough time struggling with an event receiver on SharePoint Hosted app and then I stumbled on a line in msdn

Excerpt from MSDN

Note

Remote event receivers and app event receivers work only with cloud apps for SharePoint (that is, provider-hosted apps). These receivers don't work with SharePoint-hosted apps for SharePoint.

Source - http://msdn.microsoft.com/en-us/library/office/jj220048(v=office.15).aspx

How Does it work

Web services are used in remote event receiver. 

When we add a remote event receiver to an app, a web service also gets added which handles these events.

Open Visual studio, Create a new project (App For SharePoint).  I am going to select AutoHosted.

Now Add New List.  Name the list “ListInApp”.

Now click add new item, Select Remote Event Receiver.  It would ask for list name to be associated with.  Select list just created ‘ListInApp’

image

Name it as AppListReceiver. 

Next select “List Item Event” in type of event receiver.  Select the list ListinApp that we just created. (Notice there are ItemAdding and ItemAdded, ItemDeleting and ItemDeleted and so forth)

image

I am going to select ItemDeleting and ItemAdded.

Notice AnnouncementReceiver.svc gets added in the solution explorer in the App Web project.

image

In the .svc file we notice there are 2 methods. ProcessEvent and ProcessOneWayEvent.

Now before we get into code let us look at the events

We can handle Before and After events.  Now the Before events i.e. ItemAdding, ItemDeleting, etc are always synchronous while the after events i.e. ItemAdded, ItemDeleted etc can be synchronous as well as asynchronous

ProcessEvent handles the synchronous methods while ProcessOneWayEvent are one way, i.e. asynchronous.  They just fired and are forgotten. 

Notice I selected ItemDeleting and ItemAdded.

I am going to handle ItemDeleting to stop allowing to delete any items from my list.

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
       {
           SPRemoteEventResult result = new SPRemoteEventResult();

           if (properties.EventType == SPRemoteEventType.ItemDeleting)
           {
               result.ErrorMessage = "Deleting items from this list is not allowed";
               result.Status = SPRemoteEventServiceStatus.CancelWithError;
           }

           return result;

}

 

Similarly we can write code in ItemAdded even in the method ProcessOneWayEvent

Getting ClientContext in Remote Event Receivers.

Now to get client context there is a method available TokenHelper.CreateRemoteEventReceiverClientContext(properties)

Now a point to note here is the client context we get here is that of app web.  That is because the event receiver is to handle events on a list on app web.  If the event receiver is written to handle events of list on host web, the context returned is that of host web.

This brings the question how do we create remote event receiver to a list of host web.  We do not get that option in Visual studio.  This has to be done programmatically.  Let us see how

Remote event receivers for list on host web

To do this I am going to write an app event receiver.  My plan is to code an app.  When this app gets installed, it add an event receiver to a list of host web. 

Create a new app project for sharepoint.  Select AutoHosted App. 

Go to properties of the app and select the property “HandleAppInstalled”  Set it to True

image

On doing so we will find AppEventReceiver.svc added to solution explorer in the appweb project

image

This would have method ProcessEvent

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)

Further Below code can be self explanatory

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
       {
           SPRemoteEventResult result = new SPRemoteEventResult();

           switch (properties.EventType)
           {
               case SPRemoteEventType.AppInstalled: HandleAppInstalled(properties);
                   break;

                case SPRemoteEventType.AppUnInsstalled: HandleAppUninstalled(properties); break;
            }

           return result;

 

In HandleAppInstalled we will try to attach remote event receiver to host web’s list.  Now to do this we need client context to host web. 

SP gives us a magical method TokenHelper.CreateAppEventClientContext(properties,false)

If the second parameter of this method is false, it returns us the client context to host web else it returns us the client context to app web.

Note that this method is available only with App event receiver and when we try to use it with remote event receiver it returns null.

Below is the code

private void HandleAppInstalled(SPRemoteEventProperties properties)
      {

using (ClientContext clientContext =TokenHelper.CreateAppEventClientContext(properties,false))
          {
              if (clientContext != null)
              {
                  bool rerExists = false;
                  List myList = clientContext.Web.Lists.GetByTitle("MyAnnouncements");
                  clientContext.Load(myList, p => p.EventReceivers);
                  clientContext.ExecuteQuery();

                  foreach (var rer in myList.EventReceivers)
                  {
                      if (rer.ReceiverName == "ItemAddedEvent")
                      {
                          rerExists = true;
                      }
                  }

                  if (!rerExists)
                  {
                      EventReceiverDefinitionCreationInformation receiver = new EventReceiverDefinitionCreationInformation();
                      receiver.EventType = EventReceiverType.ItemAdded;
                      receiver.ReceiverName = "ItemAddedEvent";
                      OperationContext op = OperationContext.Current;
                      receiver.ReceiverUrl = op.RequestContext.RequestMessage.Headers.To.ToString();
                      receiver.Synchronization = EventReceiverSynchronization.Synchronous;
                      myList.EventReceivers.Add(receiver);
                      clientContext.ExecuteQuery();
                  }

} }  }

 

The above code attaches event receiver to the MyAnnouncements list of host web.  Now you must be wondering where do we write the event handler for this.  If you closely observe the code we have given the Receiver url of the same class, hence we can write the event handler here itself.

The process event function of AppEventReceiver.svc gets changed to this

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
       {
           SPRemoteEventResult result = new SPRemoteEventResult();

           switch (properties.EventType)
           {
               case SPRemoteEventType.AppInstalled: HandleAppInstalled(properties);
                   break;

                case SPRemoteEventType.AppUnInsstalled: HandleAppUninstalled(properties); break;

                case SPRemoteEventType.ItemAdded: HandleItemAdded(properties); break;
            }

           return result;

}

We add a function HandleItemAdded and that would have the code what needss to be done when we an item is added to MyAnnouncements list.

Debugging

Last but not the least, how do I debug this app?  To do this we can use Windows Azure service bus.

Steps from msdn (Source - http://msdn.microsoft.com/en-us/library/office/jj220047(v=office.15).aspx#DebugRER )  I tend to copy imp things on my blog as you never know which link breaks and goes down ;-)

Debugging remote events


To debug remote event receivers and app event receivers in an app for SharePoint, perform the following steps.

  1. If you're behind a firewall, you may need to install a proxy client (such as the Forefront Threat Management Gateway (TMG) Client), depending on your company's network topology.

  2. Register for a Microsoft Azure account if you haven't already, and then sign into that account.

    For information about how to register for an Azure account, see Microsoft Azure.

  3. Create an Azure Service Bus namespace, which you can use to debug remote events.

    For more information about the Azure Service Bus, see Messaging and Managing Service Bus Service Namespaces.

    Note Note

    Remote event debugging uses the Relay Service component of the Azure Service Bus, so you'll be charged for using the Service Bus. See Service Bus Pricing FAQ. You get free access to Azure each month that you subscribe to Visual Studio Professional with MSDN, Visual Studio Premium with MSDN, or Visual Studio Ultimate with MSDN. With this access, you can use the Service Bus relay for 1,500, 3,000, or 3,000 hours, depending on your MSDN subscription. See Get some amount of Microsoft Azure Services each month at no additional charge.

  4. In Azure, choose your service namespace, choose the Access Key link, and then copy the text in the Connection String box.

  5. On the properties page of your app for SharePoint project, choose the SharePoint tab, and then select the Enable debugging via Microsoft Azure Service Bus check box.

    You must enable this feature to debug remote events in cloud apps for SharePoint. This property applies to all of your SharePoint projects in Visual Studio. Visual Studio automatically turns off remote event debugging if you package your app for distribution on the Office store.

  6. In the Microsoft Azure Service Bus connection string box, paste the connection string that you copied.

  7. If you don't enable remote debugging and don't want to receive a notification whenever your project contains a remote event receiver or an app event receiver, clear the Notify me if Microsoft Azure Service Bus debugging is not configured check box.

After you enable remote event debugging and provide a valid connection string for the Azure Service Bus, you can debug remote events.

Note Note

If the remote event receiver doesn't hit a breakpoint immediately, the event might be asynchronous. Events that contain the word "being", such as "An item is being added" or "An item is being deleted", are synchronous and complete faster. Events that contain the word "was", such as "An item was added" or "An item was deleted", are asynchronous and take slightly longer to complete.

2 comments:

Anonymous said...

Looks good and I've implemented it but just one thing. When I run the code it neither displays the message nor prevents the deletion of the item in Office365.

Any ideas?

Location Voiture à Casablanca | Aéroport. Les Meilleurs Prix‎ said...

I have thoroughly enjoyed your NYC guide – thank you for sharing! Such wonderful picks and tips!