I thought I needed a SharePoint Provider Hosted App for that. - Part 1
This is part 1 of 2 where I’ll explain deploying a SharePoint Remote Event Receiver (RER) without the need for a Provider Hosted Application (PHA). In part 2 I’ll talk a bit about the limitations of this approach and also mention some other really great client side enhancements that you can add without deploying a PHA. A code sample in GitHub is also available.
I’ve done a bunch of work with RER's and talk about them regularly. Recently, I was mentioning to a colleague that a RER would be clutch to take care of some advanced data updating and validation when adding or changing list items in lists and document libraries. He said it sounded cool, but was not excited about the prospect of deploying a complete PHA just to do some validation in the host web. I told him that he didn’t have to deploy a PHA to use an RER. He looked at me quizzically and said, “I thought I needed an app for that”. A call to an RER is simply SharePoint making a connection to a REST endpoint, passing in some arguments and retrieving a response, it does not require the high trust connection typically associated with PHA’s. The following steps will explain deployment of an RER without the need for a provider hosted app.
1. Create or use an existing SharePoint site, add a list, add some columns to the list, etc., etc. We need a list in a SharePoint site for this example, use whatever one you want.
2. In Visual Studio, create an “ASP.Net Empty Web Application” called RERWithoutPHA.
3. Right click on the RERWithoutPHA project, then choose Manage “NuGet Packages…”. In the search box enter “pnp”. Choose on-prem or cloud and install.
(The PNP NuGet package is awesome, it scaffolds your project with all you’ll need to access SharePoint from your remote web server (or any application for that matter) and includes the Tokenhelper and SharePointContext classes, so if you were creating a PHA this is all you’d need to do to get rolling. But… in all truth, for this example all we need is a reference to Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll)
4. Add a “WCF Service” to the RERWithoutPHA called RERSynchronous. Edit the RERSynchronous service code behind then implement “IRemoteEventService”.
using Microsoft.SharePoint.Client.EventReceivers;
namespace RERWithoutPHA
{
public class RERSynchronous : IRemoteEventService
{
public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
SPRemoteEventResult result = new SPRemoteEventResult();
// if this is a document library and this item is being updated, have a look at the
//value of the fields before they were changed.
// the BeforeProperties collection is only available for document libraries, it will be null for
// lists
string myFieldBefore = properties.ItemEventProperties.BeforeProperties["myField"].ToString();
// Have a look at the changed fields. Of Course you'll have to change "myField" to the name of a
// field in your list or document library
string myFieldAfter = properties.ItemEventProperties.AfterProperties["myField"].ToString();
// Maybe you'd like to change the value of a field in your list item
result.ChangedItemProperties.Add("fieldIWantToChange", "My New value");
// maybe you don't like what's been done and want to tell SharePoint to cancel the save
// comment in the lines below to see the save cancel
//result.ErrorMessage = "No can do!";
//result.Status = SPRemoteEventServiceStatus.CancelWithError;
//YOU GET THE PICTURE
return result;
}
public void ProcessOneWayEvent(SPRemoteEventProperties properties)
{
//this event will not fire unless Asynchronous methods have been registered
//but must be here to satisfy the IRemoteEventService interface
}
}
}
5. Add a console application to the solution called RERWithoutPHADeploy.
6. Add the “OfficeDevPnP.Core” NuGet reference to the RERWithoutPHADeploy as well. (Once again, you really only need a reference to Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll).
7. Add the following code to your “Main” Method in the console app. Be sure to add
using Microsoft.SharePoint.Client
above your namespace declaration.
Also, I wrote this on one of my VM’s so the logged on user had rights to run the code, if you’re deploying to o365 you’ll need to create an instance of SharePointOnlineCredentials and set it to the clientContext.Credentials, if on-prem using NTLM but not the user you’re logged in as then use NetworkCredentials.
This code verbose for example purposes, it is more efficient in the supplied code sample.
string sharePointUrl = "<the url for your SharePoint site>";
string remoteWebUrl = "<the url for your web site where the RER is hosted>";
string listName = "<The name of the SharePoint list>";
// If you are authenticating onPrem as the user you’re in as then this will work fine, else
// you’ll need to pass an instantiation of a class that implements ICredentials to the clientContext.Credentials property
ClientContext clientContext = newClientContext(sharePointUrl);
List targetList = clientContext.Web.Lists.GetByTitle(listName);
clientContext.Load(targetList);
EventReceiverDefinitionCollection ec = targetList.EventReceivers;
clientContext.Load(ec);
EventReceiverDefinitionCreationInformation eventReceiver = newEventReceiverDefinitionCreationInformation();
eventReceiver.EventType = EventReceiverType.ItemUpdating;
// The ReceiverAssembly and ReceiverClass properties, as far as I can tell, are not needed, at
// least for this example, the RER gets deployed and functions properly with or without them, you
// may choose to use them for completeness
// they are, as far as I can tell holdovers from FTC Event Receivers, I could be wrong, don’t shoot!
//eventReceiver.ReceiverAssembly = "RERWithoutPHA";
//eventReceiver.ReceiverClass = "RERWithoutPHA.Services.RERSynchronous";
eventReceiver.ReceiverName = "RERSynchronous";
eventReceiver.ReceiverUrl = remoteWebUrl + "/RERSynchronous.svc";
eventReceiver.SequenceNumber = 1000;
eventReceiver.Synchronization = EventReceiverSynchronization.Synchronous;
targetList.EventReceivers.Add(eventReceiver);
eventReceiver = new EventReceiverDefinitionCreationInformation();
eventReceiver.EventType = EventReceiverType.ItemAdding;
eventReceiver.ReceiverName = "RERSynchronous";
eventReceiver.ReceiverUrl = remoteWebUrl + "/RERSynchronous.svc";
eventReceiver.SequenceNumber = 1000;
eventReceiver.Synchronization = EventReceiverSynchronization.Synchronous;
targetList.EventReceivers.Add(eventReceiver);
eventReceiver = newEventReceiverDefinitionCreationInformation();
eventReceiver.EventType = EventReceiverType.ItemDeleting;
eventReceiver.ReceiverName = "RERSynchronous";
eventReceiver.ReceiverUrl = remoteWebUrl + " /RERSynchronous.svc";
eventReceiver.SequenceNumber = 1000;
eventReceiver.Synchronization = EventReceiverSynchronization.Synchronous;
targetList.EventReceivers.Add(eventReceiver);
clientContext.Web.Context.ExecuteQuery();
8. Run the console app to deploy the RER’s to SharePoint
9. Ensure that your web site is up and running (preferably for testing in debug so you can see the event happening in code).
10. Add/edit/delete items from your list and watch the sparks fly, no PHA required!
That’s it! Please do have a look at the code sample in GitHub, the code’s a bit nicer. But... provided as is.