Deploy Remote Event Receiver without using add-in or app (without using AppInstalled event to be precise)
UPDATED (3/31/2017): Added links to GitHub projects/source code. See at the end of this article.
You still need to create a dummy app(cliend id/secret creating an app principal) or install a provider hosted add-in/app that acts as a placeholder (dummy). More details below. Below article is based on my work on SPonline (not on-premises).
How does remote event receivers work?
The logic is simple as you know, we just need to tell
SharePoint that go and talk to a WCF URL on a certain event (e.g. ListAdded or
ItemAdding etc.) We host this WCF site in Azure and the URL is something like https://rer.azurewebsites.net. When
the event occurs, SharePoint attempts to reach out to this URL while sending
the event properties object (SPRemoteEventProperties).
Let me break it down from here.
You can start by creating a regular WCF service based web
app that implements the IRemoteEventService interface. This essentially means
it must override the methods ProcessEvent and ProcessOneWayEvent methods. Add
references to SharePoint Client 16 Dlls using Nuget manager. You can optionally
add Office Dev Pnp reference too using nuget again. Ensure
Microsoft.IdentityModel package is also added (which most probably will be
added automatically due to dependencies). Make sure that your project now has
the TokenHelper.cs class also. The clientcontext object is retrieved as a app
only access token. This code is different from the code that is used normally
for a RER. Do not publish the site to Azure yet.
Note:
Instead of creating another web app like above, you can also use the remote web
project that gets created when you create the Provider hosted app.
Create a new Provider Hosted App in visual studio. I created
one and named it as Contoso.Samples.ReRPlaceHolderApp. As the name suggests
this acts as a placeholder app only and we deploy it just once and do not
redeploy when our code change.
Now open up the AppManfiest.xml and ensure that “allow the
app to make app-only calls to sharepoint” is checked. Also, I gave full tenant
permissions so that we can attach the RER to any Web or List across the tenant.
I then generated a new client id and secret using the appregnew.aspx page. For the app domain and
redirect url you can use any test url. Below are my app details.
Used the above client id/secret values while deploying the
PHA app to the tenant. Upload the. app file and then trust it. Note that I
never bothered about the remote web that gets created in visual studio. I never
deployed it. As noted above
you can still use this remote web for the azure site.
We need to do the above so that we have an app principal
(app id and secret) that is trusted in our tenant. We later use the app id and
secret in our WCF project.
Recommended for Dev Environments:
Instead of creating a dummy Provider Hosted App just to get the app principal, you can easily create an app principal by following below steps:
Navigate to _layouts/appregnew.aspx for any of the SPO sites, create new client id/secret. Then go to _layouts/appinv.aspx, search for that client id, then add the permission XML:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest
Scope="https://sharepoint/content/tenant"
Right="FullControl"/>
</AppPermissionRequests>
Then in the next page, Trust the app. That’s it, you've created an app principal. If your prod deployment team is okay, you can follow same steps in prod too but not recommended. Otherwise, you have to deploy the app in app catalog.
Let’s go back to our WCF project and plug in the App id and
secret in the web.config file.
<appSettings>
<add key="ClientId" value="063ff54c-b94a-4e2a-880f-061cc899a239" />
<add key="ClientSecret" value="UsLDcUpWxoVuN8eKME7PhOqMTcRO+JSQb8TWkU0S7qA=" />
</appSettings>
Now go ahead and deploy the web app to Azure.
You can use a C# console or PowerShell to configure the
above Azure URL as RER, say for example, on a ListAdded event call this URL.
Here is sample code:
EventReceiverDefinitionCreationInformation eventReceiver = new EventReceiverDefinitionCreationInformation ();
eventReceiver.EventType = eventReceiverType;
eventReceiver.ReceiverClass = "Contoso.Samples.RERWeb.Services.SampleRERService";
eventReceiver.ReceiverName = "SampleRERListAdded";
eventReceiver.ReceiverUrl = "https://samplerer.azurewebsites.net/Services/SampleRERService.svc";
eventReceiver.Synchronization = EventReceiverSynchronization.Synchronous;
web.EventReceivers.Add(eventReceiver);
clientContext.ExecuteQuery();
Major benefits with this approach:
- Development is lesser hassle. I have seen dev
teams installing, uninstalling and redeploying every time they want to try
different events (ListAdded/Adding sync/async). - You can keep updating your WCF service project and deploy to Azure and then use PowerShell/C# to
add/remove receivers to different sites and for different events. - One place holder PHA is enough to deploy
multiple RERs - In traditional approach, the app appears in the
site contents page. This method gets around it.
I have code samples that I plan to link here or upload to GitHub.
Code samples are published on GitHub.
RERDeployer: https://github.com/svarukala/RemoteEventReceiverDeployerTool
RERSampleWeb: https://github.com/svarukala/RemoteEventReceiverWeb
Comments
- Anonymous
July 25, 2016
What if I don't have Azure Subscription? Can i host my *.svc on any production server and use that URL instead of azure url? I tried this but it doesn't worked.- Anonymous
September 21, 2016
Sorry the late response.I didn't get chance to log into my blog since some time. The remote service should work fine from an on-premises server (IIS) too. Just ensure it is anonymous and it doesn't require authentication.
- Anonymous
- Anonymous
March 11, 2017
this is great way Srinivas.. did u get a chance to upload sample code? I tried create WCF service , but I am messing up somewhere while referencing the dlls I guess. Sample code will help- Anonymous
March 29, 2017
Sure. I will update the post with the GitHub links to the source code. - Anonymous
March 30, 2017
@Rohit, updated the article with the GitHub project links.
- Anonymous
- Anonymous
August 23, 2017
Thanks for the Nice article! I get client Context correctly after following up with Only App Principal method (NO Dummy Provided Hosted App). But when I am loading list item on ItemAdded event it give me this exception on ExecuteQuery. "Item does not exist. It may have been deleted by another user." What could be reason for this?- Anonymous
August 24, 2017
Can you check if you are able to make any other CSOM call at all? For example, just get the SPWeb title and see if it works.
- Anonymous
- Anonymous
September 11, 2017
Hi Srinivas,I am trying to debug the ReRDeployer code, but when I enter value 2, it throws this error at ctx.ExecuteQuery inside AttachReceiver method : "An unhandled exception of type 'System.Xml.XmlException' occurred in System.Xml.dllAdditional information: For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method."Can you please help how to attach the event receiver to existing list?Thanks,Sravan- Anonymous
September 11, 2017
The comment has been removed
- Anonymous