Partager via


Résoudre les problèmes liés aux plug-ins

Cet article contient des informations sur les erreurs survenant en raison de l’exécution des plug-ins et comment les résoudre.

Erreur : le processus Sandbox Worker a échoué

Code d’erreur : -2147204723
Message d’erreur : The plug-in execution failed because the Sandbox Worker process crashed. This is typically due to an error in the plug-in code.

Cette erreur signifie simplement que le processus Worker exécutant votre code de plug-in s’est bloqué. La raison pour laquelle il s’est bloqué peut être votre plug-in, mais il peut également s’agir d’un autre plug-in s’exécutant simultanément pour votre organisation. Étant donné que le processus s’est bloqué, nous ne pouvons pas extraire d’informations plus spécifiques sur la raison pour laquelle il s’est bloqué. Mais après avoir examiné les données des vidages sur incident après coup, nous avons constaté que cela se produit généralement pour l’une des quatre raisons ci-dessous :

  • Exception non gérée dans le plug-in
  • Erreur Stack Overflow dans le plug-in
  • Utilisation de fils de discussion pour mettre le travail en file d’attente sans test/interception dans le délégué de fil de discussion
  • Le processus Worker atteint la limite de mémoire

Exception non gérée dans le plug-in

Comme mentionné dans Gérer les exceptions dans les plug-ins, lorsque vous écrivez un plug-in, vous devez essayer d’anticiper les opérations qui peuvent échouer et les inclure dans un wrapper dans un bloc tester-intercepter. Lorsque des erreurs se produisent, vous devez utiliser InvalidPluginExecutionException pour terminer correctement l’opération avec une erreur significative pour l’utilisateur.

Un scénario courant pour cela n’est autre que l’utilisation de la méthode HttpClient.SendAsync ou HttpClient.GetAsync qui sont des opérations asynchrones qui retournent une Tâche. Pour que cela fonctionne dans un plug-in où le code doit être synchrone, les utilisateurs peuvent utiliser la propriété Task<TResult>.Result. Lorsqu’une erreur se produit, cela renvoie une AggregateException qui consolide plusieurs échecs en une seule exception, qui peut être difficile à gérer. Une meilleure conception consiste à utiliser Task<TResult>.GetAwaiter().GetResult(), car il propage les résultats en tant qu’erreur spécifique à l’origine de l’échec.

L’exemple suivant montre la manière correcte de gérer l’exception et un appel sortant à l’aide de la méthode HttpClient.GetAsync. Ce plug-in tente d’obtenir le texte de réponse pour une URL définie dans la configuration non sécurisée pour une étape enregistrée pour elle.

using Microsoft.Xrm.Sdk;
using System;
using System.Net.Http;

namespace ErrorRepro
{
    public class AsyncError : IPlugin
    {
        private readonly string webAddress;

        public AsyncError(string unsecureConfig)
        {
            if (string.IsNullOrEmpty(unsecureConfig)) {
                throw new InvalidPluginExecutionException("The ErrorRepro.AsyncError plug-in requires that a Url be set in the unsecure configuration for the step registration.");
            }
            webAddress = unsecureConfig;

        }

        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService =
            (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            tracingService.Trace($"Starting ErrorRepro.AsyncError");
            tracingService.Trace($"Sending web request to {webAddress}");

            try
            {
                string responseText = GetWebResponse(webAddress, tracingService);
                tracingService.Trace($"Result: {responseText.Substring(0, 100)}");
            }
            catch (Exception ex)
            {
                tracingService.Trace($"Error: ErrorRepro.AsyncError {ex.Message}");
                throw new InvalidPluginExecutionException(ex.Message);
            }
            tracingService.Trace($"Ending ErrorRepro.AsyncError");
        }

