agentleFS
Microsoft AzureKnown publisherAzure/Connectors-NET-SDK/.github/skills/trigger-registration/SKILL.md

trigger-registration

Skill3 starsChanged 15 days agoMITView on GitHub

Register Connector Namespace trigger configs for SDK-supported connectors. USE WHEN: setting up polling triggers (e.g., OnNewEmail, OnNewFile, OnUpdatedFile) that call back to an Azure Function when events occur, creating a .NET Function App project with ConnectorTrigger, or wiring post-deploy trigger config scripts. Covers function app scaffolding, trigger config creation, callback URL wiring, parameter discovery, and binary vs metadata payload handling. NOT FOR: connection setup (use connection-setup skill).

2 other projects use a version of this, 2 of them edited.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository2 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If the connector generates a *Triggers.Operations dictionary, that dictionary only maps metadata triggers (those with typed payloads).

    line 70
  2. Very specific:

    Use the [ConnectorTrigger] attribute with SDK typed payloads for POCO binding.

    line 119
  3. Distinctive:

    Check function app logs:

    line 288

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Connector Namespace Trigger Registration

Registers polling trigger configs on a Connector Namespace so that connector events (new email, new file, etc.) call back to your Azure Function endpoint. Also covers scaffolding a .NET Function App project with the connector extension packages.

When to Use

  • Developer needs a connector trigger (e.g., "when a new file is created in OneDrive")
  • Developer has an existing Connector Namespace connection (use the connection-setup skill first if not)
  • Developer needs to wire up the callback URL from a deployed Azure Function
  • Developer needs to understand binary vs metadata trigger payload shapes

Prerequisites

  • Azure CLI installed and authenticated (az login)
  • Connector Namespace with a connected connector (see connection-setup skill)
  • The Connector Namespace must have a system-assigned managed identity enabled (required for trigger callback authentication)
  • Deployed Azure Function App with a connector trigger function
  • Supported regions for Connector Namespace: brazilsouth, centraluseuap, eastus2euap, centralusstage, eastusstage. Only the Connector Namespace location must be in a supported region; the Function App can be in any region.
  • For .NET: the Function App project must reference:
    • Microsoft.Azure.Functions.Worker.Extensions.Connector — provides the [ConnectorTrigger] attribute
    • Azure.Connectors.Sdk — provides typed connector clients and trigger payload types

Key Concepts

Trigger Config vs Connection

Connections (managed by the connection-setup skill) authenticate your app to the connector API. Trigger configs tell the Connector Namespace to poll the connector for events and POST callbacks to your function when events occur.

Connector Namespace
├── connections/
│   └── onedrive-test          ← auth + runtime URL (connection-setup skill)
└── triggerConfigs/
    └── onedrive-newfile       ← poll + callback config (THIS skill)

Binary vs Metadata Triggers

Some connectors offer two variants of the same trigger:

VariantExamplePayload ShapeBody Field
File content (binary)OnNewFileV2{"body":"<base64-string>"}String — base64-encoded file bytes
Properties only (metadata)OnNewFilesV2{"body":{"value":[{...}]}}Object — array of typed metadata items

Critical: Both variants arrive with Content-Type: application/json. You cannot use content-type to distinguish them. Instead, parse the JSON and inspect whether body is a string or an object.

Identifying binary triggers in the SDK

In the generated *TriggerOperations class, binary triggers lack a Payload type: annotation in their XML doc comment, while metadata triggers reference their typed payload class:

// Binary — no payload type annotation
/// <summary>When a file is created.</summary>
public const string OnNewFile = "OnNewFileV2";

// Metadata — has payload type annotation
/// <summary>
/// When a file is created (properties only).
/// Payload type: <see cref="OnedriveforbusinessOnNewFilesTriggerPayload"/>.
/// </summary>
public const string OnNewFiles = "OnNewFilesV2";

If the connector generates a *Triggers.Operations dictionary, that dictionary only maps metadata triggers (those with typed payloads). If an operation name is not in the dictionary, it is a binary trigger.

