11/10/2025
Når man udvikler plugins til Microsoft Dynamics CRM eller Dataverse, er det næsten uundgåeligt at støde på kryptiske fejlmeddelelser, der kan stoppe ethvert projekt. Fejl som "ISV code aborted the operation" eller "Sandbox Worker process crashed" kan være frustrerende og tidskrævende at fejlfinde. Denne artikel dykker ned i de mest almindelige plugin-fejl, forklarer de underliggende årsager og giver konkrete løsninger og bedste praksis, så du kan skrive mere robust og stabil kode. Vi vil dække alt fra simple rekursive kald til komplekse hukommelses- og transaktionsproblemer.

Forstå Fejlen: "ISV code aborted the operation"
En af de mest klassiske fejl, en udvikler kan møde, har fejlkoden -2147220891 (eller 80040265) og meddelelsen "ISV code aborted the operation". I langt de fleste tilfælde betyder denne fejl, at dit plugin kalder sig selv i en uendelig loop. Forestil dig et scenarie, hvor du har et plugin, der udløses ved ændring af feltet 'estimatedvalue' på en Opportunity. Hvis dit plugin i sin logik selv opdaterer 'estimatedvalue', vil det udløse sig selv igen. Dette fortsætter, indtil platformen stopper processen for at forhindre et systemnedbrud.
Heldigvis er løsningen ofte ganske enkel. Ved at tjekke udførelsesdybden (execution depth) kan du forhindre dit plugin i at køre mere end én gang i den samme overordnede transaktion. Dybden (depth) angiver, hvor mange gange et plugin er blevet kaldt inden for den samme transaktion. Et kald direkte fra brugerfladen har en dybde på 1. Hvis dette plugin udløser et andet plugin (eller sig selv), vil det nye kald have en dybde på 2.
Du kan stoppe denne rekursive adfærd med en simpel betingelse i starten af din `Execute`-metode:
if (context.Depth > 1) { trace.Trace("Plugin har kaldt sig selv. Afslutter."); return; } Ved at implementere dette tjek sikrer du, at din logik kun kører én gang, hvilket effektivt eliminerer den uendelige loop og den tilhørende fejl.
Den Frygtede Fejl: "Sandbox Worker process crashed"
Fejlkoden -21472204723, med meddelelsen "The plug-in execution failed because the Sandbox Worker process crashed", er en mere alvorlig og generisk fejl. Den indikerer, at hele den isolerede proces (sandbox), der kører din plugin-kode, er brudt ned. Selvom dit plugin kan være årsagen, kan det også skyldes et andet plugin, der kører samtidigt for din organisation. Fordi processen crasher, er det ofte svært at få specifik information om årsagen direkte fra fejlen. Baseret på analyser af nedbrudsdata er der dog fire primære årsager til denne fejl.
1. Ubehandlede Undtagelser (Unhandled Exceptions)
Når du skriver et plugin, er det afgørende at forudse operationer, der kan fejle, og indkapsle dem i en `try-catch`-blok. Hvis en uventet fejl opstår og ikke bliver fanget, kan det få hele worker-processen til at crashe. Når en fejl opstår, bør du kaste en `InvalidPluginExecutionException` for at afslutte operationen på en kontrolleret måde og give en meningsfuld fejlmeddelelse tilbage til brugeren.
Et almindeligt scenarie er ved brug af asynkrone metoder som `HttpClient.SendAsync`. I et synkront plugin, hvor kode skal køre sekventielt, bruger udviklere ofte `.Result` til at vente på svaret. Hvis der opstår en fejl, returnerer `.Result` en `AggregateException`, som kan være svær at håndtere. En bedre tilgang er at bruge `.GetAwaiter().GetResult()`, da den propagerer den specifikke fejl, der forårsagede problemet.
2. Brug af Tråde uden Fejlhåndtering
Det er en stærk anti-praksis at anvende parallelle eksekveringsmønstre (f.eks. at starte nye tråde) i et plugin. Dette kan skabe problemer med transaktionsstyring i synkrone plugins. En endnu større risiko er, at enhver ufanget undtagelse i en separat tråd vil få hele worker-processen til at crashe. Alt arbejde, der udføres i en tråd, skal være omgivet af en robust `try-catch`-blok for at forhindre dette.
3. Stack Overflow Fejl
Denne fejl opstår typisk fra en rekursiv funktion uden en korrekt afslutningsbetingelse. Hver gang funktionen kalder sig selv, tilføjes et nyt lag til kaldstakken (call stack). Når stakken løber tør for plads, opstår en `StackOverflowException`, hvilket øjeblikkeligt afslutter processen. Dette kan ske, hvis du har en funktion, der kalder sig selv uendeligt, eller hvis afslutningsbetingelsen ikke dækker alle mulige scenarier. Gennemgå nylige kodeændringer for rekursive kald for at identificere potentielle kilder til denne fejl.
4. Hukommelsesgrænser i Worker Process
Hver sandbox worker-proces har en begrænset mængde hukommelse. Hvis dit plugin, eller flere samtidige plugins, bruger for meget hukommelse, vil processen crashe. Dette kan ske i to primære scenarier:
- Håndtering af store datamængder: Et almindeligt eksempel er en `RetrieveMultiple`-forespørgsel, der henter poster med store vedhæftede filer (f.eks. e-mails med bilag). Mængden af data kan være uforudsigelig. For at undgå dette, bør du begrænse forespørgsler, der inkluderer fil-data. Hent i stedet posterne først, og hent derefter de relaterede filer enkeltvis efter behov.
- Hukommelseslæk (Memory Leaks): Hvis dit plugin ikke er skrevet til at være "stateless" (tilstandsløst), kan det akkumulere data i hukommelsen over tid. For eksempel, hvis data kontinuerligt tilføjes til en statisk liste eller et dictionary ved hvert kald, vil hukommelsesforbruget vokse, indtil grænsen er nået. Sørg for, at dit plugin rydder op efter sig selv og ikke gemmer data mellem udførelser.
Application Insights: Din Redning ved Fejlfinding
Tidligere var det næsten umuligt at få detaljerede oplysninger, såsom en stack trace, fra en crashet worker-proces. Heldigvis understøtter Dataverse nu logning af eksekveringsfejl til Application Insights. Ved at forbinde dit Dataverse-miljø med en Application Insights-ressource, bliver nedbrud automatisk logget med detaljerede oplysninger. Dette er et uvurderligt værktøj til fejlfinding.
For at finde nedbrudsrapporten:
- Naviger til din Application Insights-ressource i Azure Portal (eller via Power Platform admin center).
- Vælg "Failures" i venstre panel.
- Vælg fanen "Exceptions".
- Find og vælg `Microsoft.PowerPlatform.Dataverse.Plugin.PluginWorkerCrashException`.
- Her kan du se detaljer om fejlen, inklusiv en komplet stack trace under "CrashDetails", som kan pege dig direkte til den problematiske del af din kode.
Oversigt over Almindelige Fejl og Årsager
For at give et hurtigt overblik er her en tabel, der opsummerer nogle af de mest almindelige fejl, deres koder og typiske årsager.
| Fejlkode | Fejlmeddelelse (Engelsk) | Typisk Årsag |
|---|---|---|
| -2147220891 | ISV code aborted the operation. | Uendelig loop, ofte forårsaget af at et plugin opdaterer den samme post, det blev udløst af. Brug af context.Depth er løsningen. |
| -2147204723 | Sandbox Worker process crashed. | Ubehandlet undtagelse, stack overflow, hukommelseslæk eller brug af parallelle tråde. |
| -2147204783 | Sql error: 'Execution Timeout Expired.' | Databaseblokering forårsaget af samtidige operationer, kaskadehandlinger (f.eks. sletning) eller manglende indekser. |
| -2146893812 | ISV code reduced the open transaction count. | Et forsøg på at "sluge" en `OrganizationService`-fejl i en `try-catch`-blok i stedet for at lade transaktionen rulle tilbage. |
| -2147220970 | Message size exceeded when sending context to Sandbox. | En operation (f.eks. `RetrieveMultiple`) forsøger at behandle en datamængde på over 116 MB. |
Transaktionsfejl: En Almindelig Fælde
I et synkront plugin bliver alle dataoperationer udført inden for en enkelt database-transaktion. Hvis en af disse operationer fejler, rulles hele transaktionen tilbage for at sikre dataintegritet. En almindelig fejl blandt udviklere er at forsøge at fange en fejl fra et `OrganizationService`-kald i en `try-catch`-blok og derefter fortsætte med anden logik, som om intet var hændt. Dette er ikke tilladt. Når en dataoperation fejler, er transaktionen allerede afbrudt. Ethvert forsøg på at fortsætte vil resultere i fejl som "ISV code reduced the open transaction count" eller "There is no active transaction".
Den korrekte håndtering er altid at kaste en `InvalidPluginExecutionException`, når en servicefejl fanges. Dette sikrer, at platformen håndterer tilbagerulningen korrekt og giver en klar fejlmeddelelse.
Ofte Stillede Spørgsmål (FAQ)
Hvad er den mest almindelige årsag til "ISV code aborted the operation"?
Den absolut mest almindelige årsag er en uendelig loop, hvor dit plugin direkte eller indirekte kalder sig selv. Løsningen er at tjekke `context.Depth` i starten af din kode for at forhindre rekursiv udførelse.
Kan jeg bruge parallelle tråde i mit synkrone plugin?
Nej, det frarådes kraftigt. Det kan føre til uforudsigelig adfærd, problemer med transaktionsstyring og kan let få worker-processen til at crashe, hvis en fejl ikke fanges korrekt i tråden.
Hvordan kan jeg få flere detaljer, når min Sandbox Worker process crasher?
Den bedste metode er at forbinde dit Dataverse-miljø til Application Insights. Dette giver dig adgang til detaljerede nedbrudsrapporter, herunder stack traces, som er afgørende for at finde rodårsagen til problemet.
Hvorfor får jeg en SQL Timeout-fejl?
En SQL Timeout opstår, når din dataoperation venter for længe på databasen. Dette skyldes oftest, at andre processer låser de data, du forsøger at tilgå (blocking). Det kan også skyldes langvarige kaskadeoperationer (f.eks. når du sletter en Account med mange relaterede kontakter) eller ineffektive forespørgsler mod tabeller uden korrekte indekser.
Hvis du vil læse andre artikler, der ligner Løsning af almindelige Dataverse-pluginfejl, kan du besøge kategorien Teknologi.