        //Gets the text response of an outbound web service call
        public string GetWebResponse(string webAddress, ITracingService tracingService)
        {
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMilliseconds(15000); //15 seconds
                    client.DefaultRequestHeaders.ConnectionClose = true; //Set KeepAlive to false

                    HttpResponseMessage response = client.GetAsync(webAddress).GetAwaiter().GetResult(); //Make sure it is synchronous
                    response.EnsureSuccessStatusCode();

                    tracingService.Trace($"ErrorRepro.AsyncError.GetWebResponse succeeded.");

                    string responseContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); //Make sure it is synchronous

                    tracingService.Trace($"ErrorRepro.AsyncError.GetWebResponse responseContent parsed successfully.");

                    return responseContent;

                }
            }
            catch (Exception ex)
            {
                //Capture the inner exception message if it exists.
                // It should have a more specific detail.
                string innerExceptionMessage = string.Empty;
                if (ex.InnerException != null) {
                    innerExceptionMessage = ex.InnerException.Message;
                }

                tracingService.Trace($"Error in ErrorRepro.AsyncError : {ex.Message} InnerException: {innerExceptionMessage}");
                if (!string.IsNullOrEmpty(innerExceptionMessage))
                {
                    throw new Exception($"A call to an external web service failed. {innerExceptionMessage}", ex);
                }

                throw new Exception("A call to an external web service failed.", ex);
            }
        }
    }
}

Erreur Stack Overflow dans le plug-in

Ce type d’erreur se produit le plus souvent directement après avoir modifié le code de votre plug-in. Certaines personnes utilisent leur propre ensemble de classes de base pour rationaliser leur expérience de développement. Parfois, ces erreurs proviennent de modifications apportées aux classes de base dont dépend un plug-in particulier.

Par exemple, un appel récursif sans condition de terminaison ou une condition de terminaison, qui ne couvre pas tous les scénarios peut provoquer ce problème. Plus d’informations : classe StackOverflowException > Remarques

Vous devez examiner toutes les modifications de code qui ont été appliquées récemment pour le plug-in et tout autre code dont dépend le code du plug-in.

Exemple

Le code de plug-in suivant provoque une StackOverflowException en raison d’un appel récursif sans limites. Malgré l’utilisation du suivi et la tentative de capture de l’erreur, ni le suivi ni l’erreur ne sont renvoyés, car le processus Worker qui les traitait s’est arrêté.

using Microsoft.Xrm.Sdk;
using System;

namespace ErrorRepro
{
    public class SOError : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService =
           (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            tracingService.Trace($"Starting ErrorRepro.SOError");

            try
            {
                tracingService.Trace($"Calling RecursiveMethodWithNoLimit to trigger StackOverflow error.");

                RecursiveMethodWithNoLimit(tracingService); //StackOverflowException occurs here.
            }
            catch (Exception ex)
            {
                //This trace will not be written
                tracingService.Trace($"Error in ErrorRepro.SOError {ex.Message}");

                //This error will never be thrown
                throw new InvalidPluginExecutionException($"Error in ErrorRepro.SOError. {ex.Message}");
            }

            //This trace will never be written
            tracingService.Trace($"Ending ErrorRepro.SOError");
        }

        public static void RecursiveMethodWithNoLimit(ITracingService tracingService)
        {
            tracingService.Trace($"Starting ErrorRepro.SOError.RecursiveMethodWithNoLimit");

            RecursiveMethodWithNoLimit(tracingService);

            tracingService.Trace($"Ending ErrorRepro.SOError.RecursiveMethodWithNoLimit");
        }
    }
}

Lorsque le code de plug-in ci-dessus est utilisé dans un plug-in synchrone, l’erreur suivante est renvoyée par l’API web :

