Avatar billede fastpoint Nybegynder
06. december 2006 - 10:24 Der er 7 kommentarer og
1 løsning

Serializere et objekt uden at miste noget af det!

Hejsa,

Min problemstilling kan også ses i forhold til almindelig netværksprogrammering.

I mit tilfælde sendes der et objekt over en MessageQueue.

new Message(dataObject, new BinaryMessageFormatter());

Mit spørgsmål er om det er nok med BinaryMessageFormatter hvis man vil sikre sig, at det man sender med over modtages, som var det den originale kopi?

Med andre ord kunne man sige. "Hvad kan BinaryMessageFormatter" ikke håndtere ?
Avatar billede md_craig Nybegynder
06. december 2006 - 11:19 #1
Hvordan det lige går med referencer når du sender det over MessageQueue er jeg lidt i tvivl om, da jeg ikke lige har arbejdet med det...

Men Din formatter vil kunne klarre alt information der ligger i objectet uden problemer, eller skulle kunne... husk på at alt hvad der ligger i dit object i forvejen er af Binær oprindelse i din ram...

Der hvor det måske kan skabe problemer er med referencer som sagt..
dvs. at hvis du har 2 progammer med Klasserne A og B, App1 og App2

A indeholder 10 objecter af typen B... og B indeholder en række metoder, fields osv... altså som så mange andre objecter...

Hvad der så sker når du nu sender Object A til App2...
Nu henter App2 alle 10 B'er ud af A, og kalder en given metode på dem...
Hvad sker der mon så...

problemet her er nok et af de mere kendte problemer... og det bliver kun væere når man pluselig ønsker at det kald man laver i App2 på B, også går i gennem på objecterne i App1...

Normalt noget som fint kan lade sig gøre, men man skal lige lave de rigtige valg...

I dit tilfælde så Serializere du dit object og sender det... men forsøger den at beholde B som en reference, og kan en sådan reference bevares over en MessageQueue... eller Med Serializere den Objectet B, og sender det sammen med A ( altså B bliver også fuldstendigt kopieret )... så går alle kald på begge dele i App2 ikke igennem over i App1 også...

Det er også her man i andre tilfælde begynder at spekulere i om et Object skal refereres over App Domæner eller Kopieres... DTO'er skal bare råt over, mens det tit er nemmere at refererer objecter man kalder på... (igen så kommer Performance og trafik ind i billedet, det er ikke nødvendigvis sundt at lave mange kald over App domæner... så i nogle tilfælde kan det godt betale sig at Kopiere Objectet, lave de 10 kald man skal... kopiere det tilbage...)
Avatar billede fastpoint Nybegynder
06. december 2006 - 15:21 #2
Jeg stiller egentlig bare en metode til rådighed for en ekstern bruger.
Jeg modtager 3 typer data i min parameter liste. DateTime, string og et eget defineret objekt, som er en mindre klasse med 2 strings og tilhørende get properties.

Da det er messagequeues skal denne data pakkes ind i et objekt, som jeg selv definere, men har lidt problemer ved modtagelsen af objektet når det kommer over kø'en.
Avatar billede segato Nybegynder
06. december 2006 - 18:04 #3
Det er meget standard at man sender et objekt over via MQ. Man skal selvfølgelig bare sørge for det udelukkende er databærende. Og en BinaryMessageFormatter kan klare databærende objekter. Nu ved jeg ikke hvordan du har skaleret din løsning, men det bør være lige til højre foden. Hvor ligger problemet når du deserialisere den? Husk nu at det ikke er selve eventarg du skal konvertre men propertien Value du skal konvertere.
Avatar billede fastpoint Nybegynder
07. december 2006 - 09:38 #4
Jeg prøvede i første omgang at sende et komplet XML dokument over en kø med XMLMessageFormatter() og det virkede godt!

Da jeg efterfølgende ville sende en klasse lignende denne

public class MinFoersteKlasse
{

private string navn;
private DateTime tid;
private MinAndenKlasse klasse;

public MinFoersteKlasse
{}

}

public class MinAndenKlasse
{

private string etellerandet;

public MinAndenKlasse
{}

}


DenFoersteKlasse mister alt når den kommer med over køen.. nu er det et meget forsimplet eksempel men de rigtige klasse har bare flere attributter.
Det skal siges at der er mine rigtige klasse bliver implementeret serializable interfaces.

nogle ideer til hvordan jeg får MinFoersteKlasse hen over kø'en og bevare alt indhold i den?

Har et en ide om man kan bruge XmlSerializer, men man skal vidst også angive nogle speciale tags/attributter i klassen så den bliver serializeret korrekt.
Avatar billede segato Nybegynder
07. december 2006 - 14:10 #5
Det her virker fint hos mig:

      public void Send(T message)
        {
            System.Messaging.Message msg = new System.Messaging.Message();
            msg.Body = message;
            m_queue.Send(msg);
        }


Her er de klasser jeg sender over:

  [Serializable]
    public class ReutersResponse
    {
        int m_instrumentId = 0;
        string m_instrumentName = string.Empty;
        List<ReutersField> m_fields = new List<ReutersField>();

        public int InstrumentId
        {
            get { return m_instrumentId; }
            set { m_instrumentId = value; }
        }

        public string InstrumentName
        {
            get { return m_instrumentName; }
            set { m_instrumentName = value; }
        }

        public List<ReutersField> Fields
        {
            get { return m_fields; }
            set { m_fields = value; }
        }
    }

    [Serializable]
    public class ReutersField
    {
        string m_value = string.Empty;
        string m_name = string.Empty;
   
        public ReutersField()
        {
        }

        public ReutersField(string name, string value)
        {         
            this.m_name = name;
            this.m_value = value;
        }
       
        public string Value
        {
            get { return m_value; }
            set { m_value = value; }
        }

        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }
    }

