Benutzer mit den meisten Antworten
CRM-Plugin Deserialize

Frage
-
Hallo liebe Experten,
ich versuche eine (kleine) Klasse zu Deserialisieren, dabei gibt es Fehler:
public class ownerandtype { public Owner owner { get; set; } public string persontype { get; set; } public int persontypeindex { get; set; } public ownerandtype(Owner addOwner, string addPersontype, int addPersontypeindex) { owner = addOwner; persontype = addPersontype; persontypeindex = addPersontypeindex; } } /// <summary> /// Speicher für Felder die geprüft werden müssen /// </summary> public class CheckField { /// <summary> /// Name der Entität /// </summary> [XmlAttribute("entity")] public string Entity { get; set; } /// <summary> /// Name des Feldes das in der Entität geprüft wird (geprüft wird auf "Leer") /// </summary> [XmlAttribute("name")] public string FieldName { get; set; } /// <summary> /// Feld der Quellentität mit den Daten /// </summary> [XmlText()] public string checkField { get; set; } } /// <summary> /// Felder einer Entität für Regeln /// </summary> public class entityAttribute { [XmlAttribute("value")] public string EntityValue { get; set; } [XmlText()] public string FieldName { get; set; } public Boolean isIdentical(DynamicEntity entity) { Boolean result = false; if (entity.Properties.Contains(FieldName)) { switch (entity.Properties.GetType().ToString()) { case "System.String": { result = EntityValue.ToLower() == entity.Properties[FieldName].ToString().ToLower(); break; } case "Microsoft.Crm.Sdk.CrmBoolean": { Boolean secondOperator = false; Regex regx = new Regex("(ja)|(yes)|(oui)"); secondOperator = (regx.IsMatch(EntityValue.ToLower())); result = ((CrmBoolean)entity.Properties[FieldName]).Value == secondOperator; break; } case "Microsoft.Crm.Sdk.CrmNumber": { int secondOperator = 0; int.TryParse(EntityValue, out secondOperator); result = ((CrmNumber)entity.Properties[FieldName]).Value == secondOperator; break; } } } return result; } } /// <summary> /// Regelbedingung /// </summary> public class ruleCondition { [XmlAttribute("operator")] public string Operator { get; set; } [XmlArray("ownervalues")] [XmlArrayItem("value")] public List<int> ownerValues { get; set; } [XmlArray("entityattributes")] [XmlArrayItem("field")] public List<entityAttribute> entityAttributes { get; set; } public Boolean isMatchCondition(List<int> oValues, DynamicEntity entity) { List<Boolean> foundValues = new List<Boolean>(oValues.Count); foreach (int o in oValues) { foundValues.Add(ownerValues.Contains(o)); } Boolean result = false; if (Operator.ToLower() == "and") { foreach (Boolean test in foundValues) { result = test; if (!test) { break; } } if (result) { if (entityAttributes.Count > 0) { foreach (entityAttribute e in entityAttributes) { result = e.isIdentical(entity); if (!result) break; } } } } if (Operator.ToLower() == "or") { foreach (Boolean test in foundValues) { if (!result) { result = test; if (result) break; } } if (entityAttributes.Count > 0) { foreach (entityAttribute e in entityAttributes) { if (!result) { result = e.isIdentical(entity); if (result) break; } } } } return result; } } /// <summary> /// Zusatz-Regeln für die Benutzerzuweisung /// </summary> public class ownerAssignmentRule { [XmlArray("conditions")] [XmlArrayItem("condition")] public List<ruleCondition> conditions { get; set; } [XmlElement("result")] public int result { get; set; } public List<ownerandtype> MatchRuleCondition(DynamicEntity entity, List<ownerandtype> owners) { List<ownerandtype> resultOwnerList = new List<ownerandtype>(); List<int> ownerTypeNo = new List<int>(); foreach (ownerandtype selOwner in owners) { foreach (ruleCondition condition in conditions) { foreach (int i in condition.ownerValues) { if (i == selOwner.persontypeindex) ownerTypeNo.Add(selOwner.persontypeindex); } } } foreach (ruleCondition condition in conditions) { if (condition.isMatchCondition(ownerTypeNo, entity)) { resultOwnerList.Add(owners.Find(delegate(ownerandtype ow) { return ow.persontypeindex == result; })); } else { foreach (int i in ownerTypeNo) { resultOwnerList.Add(owners.Find(delegate(ownerandtype ow) { return ow.persontypeindex == i; })); } } } return resultOwnerList; } } [XmlRoot("Config")] public class ConfigBusiness { public string MandantoryMessage { get; set; } public string CreateActivityEntityName { get; set; } public string InPerson { get; set; } public List<string> ContactQueryRules { get; set; } public List<string> AccountQueryRules { get; set; } public List<string> LeadQueryRules { get; set; } public List<CheckField> CheckFields { get; set; } [XmlArray("ownerassingmentrules")] [XmlArrayItem("ownerassingmentrule")] public List<ownerAssignmentRule> OwnerAssigmentRules { get; set; } } }
Das Xml sieht so aus:
<?xml version="1.0" encoding="utf-8"?> <Config> <MandantoryMessage>not specified</MandantoryMessage> <CreateActivityEntityName>task</CreateActivityEntityName> <InPerson>1</InPerson> <ContactQueryRules> <string>rz_FindContactNameZip</string> </ContactQueryRules> <AccountQueryRules> <string>rz_FindAccountNameZip</string> </AccountQueryRules> <LeadQueryRules> <string>rz_FindLeadNameZip</string> <string>rz_FindLeadCompanynameZip</string> </LeadQueryRules> <CheckFields> <CheckField entity="account" name="address1_postalcode">rz_zip</CheckField> <CheckField entity="account" name="address1_line1">rz_street</CheckField> <CheckField entity="account" name="address1_telephone1">telephone</CheckField> <CheckField entity="account" name="orb_name2">rz_companyname2</CheckField> <CheckField entity="lead" name="mobilephone">rz_mobilephone</CheckField> </CheckFields> <ownerassingmentrules> <ownerassingmentrule> <conditions> <condition operator="AND"> <ownervalues> <value>2</value> <value>3</value> </ownervalues> <entityattributes> <field value="No">rz_categorydistributor</field> </entityattributes> </condition> </conditions> <result>3</result> </ownerassingmentrule> <ownerassingmentrule> <conditions> <condition operator="AND"> <ownervalues> <value>2</value> <value>3</value> </ownervalues> <entityattributes> <field value="Yes">rz_categorydistributor</field> </entityattributes> </condition> </conditions> <result>2</result> </ownerassingmentrule> <ownerassingmentrule> <conditions> <condition operator="AND"> <ownervalues> <value>1</value> <value>3</value> </ownervalues> <entityattributes/> </condition> </conditions> <result>1</result> </ownerassingmentrule> <ownerassingmentrule> <conditions> <condition operator="AND"> <ownervalues> <value>1</value> <value>2</value> </ownervalues> <entityattributes/> </condition> </conditions> <result>1</result> </ownerassingmentrule> </ownerassingmentrules> </Config>
Hier der Code zum deserialisieren (nach 2 Tagen verweifelter suche...)
ConfigBusiness configB = new ConfigBusiness(); //Deserialisieren try { configXml = configXml.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("'","\"").Replace("\\",""); byte[] bytes = Encoding.UTF8.GetBytes(configXml); using (MemoryStream ms = new MemoryStream(bytes)) { XmlSerializer readConfigB = new XmlSerializer(typeof(ConfigBusiness)); configB = (ConfigBusiness)readConfigB.Deserialize(ms); } } catch (Exception ex) { l.writeLog(log.logLevel.ERROR, ex.Message + ex.StackTrace); }
Das Ergebnis: Fehler im Xml-Dokument 0,0; aber erst seit 2 Tagen, davor hat es funktioniert!. Wenn ich das ganze nicht aus einem PlugIn sondern aus eine Kommandozeilen-Exe mache funktioniert das. Der Code zum Deserialisieren ist eigentlich viel kürzer:
XmlSerializer readConfig = new XmlSerializer(typeof(ConfigTech)); configT = (ConfigTech)readConfig.Deserialize(XmlReader.Create(new StringReader(_unsecureInformation)));
Die Klasse dazu:
[XmlRoot("Config")] public class ConfigTech { public string LogSource { get; set; } public int loglevel { get; set; } }
Das geht problemlos.
HILFE!
Danke.
Antworten
-
Hallo Karsten,
Versuche mal statt der generischen Liste ein Array zu verwenden:
public ownerAssignmentRule[] OwnerAssigmentRules { get; set; }
Ich habe mir das Beispiel auf folgender Seite genauer angesehen und hier werden nur Arrays verwendet: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx. Vielleicht versucht die generische Liste in der Datenbank Speicher zu allokieren, dass diese nicht bekommt oder ähnliches...
Liebe Grüße,
Andreas
P.S.: Ich bin der Andreas!
Andreas Buchinger
Microsoft Dynamics Certified Technology Specialist
MCPD: SharePoint Developer 2010 -
Hallo Andreas,
vielen Dank. Wenn ich die Klassen mit Arrays aufbaue kann ich Deserialisieren. Verstehen tue ich die Implementierung nicht (technisch könnte ich mir vorstellen warum das nicht funktioniert), aber dadurch das ich für das Problem eine Lösung habe, ist die Erkenntnis warum das so von Microsoft implementiert wurde, für mich nur akademisch. :-))
Zusammenfassung:
List<generischeKlasse> geht immer,
List<eigeneKlasse> geht NICHT wenn das PlugIn auf in der Datenbank gespeichert wird, in diesem Fall müssen Arrays verwendet werden.Schade.
- Als Antwort markiert KriegerK Mittwoch, 13. Juni 2012 14:06
Alle Antworten
-
Hallo KriegerK!
Gehe mit dem Debugger Zeile für Zeile durch und sieh dir die Werte der Objekte an
und benutze try-catch um dir die Fehlermeldung und den Exception-Type, an der Stelle wo der Fehler passiert, ausgeben zu lassen.Was war vor 2 Tagen anders, als es funktioniert hatte?
Serialisiere eine kürzere xml und erweitere sie, wenn die Serialisierung erfolgreich war, schrittweise.
Ich hoffe das bringt weiter. Andreas(a)Donaubauer.com www.crmfaq.de
-
Hallo,
Hast du schon mal versucht einerseits den CRM-Trace mitlaufen zu lassen, ob der CRM-Server eine bessere Meldung wirft, oder andererseits mit einem Netzwerk-Sniffer (z.B.: Fiddler) zu tracen, was wirklich über die Leitung gesendet wird - vielleicht wird im Zuge der Plugin-Ausführung das gesendete XML in ein weiteres XML gesteckt oder ähnliches...
Liebe Grüße,
Andreas
Andreas Buchinger
Microsoft Dynamics Certified Technology Specialist
MCPD: SharePoint Developer 2010 -
Hallo,
vielen Dank für die Antworten. Herr Buchinger: der Trace bringt natürlich nichts wenn ich mit Try..Catch die Fehler abfange. Im Debugger bekomme ich ja die genaue Fehlermeldung. Herr Donaubauer: Wenn ich in der Klasse ConfigBusiness die List<..class..> auskommentiere dann kann ich deserialisieren.
Also:
//public List<CheckField> CheckFields { get; set; } //[XmlArray("ownerassingmentrules")] //[XmlArrayItem("ownerassingmentrule")] //public List<ownerAssignmentRule> OwnerAssigmentRules { get; set; }
Jedoch: ich habe die Klasse in eine Kommandozeilen-App verwendet, hier kann ich ohne probleme Deserialisieren. Hierbei lade ich die Xml-Daten aus einer Datei. Darauf hin habe ich das selbe im Plugin versucht (aus Datei laden...) es geht nicht!
... Verzweiflung ...
-
Hallo KriegerK!
Wie ist das Plugin registriert?
Wenn es im Sandbox-Modus ist, hat das Plugin keinen Zugriff auf das Dateisystem.
Kannst du die genaue Fehlermeldung posten, die du im Debugger bekommst?Ich hoffe das bringt weiter. Andreas(a)Donaubauer.com www.crmfaq.de
-
Hallo Herr Donaubauer,
das Pluging liest die XmlDaten nicht aus dem Dateisystem sondern aus einer Entität, damit kundige User die Konfiguration im System vornehmen können :-))
Hier die Fehlermeldung:
ex
{"Fehler im XML-Dokument (0,0)."}
[System.InvalidOperationException]: {"Fehler im XML-Dokument (0,0)."}
Data: {System.Collections.ListDictionaryInternal}
HelpLink: null
InnerException: {"Der Typeninitialisierer für \"Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderConfigBusiness\" hat eine Ausnahme verursacht."}
Message: "Fehler im XML-Dokument (0,0)."
Source: "System.Xml"
StackTrace: " bei System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)\r\n bei System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)\r\n bei Crm.Plugins.FairReportPlugin1Main.Execute(IPluginExecutionContext context) in C:\\Users\\vvs09\\Documents\\Visual Studio 2010\\Projects\\FairReport1\\FairReport1\\FairReportPlugin1Main.cs:Zeile 1005."
TargetSite: {System.Object Deserialize(System.Xml.XmlReader, System.String, System.Xml.Serialization.XmlDeserializationEvents)}
ex.InnerException
{"Der Typeninitialisierer für \"Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderConfigBusiness\" hat eine Ausnahme verursacht."}
[System.TypeInitializationException]: {"Der Typeninitialisierer für \"Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderConfigBusiness\" hat eine Ausnahme verursacht."}
Data: {System.Collections.ListDictionaryInternal}
HelpLink: null
InnerException: {"Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."}
Message: "Der Typeninitialisierer für \"Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderConfigBusiness\" hat eine Ausnahme verursacht."
Source: "ajprn2ob"
StackTrace: " bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderConfigBusiness..ctor()\r\n bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract.get_Reader()\r\n bei System.Xml.Serialization.TempAssembly.InvokeReader(XmlMapping mapping, XmlReader xmlReader, XmlDeserializationEvents events, String encodingStyle)\r\n bei System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)"
TargetSite: {Void .ctor()}
ex.StackTrace
" bei System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)\r\n bei System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)\r\n bei Crm.Plugins.FairReportPlugin1Main.Execute(IPluginExecutionContext context) in C:\\Users\\vvs09\\Documents\\Visual Studio 2010\\Projects\\FairReport1\\FairReport1\\FairReportPlugin1Main.cs:Zeile 1005."
ex.Data
{System.Collections.ListDictionaryInternal}
[System.Collections.ListDictionaryInternal]: {System.Collections.ListDictionaryInternal}
IsFixedSize: false
IsReadOnly: false
Keys: {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}
Values: {System.Collections.ListDictionaryInternal.NodeKeyValueCollection}Zeile 1005 (wie erwartet):
byte[] bytes = Encoding.UTF8.GetBytes(configXml); using (MemoryStream ms = new MemoryStream(bytes)) { XmlSerializer readConfigB = new XmlSerializer(typeof(crmLib.ConfigBusiness)); //1005: configB = (crmLib.ConfigBusiness)readConfigB.Deserialize(ms); }
Was mich wie gesagt wundert: Das selbe als Kommandozeilen-App funktioniert! Die Parameter werden aus einer Datei oder aus einem (System.String) korrekt, in der Kommandozeilen-App, aus dem Xml Deserialisiert.
Danke!
- Bearbeitet KriegerK Freitag, 11. Mai 2012 08:51
-
Hallo KriegerK!
Der Fehler tritt innerhalb von using (MemoryStream ms = new MemoryStream(bytes)) {...} auf.
Welche Werte haben die Objekte ms und readConfigB?
Welchen Wert hat "typeof(crmLib.ConfigBusiness)"?
Das kannst du dir mit dem Debugger anzeigen lassen.In der Zeile "configB = (crmLib.ConfigBusiness)readConfigB.Deserialize(ms);" machst du eine Typeumwandlung.
Lässt sich der Rückgabewert von "readConfigB.Deserialize(ms)" in ein crmLib.ConfigBusiness-Objekt umwandeln?
Ich hoffe das bringt weiter. Andreas(a)Donaubauer.com www.crmfaq.de
-
Hi,
Evtl. bringt folgender Link die Lösung: http://social.msdn.microsoft.com/Forums/en-US/xmlandnetfx/thread/723caa58-a7be-4dc7-982a-1cfe9087f50d
Der Code entspricht zwar nicht ganz deinem Beispiel, aber vielleicht hilft das Setzen der Position auch in deinem Fall...
Vielleicht eine blöde Frage, aber bist du dir sicher, dass in dem geladenen XML, dass vom CRM kommt, am Anfang keine versteckten Sonderzeichen enthalten sind und der Aufbau "so ist wie er sein soll"?!
Liebe Grüße,
Andreas
Andreas Buchinger
Microsoft Dynamics Certified Technology Specialist
MCPD: SharePoint Developer 2010 -
Hallo Herr Buchinger,
vielen Dank für Ihre Antwort, das XML welches aus der Entität geladen wird ist in Ordnung, die ganze Angelegenheit hat eine andere Ursache siehe unten.
Hallo Herr Donaubauer,
vielen Dank für das Du, ich bin der Karsten. Die selbe Deserialisierungsfunktion mit der selben Klasse funktioniert ja als Kommandozeilenprogramm. Also sollte Syntaktisch und ansatzweise Logisch :-)) alles richtig sein. Das Deserialisieren funktioniert immer dann richtig wenn ich generische Klassen verwende (String, List<string>, int usw.). Wenn ich eigene "Unter"-Klassen verwende, kommt es zu der Fehlermeldung.
ABER:
Nur wenn ich für das Plugin den Speicherort "Datenbank" auswähle! Nachdem ich alle Schritte im Quellcode rückwärts gegangen bin, kam ich zu dem Schritt "PlugIn-Speicherplatz in die Datenbank verlegen" (deshalb, siehe oben, vor 2 Tagen "ging es noch..."). Für die Entwicklung lege ich den PlugIn-Speicherplatz noch nicht in die Datenbank, erst wenn ich beginne die ersten Tests zu machen.
Jetzt habe ich als Speicherplatz wieder "Disk" verwendet: Ich kann wieder alle Klassen Deserialisieren ohne irgendwelche Probleme. Ein Sandbox-Problem sollte eigentlich ausscheiden, ich greife nicht auf das Dateisystem zu. Was mich wundert ist jedoch, das sich "On Database" nur generische Klassen Deserialisieren lassen. Darin kann ich keinen Sinn sondern eher einen Fehler erkennen.
Hat jemand dieses Problem schon einmal gehabt? Gibt es hierfür eine Lösung (ausser "On Disk")?
Danke!
-
Hallo Karsten,
Versuche mal statt der generischen Liste ein Array zu verwenden:
public ownerAssignmentRule[] OwnerAssigmentRules { get; set; }
Ich habe mir das Beispiel auf folgender Seite genauer angesehen und hier werden nur Arrays verwendet: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx. Vielleicht versucht die generische Liste in der Datenbank Speicher zu allokieren, dass diese nicht bekommt oder ähnliches...
Liebe Grüße,
Andreas
P.S.: Ich bin der Andreas!
Andreas Buchinger
Microsoft Dynamics Certified Technology Specialist
MCPD: SharePoint Developer 2010 -
Hallo Andreas,
vielen Dank. Wenn ich die Klassen mit Arrays aufbaue kann ich Deserialisieren. Verstehen tue ich die Implementierung nicht (technisch könnte ich mir vorstellen warum das nicht funktioniert), aber dadurch das ich für das Problem eine Lösung habe, ist die Erkenntnis warum das so von Microsoft implementiert wurde, für mich nur akademisch. :-))
Zusammenfassung:
List<generischeKlasse> geht immer,
List<eigeneKlasse> geht NICHT wenn das PlugIn auf in der Datenbank gespeichert wird, in diesem Fall müssen Arrays verwendet werden.Schade.
- Als Antwort markiert KriegerK Mittwoch, 13. Juni 2012 14:06