Passing derived objects with webservices.

Posts   
 
    
mattc
User
Posts: 10
Joined: 20-May-2008
# Posted on: 01-Jul-2008 22:45:53   

First the info:

  • Version: 2.6 Final (June 6th, 2008 )
  • .NET 2.0+ ORM Support Classes runtime: 2.6.8.624
  • .NET framework 2.0.50727 - vs.net 2005
  • Adapter templates with the schema importer tasks turned on

Ok, so after much careful reading and trial and error I was able to get the WSDL to have my generated types. (please note that one thing i was missing was a forum post which suggested closing visual studio and reopening before trying to add the WebReference... lost a few hours on that one. simple_smile )

I have two webservices that I need to talk to each other; a "web" one and a "backend" one. The backend webservice sends a request to the "web" one, and I'd ideally like to retrieve derived objects back to be able to use all the relations and strong typing.

It's an e-commerce setup, so the top level is an "Orders" Entity (I know, it should be "Order", but I didn't design the db). If i just pass the OrdersEntity back as a return value from the webservice call, everything works fine. The problem is when I try and include related sub-entities with prefetch paths.

Here's my function on the web side which gets the OrdersEntity object along with other related objects:


public static EntityCollection RetrieveOrderEntity(int orderId)
        {

            IRelationPredicateBucket filter = new RelationPredicateBucket();
            filter.PredicateExpression.Add(OrdersFields.OrderId == orderId);

            EntityCollection orders = new EntityCollection(new OrdersEntityFactory());
            IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.OrdersEntity);

            // add order sub-entities
            prefetchPath.Add(OrdersEntity.PrefetchPathCustomers);
            prefetchPath.Add(OrdersEntity.PrefetchPathOrdersStatus);
            prefetchPath.Add(OrdersEntity.PrefetchPathOrderItems);

            DataAccessAdapter adapter = new DataAccessAdapter();
            adapter.FetchEntityCollection(orders, filter, prefetchPath);
            if (orders.Count == 1)
            {
                return orders;
            }
            else
            {
                // something happened and our query was empty.  return a blank orders entity
                // TODO: error log or message here
                EntityCollection ordersEmpty = new EntityCollection(new OrdersEntityFactory());
                return ordersEmpty;
            }

        }

Based on several earlier forum posts (and the section in the helpfile about polymorphic fetches with a single entity) I'm wrapping my response into an EntityCollection instead of a OrdersEntity object.

Abbreviated webservice function below:


public EntityCollection RetrieveOrderEntity(int orderId)
        {

            try
            {
                // make a call to the app layer
                EntityCollection orders = RetrieveOrderEntity(orderId);

                return orders;
            }
            catch (Exception e)
            {
                Response.ErrorMessage = e.Message;
                EntityCollection ordersEmpty = new EntityCollection(new OrdersEntityFactory());
                return ordersEmpty;
            }
        }

The relevant snippet on the recipient web service that is supposed to get the OrdersEntity object from the other webservice looks like this:


EntityCollection orders = webService.RetrieveOrderEntity(Int32.Parse(myRow["Orderid"].ToString()));  
//^--- error thrown on this line.

     if (orders.Count > 0)
     {
          Boolean successfulSync = SyncOrderEntity((OrdersEntity)orders[0], companyGuid);
      }

The error that gets thrown looks like this:


System.InvalidOperationException: There is an error in XML document (1, 1205). ---> System.ArgumentNullException: Value cannot be null.
Parameter name: The element 'Customers' isn't found as a property of entity eDevix.OutfoxDAL.EntityClasses.OrdersEntity
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.Xml2Entity(XmlReader reader, Dictionary`2 processedObjectIDs, List`1 nodeEntityReferences)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.Xml2EntityCollection(XmlReader reader, Dictionary`2 processedObjectIDs, List`1 nodeEntityReferences)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.ReadXml(XmlReader reader, XmlFormatAspect format)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1.System.Xml.Serialization.IXmlSerializable.ReadXml(XmlReader reader)
   at System.Xml.Serialization.XmlSerializationReader.ReadSerializable(IXmlSerializable serializable, Boolean wrappedAny)
   at System.Xml.Serialization.XmlSerializationReader.ReadSerializable(IXmlSerializable serializable)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderService.Read6_RetrieveOrderEntityResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer4.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at eDevix.InterlinxDataWS.OutfoxDataWS.Service.RetrieveOrderEntity(Int32 orderId) in C:\Documents and Settings\mcomroe\My Documents\Visual Studio 2005\Projects\eDevix.InterlinxDataWS\eDevix.InterlinxDataWS\Web References\OutfoxDataWS\Reference.cs:line 143
   at eDevix.InterlinxDataWS.Service.DoSync() in C:\Documents and Settings\mcomroe\My Documents\Visual Studio 2005\Projects\eDevix.InterlinxDataWS\eDevix.InterlinxDataWS\Service.asmx.cs:line 50


I also tried messing around and using my own .writeXml and .readXml on the sending and receiving webservices to see what that would do; got exactly the same error.

I'm sure I'm missing something fundamental. Can this be done without remoting or WCF? Neither are particularly viable. This is just something quick and dirty I'm trying to do with a minimum of impact on the databases and applications that are already out there. I'd like to not to have to resort to using a DataSet and a bunch of stored procs to move data from one webservice to the other.

Any help is greatly appreciated, as always.

matt

Walaa avatar
Walaa
Support Team
Posts: 14994
Joined: 21-Aug-2005
# Posted on: 02-Jul-2008 12:32:42   

Does the returned entity (OrderEntity) exist in an inheritance hierarchy?

mattc
User
Posts: 10
Joined: 20-May-2008
# Posted on: 02-Jul-2008 14:11:22   

Walaa wrote:

Does the returned entity (OrderEntity) exist in an inheritance hierarchy?

Hi Walaa.

Yes, and I believe the Order table is at the top of the hierarchy. It has a "customer_id" column which is a FK to the Customers table.

Reading over the documentation should I be doing this instead of prefetch paths?


OrderEntity order = new OrderEntity(orderId);
adapter.FetchEntity(order);
order.Customer = (CustomerEntity)adapter.FetchNewEntity(new CustomerEntityFactory(), 
    order.GetRelationInfoCustomer());
adapter.CloseConnection();

I think I had tried that yesterday, but I can give it another shot when I get into the office in an hour.

Or, is it that I should change the type of how I use prefetch?


--- just a snip from my first post
// add order sub-entities
            prefetchPath.Add(CustomersEntity.PrefetchPathOrders);

Thanks very much for your help on this. One reason I pushed my company to buy LLBLGen (this is the 2nd company I've done this for) is knowing there was a great support time if/when I ran into issues.

matt

mattc
User
Posts: 10
Joined: 20-May-2008
# Posted on: 02-Jul-2008 15:30:33   

Ok, I think I have it.

Just updating the DBGeneric .dlls on the backend webservice project apparently isn't good enough. I needed to actually drop and re-add the references in the project.

I had added some of the relations into the project after the initial build. There are no PK/FK relations on the "web" database (don't ask... not my choice) so I was manually adding a few relations in with the LLBLGen designer to test out sending the complex objects.

Frustrating when you lose time to things like that, but I'm happy to have it working.

Thanks very much for your help!

matt

Walaa avatar
Walaa
Support Team
Posts: 14994
Joined: 21-Aug-2005
# Posted on: 02-Jul-2008 16:53:00   

Glad you've foung it.