17/02/2018
Plugins er en fundamental del af at udvide og tilpasse Microsoft Dynamics CRM til at håndtere kompleks forretningslogik, som ikke kan opnås med standardkonfiguration. De giver udviklere mulighed for at integrere specialiseret kode, der udløses af specifikke hændelser i CRM-systemet, såsom oprettelse, opdatering eller sletning af en post. Denne artikel er en omfattende guide til udvikling, oprettelse og opdatering af plugins til Microsoft Dynamics CRM 2013. Vi vil dække alt fra de indledende forudsætninger til avancerede koncepter som pipeline-stadier og bedste praksis for ydeevne, samt konkrete eksempler på CRUD-operationer (Create, Read, Update, Delete).

Forudsætninger for at komme i gang
Før du kan begynde at udvikle plugins, er der et par essentielle værktøjer, du skal have installeret og konfigureret. Disse sikrer, at du har det rette udviklingsmiljø og de nødvendige biblioteker til at kommunikere med CRM.
- Dynamics CRM 2013 SDK: Software Development Kit (SDK) er din vigtigste ressource. Det indeholder de nødvendige assemblies (biblioteker), værktøjer og dokumentation for at udvikle til CRM. Du kan downloade det direkte fra Microsofts hjemmeside.
- Visual Studio 2012: For Dynamics CRM 2013 er det vigtigt at bemærke, at det tilhørende SDK er designet til at fungere bedst med Visual Studio 2012. Selvom der findes workarounds for nyere versioner, anbefales det at bruge Visual Studio 2012 for at undgå kompatibilitetsproblemer.
Sådan opretter du dit første CRM 2013 Plugin
Når forudsætningerne er på plads, kan vi begynde at oprette selve plugin-projektet. CRM 2013 SDK'et integreres med Visual Studio og leverer skabeloner, der markant forenkler opsætningsprocessen.
Trin-for-trin guide i Visual Studio
- Opret et nyt projekt: I Visual Studio skal du gå til 'New Project'. Under skabelonerne finder du en sektion for 'Dynamics CRM'. Vælg 'New Visual Studio Solution Template for Dynamics CRM 2013'.
- Forbind til CRM: Efter at have navngivet din løsning, vil du blive bedt om at angive forbindelsesoplysninger til din CRM-server. Dette inkluderer server-URL, login-oplysninger, organisation og løsningsnavn. Det er stærkt anbefalet at udfylde disse oplysninger, da det aktiverer 'CRM Explorer' i Visual Studio, et kraftfuldt værktøj, der letter udviklingen.
- Projektstruktur: Skabelonen opretter typisk to projekter: et 'Plugin'-projekt og et 'Workflow'-projekt, sammen med et 'CRMPackage'-projekt til implementering. Hvis du kun skal lave et plugin, er det en god idé at slette 'Workflow'-projektet for at undgå potentielle konflikter under implementering. Når du fjerner workflow-projektet, skal du også manuelt fjerne den tilsvarende sektion fra filen
RegisterFile.crmregisteri CRMPackage-projektet. - Opret selve Plugin'et: I 'CRM Explorer'-vinduet kan du navigere til den entitet, du vil oprette et plugin for (f.eks. 'Account'). Højreklik på entiteten og vælg 'Create Plugin'.
- Konfigurer Plugin-trinnet: Du vil nu blive bedt om at definere, hvornår dit plugin skal køre. For et 'Create'-plugin vælger du typisk 'Post-Operation' som 'Pipeline Stage' og 'Create' som 'Message'. Dette betyder, at din kode vil køre, lige efter at en ny post er blevet gemt i databasen.
Dette vil automatisk generere en klassefil (f.eks. PostAccountCreate.cs), der arver fra IPlugin interfacet, og som indeholder den grundlæggende struktur, du skal bygge videre på.
Forståelse af Plugin Execution Pipeline
For at skrive effektive plugins er det afgørende at forstå 'Execution Pipeline'. Dette er den sekvens af stadier, som en operation (som at gemme en post) gennemgår i Dynamics CRM. Du kan tilknytte din kode til disse forskellige stadier.

