Problembehandlung für Dataverse-Plug-Ins
Dieser Artikel enthält Informationen zu Fehlern, die während der Plug-In-Ausführung auftreten können, oder Dataverse-Fehler, die mit Plug-Ins zusammenhängen, und wie sie vermieden oder behoben werden können.
Fehler "Zeitkonvertierung konnte nicht abgeschlossen werden"
Fehlercode: -2147220956
Fehlermeldung: Die Konvertierung konnte nicht abgeschlossen werden, da die angegebene DataTime nicht ordnungsgemäß festgelegt wurde. Wenn die Kind-Eigenschaft beispielsweise DateTimeKind.Local ist, muss die Quellzeitzone TimeZoneInfo.Local sein.
Dieser Fehler kann während eines TimeZoneInfo.ConvertTimeToUtc(DateTime, TimeZoneInfo) Aufrufs im Plug-In-Code auftreten, um einen DateTime
Wert in der Zeitzone Santiago oder Volgograd in koordinierte Weltzeit (COORDINATED Universal Time, UTC) zu konvertieren.
Dieser Fehler wird durch eine bekannte Produktbeschränkung verursacht, und es gibt derzeit keine Problemumgehung.
Weitere Informationen finden Sie unter Angeben von Zeitzoneneinstellungen für einen Benutzer.
Fehler "Sandkasten-Arbeitsprozess ist abgestürzt"
Fehlercode: -2147204723
Fehlermeldung: Fehler bei der Plug-In-Ausführung, da der Sandkasten-Arbeitsprozess abgestürzt ist. Dies liegt in der Regel an einem Fehler im Plug-In-Code.
Dieser Fehler bedeutet einfach, dass der Arbeitsprozess, der Ihren Plug-in-Code ausführt, abgestürzt ist. Ihr Plug-In kann der Grund für den Absturz sein, aber es kann auch ein weiteres Plug-In sein, das gleichzeitig für Ihre Organisation ausgeführt wird. Da der Prozess abgestürzt ist, können wir keine spezifischeren Informationen darüber extrahieren, warum er abgestürzt ist. Nach der Untersuchung von Daten aus den Absturzabbildern nach der Tatsache haben wir jedoch festgestellt, dass dieser Fehler in der Regel aufgrund eines der vier Gründe auftritt:
- Ausnahmefehler im Plug-In
- Verwenden von Threads zur Warteschlange ohne Try/Catch im Threaddelegat
- Stack Overflow-Fehler im Plug-In
- Der Arbeitsprozess erreicht die Speichergrenze.
Ausnahmefehler im Plug-In
Wenn Sie ein Plug-In schreiben, sollten Sie versuchen, zu antizipieren, welche Vorgänge möglicherweise fehlschlagen und in einen Try-Catch-Block umschließen. Wenn ein Fehler auftritt, sollten Sie die InvalidPluginExecutionException Klasse verwenden, um den Vorgang ordnungsgemäß mit einem für den Benutzer sinnvollen Fehler zu beenden.
Weitere Informationen finden Sie unter Behandeln von Ausnahmen in Plug-Ins.
Ein häufiges Szenario für diese Ausnahme ist die Verwendung der HttpClient.SendAsync - oder HttpClient.GetAsync-Methode . Diese HttpClient-Methoden sind asynchrone Vorgänge, die eine Aufgabe zurückgeben. Um in einem Plug-In zu arbeiten, bei dem Code synchron sein muss, verwenden Die Benutzer möglicherweise das Aufgaben-TResult<>. Result-Eigenschaft. Wenn ein Fehler auftritt, Result
wird eine AggregateException zurückgegeben. Ein AggregateException
Konsolidiert mehrere Fehler in einer einzigen Ausnahme, was schwierig zu behandeln sein kann. Eher ist zu empfehlen, Task<TResult>.GetAwaiter().GetResult() zu verwenden, weil damit das Ergebnis als genau der Fehler weitergegeben wird, der die Störung hervorgerufen hat.
Das folgende Beispiel zeigt die richtige Methode zum Verwalten der Ausnahme und eines ausgehenden Aufrufs mithilfe der HttpClient.GetAsync-Methode . Dieses Plug-In versucht, den Antworttext für einen URI abzurufen, der in der unsicheren Konfiguration für einen für ihn registrierten Schritt festgelegt wurde.
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);
}
}
}
}
Verwendung von Threads, um Arbeit in eine Warteschlange zu stellen, ohne try/catch im Thread-Delegat
Sie sollten keine parallelen Ausführungsmuster in Plug-Ins verwenden. Dieses Antimuster wird im Artikel der bewährten Methode genannt: Verwenden Sie keine parallele Ausführung innerhalb von Plug-Ins und Workflowaktivitäten. Die Verwendung dieser Muster kann zu Problemen bei der Verwaltung der Transaktion in einem synchronen Plug-In führen. Ein weiterer Grund, diese Muster nicht zu verwenden, ist jedoch, dass alle Arbeiten außerhalb eines try
/catch
Blocks in einem Threaddelegat den Arbeitsprozess abstürzen können.
Wichtig
Wenn der Arbeitsprozess abstürzt, wird die Ausführung Des Plug-Ins und anderer Plug-Ins, die derzeit in diesem Prozess ausgeführt werden, beendet. Dazu gehören Plug-Ins, die Sie nicht besitzen oder verwalten.
Application Insights zur Rettung
In der Vergangenheit war das Abrufen der Stapelablaufverfolgung oder anderer Ausführungsinformationen für nicht behandelte Plug-In-Ausnahmen vom abgestürzten Arbeitsprozess unmöglich. Dataverse bietet jedoch jetzt Unterstützung für die Protokollierung von Ausführungsfehlern in Application Insights. Um diese Funktion zu aktivieren, können Sie Application Insights mit der Umgebung verknüpfen, in der Ihr Plug-In registriert ist. Nach der Verknüpfung treten die Protokollierung von Plug-In-Abstürzen automatisch auf.
Weitere Informationen finden Sie unter Exportieren von Daten in Application Insights.
Nachdem eine Application Insights-Umgebung verknüpft wurde, stehen die folgenden Daten eines Arbeitsprozessabsturzes zur Problembehandlung zur Verfügung.
Führen Sie die folgenden Schritte aus, um zum Absturzbericht in Application Insights zu navigieren:
- Verknüpfen Sie Application Insights mit Ihrer Umgebung.
- Warten Sie, bis eine Plug-In-Ausnahme zu einem Absturzfehler des Arbeitsprozesses führt.
- Navigieren Sie im Power Platform Admin Center zu Application Insights.
- Wählen Sie auf der Seite "Application Insights" die Option "Fehler " im linken Bereich aus.
- Wählen Sie auf der Seite "Fehler" die Option "Ausnahmen" aus.
- Wählen Sie unter "Ausnahmeproblem-ID" in der Liste "Gesamt " die Option "Microsoft.PowerPlatform.Dataverse.Plugin.PluginWorkerCrashException" aus.
- Wählen Sie auf der rechten Seite der Seite unter "Insgesamt" "PluginWorkerCrashException" aus. Nun werden die Details aller aufgezeichneten Absturzabstürzen des Arbeitsprozesses angezeigt.
- Suchen Und wählen Sie die gewünschte Ausnahme im linken Bereich aus, und der Ausnahmedetails-Bericht wird auf der rechten Seite der Seite angezeigt (siehe vorheriger Screenshot für ein Beispiel).
- Um auf die Stapelablaufverfolgung zuzugreifen, erweitern Sie "CrashDetails " im Bericht.
Stapelüberlauffehler im Plug-In
Dieser Fehlertyp tritt am häufigsten auf, nachdem Sie einige Änderungen am Plug-In-Code vorgenommen haben. Manche Leute verwenden einen eigenen Satz von Basisklassen, um ihre Entwicklung zu rationalisieren. Manchmal entstehen diese Fehler durch Änderungen an diesen Basisklassen, von denen ein bestimmtes Plug-In abhängt.
Beispielsweise kann ein rekursiver Aufruf ohne Beendigungsbedingung oder eine Beendigungsbedingung, die nicht alle Szenarien abdeckt, dazu führen, dass dieser Fehler auftritt. Weitere Informationen finden Sie in den Hinweisen zur StackOverflowException-Klasse>.
Sie sollten alle Code-Änderungen überprüfen, die in letzter Zeit für das Plug-in und jeden anderen Code, von dem der Plug-in-Code abhängt, vorgenommen wurden.
Beispiel
Der folgende Plug-In-Code führt StackOverflowException
zu einem rekursiven Aufruf ohne Einschränkungen. Trotz der Verwendung der Ablaufverfolgung und dem Versuch, den Fehler zu erfassen, werden die Ablaufverfolgung und der Fehler nicht zurückgegeben, da der Arbeitsprozess, der sie verarbeiten würde, beendet wurde.
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");
}
}
}
In einem synchronen Plug-In-Schritt gibt der zuvor gezeigte Plug-In-Code den folgenden Fehler in der Web-API zurück, wenn die Anforderung so konfiguriert ist, dass zusätzliche Details mit Fehlern eingeschlossen werden.
{
"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"
}
}
Im Folgenden wird gezeigt, wie dieser Fehler im Plug-In Tracelog aufgezeichnet wird:
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& 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: #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& wcfExecInMs, Int64& initializeInMs, Int64& trackCallInMs, Int64& trackGoodReturnInMs, Int64& waitInMs, Int64& taskStartDelay)</OriginalException>
<TraceText i:nil="true" />
</OrganizationServiceFault>
Der Arbeitsprozess erreicht die Speichergrenze.
Jeder worker-Prozess verfügt über eine endliche Menge an Speicher. Es gibt Bedingungen, unter denen mehrere gleichzeitige Operationen, die große Datenmengen beinhalten, den verfügbaren Speicher überschreiten und den Arbeitsprozess zum Absturz bringen können.
RetrieveMultiple mit Dateidaten
Das häufige Szenario ist in diesem Fall, wenn ein Plug-In für einen RetrieveMultiple
Vorgang ausgeführt wird, bei dem die Anforderung Dateidaten enthält. Beispielsweise beim Abrufen von E-Mails, die Dateianlagen enthalten. Die Menge der Daten, die in einer Abfrage zurückgegeben werden können, ist unvorhersehbar, da jede E-Mail möglicherweise mit einer beliebigen Anzahl von Dateianlagen verknüpft ist, und die Anlagen können in der Größe variieren.
Wenn mehrere Anfragen ähnlicher Art gleichzeitig ausgeführt werden, wird der benötigte Speicherplatz groß. Wenn die Speichermenge den Grenzwert überschreitet, stürzt der Prozess ab. Der Schlüssel, um diese Situation zu verhindern, ist das Einschränken von RetrieveMultiple
Abfragen, die Entitäten mit verwandten Dateianlagen enthalten. Rufen Sie die Datensätze mit RetrieveMultiple
ab, aber rufen Sie bei Bedarf alle zugehörigen Dateien mit einzelnen Retrieve
-Operationen ab.
Speicherlecks
Ein weniger allgemeines Szenario ist, dass der Code des Plug-Ins Speicherlecks aufweist. Diese Situation kann auftreten, wenn das Plug-In nicht als zustandslos geschrieben wird, was eine weitere bewährte Methode ist. Weitere Informationen finden Sie unter Entwickeln von Plug-In-Implementierungen als zustandslos. Wenn das Plug-In nicht zustandslos ist und versucht wird, einer zustandsbehafteten Eigenschaft wie einem Array fortlaufend Daten hinzuzufügen, wird die Datenmenge bis zum Punkt wächst, an dem der gesamte verfügbare Arbeitsspeicher verwendet wird.
Transaktionsfehler
Es gibt zwei häufige Arten von Fehlern im Zusammenhang mit Transaktionen:
Fehlercode: -2146893812
Fehlermeldung: DER ISV-Code hat die Anzahl der geöffneten Transaktionen reduziert. Benutzerdefinierte Plug-Ins sollten keine Ausnahmen von OrganizationService-Aufrufen abfangen und die Verarbeitung fortsetzen.
Fehlercode: -2147220911
Fehlermeldung: Es gibt keine aktive Transaktion. Dieser Fehler wird in der Regel durch benutzerdefinierte Plug-Ins verursacht, die Fehler von Dienstaufrufen ignorieren und die Verarbeitung fortsetzen.
Notiz
Der oberste Fehler wurde zuletzt hinzugefügt. Sie sollte sofort und im Zusammenhang mit dem Plugin, das das Problem enthält, auftreten. Der untere Fehler kann immer noch unter verschiedenen Umständen auftreten, typischerweise mit benutzerdefinierten Workflow-Aktivitäten. Dies kann auf Probleme in einem anderen Plug-In zurückzuführen sein.
Wenn ein Fehler im Zusammenhang mit einem Datenvorgang innerhalb eines synchronen Plug-Ins auftritt, wird die Transaktion für den gesamten Vorgang beendet.
Weitere Informationen finden Sie unter Skalierbares Anpassungsdesign in Microsoft Dataverse.
Eine häufige Ursache ist, dass ein Entwickler glaubt, dass er versuchen kann, einen Vorgang auszuführen, der erfolgreich sein kann , sodass er diesen Vorgang in einem try
/catch
Block umschließt und versucht, den Fehler zu schlucken, wenn er fehlschlägt.
Dieses Muster kann zwar für eine Clientanwendung funktionieren, während innerhalb der Ausführung eines Plug-Ins ein Datenvorgangsfehler dazu führt, dass die gesamte Transaktion zurückgerollt wird. Sie können die Fehler nicht schlucken, daher müssen Sie sicherstellen, stets InvalidPluginExecutionException zurückzugeben.
Fehler "SQL-Fehler: Ausführungstimeout abgelaufen"
Fehlercode: -2147204783
Fehlermeldung: SQL-Fehler: 'Ausführungstimeout abgelaufen. Der Timeoutzeitraum, der vor abschluss des Vorgangs verstrichen ist oder der Server nicht reagiert."
Ursache
Es gibt eine Vielzahl von Gründen, warum ein SQL-Timeoutfehler auftreten kann. Drei davon werden hier beschrieben:
Blockierung
Die häufigste Ursache für einen SQL-Timeoutfehler ist, dass der Vorgang auf Ressourcen wartet, die von einer anderen SQL-Transaktion blockiert wurden. Der Fehler ist das Ergebnis des Dataverse-Schutzes der Integrität der Daten und von lang ausgeführten Anforderungen, die sich auf die Leistung für Benutzer auswirken.
Das Blockieren kann auf andere gleichzeitige Vorgänge zurückzuführen sein. Ihr Code funktioniert möglicherweise isoliert in einer Testumgebung und ist weiterhin anfällig für Bedingungen, die nur auftreten, wenn mehrere Benutzer die Logik in Ihrem Plug-In initiieren.
Beim Schreiben von Plug-Ins ist es wichtig, nachvollziehen zu können, wie skalierbare Anpassungen entwickelt werden. Weitere Informationen finden Sie unter Skalierbares Anpassungsdesign in Dataverse.
Weitergabevorgänge
Bestimmte Aktionen, die Sie in Ihrem Plug-In vornehmen, z. B: das Zuweisen oder Löschen eines Datensatzes, kann einzelne Vorgänge in verknüpften Datensätzen initiieren. Diese Aktionen können Sperren für verwandte Datensätze anwenden, wodurch nachfolgende Datenvorgänge blockiert werden, was wiederum zu einem SQL-Timeout führen kann.
Sie sollten die möglichen Auswirkungen dieser überlappenden Vorgänge auf Datenvorgänge in Ihrem Plug-In bedenken. Weitere Informationen finden Sie unter Verhalten von Tabellenbeziehungen.
Da diese Verhaltensweisen zwischen Umgebungen unterschiedlich konfiguriert werden können, kann die Wiedergabe des Verhaltens schwierig sein, es sei denn, die Umgebungen sind auf die gleiche Weise konfiguriert.
Indizes auf neuen Tabellen
Wenn das Plug-In Vorgänge mit einer Tabelle oder Spalte ausführt, die kürzlich erstellt wurde, können einige Azure SQL-Funktionen zum Verwalten von Indizes nach einigen Tagen einen Unterschied machen.
Fehler aufgrund von Benutzerrechten
In einer Clientanwendung können Sie Befehle deaktivieren, die Benutzer nicht ausführen dürfen. Innerhalb eines Plug-Ins haben Sie diese Möglichkeit nicht. Ihr Code enthält möglicherweise eine Automatisierung, die der aufrufende Benutzer nicht über die erforderlichen Berechtigungen verfügt.
Sie können registrieren, dass das Plug-In im Rahmen eines Benutzers ausgeführt wird, der die richtigen Rechte hat, indem Sie den Wert Ausführung im Kontext des Benutzers für den Benutzer festlegen. Sie können den Vorgang auch ausführen, indem Sie einen anderen Benutzer imitieren. Weitere Informationen finden Sie unter:
Fehler beim Ausführen im Kontext eines deaktivierten Benutzers
Wenn ein Plug-In im Kontext eines deaktivierten Benutzers ausgeführt wird, wird der folgende Fehler zurückgegeben:
Fehlermeldung: System.ServiceModel.FaultException'1[Microsoft.Xrm.Sdk.OrganizationServiceFault]: Der Benutzer mit SystemUserId=<User-ID> in OrganizationContext=<Context> ist deaktiviert. Deaktivierte Benutzer können nicht auf das System zugreifen. Erwägen Sie, diesen Benutzer zu aktivieren. Außerdem werden Benutzer deaktiviert, wenn ihnen keine Lizenz zugewiesen ist.
Um diesen Fehler zu beheben, können Sie eine Abfrage ausführen, um die Schritte zu finden, die für den deaktivierten Benutzer registriert sind, sowie das zugeordnete Plug-In und SdkMessage
Details.
https://<env-url>/api/data/v9.2/sdkmessageprocessingsteps
?$filter=_impersonatinguserid_value eq '<disabled-userId-from-error>'&
$expand=plugintypeid($select=name,friendlyname,assemblyname;
$expand=pluginassemblyid($select=solutionid,name,isolationmode)),sdkmessageid($select=solutionid,name)&
$select=solutionid,name,stage,_impersonatinguserid_value,mode
Fehler "Die Nachrichtengröße wurde überschritten, wenn Kontext an Sandkasten gesendet wird"
Fehlercode: -2147220970
Fehlermeldung: Die Nachrichtengröße wurde beim Senden des Kontexts an den Sandkasten überschritten. Nachrichtengröße: ### Mb
Dieser Fehler tritt auf, wenn eine Nachrichtennutzlast größer als 116,85 MB ist und ein Plug-In für die Nachricht registriert wird. Die Fehlermeldung enthält die Größe der Nutzlast, die diesen Fehler verursacht hat.
Der Grenzwert trägt dazu bei, dass Benutzer, die Anwendungen ausführen, nicht auf der Grundlage von Ressourceneinschränkungen miteinander stören können. Der Grenzwert trägt dazu bei, ein Maß an Schutz vor ungewöhnlich großen Nachrichtennutzlasten bereitzustellen, die die Verfügbarkeit und Leistungsmerkmale der Dataverse-Plattform gefährden.
116,85 MB ist groß genug, dass dieser Fall eher selten eintreten sollte. Die wahrscheinlichste Situation, in der dieser Fall eintreten könnte, ist, wenn Sie einen Datensatz mit mehreren Datensätzen abrufen, die große Binärdateien enthalten.
Wenn Sie diese Fehlermeldung erhalten, können Sie:
- Das Plug-In für die Message entfernen Wenn keine Plug-Ins für die Nachricht registriert sind, wird der Vorgang ohne Fehler abgeschlossen.
- Wenn der Fehler in einem benutzerdefinierten Client auftritt, können Sie Ihren Code ändern, damit er nicht versucht, die Aufgabe in einem einzelnen Vorgang auszuführen. Schreiben Sie stattdessen Code, um die Daten in kleineren Teilen abzurufen.
Fehler "Der angegebene Schlüssel war im Wörterbuch nicht vorhanden"
Dataverse verwendet häufig Klassen, die von der abstrakten DataCollection<TKey,TValue>-Klasse abgeleitet wurden, die eine Sammlung von Schlüsseln und Werten darstellt. Bei Plug-Ins ist die IExecutionContext.InputParameters -Eigenschaft z. B. eine ParameterCollection abgeleitete DataCollection<TKey,TValue> Klasse. Diese Klassen sind im Wesentlichen Wörterbuchobjekte, bei denen Sie mithilfe des Schlüsselnamens auf einen bestimmten Wert zugreifen.
Fehlercodes
Dieser Fehler tritt auf, wenn der Schlüsselwert im Code in der Auflistung nicht vorhanden ist. Das Ergebnis ist ein Laufzeitfehler, sondern ein Plattformfehler. Wenn dieser Fehler innerhalb eines Plug-Ins auftritt, hängt der Fehlercode davon ab, ob der Fehler abgefangen wurde.
Wenn der Entwickler die Ausnahme erfasst und zurückgegeben hat InvalidPluginExecutionException, wie in "Ausnahmen behandeln" in Plug-Ins beschrieben, wird der folgende Fehler zurückgegeben:
Fehlercode: -2147220891
Fehlermeldung: DER ISV-Code hat den Vorgang abgebrochen.
Bei diesem Fehler ist es jedoch üblich, dass der Entwickler ihn nicht ordnungsgemäß abfangen und der folgende Fehler zurückgegeben wird:
Fehlercode: -2147220956
Fehlermeldung: Unerwarteter Fehler aus ISV-Code.
Notiz
„ISV” steht für Unabhängige Softwarehersteller (Independent Software Vendor).
Ursache
Dieser Fehler tritt auf häufig zur Entwurfszeit auf und kann aufgrund eines Schreibfehlers oder durch Verwendung der falschen Groß-/Kleinschreibung auftreten. Bei den Schlüsselwerten wird zwischen Groß- und Kleinschreibung unterschieden.
Zur Laufzeit liegt der Fehler häufig daran, dass der Entwickler davon ausgeht, dass der Wert vorhanden ist, wenn er nicht vorhanden ist. Beispielsweise werden in einem Plug-In, das für die Aktualisierung einer Tabelle registriert ist, nur die Werte, die geändert werden, in der EntityAuflistungAttributes enthalten.
Lösung
Um diesen Fehler zu beheben, müssen Sie überprüfen, ob der Schlüssel vorhanden ist, bevor Sie versuchen, ihn für den Zugriff auf einen Wert zu verwenden.
Wenn Sie beispielsweise auf eine Tabellenspalte zugreifen, können Sie mit der EntityMETHODEContains(String) überprüfen, ob eine Spalte in einer Tabelle vorhanden ist, wie im folgenden Code gezeigt.
// 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"];
}
Einige Entwickler verwenden die Entity.GetAttributeValue<T>(String) -Methode, um diesen Fehler beim Zugriff auf eine Tabellenspalte zu vermeiden. Diese Methode gibt den Standardwert des Typs zurück, wenn die Spalte nicht vorhanden ist. Wenn der Standardwert NULL ist, funktioniert diese Methode erwartungsgemäß. Wenn der Standardwert jedoch nicht NULL zurückgibt, z. B. mit einem DateTime
, ist 1/1/0001 00:00
der zurückgegebene Wert nicht null.
Fehler "Sie können eine Transaktion nicht mit einer anderen Isolationsstufe starten, als sie bereits für die aktuelle Transaktion festgelegt ist"
Fehlercode: -2147220989
Fehlermeldung: Sie können eine Transaktion nicht mit einer anderen Isolationsstufe starten, als bereits für die aktuelle Transaktion festgelegt ist.
Plug-ins sind dazu gedacht, Geschäftslogik zu unterstützen. Das Ändern eines Teils des Datenschemas innerhalb eines synchronen Plug-Ins wird nicht unterstützt. Diese Vorgänge dauern häufig länger und können dazu führen, dass zwischengespeicherte Metadaten, die von Anwendungen verwendet werden, nicht mehr synchronisiert werden. Diese Vorgänge können jedoch in einem Plug-In-Schritt ausgeführt werden, der für die asynchrone Ausführung registriert ist.
Bekanntes Problem: Activity.RegardingObjectId-Namenswert nicht mit Plug-In festgelegt
Das häufigste Symptom dieses Problems ist, dass das Feld "In Bezug" in einem Aktivitätsdatensatz anstelle des Werts des primären Namensattributes angezeigt (No Name)
wird.
Innerhalb eines Plug-Ins können Sie Nachschlageattribute mit einem EntityReference-Wert festlegen. Die EntityReference.Name-Eigenschaft ist nicht erforderlich. In der Regel müssen Sie ihn nicht einschließen, wenn Sie einen Nachschlageattributewert festlegen, da Dataverse ihn festlegt. Sie sollten Werte wie diese während der PreOperation-Phase der Ereignispipeline festlegen. Weitere Informationen finden Sie unter Ereignisausführungspipeline.
Die Ausnahme dieser Regel ist das Festlegen des ActivityPointer.RegardingObjectId-Nachschlagevorgangs . Alle Entitätstypen, die von ActivityPointer
dieser Suche abgeleitet werden. Diese umfassen standardmäßig "Appointment", "Chat", "Email", "Fax", "Letter", "PhoneCall", "RecurringAppointmentMaster" und alle benutzerdefinierten Tabellen, die als Aktivitätstypen erstellt wurden. Weitere Informationen finden Sie in den Aktivitätstabellen.
Wenn Sie diesen Wert in der PreOperation-Phase festlegen, wird der Namenswert nicht von Dataverse hinzugefügt. Der Wert ist NULL, und der formatierte Wert, der diesen Wert enthalten soll, ist beim Abrufen des Datensatzes nicht vorhanden.
Problemumgehung
Es gibt zwei Wege, dieses Problem zu umgehen:
- Sie können den wert der EntityReference.Name Eigenschaft mit dem richtigen wert des primären Namensfelds festlegen, bevor Sie den Wert des Nachschlageattributes festlegen.
- Sie können den Nachschlagewert in der PreValidation-Phase und nicht in der PreOperation-Phase festlegen.