XML serialisation problem

Last post 05-27-2005 11:59 AM by mikecole. 14 replies.

Sort Posts:

  • XML serialisation problem

    05-25-2005, 7:23 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    Hi,

    I'm developing a webservice that will accept an Order and forward it to a backend system, but I'm having a problem with transferring my "Order" class over a webservice.

    When I try and call the webservice and pass it an Order, I get the following error message:

    The type Wright.BusinessLogicLayer.OrderLine was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

    Source Error:

    Line 55:         public string EchoOrder(Order order) {
    Line 56:             object[] results = this.Invoke("EchoOrder", new object[] {
    Line 57:                         order});
    Line 58:             return ((string)(results[0]));


    My Order class contains a single property, which is just an ArrayList of  OrderLines.

    I've tried adding the SoapAttribute but it seems to have no effect:

    [WebMethod]
    [SoapInclude(typeof(OrderLine))]
    public string EchoOrder(Order order) {
       return order.ToString();
    }


    Any ideas what am I doing wrong?

    Thanks!

    Nick...


  • Re: XML serialisation problem

    05-25-2005, 9:06 AM
    • Participant
      1,026 point Participant
    • blahhumbug
    • Member since 04-13-2003, 10:32 PM
    • Ruffiac, France
    • Posts 223
    Is your Order class marked Serializable?
  • Re: XML serialisation problem

    05-25-2005, 9:28 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    My order class is just this:

    using System;
    using System.Collections;
    using System.Text;

    namespace Wright.BusinessLogicLayer {
        public class Order {
            private ArrayList orderItems;

            public Order() {
               
            }

            public ArrayList OrderItems {
                get { return orderItems; }
                set { orderItems = value; }
            }
        }
    }

    But if I mark it as Serializable it doesn't seem to make any difference.


  • Re: XML serialisation problem

    05-25-2005, 10:31 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    The odd thing is, if I change my class so that it has a single OrderLine object instead of an arraylist of them:

            public OrderLine Item {
                get { return item; }
                set { item = value; }
            }


    as opposed to:

            public ArrayList OrderItems {
                get { return orderItems; }
                set { orderItems = value; }
            }


    Then it works fine. So it's obviously having trouble serializing the ArrayList of OrderItems.

    I don't know how to fix this and I can't proceed with my project until I've got this working! Needless to say - I'm getting very stressed and worried!

    Nick...

  • Re: XML serialisation problem

    05-25-2005, 10:52 AM
    • Participant
      1,026 point Participant
    • blahhumbug
    • Member since 04-13-2003, 10:32 PM
    • Ruffiac, France
    • Posts 223
    I seem to recall a similiar issue I had like this, and I believe that I resolved it by creating a custom collection class which inherited from CollectionBase instead of using the ArrayList. Here's my implementation below.

    The odd thing was that the web service implemented the CollectionBase class as an Array of RegistrationFields

    [Serializable]
        public class EventRegistration
        {
            public EventRegistration()
            {
                _eventData = new EventData();
                _eventFields = new FieldsCollection();
            }

            private EventData _eventData;
            private FieldsCollection _eventFields;
            private string _formName;

            public EventData EventInfo
            {
                get{return _eventData;}
                set{_eventData = value;}
            }

            public FieldsCollection EventFields
            {
                get{return _eventFields;}
                set{_eventFields = value;}
            }

            public string FormName
            {
                get{return _formName;}
                set{_formName = value;}
            }
    }

    [Serializable]
        public class FieldsCollection : CollectionBase
        {
            public FieldsCollection()
            {
              
            }

            public int Add(RegistrationField field)
            {
                return List.Add(field);
            }

            public void Remove(RegistrationField field)
            {
                List.Remove(field);
            }

            public RegistrationField this[int index]
            {
                get
                {
                    return ((RegistrationField)List[index]);
                }
                set
                {
                    List[index] = value;
                }
            }
        }

    Web Service Proxy code for using the above classes:

    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.tq3navigant.com/WebServices/EventsWS")]
        public class EventRegistration {
           
            /// <remarks/>
            public EventData EventInfo;
           
            /// <remarks/>
            public RegistrationField[] EventFields;  // NOTE: EventFields is now an Array of RegistrationFields, not a FieldsCollection object.
           
            /// <remarks/>
            public string FormName;
        }
     
       
        /// <remarks/>
        [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.tq3navigant.com/WebServices/EventsWS")]
        public class RegistrationField {
           
            /// <remarks/>
            public string FieldName;
           
            /// <remarks/>
            public string FieldValue;
           
            /// <remarks/>
            public int Sequence;
           
            /// <remarks/>
            public char EncryptFlag;
        }

    Anyway, Good luck,
    Sam

  • Re: XML serialisation problem

    05-25-2005, 10:55 AM
    • Contributor
      4,280 point Contributor
    • tomasr
    • Member since 04-28-2003, 11:18 AM
    • Colombia
    • Posts 852
    Try this, instead:

    using System.Xml.Serialization;
    ...

    [ XmlArray(), XmlArrayItem(typeof(OrderItem)) ]
    public ArrayList OrderItems {
       get { return orderItems; }
       set { orderItems = value; }
    }


    Tomas Restrepo [MVP]
    tomasr@mvps.org
  • Re: XML serialisation problem

    05-25-2005, 11:09 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35

    I fixed it by just changing SoapInclude to XmlInclude and it started working! Not quite sure why SoapInclude doesn't work.

    [WebMethod]
    [XmlInclude(typeof(OrderLine))]
    public string EchoOrder(Order order) {
       return "WebService: " + order.ToString();
    }


    Now that I've put XmlInclude in instead, it seems to have added an extra line in Reference.cs which I didn't have before:

    [System.Xml.Serialization.XmlIncludeAttribute(typeof(OrderLine))]

    The odd thing is, I tried inserting that line manually myself but it didn't fix it completely (I got a different error about a type conversion problem), so it must have changed something else as well.

    Thanks for your replies,

    Nick...

  • Re: XML serialisation problem

    05-25-2005, 2:30 PM
    • Contributor
      4,280 point Contributor
    • tomasr
    • Member since 04-28-2003, 11:18 AM
    • Colombia
    • Posts 852
    Nick,

    SoapInclude doesn't work because that attribute is used when using RPC/Encoded services (the default for ASP.NET is to use document/literal encoding).

    Also, regarding modifying reference.cs, was that from a client proxy? if so, then regenerating the proxy once you changed the service should've been enough....


    Tomas Restrepo [MVP]
    tomasr@mvps.org
  • Re: XML serialisation problem

    05-25-2005, 3:12 PM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    Thanks for that...

    What do you mean by "regenerating the client proxy"?  Reference.cs was from the web reference in my client application.  After I edited it, I recompiled... Shouldn't that have been enough?

    Thanks,

    Nick...

  • Re: XML serialisation problem

    05-25-2005, 11:39 PM
    • Contributor
      4,280 point Contributor
    • tomasr
    • Member since 04-28-2003, 11:18 AM
    • Colombia
    • Posts 852
    There's no need for you to go around modifying reference.cs directly.... you can just click on the web reference and select "refresh" (or is it update? can't remember right now) from the drop down menu, and VS will go and fetch the updated WSDL and regenerate the code for you.
    Tomas Restrepo [MVP]
    tomasr@mvps.org
  • Re: XML serialisation problem

    05-26-2005, 4:50 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    > There's no need for you to go around modifying reference.cs directly....

    Of course there is. The automatically generated reference.cs is just a basic example which usually contains many problems.
     
    For example, it creates server side skeleton classes which contain the properties of your own business classes but do not contain any of the methods. Therefore it's useless to most people. Every time I regenerate the reference.cs file, I have to go in and delete all these classes and instead include the namespace of where my real classes reside so I have the full functionality of the class at the server end as well as the client end.

    It's good enough for writing "hello world" but not much else...

    Nick...
  • Re: XML serialisation problem

    05-26-2005, 11:17 AM
    • Member
      566 point Member
    • mikecole
    • Member since 12-08-2003, 12:26 PM
    • Atlanta, Georgia, USA
    • Posts 113

    <cite>
    The automatically generated reference.cs is just a basic example which usually contains many problems. For example, it creates server side skeleton classes which contain the properties of your own business classes but do not contain any of the methods. Therefore it's useless to most people.
    </cite>

    Respectfully, you are missing the boat a little here. There is a really, really good reason why there are no methods generated in your proxy classes. The idea behind web services is to move documents around - not to move objects.

    By sharing type (classes) between your server and clients, you are creating a fragile architecture. The code on your server cannot vary independently from your clients.  Do you really want to distribute a new assembly to all your clients whenever you need to make a change? How about your java-clients? What are they going to do with your .net assembly?

    Certainly, your approach may work fine in your scenario. That is, sharing type in a dcom/.net remoting style. However, it is not in the spirit of webservices and SOA.   Consider leaving your reference.cs alone.... think of these classes as transfer objects -- use them to load your business objects, only. These transfer objects describe a contract you have with the webservice - that is their only responsibility. They provide you convenient mechanism to parse the xml coming back from the webservice. Don't confuse them with your actual business objects.

    Mike
     

  • Re: XML serialisation problem

    05-26-2005, 12:20 PM
    • Contributor
      4,280 point Contributor
    • tomasr
    • Member since 04-28-2003, 11:18 AM
    • Colombia
    • Posts 852
    Nickg,

    I agree with the other poster here: WS are not about remoting or distributed object-oriented systems. With WS, what you're moving around are XML documents, not objects. The fact that the platform allows you to see the messages as if they were strongly typed classes instead of the raw XML is just a convinience of the object model, but not the end itself of the technology.

    Tomas Restrepo [MVP]
    tomasr@mvps.org
  • Re: XML serialisation problem

    05-27-2005, 9:54 AM
    • Member
      150 point Member
    • nickg
    • Member since 06-17-2002, 7:23 PM
    • Posts 35
    Perhaps you're correct and I'm approaching this wrong way, but I a problem and others told me that editing Reference.cs to point to my 'real' classes was the only way to solve the problem.  If instead I elect to use the generated classes, how do I pass my "Order" to the webservice and make sense of it at the other end? Perhaps you are able to give me some advice on the 'proper' way to solve my problem: 

    I always get the following error:


    Wright.BusinessLogicLayer.WrightWebService.OrderWebService webService = new Wright.BusinessLogicLayer.WrightWebService.OrderWebService();
    MessageLabel.Text = webService.EchoOrder(order); // EchoOrder takes a Wright.BusinessLogicLayer.Order

    c:\inetpub\wwwroot\wright\cdwebsite\checkout.aspx.cs(103,24): error CS1502: The best overloaded method match for 'Wright.BusinessLogicLayer.WrightWebService.OrderWebService.EchoOrder(Wright.BusinessLogicLayer.WrightWebService.Order)' has some invalid arguments
    c:\inetpub\wwwroot\wright\cdwebsite\checkout.aspx.cs(103,45): error CS1503: Argument '1': cannot convert from 'Wright.BusinessLogicLayer.Order' to 'Wright.BusinessLogicLayer.WrightWebService.Order'

    It doesn't seem to like converting my local "Order" class to the remote "Order" class.  Or should I manually copy all the properties from my BusinessLogicLayer.Order class to the WrightWebService.Order class before passing it to the webservice?

    I think I'm a bit lost... All I really need is my Order data in a sensible structure at the remote end! :)

    Thanks,

    Nick...

  • Re: XML serialisation problem

    05-27-2005, 11:59 AM
    • Member
      566 point Member
    • mikecole
    • Member since 12-08-2003, 12:26 PM
    • Atlanta, Georgia, USA
    • Posts 113
    <cite>
    Or should I manually copy all the properties from my BusinessLogicLayer.Order class to the WrightWebService.Order class before passing it to the webservice?
    </cite>
    Yes! Thats exactly it - you answered your question.  At first look it seems like this is a bunch of overhead, right? Think of it this way, though... as you are copying the properties, what you are really doing is building an outbound document. 

    <cite>
    All I really need is my Order data in a sensible structure at the remote end!
    </cite>
    Yep. And thats what you will have. WrightWebService.Order represents the sensible structure. Its the contract the webservice supports. Your actual order business objects on the client and on the server can vary independently.  You just need methods on the client and server to map to & from the contract.

    For some additional background, check out this post by Kirk Evans: http://forums.asp.net/879657/ShowPost.aspx  He explains here the advantages of defining our contracts first, rather than striving to remote our objects over web-services.

    HTH,
    Mike
     
Page 1 of 1 (15 items)