The project that I’m working on requires that I add remote event receivers to the host web for my Provider-hosted app. This is a little unusual – most of the stuff I found about remote event receivers was using the app web. It turns out, though, that it is possible, and there is a good explanation of how it works by Johnny Tordgeman on CodeProject. Rather than repeat all he’s said, I suggest you take a look. I just want to expand on some of the things I learnt doing this, that he didn’t mention.
For the lazy, here are the highlights:
- Declarative Remote Event Receiver definitions can only be used in the app web, not the host.
- You can add a Remote Event Receiver programmatically to the host web. The best way of doing this in the App Installed event.
- The app will need ‘Manage’ rights to do this.
Okay, sounds simple enough. To handle the App Installed/Uninstalling events I created the following method:
public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) { SPRemoteEventResult result = new SPRemoteEventResult(); using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false)) { if (clientContext != null) { clientContext.Load(clientContext.Web); List exampleList = clientContext.Web.Lists.GetByTitle("Example"); clientContext.Load(exampleList); clientContext.ExecuteQuery(); if (properties.EventType == SPRemoteEventType.AppInstalled) { string opContext = OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.Substring(0, OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri.LastIndexOf("/")); string rerSvcUrl = string.Format("{0}/RemoteEventReceiver.svc", opContext); RegisterEventReceiver(clientContext, exampleList, "MyRemoteEventReceiver", rerSvcUrl, EventReceiverType.ItemAdded, 1000); } else if (properties.EventType == SPRemoteEventType.AppUninstalling) { UnregisterAllEventReceivers(clientContext, exampleList, "MyRemoteEventReceiver"); } } } return result; }
You’ll notice that much of the above is based on Johnny Tordgeman’s example. This used the following to register an event:
private void RegisterEventReceiver(ClientContext clientContext, List list, string name, string serviceUrl,EventReceiverType eventType, int sequence) { EventReceiverDefinitionCreationInformation newEventReceiver = new EventReceiverDefinitionCreationInformation() { EventType = eventType, ReceiverName = name, ReceiverUrl = serviceUrl, SequenceNumber = sequence }; list.EventReceivers.Add(newEventReceiver); clientContext.ExecuteQuery(); }
And this to remove any event receiver registrations:
private void UnregisterAllEventReceivers(ClientContext clientContext, List list, string name) { EventReceiverDefinitionCollection erdc = list.EventReceivers; clientContext.Load(erdc); clientContext.ExecuteQuery(); List<EventReceiverDefinition> toDelete = new List<EventReceiverDefinition>(); foreach (EventReceiverDefinition erd in erdc) { if (erd.ReceiverName == name) { toDelete.Add(erd); } } foreach (EventReceiverDefinition item in toDelete) { item.DeleteObject(); clientContext.ExecuteQuery(); } }
Note that I am identifying what should be removed by the registration’s name.
This removal of remote event receiver registrations is actually pretty important. It turns out that you can’t remove those registrations with, say, a console application and some C# client-side object model code – you’ll just get an error “Access Denied”. It appears that only the app itself can remove it’s own event receiver registrations. This makes sense – you don’t want other scripts/apps removing the event receivers your solution relies on. However, I think it could lead to a lot of orphaned event receivers if people just follow Johnny’s example, and don’t tidy up after themselves. Certainly, there are a few people asking about it and I believe the following:
I’ve been in touch with someone at Microsoft. He said the behaviour was as-designed and that a remote event receiver could only be removed by the app that added it.
Taking that at it’s word, I wrote my app to do just that. That worked, albeit that I had problems using F5-debug deployment and the App Uninstalling event.
I found your post and it helped me out quite a bit. I for one don’t like seem to like that other programs cannot remove your event receivers. This is especially painful when your RER is on the Web. If your remote event receiver cannot be reached for whatever reason you still can have orphaned event receivers. What then? Subsequent deploys duplicate the event receiver and then cannot be removed even by the uninstalling event. It seems SPOnline even knows what instance of your app deployed the RER so looping and getting all orphaned RER of your same type will throw and error when deleting.
I agree Tim… This is a huge joke… Remote Event Receivers on SharePoint Online (maybe on prem also) are terrible to write… I have wasted far too much time messing around with this and I’m a SharePoint developer veteran… I find this happens over and over again with Microsoft… The development experience is a terribly unpredictable experience…