{
    "error": {
        "code": "0x8004418d",
        "message": "The plug-in execution failed because the Sandbox Worker process crashed. This is typically due to an error in the plug-in code.\r\nSystem.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.\r\n   at Microsoft.Crm.Sandbox.SandboxWorkerProcess.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, Boolean returnTraceInfo, Int64& wcfExecInMs, Int64& initializeInMs, Int64& trackCallInMs, Int64& trackGoodReturnInMs, Int64& waitInMs, Int64& taskStartDelay) +0x330: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #8503641A",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiExceptionSourceKey": "Plugin/ErrorRepro.SOError, ErrorRepro, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2bee3e550ec0851",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiStepKey": "d5958631-b87e-eb11-a812-000d3a4f50a7",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiDepthKey": "1",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiActivityIdKey": "a3028bda-73c2-4eef-bcb5-157c5a4c323e",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiPluginSolutionNameKey": "Active",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiStepSolutionNameKey": "Active",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiExceptionCategory": "SystemFailure",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiExceptionMesageName": "SandboxWorkerNotAvailable",
        "@Microsoft.PowerApps.CDS.ErrorDetails.ApiExceptionHttpStatusCode": "500",
        "@Microsoft.PowerApps.CDS.HelpLink": "http://go.microsoft.com/fwlink/?LinkID=398563&error=Microsoft.Crm.CrmException%3a8004418d&client=platform",
        "@Microsoft.PowerApps.CDS.TraceText": "\r\n[ErrorRepro: ErrorRepro.SOError]\r\n[d5958631-b87e-eb11-a812-000d3a4f50a7: ErrorRepro.SOError: Create of account]\r\n\r\n",
        "@Microsoft.PowerApps.CDS.InnerError.Message": "The plug-in execution failed because the Sandbox Worker process crashed. This is typically due to an error in the plug-in code.\r\nSystem.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.\r\n   at Microsoft.Crm.Sandbox.SandboxWorkerProcess.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, Boolean returnTraceInfo, Int64& wcfExecInMs, Int64& initializeInMs, Int64& trackCallInMs, Int64& trackGoodReturnInMs, Int64& waitInMs, Int64& taskStartDelay) +0x330: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #8503641A"
    }
}

Voici comment cette erreur est enregistrée dans le journal de suivi du plug-in :

