Laden...

NHibernate Bag / ISet via WCF übermitteln

Erstellt von fr3sh vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.697 Views
F
fr3sh Themenstarter:in
51 Beiträge seit 2007
vor 10 Jahren
NHibernate Bag / ISet via WCF übermitteln

Hallo,

Ich habe ein relativ simples NHibernate Projekt in dem es die Klasse Kunde (Id, Vorname, Nachname, Bestellungen) und die Klasse Bestellung (Id, BestNr, Kunde) gibt.
Nun sind in der Kunde-Mappings Datei die Bestellungen des Kunden als Set hinterlegt. In der Klasse Kunde demnach als Iesi.Collections.Generic.ISet.
Wenn ich nun aber in der Konstellation eine IList<Kunde> via WCF vom Service zum Client schicken möchte, dann erscheint die Meldung:

Fehlermeldung:
Die Socketverbindung wurde abgebrochen. Dies kann durch einen Fehler beim Verarbeiten der Nachricht, durch ein Überschreiten des Empfangstimeouts durch den Remotehost oder durch eine Problem bei der zugrundeliegenden Netzwerkressource verursacht sein. Lokaler Sockettimeout: "00:00:59.9399988".

Sobald ich die Bestellungen aus der Klasse Kunde entferne, klappt der Datenaustausch. Mir kommt es so vor, als könnte WCF ISet nicht serialisieren. Als Binding wird NetTcpBinding verwendet.
Hätte vielleicht jemand einen Tipp für mich?

Vielen vielen Dank.

R
212 Beiträge seit 2012
vor 10 Jahren

Anscheinend brauchst du zu lange zum senden, geh mal in die config(is ne xaml datei/ weiß grad nich wie die heißt) und änder das timeout von (00:00:60:0000000) auf (00:02:00:0000000) dann hast du 2 minuten zeit zum senden, dies musst du aber beim Sender und Empfänger gleich einstellen.

Wenn du glaubst das ISet nicht serialisierbar ist, versuch es mal eine einzigen datensatz dsavon übertragen und schau ob es funktioniert.

Wenn noch fragen bestehn, wieviele datensätze möchtest du übermitteln?
Wenn es zuviele sind wäre es hilfreich dem Client vorerst nur die Daten zu senden die er benötigt, und den rest im Hintergrund herrunterzuladen.

F
fr3sh Themenstarter:in
51 Beiträge seit 2007
vor 10 Jahren

Hallo Robin0,

vielen Dank für Deine Hilfe. Das Hochsetzen des Timeouts resultiert in der gleichen Fehlermeldung, nur dass das Sockettimeout nun höher ist.

Wenn ich ein Objekt der Klasse Kunde (Id, Vorname, Nachname, Bestellung) derart übertrage, dass es sich bei Bestellung um EIN Bestellung Objekt handelt (statt mehrerer Bestellungen in einem ISet), dann klappt alles. Die Datenmenge kann es nicht sein, das ist eine Testdatenbank mit insgesamt 3 Kunden und 3 Bestellungen.

Hier vielleicht der wichtige Teil der Kunden Klasse:


    [DataContract]    
    [KnownType(typeof(Bestellung))]
    public class Kunde
    {
        [DataMember]
        private string _vorname;
        [DataMember]
        private string _nachname;
        [DataMember]
        private int _Id;
        [DataMember]
        private Bestellung _bestellung;   //Das hier klappt
        [DataMember]
        private Iesi.Collections.Generic.ISet<Bestellung> _bestellungen;   //Das hier nicht
        ...
    }

R
212 Beiträge seit 2012
vor 10 Jahren

Wenn ich das richtig sehe erbt "Order" von "Kunde".

Wenn du bei einem WCF service mit Interfaces arbeitest, ist der Typ, die Klasse bekannt und du kannst:


[KnownType(typeof(Order))]

Weglassen.

F
fr3sh Themenstarter:in
51 Beiträge seit 2007
vor 10 Jahren

Ups, das sollte natürlich wie folgt lauten:


[KnownType(typeof(Bestellung))]

