Table of Contents

Créer un gestionnaire

Envoyer les données des dépôts vers votre propre système. Un gestionnaire est une classe qui hérite de WebhookHandlerBase, compilée dans une DLL que l'application charge au démarrage. Vous n'avez pas à modifier ni à recompiler le webhook.

1. Créer le projet

Une bibliothèque de classes pour la même plateforme que le webhook, qui référence sa bibliothèque SESARWebHook.Core.NetCore et le SDK Secure Exchanges, dans la version qu'utilise le webhook (voir SESARWebHook.Core.NetCore.csproj) :

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0-windows</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <!-- Fournis par le webhook à l'exécution : ne pas les copier avec le gestionnaire -->
    <ProjectReference Include="..\SESARWebhookCore\SESARWebHook.Core.NetCore\SESARWebHook.Core.NetCore.csproj" Private="false" />
    <PackageReference Include="SecureExchanges.NetCore" Version="26.4.20.2" ExcludeAssets="runtime" />
  </ItemGroup>
</Project>

2. Écrire la classe

using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using SecureExchangesSDK.Models.Messenging;
using SESARWebHook.Core;
using SESARWebHook.Core.Auth;
using SESARWebHook.Core.Models;

namespace Exemple.Gestionnaires
{
  public class DossiersHandler : WebhookHandlerBase
  {
    // Un seul HttpClient pour toute la vie de l'application.
    private static readonly HttpClient Http = new HttpClient();
    private ApiKeyHelper _auth;
    private string _endpoint;

    public override string HandlerId => "mes-dossiers";
    public override string DisplayName => "Mes dossiers";

    public override void Initialize(Dictionary<string, string> settings)
    {
      base.Initialize(settings);
      _endpoint = GetRequiredSetting("ApiUrl");                     // appsettings.json
      _auth = ApiKeyHelper.AsBearer(GetRequiredSetting("ApiKey"));  // fichier de secrets
    }

    public override async Task<IntegrationResult> ProcessAsync(StoreManifest manifest, WebhookContext context)
    {
      var dossier = new
      {
        suivi = GetTrackingId(manifest),  // identifiant stable : sert à écarter les doublons
        objet = GetSubject(manifest),
        fichiers = GetFileCount(manifest)
      };

      using var request = new HttpRequestMessage(HttpMethod.Post, _endpoint)
      {
        Content = new StringContent(JsonSerializer.Serialize(dossier), Encoding.UTF8, "application/json")
      };
      _auth.ApplyTo(request);

      using var response = await Http.SendAsync(request);
      return response.IsSuccessStatusCode
        ? IntegrationResult.Ok("Dossier transmis", HandlerId)
        : IntegrationResult.Fail("Refus du système cible", $"HTTP {(int)response.StatusCode}", HandlerId);
    }
  }
}

Le webhook retient une classe si elle est publique, non abstraite, implémente IWebhookHandler et a un constructeur public sans paramètre. Son HandlerId fait partie de l'adresse : choisissez-le stable, en minuscules, sans espace.

Membres à connaître

Membre Rôle
HandlerId, DisplayName Obligatoires. Description et Version sont facultatifs.
Initialize(settings) Appelé une fois, à la première utilisation du gestionnaire. Appelez base.Initialize(settings) en premier.
ProcessAsync(manifest, context) Appelé pour chaque dépôt. Renvoyez IntegrationResult.Ok ou IntegrationResult.Fail.
ValidateConfigurationAsync, TestConnectionAsync Appelés par POST /api/handlers/{id}/test. Renvoient true par défaut.
GetSetting, GetRequiredSetting, GetSettingBool, GetSettingInt Lisent les réglages et les secrets. GetRequiredSetting lève une exception si la valeur manque, sans la citer.
GetSubject, GetRecipientEmails, GetFileCount, GetTrackingId, IsReply, DecodeBase64 Lisent le manifeste.

La liste complète est dans la référence .NET.

Règles de conception

  • Une instance pour toute la vie de l'application. Le gestionnaire est créé une fois, puis réutilisé, y compris pour des requêtes simultanées : ne gardez pas l'état d'un dépôt dans un champ.
  • Un constructeur léger. Il s'exécute au chargement de la DLL et à chaque GET /api/handlers. Mettez la préparation dans Initialize.
  • Moins de 60 secondes par dépôt, et des doublons acceptés : voir Configurer SESAR.
  • Aucun renseignement personnel dans les journaux ni dans l'IntegrationResult, qui est renvoyé tel quel dans la réponse HTTP. N'utilisez pas context.RawPayload en dehors du traitement : il contient le manifeste déchiffré.
  • Les exceptions levées dans ProcessAsync sont interceptées et renvoyées en échec, avec leur détail. Celles d'Initialize ne le sont pas : la requête reçoit une erreur 500.

3. Configurer

Les réglages vont dans appsettings.json, les secrets dans le fichier de secrets. Le gestionnaire reçoit les deux, fusionnés, dans ses Settings.

{
  "Handler": {
    "mes-dossiers": { "ApiUrl": "https://api.example.com/dossiers" }
  }
}
{
  "Handlers": {
    "mes-dossiers": { "Secrets": { "ApiKey": "<votre clé d'API>" } }
  }
}

4. Déployer

  1. Compilez le projet en Release.
  2. Copiez la DLL du gestionnaire, et ses propres dépendances seulement, dans le dossier des gestionnaires : Handlers, dans le dossier de l'application, ou celui de HandlersPath. Les sous-dossiers ne sont pas lus.
  3. Redémarrez l'application. Une DLL déjà chargée reste en mémoire jusqu'au redémarrage, et POST /api/handlers/rescan ne relit que le dossier par défaut.
  4. Vérifiez qu'il apparaît dans GET /api/handlers, puis testez-le avec POST /api/handlers/mes-dossiers/test.
  5. Dans SESAR, indiquez l'adresse https://<serveur>/api/webhook/handler/mes-dossiers.

Si deux DLL déclarent le même HandlerId, la dernière chargée l'emporte, sans avertissement.

Attention

Un gestionnaire s'exécute dans le processus du webhook, avec tous ses droits, et peut lire tous les secrets de l'application. Ne déposez dans le dossier des gestionnaires que des DLL dont vous connaissez le code, et réservez l'écriture de ce dossier aux administrateurs.

Connecteur intégré : pour qui maintient sa propre version du webhook

Un connecteur intégré implémente IIntegrationConnector. Il n'est pas chargé depuis un dossier : il faut l'ajouter au projet, puis à StartupConfig.InitializeConnectors dans Program.cs (ConnectorRegistry.RegisterConnector<T>()), et recompiler le webhook. Le projet SESARWebHook.Connectors.Template.NetCore sert de modèle ; ses commentaires mentionnent encore Web.config, remplacé par appsettings.json.

Préférez un gestionnaire : il survit aux mises à jour du webhook sans fusion de code.