Unhandled exception: 
Exception type: System.ServiceModel.FaultException`1[Microsoft.Xrm.Sdk.OrganizationServiceFault]
Message: The plug-in execution failed because the Sandbox Worker process crashed. This is typically due to an error in the plug-in code.
System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
   at Microsoft.Crm.Sandbox.SandboxWorkerProcess.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, Boolean returnTraceInfo, Int64& wcfExecInMs, Int64& initializeInMs, Int64& trackCallInMs, Int64& trackGoodReturnInMs, Int64& waitInMs, Int64& taskStartDelay) +0x330: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #4BC22433Detail: 
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
  <ActivityId>48c5818e-4912-42f0-b1b6-e3bbe7ae013d</ActivityId>
  <ErrorCode>-2147204723</ErrorCode>
  <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
  <HelpLink i:nil="true" />
  <Message>The plug-in execution failed because the Sandbox Worker process crashed. This is typically due to an error in the plug-in code.
System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
   at Microsoft.Crm.Sandbox.SandboxWorkerProcess.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, Boolean returnTraceInfo, Int64&amp; wcfExecInMs, Int64&amp; initializeInMs, Int64&amp; trackCallInMs, Int64&amp; trackGoodReturnInMs, Int64&amp; waitInMs, Int64&amp; taskStartDelay) +0x330: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #4BC22433</Message>
  <Timestamp>2021-03-06T22:14:22.0629638Z</Timestamp>
  <ExceptionRetriable>false</ExceptionRetriable>
  <ExceptionSource>WorkerCommunication</ExceptionSource>
  <InnerFault i:nil="true" />
  <OriginalException>System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at Microsoft.Crm.Sandbox.SandboxWorkerProcess.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, Boolean returnTraceInfo, Int64&amp; wcfExecInMs, Int64&amp; initializeInMs, Int64&amp; trackCallInMs, Int64&amp; trackGoodReturnInMs, Int64&amp; waitInMs, Int64&amp; taskStartDelay)</OriginalException>
  <TraceText i:nil="true" />
</OrganizationServiceFault>

Utilisation de fils de discussion pour mettre le travail en file d’attente sans test/interception dans le délégué de fil de discussion

Vous ne devez pas utiliser de modèles d’exécution parallèle dans les plug-ins. Ceci est indiqué dans cet article de bonnes pratiques : N’utilisez pas l’exécution parallèle dans les plug-ins et les activités de workflow. L’utilisation de ces modèles peut entraîner des problèmes de gestion de la transaction dans un plug-in synchrone. Cependant, une autre raison de ne pas utiliser ces modèles est que tout travail effectué en dehors d’un blocage de test/d’interception dans un délégué de fil de discussion peut bloquer le processus Worker.

Le processus Worker atteint la limite de mémoire

Chaque processus Worker a une quantité limitée de mémoire. Il existe des conditions dans lesquelles plusieurs opérations simultanées qui incluent de grandes quantités de données peuvent dépasser la mémoire disponible et provoquer le blocage du processus Worker.

RetrieveMultiple avec données de fichier

Le scénario courant dans ce cas est celui où un plug-in s’exécute pendant une opération RetrieveMultiple où la demande comprend des données de fichier. Par exemple, lors de la récupération d’e-mails contenant des pièces jointes. La quantité de données qui peuvent être renvoyées dans une requête comme celle-ci est imprévisible, car tout e-mail peut être lié à un nombre quelconque de pièces jointes et les pièces jointes elles-mêmes peuvent varier en taille.

Lorsque plusieurs requêtes de même nature sont exécutées simultanément, la quantité de mémoire requise devient importante. S’il dépasse la limite, le processus se bloque. La solution pour éviter cela consiste à limiter les requêtes RetrieveMultiple qui incluent des entités avec des pièces jointes associées. Récupérez les enregistrements en utilisant RetrieveMultiple, mais récupérez tous les fichiers associés, le cas échéant, à l’aide des opérations Retrieve.

Fuites de la mémoire

Un scénario moins courant est celui où le code du plug-in perd de la mémoire. Cela peut se produire lorsque le plug-in n’est pas écrit en mode sans état, ce qui est une autre bonne pratique : Développer des implémentations IPlugin en mode sans état. Lorsque le plug-in n’est pas en mode sans état et qu’il y a une tentative d’ajouter continuellement des données à une propriété avec état comme un tableau. La quantité de données augmente au point où elle utilise toute la mémoire disponible.

Erreurs de transaction

Il existe deux types courants d’erreurs liées à des transactions :

Code d’erreur : -2146893812
Message d’erreur : ISV code reduced the open transaction count. Custom plug-ins should not catch exceptions from OrganizationService calls and continue processing.

Code d’erreur : -2147220911
Message d’erreur : There is no active transaction. This error is usually caused by custom plug-ins that ignore errors from service calls and continue processing.

Notes

L’erreur de niveau supérieur a été ajoutée récemment. Elle doit se produire immédiatement et dans le cadre d’un plug-in qui contient un problème. Une erreur de niveau inférieur peut toujours se produire dans différentes circonstances, impliquant généralement des activités de workflow personnalisées. Cela peut provenir de problèmes dans un autre plug-in.

Pour comprendre le message, vous devez considérer que chaque fois qu’une erreur liée à une opération de données se produit dans un plug-in synchrone, la transaction de l’opération entière prend fin.

Plus d’informations : Conception de personnalisation évolutive dans Microsoft Dataverse

La cause la plus courante est simplement qu’un développeur peut croire qu’il peut tenter d’effectuer une opération qui peut réussir. Ils incluet donc dans un wrapper cette opération dans un bloc try/catch et tentent d’avaler l’erreur lorsque celle-ci échoue.

Bien que cela puisse fonctionner pour une application cliente, dans l’exécution d’un plug-in, n’importe quel échec d’opération de données entraînera l’annulation de la transaction complète. Vous ne pouvez pas avaler l’erreur, vous devez veiller à retourner toujours une InvalidPluginExecutionException.

Erreur : erreur Sql : Délai d’exécution expiré

Code d’erreur : -2147204783
Message d’erreur : Sql error: 'Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.'

Il existe un large éventail de raisons pour lesquelles une erreur de délai d’exécution SQL peut se produire.

Blocage

Le blocage est la cause la plus courante d’erreur de délai d’exécution SQL, car l’opération attend des ressources qui sont verrouillées par une autre transaction SQL. L’erreur est le résultat du système qui protège l’intégrité des données et contre les demandes longues qui impactent les performances pour les utilisateurs.

Le blocage peut provenir d’autres opérations simultanées. Votre code peut fonctionner parfaitement dans un contexte isolé dans un environnement de test et être vulnérable aux conditions qui se produisent uniquement lorsque plusieurs utilisateurs lancent la logique de votre plug-in.

Lorsque vous écrivez des plug-ins, il est essentiel de comprendre comment concevoir des personnalisations qui sont évolutives. Plus d’informations : Conception de personnalisation évolutive dans Dataverse

Opérations en cascade

Certaines actions que vous effectuez dans votre plug-in, telles qu’attribuer ou supprimer un enregistrement, peuvent initialiser la mise en cascade des opérations sur des enregistrements associés. Ces actions peuvent appliquer des verrouillages sur des enregistrements associés entraînant le blocage des opérations de données suivantes qui peuvent ensuite conduire à un l’expiration de l’exécution SQL.

Vous devez tenir compte de l’impact possible de ces opérations en cascade sur des opérations de données dans votre plug-in. Pour plus d’informations : Comportement des relations de table

Comme ces comportements peuvent être configurés différemment entre les environnements, ils peuvent être difficiles à reproduire, à moins que les environnements soient configurés de la même manière.

Index sur de nouvelles tables

Si le plug-in effectue des opérations à l’aide d’une table ou d’une colonne créé récemment, certaines fonctionnalités d’Azure SQL pour gérer les index peuvent faire la différence après plusieurs jours.

Erreurs dues aux privilèges de l’utilisateur

Dans une application cliente, vous pouvez désactiver les commandes que les utilisateurs ne sont pas autorisés à effectuer. Dans un plug-in vous ne le pouvez pas. Votre code peut inclure de l’automatisation que l’utilisateur appelant n’a pas les privilèges d’effectuer.

Vous pouvez enregistrer le plug-in pour s’exécuter dans le contexte d’un utilisateur connu pour disposer des privilèges appropriés en définissant la valeur Exécuter dans le contexte de l’utilisateur sur cet utilisateur. Sinon, vous pouvez exécuter l’opération en empruntant l’identité d’un autre utilisateur. Pour plus d’informations :

Erreur : Taille de messages dépassée en envoyant le contexte dans le Bac à sable

Code d’erreur : -2147220970
Message d’erreur : Message size exceeded when sending context to Sandbox. Message size: ### Mb

Cette erreur se produit lorsqu’une charge de messages est supérieure à 116,85 Mo ET qu’un plug-in est enregistré pour le message. Le message d’erreur contient la taille de la charge utile à l’origine de cette erreur.

La limite vous permet de garantir que utilisateurs exécutant les applications ne puissent pas interférer l’un avec l’autre selon les contraintes de ressource. La limite contribuera à fournir un niveau de protection contre les charges utiles de messages inhabituellement volumineuses qui menacent les caractéristiques de disponibilité et de performance de la plateforme Dataverse.

116,85 Mo est suffisamment grand pour qu’il soit rare de rencontrer ce cas. Ce cas de figure plus probable peut se produire lorsque vous récupérez un enregistrement avec plusieurs enregistrements associés comprenant des fichiers binaires volumineux.

Si vous rencontrez cette erreur, vous pouvez :

  1. Supprimer le plug-in pour le message. S’il n’y a aucun plug-in inscrit pour le message, le processus se déroule sans erreur.
  2. Si l’erreur se produit dans un client personnalisé, vous pouvez modifier votre code afin qu’il ne tente pas d’effectuer le travail en une seule opération. Au lieu de cela, entrez le code pour extraire les données par petits morceaux.

Erreur : La clé donnée n’est pas présente dans le dictionnaire

Dataverse utilise fréquemment des classes dérivées de la classe DataCollection<TKey,TValue> abstraite qui représente un ensemble de clés et de valeurs. Par exemple, avec les plug-ins, la propriété IExecutionContext.InputParameters est une ParameterCollection dérivée à partir de la classe DataCollection<TKey,TValue>. Ces classes sont essentiellement des objets de dictionnaire permettant d’accéder à une valeur spécifique à l’aide du nom de la clé.

Codes d’erreur

Cette erreur se produit lorsque la valeur principale en code n’existe pas dans la collection. Il s’agit d’une erreur d’exécution plutôt qu’une erreur de plateforme. Lorsque cette erreur se produit dans un plug-in, le code d’erreur dépend de si l’erreur a été interceptée.

Si le développeur interceptait l’exception et retournait InvalidPluginExecutionException comme décrit dans Gérer les exceptions dans les plug-ins, l’erreur suivante sera retournée :

Code d’erreur : -2147220891
Message d’erreur : ISV code aborted the operation.

Cependant, avec cette erreur, il est courant que le développeur ne la récupère pas correctement et l’erreur suivante sera renvoyée :

Code d’erreur : -2147220956
Message d’erreur : An unexpected error occurred from ISV code.

Notes

« ISV » (Independent Software Vendor) signifie pour Éditeur de logiciels indépendants.

Causes

Cette erreur se produit fréquemment au moment de la conception et peut être due à une faute d’orthographe ou à l’utilisation d’une casse incorrecte. Les principales valeurs respectent la casse.

Au moment de l’exécution, l’erreur est souvent due au développeur qui suppose que la valeur est présente alors que ce n’est pas le cas. Par exemple, dans un plug-in qui est enregistré pour la mise à jour d’une table, seules ces valeurs qui sont modifiées seront incluses dans Entity.Attributes .

Prévention

Pour éviter cette erreur, vous devez vérifier que la clé existe avant de tenter de l’utiliser pour accéder à une valeur.

Par exemple, en accédant à une colonne de table, vous pouvez utiliser la méthode Entity.Contains(String) pour vérifier si une colonne existe dans une table comme indiqué dans le code suivant.

// Obtain the execution context from the service provider.  
IPluginExecutionContext context = (IPluginExecutionContext)
    serviceProvider.GetService(typeof(IPluginExecutionContext));

// The InputParameters collection contains all the data passed in the message request.  
if (context.InputParameters.Contains("Target") &&
    context.InputParameters["Target"] is Entity)
    {
    // Obtain the target entity from the input parameters.  
    Entity entity = (Entity)context.InputParameters["Target"];

    //Check whether the name attribute exists.
    if(entity.Contains("name"))
    {
        string name = entity["name"];
    }

Certains développeurs utilisent la méthode Entity.GetAttributeValue<T>(String) pour éviter cette erreur lors de l’accès à une colonne de table, mais sachez que cette méthode renverra la valeur par défaut du type si la colonne n’existe pas. Si la valeur par défaut est nulle, cela fonctionne comme prévu. Si la valeur par défaut ne retourne pas la valeur null, par exemple avec DateTime, la valeur retournée est 1/1/0001 00:00 plutôt que la valeur null.

Erreur : vous ne pouvez pas démarrer une transaction avec un niveau d’isolement différent de celui déjà défini sur la transaction en cours

Code d’erreur : -2147220989
Message d’erreur : You cannot start a transaction with a different isolation level than is already set on the current transaction

Les plug-ins sont destinés à prendre en charge la logique métier. La modification d’une partie quelconque du schéma de données dans le plug-in synchrone n’est pas prise en charge. Ces opérations prennent souvent plus de temps et peuvent entraîner la désynchronisation des métadonnées mises en cache utilisées par les applications. Cependant, ces opérations peuvent être effectuées dans une étape de plug-in enregistrée pour s’exécuter de manière asynchrone.

Notes

Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)

Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).