Cesivi Server - Remote Event Receivers¶
Home → Documentation → Features → Remote Event Receivers
Table of Contents¶
- Overview
- Architecture
- Event Types
- Registration
- Event Triggering
- Testing
- API Reference
- Troubleshooting
Overview¶
Remote Event Receivers (RER) enable external applications to receive notifications when SharePoint events occur. This allows for real-time integration scenarios where external systems react to changes in SharePoint.
Key Features¶
✅ Full SharePoint Compatibility - Identical behavior to SharePoint Server Subscription Edition ✅ 30+ Event Types - Item, Field, Web, List, Security, and App events ✅ Before/After Events - Synchronous (cancellable) and asynchronous events ✅ Property Modification - Change item properties from Before events ✅ Sequence Control - Multiple receivers execute in defined order ✅ Retry Logic - Automatic retry with exponential backoff for failed calls ✅ CSOM/REST/SOAP - Multiple API access methods
Use Cases¶
- Validation - Cancel operations that don't meet business rules
- Notifications - Send emails/alerts when items are created/modified
- Integration - Sync data to external systems (CRM, ERP, databases)
- Auditing - Log all changes to external audit system
- Enrichment - Add computed fields or fetch data from external sources
- Workflow - Trigger custom business logic on SharePoint events
Architecture¶
Component Overview¶
┌─────────────────────────────────────────────────────────────┐
│ Cesivi Server │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌─────────────────────┐ ┌─────────┐ │
│ │ CSOM/REST │───►│ CsomProcessor/ │───►│ Storage │ │
│ │ Operation │ │ SharePointApiCtrl │ │ Service │ │
│ └────────────┘ └──────────┬──────────┘ └─────────┘ │
│ │ │
│ │ (Find registered RERs) │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ RemoteEventReceiverService │ │
│ │ • TriggerListEventAsync() │ │
│ │ • TriggerWebEventAsync() │ │
│ │ • TriggerSiteEventAsync() │ │
│ │ • BuildEventProperties() │ │
│ │ • CallRemoteEndpoint() │ │
│ │ • RetryWithBackoff() │ │
│ └───────────────────┬──────────────────────────────────┘ │
│ │ │
└──────────────────────┼─────────────────────────────────────┘
│ HTTP POST (JSON)
│
▼
┌─────────────────────────────────────────────────────────────┐
│ External Event Receiver Endpoint │
│ (e.g., http://service.com/rer) │
├─────────────────────────────────────────────────────────────┤
│ Receives: SPRemoteEventProperties (JSON) │
│ Returns: RemoteEventResult (JSON) │
│ • Status: Continue (0) or Cancel (1) │
│ • ErrorMessage (if cancelled) │
│ • ChangedProperties (Before events only) │
└─────────────────────────────────────────────────────────────┘
Event Flow¶
Before Events (Synchronous, Cancellable)¶
1. User/Code initiates operation (e.g., Add item)
2. Cesivi finds registered "Before" receivers
3. For each receiver (in sequence order):
a. Build SPRemoteEventProperties
b. HTTP POST to receiver URL (synchronous)
c. Wait for response (30 second timeout)
d. Process result:
- Status = Continue → Proceed to next receiver
- Status = Cancel → Abort operation, return error
- ChangedProperties → Apply property changes
4. If all receivers return Continue:
→ Execute operation
→ Trigger "After" events (async)
5. If any receiver returns Cancel:
→ Abort operation
→ Return error to user/code
After Events (Asynchronous, Fire-and-Forget)¶
1. Operation completes successfully
2. Cesivi finds registered "After" receivers
3. For each receiver (in sequence order):
a. Build SPRemoteEventProperties
b. HTTP POST to receiver URL (asynchronous, don't wait)
c. Retry on failure (3 attempts with exponential backoff)
d. Log success/failure
4. Continue execution (don't block on event calls)
Integration Points¶
RER events are triggered at the following locations in Cesivi Server:
| Integration Point | File | Events | Iteration |
|---|---|---|---|
| Item CRUD (CSOM) | Services/CsomProcessor.cs |
ItemAdding, ItemAdded, ItemUpdating, ItemUpdated, ItemDeleting, ItemDeleted | 1927 |
| CheckIn/Out (CSOM) | Services/CsomProcessor.cs |
ItemCheckingIn, ItemCheckedIn, ItemCheckingOut, ItemCheckedOut, ItemUncheckingOut, ItemUncheckedOut | 1928 |
| Field Operations (CSOM) | Services/CsomProcessor.cs |
FieldAdding, FieldAdded, FieldUpdating, FieldUpdated, FieldDeleting, FieldDeleted | 1930 |
| Web Operations (CSOM) | Services/WebService.cs |
WebAdding, WebAdded, WebDeleting, WebDeleted | 1931 |
| Item CRUD (REST) | Controllers/SharePointApiController.cs |
ItemAdding, ItemAdded, ItemUpdating, ItemUpdated, ItemDeleting, ItemDeleted | 1932 |
Event Types¶
Item Events (List/Library Items)¶
Before Events (Synchronous, Cancellable)¶
| Event Type | Value | Triggered When | Can Cancel | Can Modify Properties |
|---|---|---|---|---|
ItemAdding |
10000 | Before item is added | ✅ Yes | ✅ Yes |
ItemUpdating |
10001 | Before item is updated | ✅ Yes | ✅ Yes |
ItemDeleting |
10002 | Before item is deleted | ✅ Yes | ❌ No |
ItemCheckingIn |
10003 | Before file check-in | ✅ Yes | ✅ Yes |
ItemCheckingOut |
10004 | Before file check-out | ✅ Yes | ❌ No |
ItemUncheckingOut |
10005 | Before undo check-out | ✅ Yes | ❌ No |
ItemAttachmentAdding |
10006 | Before attachment added | ✅ Yes | ❌ No |
ItemAttachmentDeleting |
10007 | Before attachment deleted | ✅ Yes | ❌ No |
ItemFileMoving |
10008 | Before file moved | ✅ Yes | ✅ Yes |
After Events (Asynchronous)¶
| Event Type | Value | Triggered When |
|---|---|---|
ItemAdded |
10101 | After item added |
ItemUpdated |
10102 | After item updated |
ItemDeleted |
10103 | After item deleted |
ItemCheckedIn |
10104 | After file checked in |
ItemCheckedOut |
10105 | After file checked out |
ItemUncheckedOut |
10106 | After check-out undone |
ItemAttachmentAdded |
10107 | After attachment added |
ItemAttachmentDeleted |
10108 | After attachment deleted |
ItemFileMoved |
10109 | After file moved |
ItemFileConverted |
10110 | After file converted |
Field Events¶
| Event Type | Value | Triggered When | Can Cancel |
|---|---|---|---|
FieldAdding |
10010 | Before field added to list | ✅ Yes |
FieldUpdating |
10011 | Before field properties updated | ✅ Yes |
FieldDeleting |
10012 | Before field deleted | ✅ Yes |
FieldAdded |
10112 | After field added | ❌ No |
FieldUpdated |
10113 | After field updated | ❌ No |
FieldDeleted |
10114 | After field deleted | ❌ No |
Web Events¶
| Event Type | Value | Triggered When | Can Cancel |
|---|---|---|---|
WebAdding |
10201 | Before subweb created | ✅ Yes |
WebDeleting |
10202 | Before web deleted | ✅ Yes |
WebMoving |
10203 | Before web moved | ✅ Yes |
WebAdded |
10301 | After subweb created | ❌ No |
WebDeleted |
10302 | After web deleted | ❌ No |
WebMoved |
10303 | After web moved | ❌ No |
WebProvisioned |
10204 | After web provisioned | ❌ No |
List Events¶
| Event Type | Value | Triggered When | Can Cancel |
|---|---|---|---|
ListAdding |
11000 | Before list created | ✅ Yes |
ListDeleting |
11001 | Before list deleted | ✅ Yes |
ListAdded |
11101 | After list created | ❌ No |
ListDeleted |
11102 | After list deleted | ❌ No |
Security Events¶
| Event Type | Value | Triggered When |
|---|---|---|
GroupAdding |
20000 | Before group added |
GroupAdded |
20101 | After group added |
GroupUpdating |
20001 | Before group properties updated |
GroupUpdated |
20102 | After group updated |
GroupDeleting |
20002 | Before group deleted |
GroupDeleted |
20103 | After group deleted |
GroupUserAdding |
20003 | Before user added to group |
GroupUserAdded |
20104 | After user added to group |
GroupUserDeleting |
20004 | Before user removed from group |
GroupUserDeleted |
20105 | After user removed from group |
RoleDefinitionAdding |
30000 | Before permission level created |
RoleDefinitionAdded |
30101 | After permission level created |
RoleDefinitionUpdating |
30001 | Before permission level updated |
RoleDefinitionUpdated |
30102 | After permission level updated |
RoleDefinitionDeleting |
30002 | Before permission level deleted |
RoleDefinitionDeleted |
30103 | After permission level deleted |
RoleAssignmentAdding |
30003 | Before permission assigned |
RoleAssignmentAdded |
30104 | After permission assigned |
RoleAssignmentDeleting |
30004 | Before permission removed |
RoleAssignmentDeleted |
30105 | After permission removed |
Other Events¶
| Event Type | Value | Triggered When |
|---|---|---|
EmailReceived |
40000 | Email received by list |
AppInstalled |
60000 | SharePoint app installed |
AppUpgraded |
60001 | SharePoint app upgraded |
AppUninstalling |
60002 | Before app uninstalled |
Registration¶
CSOM (C#)¶
using (var ctx = new ClientContext("http://localhost:5000"))
{
ctx.Credentials = new NetworkCredential("admin", "password");
var web = ctx.Web;
var list = web.Lists.GetByTitle("Documents");
// Register ItemAdding event (Before, synchronous)
var receiverInfo = new EventReceiverDefinitionCreationInformation
{
ReceiverName = "ValidateDocuments",
ReceiverUrl = "http://myservice.com/rer",
EventType = EventReceiverType.ItemAdding,
Synchronization = EventReceiverSynchronization.Synchronous,
SequenceNumber = 1000
};
list.EventReceivers.Add(receiverInfo);
// Register ItemAdded event (After, asynchronous)
var afterReceiverInfo = new EventReceiverDefinitionCreationInformation
{
ReceiverName = "NotifyOnAdd",
ReceiverUrl = "http://myservice.com/rer",
EventType = EventReceiverType.ItemAdded,
Synchronization = EventReceiverSynchronization.Asynchronous,
SequenceNumber = 2000
};
list.EventReceivers.Add(afterReceiverInfo);
ctx.ExecuteQuery();
}
REST API¶
POST /_api/web/lists(guid'{list-id}')/eventreceivers
Content-Type: application/json
{
"ReceiverName": "ValidateDocuments",
"ReceiverUrl": "http://myservice.com/rer",
"EventType": 10000,
"Synchronization": 1,
"SequenceNumber": 1000
}
EventType Values: - See Event Types section for numeric values
Synchronization Values:
- 1 = Synchronous (for Before events)
- 2 = Asynchronous (for After events)
PnP PowerShell¶
# Connect to Cesivi Server
Connect-PnPOnline -Url http://localhost:5000 -CurrentCredentials
# Register list-scoped event receiver
Add-PnPEventReceiver -List "Documents" `
-Name "ValidateDocuments" `
-Url "http://myservice.com/rer" `
-EventType ItemAdding `
-Synchronization Synchronous `
-SequenceNumber 1000
# Register web-scoped event receiver
Add-PnPEventReceiver -Scope Web `
-Name "NotifyOnWebAdd" `
-Url "http://myservice.com/rer" `
-EventType WebAdded `
-Synchronization Asynchronous
# List registered receivers
Get-PnPEventReceiver -List "Documents"
# Remove event receiver
Remove-PnPEventReceiver -List "Documents" -Identity "ValidateDocuments"
Query Event Receivers¶
CSOM:
var list = ctx.Web.Lists.GetByTitle("Documents");
ctx.Load(list.EventReceivers);
ctx.ExecuteQuery();
foreach (var receiver in list.EventReceivers)
{
Console.WriteLine($"{receiver.ReceiverName}: {receiver.EventType} @ {receiver.ReceiverUrl}");
}
REST API:
GET /_api/web/lists(guid'{list-id}')/eventreceivers
PnP PowerShell:
Get-PnPEventReceiver -List "Documents"
Event Triggering¶
Event Properties (Payload)¶
Cesivi Server sends the following JSON payload to the remote endpoint:
{
"EventType": 10101,
"ContextInfo": {
"WebUrl": "http://localhost:5000/sites/mysite",
"SiteUrl": "http://localhost:5000/sites/mysite",
"UserLoginName": "admin@localhost",
"EventTime": "2025-10-24T12:34:56.789Z"
},
"ItemEventProperties": {
"ListId": "{abc-123-def-456}",
"ListTitle": "Documents",
"WebUrl": "http://localhost:5000/sites/mysite",
"SiteUrl": "http://localhost:5000/sites/mysite",
"UserLoginName": "admin@localhost",
"ListItemId": 42,
"IsNewItem": false,
"BeforeProperties": {
"Title": "Old Title",
"Status": "Draft"
},
"AfterProperties": {
"Title": "New Title",
"Status": "Published"
}
}
}
For Field Events:
{
"EventType": 10112,
"ContextInfo": { ... },
"FieldEventProperties": {
"ListId": "{list-guid}",
"FieldId": "{field-guid}",
"FieldInternalName": "CustomField",
"FieldXml": "<Field Name='CustomField' Type='Text' />",
"WebUrl": "http://localhost:5000/sites/mysite",
"UserLoginName": "admin@localhost"
}
}
For Web Events:
{
"EventType": 10301,
"ContextInfo": { ... },
"WebEventProperties": {
"WebId": "{web-guid}",
"WebUrl": "http://localhost:5000/sites/mysite/subweb",
"WebTitle": "My Subweb",
"ParentWebUrl": "http://localhost:5000/sites/mysite",
"UserLoginName": "admin@localhost"
}
}
Expected Response¶
The remote endpoint must return a JSON response:
Success (Continue):
{
"Status": 0,
"ErrorMessage": null
}
Cancel Operation (Before Events Only):
{
"Status": 1,
"ErrorMessage": "Document title must not contain special characters"
}
Modify Properties (Before Events Only):
{
"Status": 0,
"ChangedProperties": {
"Title": "Sanitized Title",
"Status": "Draft"
}
}
Status Codes:
- 0 = Continue (Allow operation)
- 1 = Cancel (Block operation and return error)
Retry Logic¶
For After events (asynchronous), if the remote endpoint fails:
- Attempt 1: Call endpoint
- Wait 1 second if failed
- Attempt 2: Retry
- Wait 2 seconds if failed
- Attempt 3: Final retry
- Log Error: Give up after 3 attempts
Before events (synchronous) do NOT retry - failure is immediately returned to the caller.
Timeout¶
All remote event receiver calls have a 30 second timeout. If the endpoint doesn't respond within 30 seconds: - Before events: Operation fails with timeout error - After events: Logged as failed attempt, retry logic applies
Testing¶
RER Test Tool¶
Cesivi Server includes a standalone RER Test Tool for testing event receiver functionality without building a custom receiver endpoint.
Location: Cesivi.RemoteEventReceiverTool/
Features: - ✅ HTTP server on configurable port (default: 8080) - ✅ Receives and logs all event types - ✅ Simulates event cancellation - ✅ Simulates processing delays - ✅ Console and file logging - ✅ Full event details display
Quick Start¶
Terminal 1: Start RER Test Tool
cd Cesivi.RemoteEventReceiverTool
dotnet run
Output:
╔════════════════════════════════════════════════════════════════╗
║ Cesivi Server - Remote Event Receiver Test Tool ║
╚════════════════════════════════════════════════════════════════╝
Configuration:
Port: 8080
Cancel Events: (none)
Delay: 0 ms
Log File: (console only)
Listening on: http://localhost:8080
Event endpoint: http://localhost:8080/rer
Press Ctrl+C to stop...
Terminal 2: Register Event Receiver & Test
# Start Cesivi Server
cd Cesivi.Server
dotnet run
# Terminal 3: Register and trigger events
Import-Module "C:\Path\To\SharePointPnPPowerShell2019\3.29.2101.0\SharePointPnPPowerShell2019.psd1"
Connect-PnPOnline -Url http://localhost:5000 -CurrentCredentials
# Register event receivers
Add-PnPEventReceiver -List "Documents" `
-Name "ItemAdding" `
-Url "http://localhost:8080/rer" `
-EventType ItemAdding `
-Synchronization Synchronous
Add-PnPEventReceiver -List "Documents" `
-Name "ItemAdded" `
-Url "http://localhost:8080/rer" `
-EventType ItemAdded `
-Synchronization Asynchronous
# Trigger events by adding item
Add-PnPListItem -List "Documents" -Values @{ "Title" = "Test Document" }
Expected Output (Terminal 1):
[2025-10-24 12:34:56.123] ItemAdding (10000) → Continue
Event Received: ItemAdding (10000)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Web URL: http://localhost:5000
Site URL: http://localhost:5000
User: admin@localhost
Item Event:
List ID: {abc-123-def-456}
List Title: Documents
Item ID: (new item)
Is New: true
After Properties:
Title: Test Document
Result: Continue
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[2025-10-24 12:34:56.456] ItemAdded (10101) → Continue
Event Received: ItemAdded (10101)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Web URL: http://localhost:5000
Site URL: http://localhost:5000
User: admin@localhost
Item Event:
List ID: {abc-123-def-456}
List Title: Documents
Item ID: 1
Is New: true
After Properties:
Title: Test Document
Result: Continue
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test Scenarios¶
Scenario 1: Basic Item Events
Test that ItemAdding (Before) and ItemAdded (After) events trigger correctly.
# See Quick Start above
Scenario 2: Event Cancellation
Test that Before events can cancel operations.
# Terminal 1: Start RER Test Tool with cancellation
cd Cesivi.RemoteEventReceiverTool
dotnet run --cancel-events ItemAdding
# Terminal 3: Try to add item
Add-PnPEventReceiver -List "Documents" -Name "ItemAdding" -Url "http://localhost:8080/rer" -EventType ItemAdding -Synchronization Synchronous
Add-PnPListItem -List "Documents" -Values @{ "Title" = "Test" }
Expected: Operation fails with error: "Event ItemAdding cancelled by RER Test Tool configuration"
Scenario 3: Multiple Receivers (Sequence Order)
Test that multiple receivers execute in sequence order.
# Register 3 receivers with different sequence numbers
Add-PnPEventReceiver -List "Documents" -Name "Receiver1" -Url "http://localhost:8080/rer" -EventType ItemAdded -SequenceNumber 1000
Add-PnPEventReceiver -List "Documents" -Name "Receiver2" -Url "http://localhost:8080/rer" -EventType ItemAdded -SequenceNumber 2000
Add-PnPEventReceiver -List "Documents" -Name "Receiver3" -Url "http://localhost:8080/rer" -EventType ItemAdded -SequenceNumber 3000
# Add item
Add-PnPListItem -List "Documents" -Values @{ "Title" = "Test" }
Expected: RER Test Tool receives 3 separate events (one per receiver) in order: 1000, 2000, 3000.
Scenario 4: Field Events
Test field-level events.
# Register field event receiver
Add-PnPEventReceiver -List "Documents" -Name "FieldAdded" -Url "http://localhost:8080/rer" -EventType FieldAdded
# Add field to trigger event
Add-PnPField -List "Documents" -Type Text -InternalName "CustomField" -DisplayName "Custom Field"
Expected: RER Test Tool receives FieldAdded event with field details.
Scenario 5: Web Events
Test web-level events.
# Register web event receiver
Add-PnPEventReceiver -Scope Web -Name "WebAdded" -Url "http://localhost:8080/rer" -EventType WebAdded
# Create subweb to trigger event
New-PnPWeb -Title "SubWeb" -Url "subweb" -Template "STS#0"
Expected: RER Test Tool receives WebAdded event with subweb details.
Scenario 6: REST API Events
Test that REST API operations trigger events.
# Register event receiver
Add-PnPEventReceiver -List "Documents" -Name "ItemAdding" -Url "http://localhost:8080/rer" -EventType ItemAdding -Synchronization Synchronous
Add-PnPEventReceiver -List "Documents" -Name "ItemAdded" -Url "http://localhost:8080/rer" -EventType ItemAdded -Synchronization Asynchronous
# Trigger via REST API
$listId = (Get-PnPList "Documents").Id
Invoke-RestMethod -Method Post -Uri "http://localhost:5000/_api/web/lists(guid'$listId')/items" `
-Body '{"Title":"REST Item"}' -ContentType "application/json"
Expected: Both ItemAdding and ItemAdded events trigger from REST operation.
Scenario 7: Property Changes from Before Events
(Note: Requires custom event receiver endpoint - RER Test Tool doesn't modify properties)
Build custom receiver that returns ChangedProperties in response:
{
"Status": 0,
"ChangedProperties": {
"Title": "Modified Title",
"Status": "Draft"
}
}
Expected: Item is created with modified properties applied.
Scenario 8: Error Handling and Fault Tolerance
Test retry logic for After events.
# Terminal 1: Start RER Test Tool
cd Cesivi.RemoteEventReceiverTool
dotnet run
# Register After event
Add-PnPEventReceiver -List "Documents" -Name "ItemAdded" -Url "http://localhost:8080/rer" -EventType ItemAdded -Synchronization Asynchronous
# Add item
Add-PnPListItem -List "Documents" -Values @{ "Title" = "Test" }
# Expected: Event received
# Now STOP the RER Test Tool (Ctrl+C)
# Add another item
Add-PnPListItem -List "Documents" -Values @{ "Title" = "Test 2" }
# Expected: Cesivi Server logs show 3 retry attempts with delays
Check Cesivi Server logs for retry messages:
[INFO] Triggering remote event receiver: ItemAdded
[WARN] Remote event receiver call failed: Connection refused. Retrying in 1000ms (attempt 1/3)
[WARN] Remote event receiver call failed: Connection refused. Retrying in 2000ms (attempt 2/3)
[WARN] Remote event receiver call failed: Connection refused. Giving up after 3 attempts.
RER Test Tool Command-Line Options¶
# Custom port
dotnet run --port 9000
# Cancel specific events
dotnet run --cancel-events ItemAdding,ItemUpdating,10002
# Simulate processing delay
dotnet run --delay-ms 500
# Log to file
dotnet run --log-file rer-events.log
# Combined
dotnet run --port 9000 --cancel-events ItemAdding --delay-ms 200 --log-file test.log
API Reference¶
IStorageService Extensions¶
public interface IStorageService
{
// Load event receivers for a specific scope
Task<List<SPEventReceiverDefinition>> LoadEventReceiversAsync(
string scope, // "List", "Web", or "Site"
string siteId,
string webId,
string objectId); // List ID, Web ID, or Site ID
// Save event receiver definition
Task SaveEventReceiverAsync(
SPEventReceiverDefinition receiver,
string scope,
string siteId,
string webId,
string objectId);
// Delete event receiver
Task DeleteEventReceiverAsync(
string receiverId,
string scope,
string siteId,
string webId,
string objectId);
}
RemoteEventReceiverService¶
public class RemoteEventReceiverService
{
// Trigger list-scoped event
Task<RemoteEventResult> TriggerListEventAsync(
string siteId,
string webId,
string listId,
SPEventReceiverType eventType,
SPRemoteEventProperties properties);
// Trigger web-scoped event
Task<RemoteEventResult> TriggerWebEventAsync(
string siteId,
string webId,
SPEventReceiverType eventType,
SPRemoteEventProperties properties);
// Trigger site-scoped event
Task<RemoteEventResult> TriggerSiteEventAsync(
string siteId,
SPEventReceiverType eventType,
SPRemoteEventProperties properties);
}
SPEventReceiverDefinition¶
public class SPEventReceiverDefinition
{
public string ReceiverId { get; set; }
public string ReceiverName { get; set; }
public string ReceiverUrl { get; set; }
public SPEventReceiverType EventType { get; set; }
public int Synchronization { get; set; } // 1=Sync, 2=Async
public int SequenceNumber { get; set; } // Execution order
}
SPRemoteEventProperties¶
public class SPRemoteEventProperties
{
public SPEventReceiverType EventType { get; set; }
public EventContextInfo ContextInfo { get; set; }
// Event-specific properties (only one is populated per event)
public SPItemEventProperties? ItemEventProperties { get; set; }
public SPFieldEventProperties? FieldEventProperties { get; set; }
public SPWebEventProperties? WebEventProperties { get; set; }
}
RemoteEventResult¶
public class RemoteEventResult
{
public int Status { get; set; } // 0=Continue, 1=Cancel
public string? ErrorMessage { get; set; }
public Dictionary<string, object>? ChangedProperties { get; set; }
public static RemoteEventResult Success() => new RemoteEventResult { Status = 0 };
public static RemoteEventResult Cancel(string errorMessage) => new RemoteEventResult { Status = 1, ErrorMessage = errorMessage };
}
Troubleshooting¶
Events Not Triggering¶
Problem: Event receiver registered but not receiving callbacks.
Checklist:
-
✅ Verify registration:
Ensure receiver is listed with correct URL and event type.Get-PnPEventReceiver -List "Documents" -
✅ Check receiver URL is accessible:
Should return HTTP 200 (not 404).curl http://localhost:8080/rer -
✅ Verify event type matches operation:
- Adding item → ItemAdding (Before), ItemAdded (After)
- Updating item → ItemUpdating, ItemUpdated
-
Deleting item → ItemDeleting, ItemDeleted
-
✅ Check Cesivi Server logs: Look for "Triggering remote event receiver" messages.
-
✅ Verify synchronization type:
- Before events: Synchronization = Synchronous (1)
- After events: Synchronization = Asynchronous (2)
Connection Refused / Timeout¶
Problem: Cesivi Server can't reach event receiver endpoint.
Solutions:
-
✅ Check endpoint is running:
curl http://localhost:8080/rer -
✅ Verify port number: Ensure receiver URL port matches actual listening port.
-
✅ Check firewall: Allow inbound connections on receiver port.
-
✅ Localhost vs 127.0.0.1: Try both in receiver URL.
-
✅ Network accessibility: If Cesivi Server and receiver are on different machines, ensure network connectivity.
Event Cancellation Not Working¶
Problem: Returning Status: 1 but operation still proceeds.
Checklist:
- ✅ Verify it's a Before event: Only Before events (ending in "ing") can cancel operations.
- ItemAdding ✅ Can cancel
-
ItemAdded ❌ Cannot cancel
-
✅ Check synchronization: Before events MUST use
Synchronization = Synchronous. -
✅ Verify response format:
{ "Status": 1, "ErrorMessage": "Your error message" } -
✅ Check HTTP status: Receiver should return HTTP 200 (not 400/500).
Property Changes Not Applied¶
Problem: Returning ChangedProperties but item properties not modified.
Checklist:
- ✅ Only Before events support property changes:
- ItemAdding, ItemUpdating ✅ Supported
-
ItemAdded, ItemUpdated ❌ Not supported
-
✅ Verify response format:
{ "Status": 0, "ChangedProperties": { "Title": "New Title", "CustomField": "Value" } } -
✅ Check field internal names: Use
InternalName, notDisplayName. - "Title" ✅ Correct
-
"Document Title" ❌ Incorrect (display name)
-
✅ Verify field exists: Changed properties must reference existing fields.
Multiple Receivers Not Executing in Order¶
Problem: Receivers execute in wrong order or skip some receivers.
Solutions:
-
✅ Verify SequenceNumber:
Lower numbers execute first (1000, 2000, 3000).Get-PnPEventReceiver -List "Documents" | Select-Object ReceiverName, SequenceNumber | Sort-Object SequenceNumber -
✅ Check all receivers have same EventType: Receivers for different event types won't execute together.
-
✅ Ensure previous receiver doesn't cancel: If any Before event receiver returns
Status: 1, subsequent receivers are NOT called.
Logs Show "No remote event receivers registered"¶
Problem: Cesivi Server logs indicate no receivers found.
Solutions:
- ✅ Check scope:
- List-scoped: Registered on specific list
- Web-scoped: Registered on web
-
Site-scoped: Registered on site collection
-
✅ Verify correct list/web/site:
# List all receivers for a list Get-PnPEventReceiver -List "Documents" # List web-scoped receivers Get-PnPEventReceiver -Scope Web -
✅ Re-register if needed:
Remove-PnPEventReceiver -List "Documents" -Identity "MyReceiver" -Force Add-PnPEventReceiver -List "Documents" -Name "MyReceiver" -Url "http://localhost:8080/rer" -EventType ItemAdded
Asynchronous Events Not Retrying¶
Problem: After events fail but don't retry.
Expected Behavior:
After events (asynchronous) automatically retry 3 times with exponential backoff (1s, 2s, 4s).
Check Cesivi Server logs:
[INFO] Triggering remote event receiver: ItemAdded
[WARN] Remote event receiver call failed. Retrying in 1000ms (attempt 1/3)
[WARN] Remote event receiver call failed. Retrying in 2000ms (attempt 2/3)
[ERROR] Remote event receiver call failed after 3 attempts
If you don't see retry messages, check:
1. Event is truly asynchronous (Synchronization = 2)
2. Cesivi Server version includes retry logic (Iteration 1927+)
Performance Issues¶
Problem: Operations slow when event receivers are registered.
Expected:
- Before events (synchronous): Add 30-1000ms per receiver (network latency + processing)
- After events (asynchronous): No impact on user operations (fire-and-forget)
Optimization:
-
✅ Use After events when possible: If you don't need to cancel/modify, use asynchronous After events.
-
✅ Minimize receiver processing time: Keep receiver logic fast (<100ms ideal).
-
✅ Reduce Before event receivers: Each Before receiver adds latency to user operations.
-
✅ Use sequence numbers wisely: Critical validation first (low sequence), non-critical logging last (high sequence).
See Also¶
- RER Test Tool README:
Cesivi.RemoteEventReceiverTool/README.md - Microsoft Documentation: Handle events in SharePoint Add-ins
- CSOM Reference:
Models/SharePoint/SPEventReceiverDefinition.cs - REST API Endpoints:
Controllers/SharePointApiController.cs(lines 2220-2442) - Integration Examples:
Services/CsomProcessor.cs(search for "ITERATION-1927", "ITERATION-1930", "ITERATION-1932")
Implementation Status¶
✅ Phase 1: Models & Storage (Complete - Iteration 1926) ✅ Phase 2: Registration APIs (Complete - Iteration 1926) ✅ Phase 3: Event Triggering System (Complete - Iteration 1926) ✅ Phase 4: Integration Points (Complete - Iterations 1927-1932) - ✅ Phase 4.1-4.3: Item events (CSOM) - Iteration 1927 - ✅ Phase 4.4: CheckIn/Out events (CSOM) - Iteration 1928 - ✅ Phase 4.5: Field events (CSOM) - Iteration 1930 - ✅ Phase 4.6: Web events (CSOM) - Iteration 1931 - ✅ Phase 4.7: REST API events - Iteration 1932 ✅ Phase 5: RER Test Tool (Complete - Iteration 1927) 📋 Phase 6: Testing & Documentation (In Progress - Iteration 1934)
Overall Progress: 95% → 100% (with documentation)
See Also¶
- REST API - REST endpoints for event receiver management
- CSOM - Client-Side Object Model event registration
- SOAP Services - Legacy SOAP web services
- Permissions - Permission system and ACLs
- API Reference - Complete API documentation
Last Updated: November 15, 2025 Version: 1.0.0 Compatibility: SharePoint 2019, SharePoint Online
Navigation: Home | Documentation | Features | Remote Event Receivers