Avatar billede hotmoller Nybegynder
17. juli 2008 - 16:26 Der er 9 kommentarer

Webservice newbie spørgsmål

Hej eksperter

Jeg er begyndt at rode med webservices, og er nu nået til et punkt, hvor jeg har brug for jeres hjælp.

Udfordringen består i, at jeg gerne vil udstille et hieraki af klasser.

Nedenfor kan i se min kode. Koden optræder i et asp.net webservice projekt, hvilket bevirker at wsdl-filen genereres for mig.

// Klassen Supertype (fantastisk navngivning)
//-------------------

namespace WebService1
{
   
    public class SuperType
    {
        public String typeName;

        public virtual void TypeNameToFile()
        {
            // create a writer and open the file
            TextWriter tw = new StreamWriter("C:/created_by_super.txt");

            // write a line of text to the file
            tw.WriteLine("I am superType - " + typeName);

            // close the stream
            tw.Close();
        }

    }
}

// Klassen SubTypeA
//-------------------

namespace WebService1
{
   
    public class SubTypeA : SuperType
    {
       
        public SubTypeA()
        {
        }

        public override void TypeNameToFile()
        {
            // create a writer and open the file
            TextWriter tw = new StreamWriter("C:/created_by_subTypeA.txt");

            // write a line of text to the file
            tw.WriteLine("I am SubType A - " + typeName);

            // close the stream
            tw.Close();
        }

    }
}

// WebService1.asmx
//-------------------

namespace WebService1
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    // [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {

        //[WebMethod]
        //public void DummySubA(SubTypeA a) { }
        //[WebMethod]
        //public void DummySubB(SubTypeB b) { }

        [WebMethod]
        public String SubTypeTest(SuperType a)
        {
            a.TypeNameToFile();
            return "hat";
        }

    }
}


///////////////////////////
//Uddrag fra den fil der gør brug af servicen

            //TypeA a = new SubTypeA();
            SuperType super = new SuperType();
            super.typeName = "super";
           
            SubTypeA subA = new SubTypeA();
            subA.typeName = "subA";

            //SuperType subB = new SubTypeB();
            SubTypeB subB = new SubTypeB();
            subB.typeName = "subB";
           
            WebService1SoapClient client = new WebService1SoapClient();
            client.SubTypeTest(super);
            client.SubTypeTest(subA);
            client.SubTypeTest(subB);

////////////////////////////////////

Jeg vil gerne opnå, at klienten til servicen har kendskab til typerne SubTypeA og SubTypeB, som begge nedarver fra SuperType.

For at dette skal være muligt, så er det velsagtens nødvendigt at subtyperne optræder i wsdl-filen. Det er imidlertid kun typerne der optræder som metode-parametre, der som udgangspunkt indgår i den wsdl-fil, som der bliver genereret automatisk for mig.

Jeg kan lave en hacket løsning, hvor jeg opretter tomme web-methods (se asmx filen ovenfor), der tager subtyperne som argument. Men dette virker klodset.

Det er min opfattelse, at jeg skal kontrollere at subtyperne kommer med som en del af wsdl-filen, men jeg ved ikke hvordan dette gøres. Skal jeg bruge attributter, skal jeg benytte wsdl.exe eller noget helt tredie?

Afslutningsvis - skulle I evt. kende til gode ressourcer angående web services, så vil meget gerne høre om dette også.

På forhånd tak.

/hotmoller
Avatar billede arne_v Ekspert
17. juli 2008 - 16:37 #1
Der er noget galt i logikken.

Du overfoerer ikke et helt objekt med et web service kald. Groft sagt indeholder
din SOAP alle vaerdierne for dine public properties - server side instantierer
saa et objekt af den rigtige type og saetter alle properties.

Derfor kan du ikke goerde det du vil.

Saa vidt jeg ved bliver det mere tydeligt hvis du skifter fra asmx til WCF.

Det du kan goere er at sende et argument med som web service metoden saa sender
til en factory og factory saa bruger til at instantiere den rigtige sub klasse.
Avatar billede hotmoller Nybegynder
18. juli 2008 - 09:25 #2
Hej arne_v

Mange tak for dit svar.