- Stage 10: Pre-validation (Før-validering): Dette stadie sker uden for databasetransaktionen. Det er ideelt til at køre valideringslogik, der ikke kræver databaseadgang. Du bør undgå at lave opdateringer, oprettelser eller sletninger her.
- Stage 20: Pre-operation (Før-operation): Dette stadie er inden for databasetransaktionen, men før hovedoperationen udføres. Dette er det perfekte sted at modificere data på den post, der bliver behandlet, da ændringerne vil blive gemt sammen med hovedoperationen i en enkelt transaktion.
- Stage 30: Main Operation (Hovedoperation): Dette er selve kernehandlingen, som systemet udfører (f.eks. gemmer data i SQL-databasen). Du kan ikke registrere dine plugins i dette stadie.
- Stage 40: Post-operation (Efter-operation): Dette stadie er også inden for databasetransaktionen, men kører lige efter, at hovedoperationen er fuldført. Det er nyttigt, når du har brug for ID'et på den netop oprettede post, eller når du skal udføre handlinger baseret på det endelige resultat af operationen.
Bedste Praksis: Pre-Operation vs. Post-Operation
En almindelig fejl blandt udviklere er at placere for meget logik i Post-Operation, især logik, der modificerer den samme post, som udløste plugin'et. Dette fører til unødvendige kald til databasen og kan påvirke systemets ydeevne negativt.
Overvej et scenarie, hvor du vil opdatere to felter på en ordre, når den gemmes. Hvis dette gøres i Post-Operation, vil koden typisk hente posten, ændre felterne og derefter kalde service.Update(order). Dette resulterer i to separate databasehandlinger: den oprindelige gem-handling og en efterfølgende opdatering fra plugin'et.
Hvis den samme logik flyttes til Pre-Operation, kan du direkte modificere 'Target'-entiteten i inputparametrene. Systemet vil derefter gemme disse ændringer som en del af den oprindelige databasehandling. Dette reducerer antallet af databasekald fra to til ét.
Sammenligningstabel
| Aspekt | Pre-Operation | Post-Operation |
|---|---|---|
| Timing | Før hoveddatabasen gemmer | Efter hoveddatabasen har gemt |
| Effektivitet | Meget høj. Ændringer til 'Target' gemmes i samme transaktion. | Lavere. Kræver et ekstra service.Update() kald for at ændre den samme post. |
| Post ID | Ikke tilgængeligt for 'Create'-beskeder, da posten endnu ikke er oprettet. | Tilgængeligt. Postens ID findes i context.PrimaryEntityId. |
| Anvendelse | Ideel til at ændre værdier på den aktuelle post, før den gemmes. | Ideel til handlinger, der kræver det endelige resultat eller ID'et, f.eks. oprettelse af relaterede poster. |
Praktiske eksempler: CRUD-operationer i et Plugin
Lad os se på nogle konkrete kodeeksempler for, hvordan man udfører grundlæggende dataoperationer inden for et plugin. Koden er skrevet i C#.

