Skip to content

Cesivi Server - Remote Event Receivers

HomeDocumentationFeatures → Remote Event Receivers


Table of Contents


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:

  1. Attempt 1: Call endpoint
  2. Wait 1 second if failed
  3. Attempt 2: Retry
  4. Wait 2 seconds if failed
  5. Attempt 3: Final retry
  6. 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:

  1. Verify registration:

    Get-PnPEventReceiver -List "Documents"
    
    Ensure receiver is listed with correct URL and event type.

  2. Check receiver URL is accessible:

    curl http://localhost:8080/rer
    
    Should return HTTP 200 (not 404).

  3. Verify event type matches operation:

  4. Adding item → ItemAdding (Before), ItemAdded (After)
  5. Updating item → ItemUpdating, ItemUpdated
  6. Deleting item → ItemDeleting, ItemDeleted

  7. Check Cesivi Server logs: Look for "Triggering remote event receiver" messages.

  8. Verify synchronization type:

  9. Before events: Synchronization = Synchronous (1)
  10. After events: Synchronization = Asynchronous (2)

Connection Refused / Timeout

Problem: Cesivi Server can't reach event receiver endpoint.

Solutions:

  1. Check endpoint is running:

    curl http://localhost:8080/rer
    

  2. Verify port number: Ensure receiver URL port matches actual listening port.

  3. Check firewall: Allow inbound connections on receiver port.

  4. Localhost vs 127.0.0.1: Try both in receiver URL.

  5. 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:

  1. Verify it's a Before event: Only Before events (ending in "ing") can cancel operations.
  2. ItemAdding ✅ Can cancel
  3. ItemAdded ❌ Cannot cancel

  4. Check synchronization: Before events MUST use Synchronization = Synchronous.

  5. Verify response format:

    {
      "Status": 1,
      "ErrorMessage": "Your error message"
    }
    

  6. Check HTTP status: Receiver should return HTTP 200 (not 400/500).

Property Changes Not Applied

Problem: Returning ChangedProperties but item properties not modified.

Checklist:

  1. Only Before events support property changes:
  2. ItemAdding, ItemUpdating ✅ Supported
  3. ItemAdded, ItemUpdated ❌ Not supported

  4. Verify response format:

    {
      "Status": 0,
      "ChangedProperties": {
        "Title": "New Title",
        "CustomField": "Value"
      }
    }
    

  5. Check field internal names: Use InternalName, not DisplayName.

  6. "Title" ✅ Correct
  7. "Document Title" ❌ Incorrect (display name)

  8. 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:

  1. Verify SequenceNumber:

    Get-PnPEventReceiver -List "Documents" | Select-Object ReceiverName, SequenceNumber | Sort-Object SequenceNumber
    
    Lower numbers execute first (1000, 2000, 3000).

  2. Check all receivers have same EventType: Receivers for different event types won't execute together.

  3. 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:

  1. Check scope:
  2. List-scoped: Registered on specific list
  3. Web-scoped: Registered on web
  4. Site-scoped: Registered on site collection

  5. Verify correct list/web/site:

    # List all receivers for a list
    Get-PnPEventReceiver -List "Documents"
    
    # List web-scoped receivers
    Get-PnPEventReceiver -Scope Web
    

  6. 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:

  1. Use After events when possible: If you don't need to cancel/modify, use asynchronous After events.

  2. Minimize receiver processing time: Keep receiver logic fast (<100ms ideal).

  3. Reduce Before event receivers: Each Before receiver adds latency to user operations.

  4. 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


Last Updated: November 15, 2025 Version: 1.0.0 Compatibility: SharePoint 2019, SharePoint Online

Navigation: Home | Documentation | Features | Remote Event Receivers