Hab das in meinem Post korrigiert.
Bestellung erbt nicht wirklich von Kunde.
Vielmehr existiert 1:n Beziehung zwischen Kunde und Bestellung.
Demnach hat ein Kunde eine oder mehrere Bestellungen.
Das löst mir das Problem leider noch immer nicht.
Ich schau mal - vielleicht muss ich einen anderen Serializer hernehmen.
Ich bin echt grad am Zweifeln ob das Entity Framework diesbezüglich vielleicht kompatibler wäre als NHibernate...

R
212 Beiträge seit 2012
vor 10 Jahren

Ok, Wenn du nicht weißt ob du das Serialisieren kannst setz mal das attribiut


[serializable]

Über deine klasse und Speicher diese in ein Textdokument.

mit

Wenn das funktioniert, köntest du Deine klasse Serialisieren und Sie dann rüber schicken und dann wider Deserialisieren, das ist zwar aufwendig, gibt dir aber die möglichkeit Typen die vom WCF Service nicht automatisch serialisiert werden können auf die generelle Serialisierbarkeit zu testen.

Hier ein Beispiel wo eine Klasse Serialisiert in ein Textdocument geschrieben wird und wider Deserialisiert wird.

Wenn das funktioniert kannst du deine daten serialisieren, sie über trage....
indem du aus dem in ein Textdoc schreiben ein Senden per WCF machst

Achtung ungetestet!!


        /// <summary>
        /// Serielles schreiben der klasse in ein textdokument
        /// </summary>
 public string Serialize(string ConfigElement, params Element[] Elements)
        {
            FileStream fs = new FileStream(ConfigElement+".Con", FileMode.Truncate);

            BinaryFormatter formatter = new BinaryFormatter();
            try
            {
                formatter.Serialize(fs, /*Deine klasse*/);
            }
            catch (SerializationException e)
            {
                Debug.Print("Failed to serialize. Reason: " + e.Message);
                throw;
            }
            finally
            {
                fs.Close();
            }

            return String.Empty;
        }

        /// <summary>
        /// Serielles auslesen der klasse aus einem textdokument
        /// </summary>
        public Element[] Deserialize(string ConfigElement)
        {
             /*Deine klasse*/[] Elements = null;

            FileStream fs = new FileStream(ConfigElement + ".Con", FileMode.Open);
            try
            {
                BinaryFormatter formatter = new BinaryFormatter();

                 /*Deine klasse*/= ( /*Deine klasse*/[])formatter.Deserialize(fs);
            }
            catch (SerializationException e)
            {
                Debug.Print("Failed to deserialize. Reason: " + e.Message);
                throw;
            }
            finally
            {
                fs.Close();
            }
            return Elements;
        }
    }

[EDIT]Du solltest im Catch Block in der Finalen version das throw; rausnehmen sonst wirdt du trotz try catch aus deinem programm geworfen in beispiel dient das throw nur der fehleranalyse ohne einen Haltepunkt in den Catch block setzten zu müssen[/EDIT]

[EDIT]Wichtig, Du musst deine Klassen auch untergeordnete als Serialisierbar kennzeichnen sonst gibt es eine Fehlermeldung[/EDIT]

F
fr3sh Themenstarter:in
51 Beiträge seit 2007
vor 10 Jahren

Hallo,

ich habe das Problem also inzwischen lösen können. Vielen Dank Robin0 für Deine Unterstützung. Das Problem bestand zunächst darin, dass die Fehlermeldung zu unspezifisch war. Kaum hatte ich in der App.Config des Services das Logging aktiviert:


<system.diagnostics>
      <sources>
            <source name="System.ServiceModel" 
                    switchValue="Information, ActivityTracing"
                    propagateActivity="true">
            <listeners>
               <add name="traceListener" 
                   type="System.Diagnostics.XmlWriterTraceListener" 
                   initializeData= "c:\log\Traces.svclog" />
            </listeners>
         </source>
      </sources>
   </system.diagnostics>

wurde mir konkreter angezeigt worin das Problem besteht.
Zum Schluss half die Verwendung von NetDataContractSerializer WCF — Using the NetDataContractSerializer to share your type

Vielen Dank nochmal!