Jeg skulle lige til at skrive et lidt forhurtigt svar/spørgsmål til dig. Nåede dog at tænke lidt dybere over det du har skrevet :]

Kernen i dit svar er velsagtens, hvordan SOAP'en deserialiseres og hvordan der instansieres et nyt objekt på server-siden.

Jeg må indrømme, at jeg ikke har tænkt over, hvilke informationer der sendes fra klienten til serveren, og hvordan dataene deserialiseres
(det er vel i denne forbindelse der instansieres et nyt objekt). Kan man følge med i denne proces?

Du skriver i dit svar, at det jeg forsøger ikke er muligt. Mener du da i det hele taget? Da jeg arbejdede med projektet her, lod det til at virke ok,
sålænge jeg sørgede for at implementere de føromtalte dummy-metoder (dvs. de metoder der udstiller sub-typerne).

De ovenfor beskrevne kald foretaget af klienten: client.SubTypeTest(super),
client.SubTypeTest(subA) og client.SubTypeTest(subB) fører til at der oprettes 3 forskellige filer på c-drevet:

- created_by_super.txt
- created_by_subTypeA.txt
- created_by_subTypeB.txt

Dette er netop hvad jeg ønsker. Når web-metoden SubTypeTest(SuperType a) eksekverer og kaldet a.TypeNameToFile, så tages der højde for hvilken runtime type argumentet har, og den specifikke implementering af metoden TypeNameToFile kaldes.

Jeg arbejder med en opgave helt tilbage på .net 1.1 frameworket. Derfor er WCF lukket land i relation til dette. Men jeg vil prøve at kigge på WCF senere.

Håber du kan hjælpe mig videre, evt. ved at skære tingene yderligere ud i pap, hvis jeg er helt galt på den :]

vh/ hotmoller
Avatar billede arne_v Ekspert
19. juli 2008 - 04:44 #3
Når du laver et normalt kald så vil:

SuperType o = new SubTypeA();
o.TypeNameToFile();

kalde den rigtige metode, fordi der ligger skjulte felter i data med adressen
på alle virtuelle metoder, objektet o har derfor et felt med adressen på
SubTypeA TypeNameToFile som kan bruges til at kalde den rigtige metode.

Et web service kald sender ikke det felt med den virtuelle metode med over i
SOAP XML'en.

client.SubTypeTest(x);

vil derfor sende:
  service navn
  metode navn inkl. argument typer i web servicen
  værdier alle dine public properties på x

På server siden instantierer web service skeleton koden et objekt af typen for x,
sætter all properties og kalder metoden.

Det hjælper ikke engang at få subklasserne med i WSDL. Fordi problemet er at din
virtuelle metode adresse ikke kommer med over.

Det virker med de 3 metoder fordi kald af de 3 metoder hver instantierer en instans af
den rigtige klasse.

Jeg har foreslået en pænere workaround.
Avatar billede hotmoller Nybegynder
22. juli 2008 - 14:28 #4
Hej arne

Jeg takker for din tålmodighed. Er dog lidt lost, da jeg synes det virker efter hensigten. Jeg vil undersøge det du siger omkring brug af factory til at instantiere.

Hvis du ikke har givet helt op, så har jeg ændret mit kode-eksempel en smule, for at se hvilke typer der instansieres.

///////////////////
//Server-siden

1)
    public class SuperType
    {
        public String typeName;
        public virtual void TypeNameToFile()
        {
            typeName += " manipulated inside super method";
        }
    }

2)
    public class SubTypeA : SuperType
    {
        public override void TypeNameToFile()
        {
            typeName += " manipulated inside SubA method";
        }
    }
3)
    public class SubTypeB : SuperType
    {
        public override void TypeNameToFile()
        {
            typeName += " manipulated inside SubB method";
        }
    }           

///////////////////
//Klient-siden

    public class TestTypeHirarchyColl
    {
        static void Main(String [] args)
        {
            // service attr
            WSSonWinSyncColl.SonWinSyncCollection sonWinSyncColl = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SonWinSyncCollection();
            WSSonWinSyncColl.SuperType super1 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SuperType();
            WSSonWinSyncColl.SuperType subA1 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeA();
            WSSonWinSyncColl.SuperType subB1 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeB();
           
            WSSonWinSyncColl.SuperType super2 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SuperType();
            WSSonWinSyncColl.SuperType subA2 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeA();
            WSSonWinSyncColl.SuperType subB2 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeB();

            WSSonWinSyncColl.SuperType super3 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SuperType();
            WSSonWinSyncColl.SuperType subA3 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeA();
            WSSonWinSyncColl.SuperType subB3 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeB();

            WSSonWinSyncColl.SuperType super4 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SuperType();
            WSSonWinSyncColl.SuperType subA4 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeA();
            WSSonWinSyncColl.SuperType subB4 = new TestEDDIWebService_AndTest.WSSonWinSyncColl.SubTypeB();

            WSSonWinSyncColl.SuperType[] superColl = new WSSonWinSyncColl.SuperType[12];

            superColl[0] = super1;
            superColl[1] = subA1;
            superColl[2] = subB1;

            superColl[3] = super2;
            superColl[4] = subA2;
            superColl[5] = subB2;

            superColl[6] = super3;
            superColl[7] = subA3;
            superColl[8] = subB3;

            superColl[9] = super4;
            superColl[10] = subA4;
            superColl[11] = subB4;

            Console.WriteLine(sonWinSyncColl.SubTypeTestColl(superColl));
            Console.WriteLine("happy days :)");
        }
    }

////////////////////////////
// Resulterer i følgende:

i=0 manip. by:  manipulated inside super method
i=1 manip. by:  manipulated inside SubA method
i=2 manip. by:  manipulated inside SubB method
i=3 manip. by:  manipulated inside super method
i=4 manip. by:  manipulated inside SubA method
i=5 manip. by:  manipulated inside SubB method
i=6 manip. by:  manipulated inside super method
i=7 manip. by:  manipulated inside SubA method
i=8 manip. by:  manipulated inside SubB method
i=9 manip. by:  manipulated inside super method
i=10 manip. by:  manipulated inside SubA method
i=11 manip. by:  manipulated inside SubB method

happy days :)


/////////
Håber ikke at jeg driver dig til vanvid med mine spørgsmål. Synes mit eksempel viser at det jeg gerne vil opnå, rent faktisk godt kan lade sig gøre.

Hvornår er det problemet omkring virtuelle adresser opstår?

På forhånd tak / hotmoller
Avatar billede hotmoller Nybegynder
22. juli 2008 - 14:29 #5
Hov glemte at tilføje web-metoden på server-siden. Den kommer her:

        [WebMethod]
        [XmlInclude(typeof(SubTypeA)), XmlInclude(typeof(SubTypeB))]
        public String SubTypeTestColl(SuperType[] coll)
        {
            for(int i = 0 ; i < coll.Length ; i++)
            {
                coll[i].TypeNameToFile();
            }
            String returnString = "";
            for(int i = 0 ; i < coll.Length ; i++)
            {
                returnString += "i=" + i.ToString() + " manip. by: " + coll[i].typeName + "\n";
            }
            return returnString;
        }
Avatar billede arne_v Ekspert
23. juli 2008 - 01:17 #6
Der sender du ikke objekterne direkte over men en collection med objekterne.

Så kommer klasse navnene med over.
Avatar billede arne_v Ekspert
23. juli 2008 - 01:22 #7
Og ikke bare kommer klassenavnene med over - de bliver også brugt til at genskabe
collection server side - det er de simpelthen nødt til.

Hvis jeg får tid i weekenden kan jeg prøve at lave et tilsvarende eksempel og vise
hvad der bliver sendt på SOAP niveau.
Avatar billede hotmoller Nybegynder
22. august 2008 - 10:05 #8
Hej arne

Kan du referere til noget litteratur/dokumentation der beskriver ovenstående mekanismer?

På forhånd tak.

/moller
Avatar billede arne_v Ekspert
02. september 2008 - 02:48 #9
Ikke lige umiddelbart.

Men jeg tror at du ville lære en del hvis du satte noget op imellem client og server
som loggede de rå request og response, så kunne du se hvad der faktisk blev sendt. Og så
overveje, hvad serveren kunne gøre med det den får i request.
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