Læsning af data (Read)
Når et plugin kører, kan du få adgang til data fra den post, der udløste det. I et 'Create' eller 'Update' plugin findes disse data i context.InputParameters["Target"].
// Kører i Post-Operation på 'Create' af en Account Entity eTarget = (Entity)context.InputParameters["Target"]; if (eTarget.LogicalName == "account") { // Hent værdier fra forskellige felttyper string accountName = eTarget.GetAttributeValue<string>("name"); EntityReference primaryContact = eTarget.GetAttributeValue<EntityReference>("primarycontactid"); Money revenue = eTarget.GetAttributeValue<Money>("revenue"); OptionSetValue category = eTarget.GetAttributeValue<OptionSetValue>("accountcategorycode"); // Hvis du har brug for ID'et på den nye post (kun i Post-Operation) Guid newAccountId = context.PrimaryEntityId; }Oprettelse af data (Create)
Du kan nemt oprette nye poster i andre entiteter fra dit plugin. Her opretter vi en 'Task'-aktivitet, når en ny 'Account' oprettes.
// Opret en ny Task-entitet Entity newTask = new Entity("task"); // Sæt attributter newTask["subject"] = "Follow up with new account: " + accountName; newTask["description"] = "Initial follow-up task created by plugin."; // Sæt 'Regarding' feltet til at pege på den nye Account newTask["regardingobjectid"] = new EntityReference("account", newAccountId); // Kald service.Create for at gemme den nye post service.Create(newTask);Opdatering af data (Update)
Opdatering af en eksisterende post er lige så ligetil. Du skal blot kende postens ID.
// Opdater en relateret kontakt if (primaryContact != null) { // Opret en entitet med reference til den post, der skal opdateres Entity contactToUpdate = new Entity("contact", primaryContact.Id); // Sæt den nye værdi for det felt, du vil ændre contactToUpdate["jobtitle"] = "Primary Contact at " + accountName; // Kald service.Update service.Update(contactToUpdate); }Sletning af data (Delete)
For at slette en post skal du blot angive entitetens logiske navn og postens ID.

// Scenarie: Slet en gammel, midlertidig post, når en ny oprettes // (Antager at vi har hentet 'oldTempRecordId' fra et andet sted) Guid oldTempRecordId = ...; service.Delete("new_temporaryrecord", oldTempRecordId);Implementering (Deployment) af dit Plugin
Når dit plugin er færdigudviklet og testet, skal det implementeres på CRM-serveren.
- Signer dit Assembly: Før implementering skal dit plugin-projektets assembly signeres med en 'strong name key file' (.snk). Dette gøres i projektets egenskaber under fanen 'Signing'.
- Deploy fra Visual Studio: Den nemmeste måde at implementere på er at højreklikke på 'CRMPackage'-projektet i Solution Explorer og vælge 'Deploy'. Dette vil kompilere, pakke og registrere dit plugin på den CRM-server, du konfigurerede i starten.
- Afregistrering: Hvis du har brug for at fjerne eller opdatere dit plugin, kan du bruge 'CRM Explorer' til at finde dit assembly under 'Plug-in Assemblies' og vælge 'Delete'.
Ofte Stillede Spørgsmål (FAQ)
Hvad er de fire stadier i en Dynamics CRM-plugin-pipeline?
De fire stadier er: Pre-validation (uden for transaktion), Pre-operation (inden for transaktion, før hovedhandling), Main Operation (systemets kernehandling) og Post-operation (inden for transaktion, efter hovedhandling).
Hvorfor er Pre-Operation ofte bedre end Post-Operation?
Pre-Operation er mere effektivt, når du skal modificere data på den samme post, som udløste plugin'et. Ændringerne bliver en del af den oprindelige databasehandling, hvilket reducerer antallet af kald til databasen og forbedrer ydeevnen sammenlignet med at skulle lave et separat service.Update() kald i Post-Operation.
Hvordan undgår man uendelige loops i plugins?
Et uendeligt loop kan opstå, hvis et plugin, der opdaterer en post, selv bliver udløst af opdateringen. For at undgå dette kan du tjekke 'Depth'-egenskaben på konteksten: if (context.Depth > 1) { return; }. Dette stopper eksekveringen, hvis plugin'et er blevet kaldt af et andet plugin. En anden metode er at tjekke, om den bruger, der startede handlingen (InitiatingUserId), er en specifik servicekonto, som bruges til integrationer, for at forhindre rekursive kald.
Hvis du vil læse andre artikler, der ligner Guide til Dynamics CRM 2013 Plugin Udvikling, kan du besøge kategorien Sundhed.
