Vai al contenuto

Threading e UI thread

Le chiamate alla UI API devono avvenire sul thread su cui SAP si aspetta di ricevere le interazioni — tipicamente il thread principale dell'add-on, quello su cui sono stati registrati gli event handler (ItemEvent, FormDataEvent, ecc.).

Il problema

Se l'add-on fa qualcosa di asincrono — es. una chiamata HTTP, un'operazione su file, una query lunga — e poi, nel completamento di quella chiamata asincrona (spesso su un thread diverso, es. da async/await, Task.Run, o un timer), prova ad aggiornare direttamente una Form o un Item, il comportamento può essere imprevedibile: eccezioni COM, form che non si aggiornano, crash intermittenti difficili da riprodurre.

Perché capita spesso a chi viene dal web

Chi è abituato a sviluppo web/API moderno dà per scontato che async/await "funzioni ovunque senza pensarci" — nella UI API di SAP, che è basata su COM Interop, questo assunto non vale: gli oggetti COM sono spesso legati (apartment-threaded) al thread su cui sono stati creati.

Approfondimento sul modello COM

Per comprendere la differenza tra modelli di threading COM (STA vs MTA) e come funziona il marshalling, vedi la pagina: Cos'è COM e cosa sono le API COM.

Pattern per rientrare sul thread giusto

Se l'add-on ha una UI .NET propria (WinForms/WPF) oltre all'integrazione SAP, si può usare il meccanismo standard di Invoke/Dispatcher per marshallare la chiamata sul thread corretto:

// Esempio concettuale con WinForms
if (this.InvokeRequired)
{
    this.Invoke(new Action(() => AggiornaFormSAP()));
}
else
{
    AggiornaFormSAP();
}

Se invece il codice è puramente nell'event loop di SAP (senza una propria finestra WinForms), la regola pratica è: evitare operazioni asincrone "fire and forget" che poi toccano Form/Item — meglio strutturare il codice in modo sincrono all'interno degli handler evento, oppure sincronizzare esplicitamente il rientro.