Og her modtager jeg messages:

  void Queue_ReceiveCompleted(object sender, System.Messaging.ReceiveCompletedEventArgs e)
        {
            System.Messaging.Message requestMessage = m_queue.EndReceive(e.AsyncResult);
            T response;

            try
            {
                response = (T)requestMessage.Body;

                if (responseReceived != null)
                    responseReceived(this, new ResponseReceivedEventArg<T>(response));
            }
            catch(Exception ex)
            {
                if (errorOnReceive != null)
                    errorOnReceive(this, new ResponseReceivedErrorEventArg(ex.Message));

                SendErrorMessage(requestMessage);
            }
            finally
            {
                if (m_continueReceiving)
                    BeginReceive();
            }
        }
Avatar billede segato Nybegynder
07. december 2006 - 14:12 #6
Her har du hele min specialisret MSMQ klasse. Den kan sende alle typer klasser over, og i event får man den type der er sendt over. Det kræver dog du koder imod C# 2.0:

    public class MessageQueue<T>
    {
        System.Messaging.MessageQueue m_queue      = null;
        System.Messaging.MessageQueue m_queueError  = null;

        public event ResponseReceived responseReceived;
        public event ErrorOnReceive errorOnReceive;

        bool m_continueReceiving = false;

        public delegate void ResponseReceived(object sender, ResponseReceivedEventArg<T> e);
        public delegate void ErrorOnReceive(object sender, ResponseReceivedErrorEventArg e);
           
        public MessageQueue(string requestQueue, bool createQueuesIfNotExixst)
        {
            if (!System.Messaging.MessageQueue.Exists(requestQueue) && createQueuesIfNotExixst)
                m_queue = System.Messaging.MessageQueue.Create(requestQueue);           
            else
                m_queue = new System.Messaging.MessageQueue(requestQueue);           
           
            m_queue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(T) });
            m_queue.ReceiveCompleted += new System.Messaging.ReceiveCompletedEventHandler(Queue_ReceiveCompleted);
        }

        public MessageQueue()
        {
            m_queue = new System.Messaging.MessageQueue();
           
            m_queue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(T) });
            m_queue.ReceiveCompleted += new System.Messaging.ReceiveCompletedEventHandler(Queue_ReceiveCompleted);
        }

        public string QueuePath
        {
            get
            {               
                return m_queue.Path;
            }

            set
            {
                m_queue.Path = value;
            }
        }

        void Queue_ReceiveCompleted(object sender, System.Messaging.ReceiveCompletedEventArgs e)
        {
            System.Messaging.Message requestMessage = m_queue.EndReceive(e.AsyncResult);
            T response;

            try
            {
                response = (T)requestMessage.Body;

                if (responseReceived != null)
                    responseReceived(this, new ResponseReceivedEventArg<T>(response));
            }
            catch(Exception ex)
            {
                if (errorOnReceive != null)
                    errorOnReceive(this, new ResponseReceivedErrorEventArg(ex.Message));

                SendErrorMessage(requestMessage);
            }
            finally
            {
                if (m_continueReceiving)
                    BeginReceive();
            }
        }

        public void BeginReceive()
        {
            m_continueReceiving = true;
            m_queue.BeginReceive();
        }

        public void EndReceive()
        {
            m_continueReceiving = false;
        }

        void SendErrorMessage(System.Messaging.Message errorMsg)
        {
            if (m_queueError == null)
            {
                string errorQueue = m_queue.Path + "_error";

                if (!System.Messaging.MessageQueue.Exists(errorQueue))
                    m_queueError = System.Messaging.MessageQueue.Create(errorQueue);
                else
                    m_queueError = new System.Messaging.MessageQueue(errorQueue);
            }
            m_queueError.Send(errorMsg);
        }

        public void Send(T message)
        {
            System.Messaging.Message msg = new System.Messaging.Message();
            msg.Body = message;
            m_queue.Send(msg);
        }

        public void Close()
        {
            m_queue.Close();
        }
    }

    public class ResponseReceivedEventArg<T> : EventArgs
    {
        T m_msg;

        public ResponseReceivedEventArg(T msg)
        {
            m_msg = msg;
        }

        public T MessageBody
        {
            get { return m_msg; }
            set { m_msg = value; }
        }
    }

    public class ResponseReceivedErrorEventArg : EventArgs
    {
        string m_errorMessage = string.Empty;

        public ResponseReceivedErrorEventArg(string errorMsg)
        {
            m_errorMessage = errorMsg;
        }

        public string ErrorMessage
        {
            get { return m_errorMessage; }
        }

    }
Avatar billede fastpoint Nybegynder
07. december 2006 - 16:23 #7
segato og md_craig i må gerne begge ligge et svar.
Jeg gik uden om problemet og oprettede istedet en XML fil med alt den data, som skulle sendes over, men segato din kode vil jeg have i baghånden hvis det senere skulle blive relevant.
Avatar billede segato Nybegynder
07. december 2006 - 18:57 #8
ok held og lykke med det.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester