PDA

View Full Version : Retriving complex objects from a c# web service


maglez
06-10-2005, 02:00 PM
Hi guys.

I have posted a few questions on the ActionScript forum without an answer so I guess I was posting in the wrong forum. I hope someone could put me on the right direction.

This is a very long post with all my findings, I have tried to solve the problem myself without success, that's why this post is so long, I don't like to post just saying 'PLEASE HELP' and leaving you guys the hard work so, PLEASE HELP :-)

What I'm trying to do.
I need to get data from a MS SQL database through a webservice written in c#. This webservice return a collection of objects of a custom type, Product, below you can see the c# structure for this object.
public abstract class Product
{
public string Title;
}

public class SoftwareProduct : Product
{
public string PublisherName;
}

public class SuppliedSoftwareProduct : SoftwareProduct
{
public bool IsDistributed;
}

public class ManufacturedSoftwareProduct : SoftwareProduct
{
public int NoOfCDs;
}
I've also created the same object structure in Flash as follow, each class in an independent external file in the same folder than the main movie...
class Product
{
public var Title:String;
}

class SoftwareProduct extends Product
{
public var PublisherName:String;
}

class SuppliedSoftwareProduct extends SoftwareProduct
{
public var IsDistributed:Boolean;
}

class ManufacturedSoftwareProduct extends SoftwareProduct
{
public var NoOfCDs:Number;
}
...and I have written my code to consume this webservice as follow...
import mx.services.*

//Connecting to the web service
myWebService = new WebService("http://webservicepath/Service1.asmx?wsdl");

//Executing a method of this previous web service
getComplexData = myWebService.GetComplexData();

//Receiving the web service response
getComplexData.onResult = function(theResult:Product){
//check what instance of the response is
trace(theResult[0].Title); //it successfully traces the title from the first object
trace(theResult[1].Title); //it successfully traces the title from the second object
}
...so initially it seems to work, it seems that I got a collection of objects from the server, but then I found something wrong. We set the webservice to return a collection of two objects, the first of type 'SuppliedSoftwareProduct' and the second of type 'ManufacturedSoftwareProduct' so I should be able to do something like...
//Receiving the web service response
getData.onResult = function(theResult){
//check what instance of the response is
trace(theResult[0] instanceof SuppliedSoftwareProduct); //it fails since it traces false
trace(theResult[1] instanceof ManufacturedSoftwareProduct); //it fails since it traces false
}
This shows up that when the data is taken from the webservice and decoded to ActionScript, it ignores the data type.
So I wanted to see how the XML data looks like, then I turned off the ActionScript decoding by doing...
//Turning off ActionScript decoding once a webservice method is called
getComplexData = myWebService.GetComplexData();
getComplexData.doDecoding = false;
//and then I trace out the request and response xml data...
trace("Request" + "\n" + GetProducts_WSCBO.request);
trace("Response" + "\n" + GetProducts_WSCBO.response);
...the request is...
--It comes in one line but I've formatted for easy reading
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<GetProducts xmlns="undefined" />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
...and the response...
--It comes in one line but I've formatted for easy reading
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetProductsResponse xmlns="http://tempuri.org/">
<GetProductsResult>
<Product xsi:type="ManufacturedSoftwareProduct">
<Title>My product title 01</Title>
<PublisherName>My publisher 01</PublisherName>
<NoOfCDs>2</NoOfCDs>
</Product>
<Product xsi:type="SuppliedSoftwareProduct">
<Title>My product title 02</Title>
<PublisherName>My publisher 02</PublisherName>
<IsDistributed>true</IsDistributed>
</Product>
</GetProductsResult>
</GetProductsResponse>
</soap:Body>
</soap:Envelope>
...as you see, the information related to the object type is already there, but ActionScript fails to convert the received XML to an object of type Product with the proper inheritance.

I know some workaround to get it works, but I will really appreciate if any of you could tell me if there is a way to make ActionScript to make the proper conversion.

I was thinking of manipulating the XML Schema but I'm not sure if that will work. In an example I saw at http://www.flash-db.com/services/tutorials/mxclasses/mxwebservices.php?page=4, I found a method to get all the SOAPObject properties and I see that there is a PendingCall.myCall property called 'encodingStyle' which in my case returns 'undefined'. I tried to change that without success. Anyway, I don't know if that could help.

Alright, all this is what I found so far, I know I've been very long to explain all this, but it is the result of many hours trying different ways. I hope some of you had the time to read through this long post and more hope in any of you with some answer.

Thanks a lot for any help.

maglez
06-10-2005, 02:58 PM
Hello again.

I successfully changed the 'encodingStyle' SOAPObject property but that changes nothing.

I did it through...
getComplexData.myCall.encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/";

Any other idea?

tg
06-10-2005, 04:45 PM
try this in your results function

getData.onResult = function(o){/// i changed theResult to o cause i'm lazy.
for(var a in o){
trace(a);
for(var b in o[a]){
trace(b+":"+o[a][b]);
// nest another in here if you need to (or 2)
}
}
};


when flash gets complex types from web services it usually handles them ok. with coldfusion it converts structs to associative arrays, and query results to recordsets... the trace loops should trace out the general sturcture of the returned object.

since your returning two objects, they content you want may just be nested alittle further into the associative array... but then again, it may be different with c#... i'm still kinda new with the webservices/flash remoting thing myself... but i like it.

maglez
06-13-2005, 10:53 AM
After a few days working on this matter I have found that ActionScript doesn't work well with webservices.

When sending an ActionScript complex object to a webservice, only properties of the super class are sent over. Consider the next example...


class MySuperClass
{
var theName:String;
var quantity:Number;
}
class SubClass extends MySuperClass
{
var theSize:Number;
}


...know we create an instance of SubClass and set properties...

myNewObject:SubClass = new SubClass();

myNewObject.theName = "Some name";
myNewObject.quantity = 3;
myNewObject.theSize = 10;


...now we send that myNewObject to a webservice, something like...

sendData = myWebServiceInstance.SendDataMethod(myNewObject);


...but, let check out what actually ActionScript is sending out through...

trace("Request" + "\n" + sendData.request);

...and you'll find out that it's only sending properties 'theName' and 'quantity', it ignores 'theSize', that's it, it only sends out the super class properties. What a surprise!.

I don't know, it may be a limitation of the ECMA-262 standard in what ActionScript 2.0 is based on, whatsoever the reason, I think Macromedia should do something on this matter.

I give it up.

Thanks for reading or any comment.