Some connectors may not generate a *Triggers registry at all. When *Triggers.Operations is unavailable, check the XML doc comment on the *TriggerOperations constant: a Payload type: annotation indicates a metadata trigger, while no annotation indicates a binary trigger.

.NET Function App with Connector Extension

Scaffolding a New Project

There is no ConnectorTrigger template yet. Use azd with an HTTP trigger template and replace the trigger:

  1. Initialize with the Azure Functions .NET quickstart:

    azd init -t functions-quickstart-dotnet-azd
  2. Replace the HTTP trigger with a [ConnectorTrigger] function. Delete any sample HTTP functions and create your trigger function (see example below).
  3. Add packages to the Function App .csproj:

    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Connector" Version="0.1.0-alpha" />

    For SDK typed payloads, also add:

    <PackageReference Include="Azure.Connectors.Sdk" Version="*" />

    Note: If Azure.Connectors.Sdk is not yet published on NuGet, use a project reference to the local SDK repo instead:

    <ProjectReference Include="..\..\Connectors-NET-SDK\src\Azure.Connectors.Sdk\Azure.Connectors.Sdk.csproj" />
  4. Build and deploy:

    azd up

Packages

  • Microsoft.Azure.Functions.Worker.Extensions.Connector — provides the [ConnectorTrigger] attribute and POCO converter. See azure-functions-connector-extension.
  • Azure.Connectors.Sdk — typed connector clients and trigger payload types (e.g., Office365OnNewEmailTriggerPayload, TeamsClient)

Example: ConnectorTrigger Function

Use the [ConnectorTrigger] attribute with SDK typed payloads for POCO binding. Payload types are in the Azure.Connectors.Sdk.<Connector> namespace:

using Azure.Connectors.Sdk.Office365;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

public class EmailTrigger(ILogger<EmailTrigger> logger)
{
    [Function("OnNewEmailReceived")]
    public void OnNewEmailReceived(
        [ConnectorTrigger] Office365OnNewEmailTriggerPayload payload)
    {
        var emails = payload.Body?.Value ?? [];
        foreach (var email in emails)
        {
            logger.LogInformation("Subject: {Subject}, From: {From}", email.Subject, email.From);
        }
    }
}

The connector extension registers a webhook endpoint on the Function App at:

POST /runtime/webhooks/connector?functionName={FunctionName}&code={connector_extension_key}

The connector_extension system key is auto-generated when the extension loads. Use this URL as the callback when creating trigger configs (see Step 1 below).

Procedure

Step 1: Get the Callback URL

The connector extension exposes a webhook endpoint on the Function App. Build the callback URL using the connector_extension system key:

$resourceGroup = "<resource-group>"
$functionAppName = "<function-app-name>"
$functionName = "<connector-trigger-function-name>"

$connectorExtensionKey = az functionapp keys list -g $resourceGroup -n $functionAppName --query "systemKeys.connector_extension" -o tsv
$callbackUrl = "https://$functionAppName.azurewebsites.net/runtime/webhooks/connector?functionName=$functionName&code=$connectorExtensionKey"

Important: The functionName query parameter must exactly match the [Function("...")] attribute name in your code. A mismatch means the connector extension cannot route the callback to your function.

Step 2: Get Trigger Parameters

Each trigger operation requires specific parameters. Find them in the SDK's generated *TriggerParameters class:

// Example: OneDrive OnNewFileV2 parameters
OnedriveforbusinessTriggerParameters.OnNewFile.FolderId      // Required — folder to watch
OnedriveforbusinessTriggerParameters.OnNewFile.IncludeSubfolders  // Optional, default: false
OnedriveforbusinessTriggerParameters.OnNewFile.InferContentType   // Optional, default: true

For folder IDs, use the connector's list operations to discover them:

Note: Listing folders requires a data-plane call to the connection runtime URL. If you skipped access policies in the connection-setup skill (trigger-only flow), you must first add a local-dev access policy (connection-setup Step 5) to avoid 403 errors.

$runtimeUrl = "<connection-runtime-url>"  # from connection-setup skill Step 4
az rest --method GET `
    --uri "$runtimeUrl/datasets/default/folders" `
    --resource "https://apihub.azure.com" -o json

Step 3: Create Trigger Config

$subscriptionId = "<subscription-id>"
$resourceGroup = "<resource-group>"
$namespaceName = "<namespace-name>"
$nsId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.Web/connectorGateways/$namespaceName"

$triggerName = "<trigger-config-name>"   # e.g., "onedrive-newfile-binary"
$connectionName = "<connection-name>"    # e.g., "onedrive-test"
$connectorName = "<connector-name>"      # e.g., "onedriveforbusiness"
$operationName = "<operation-name>"      # e.g., "OnNewFileV2"

Build and send the PUT request. Use Invoke-WebRequest (not az rest) because az rest silently swallows error responses from this API:

$token = az account get-access-token `
    --resource "https://management.core.windows.net/" `
    --query "accessToken" -o tsv

$body = @{
    properties = @{
        operationName = $operationName
        connectionDetails = @{
            connectorName = $connectorName
            connectionName = $connectionName
        }
        notificationDetails = @{
            callbackUrl = $callbackUrl
            httpMethod = "Post"
        }
        parameters = @(
            @{ name = "folderId"; value = "<folder-id-from-step-2>" }
            @{ name = "includeSubfolders"; value = "false" }
        )
    }
} | ConvertTo-Json -Depth 4

$uri = "https://management.azure.com/$($nsId.TrimStart('/'))/triggerConfigs/${triggerName}?api-version=2026-05-01-preview"
try {
    $response = Invoke-WebRequest -Uri $uri -Method PUT -Body $body `
        -ContentType "application/json" `
        -Headers @{ Authorization = "Bearer $token" }
    Write-Output "Status: $($response.StatusCode)"
} catch {
    Write-Output "Error: $($_.Exception.Response.StatusCode) $($_.Exception.Response.ReasonPhrase)"
    $_.ErrorDetails.Message
}

Alternative: Using az rest

$bodyFile = [System.IO.Path]::GetTempFileName()
$body | Out-File -FilePath $bodyFile -Encoding utf8

az rest --method PUT --url $uri --body "@$bodyFile" --headers "Content-Type=application/json"
Remove-Item $bodyFile -ErrorAction SilentlyContinue

Expected: HTTP 201 Created.

Step 4: Verify Trigger Config

az rest --method GET `
    --uri "https://management.azure.com/$($nsId.TrimStart('/'))/triggerConfigs/${triggerName}?api-version=2026-05-01-preview" `
    --query "properties.{operation:operationName, state:state, hasCallback:notificationDetails.callbackUrl!=null}" `
    -o table

Expected: state = Enabled, hasCallback = True.

Step 5: List All Trigger Configs

az rest --method GET `
    --uri "https://management.azure.com/$($nsId.TrimStart('/'))/triggerConfigs?api-version=2026-05-01-preview" `
    --query "value[].{name:name, operation:properties.operationName, state:properties.state}" `
    -o table

Step 6: Fire the Trigger

Upload or create content in the watched location to trigger the callback:

# Example: upload a file to OneDrive to fire OnNewFileV2
# Set $baseUrl to your deployed Function App, e.g.:
# $baseUrl = "https://<function-app-name>.azurewebsites.net/api"
$uploadBody = '{"folderPath":"/Documents","fileName":"trigger-test.txt","content":"Hello from trigger test"}'
Invoke-RestMethod -Uri "$baseUrl/onedrive/upload?code=$functionKey" `
    -Method POST -Body $uploadBody -ContentType "application/json"

The Connector Namespace polls the connector every 1-5 minutes. After polling detects the new content, it POSTs the trigger payload to your callback URL.

Step 7: Verify Callback Received

Check function app logs:

az webapp log download -g $resourceGroup -n $functionAppName --log-file "$env:TEMP/func-logs.zip"
Expand-Archive -Path "$env:TEMP/func-logs.zip" -DestinationPath "$env:TEMP/func-logs" -Force
Get-ChildItem "$env:TEMP/func-logs" -Recurse -Filter "*.log" |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 3 |
    ForEach-Object { Select-String -Path $_.FullName -Pattern "TriggerCallback" }

API Schema Reference

TriggerConfig PUT Body

{
  "properties": {
    "operationName": "OnNewFileV2",
    "connectionDetails": {
      "connectorName": "onedriveforbusiness",
      "connectionName": "onedrive-test"
    },
    "notificationDetails": {
      "callbackUrl": "https://my-func.azurewebsites.net/runtime/webhooks/connector?functionName=OnNewFile&code=<connector-extension-key>",
      "httpMethod": "Post"
    },
    "parameters": [
      { "name": "folderId", "value": "<folder-id>" },
      { "name": "includeSubfolders", "value": "false" }
    ]
  }
}

Property Names (Validated)

PropertyNotes
properties.connectionDetailsNot connectionName at top level
properties.connectionDetails.connectorNameRequired — the API connector name
properties.connectionDetails.connectionNameRequired — the connection resource name
properties.notificationDetails.callbackUrlMissing = trigger has no target — trigger provisions but never calls back
properties.notificationDetails.httpMethod"Post"
parameters[].nameNot parameterName
parameters[].valueString value

Common Errors

ErrorCauseFix
Could not find member 'connectionName'Used connectionName instead of connectionDetailsUse connectionDetails with nested connectorName + connectionName
Could not find member 'callbackUrl'Put callbackUrl at properties levelWrap in notificationDetails
Could not find member 'parameterName'Used parameterName in parameter arrayUse name
Cannot deserialize... into ConnectorGatewayOperationsParameter[]Parameters as object, not arrayUse [{"name":"...","value":"..."}] array
missing required property 'folderId'Required trigger parameter not providedAdd to parameters array
Trigger provisions but never fires callbackMissing notificationDetails or empty notificationDetails.callbackUrlAdd notificationDetails with a non-empty callbackUrl and httpMethod
az rest PUT returns no output/erroraz rest swallows non-2xx responses silentlyUse Invoke-WebRequest instead for PUT operations

Handling Trigger Payloads in Code

Binary Content Triggers (e.g., OnNewFileV2)

using var document = JsonDocument.Parse(body);
var root = document.RootElement;

if (root.TryGetProperty("body", out var bodyElement) &&
    bodyElement.ValueKind == JsonValueKind.String)
{
    // Binary trigger — body is base64-encoded file content.
    // NOTE: The base64 string may be wrapped in extra quotes
    // from the Logic Apps expression engine. Strip them.
    var base64Content = bodyElement.GetString()?.Trim('"') ?? string.Empty;

    if (!string.IsNullOrWhiteSpace(base64Content))
    {
        var maximumDecodedLength = (base64Content.Length / 4) * 3;
        var fileBytesBuffer = new byte[maximumDecodedLength];

        if (Convert.TryFromBase64String(base64Content, fileBytesBuffer, out var bytesWritten))
        {
            var fileBytes = fileBytesBuffer.AsSpan(0, bytesWritten).ToArray();

            // fileBytes contains the actual file content
        }
        else
        {
            // Invalid base64 payload — handle gracefully
        }
    }
}

Metadata Triggers (e.g., OnNewFilesV2)

// Callback JSON shape: {"body":{"value":[{...BlobMetadata...}]}}
// Deserialize using the SDK's typed trigger payload class.
var payload = JsonSerializer.Deserialize<OnedriveforbusinessOnNewFilesTriggerPayload>(
    body, jsonOptions);

var files = payload?.Body?.Value;

Detecting the Variant at Runtime

using var document = JsonDocument.Parse(body);
if (document.RootElement.TryGetProperty("body", out var bodyElement))
{
    if (bodyElement.ValueKind == JsonValueKind.String)
    {
        // Binary content trigger (OnNewFileV2, OnUpdatedFileV2)
    }
    else if (bodyElement.ValueKind == JsonValueKind.Object)
    {
        // Metadata trigger (OnNewFilesV2, OnUpdatedFilesV2)
    }
}

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.