Toon posts:

[.NET] Client faalt na verandering in webservice

Pagina: 1
Acties:

Onderwerpen


Anoniem: 244685

Topicstarter
Hallo. Ik heb als "handige buurjongen" voor iemand een programmaatje gemaakt dat via een bestaande webservice informatie ophaalt en er dingen mee doet. Over die webservice hebben we geen controle, we zijn slechts afnemer. Ik zal direct bekennen niet precies te weten wat er "under the hood" allemaal gebeurt (vast één groot feest van SOAP en XML), maar het werd me allemaal erg makkelijk gemaakt door de .NET tools: de webservice gaf me een WSDL, ik kon daarvan met "svcutil" een soort proxy-code mee produceren, en die code deed het in mijn project vrijwel direct.

Nu is de webservice een beetje veranderd. Volgens mij zijn er maar twee velden toegevoegd aan een object. Helaas hield mijn programma hierdoor er mee op te werken: die nieuwe objecten werden volledig "null" ingevuld. Even opnieuw de proxy-code generen met de nieuwe WSDL loste het probleem direct op.

Hoe dan ook: is het mogelijk ergens in te stellen nieuwe/onbekende velden gewoonweg te negeren? Als ik zelf handmatig het service-praat-werk zou doen, zou ik gewoon de onbekende XML-elementen negeren. Kan ik de .NET-machinerie vertellen hetzelfde te doen? Het zou prettig zijn dat ik als afnemer niet iedere keer moet updaten als de service slechts iets toevoegt dat ik simpelweg kan negeren. En ik kan me voorstellen dat ik niet de eerste ben met dit probleem. Op het net kon ik niet zo snel iets vinden (of geen pakkende zoekterm bedenken).

Bij voorbaat dank!

PS. Ik gebruik de "System.ServiceModel.*" klassen, ik geloof niet dat er veel andere keuze is, maar voor de volledigheid...

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 30-05 14:46
Het lijkt mij toch dat je een check op null zou kunnen doen? Ook zou je eventueel via een programma als Wireshark of de debugger in VS kunnen kijken welke informatie er binnen komt. Zo zou je meer controle moeten hebben over de informatie.

Anoniem: 244685

Topicstarter
Hmm, laat ik een voorbeeld geven. Ik heb een object dat de webservice voorstelt en intern met de webservice praat (maar daar merk ik als gebruiker niets van, dat is allemaal .NET-magie). Dat object heeft dezelfde methoden als de webservice aanbiedt. Bijvoorbeeld:
code:
1
2
ServiceSoapClient service = new ServiceSoapClient("ServiceSoap");
Persoon persoon1 = service.geefPersoon();

De code achter ServiceSoapClient en Persoon is gegenereerd a.d.h.v. de WSDL van de service. Tot voor kort zag persoon1 er na een geefPersoon() bijvoorbeeld zo uit:
code:
1
2
string persoon1.naam = "wintermute.";
int persoon1.leeftijd = 87;

Toen besloot de baas van de webservice een veld toe te voegen aan Persoon: string woonplaats. Opeens zag persoon1 er zo uit na een geefPersoon():
code:
1
2
string persoon1.naam = null;
int persoon1.leeftijd = 0;

Omdat mijn Persoon (de oude) niet meer overeenkwam met de nieuwe. Uiteraard kan ik op null checken, maar wat dan? Wat mij betreft blijven de ongewijzigde velden (naam, leeftijd) gewoon ingevuld worden, en negeert hij het nieuwe veld. Ik zou met wireshark kunnen kijken, maar dat lost niets op; de webservice spuwt z'n SOAP data uit, maar de koppeling bij mij tussen SOAP en mijn Persoon-object gaat mis. Met een debugger kan ik er niet diep genoeg in stappen, Persoon bestaat uit gegenereerde code die alleen maar een soort van structuur of sjabloon is van hetgeen de service aanbiedt. En is van allerlei .NET framework klassen afgeleid en z'n methoden zijn leeg, en worden alleen voorafgegaan door wat "annotations" of "attributes" of hoe die dingen in C# ook heten, zoals "[Serializable]" e.d. Ik kan (en wil) er niet met m'n debugger doorheen lopen, daar zit gewoon de onderliggende .NET-magie waar ik niets mee te maken heb.

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 31-05 20:05
alex3305 schreef op woensdag 01 juni 2011 @ 12:30:
Het lijkt mij toch dat je een check op null zou kunnen doen? Ook zou je eventueel via een programma als Wireshark of de debugger in VS kunnen kijken welke informatie er binnen komt. Zo zou je meer controle moeten hebben over de informatie.
Nee zo werkt het niet. Als je via visual studio vanuit de wsdl een proxy genereert worden er ook klasses voor het datamodel gegenereert. Als de service veranderd waardoor het datamodel veranderd is kan de deserializer niet meer goed zijn werk doen omdat de type definitie veranderd is, in wcf vertaald dit (o.a.) zich naar een leeg object.

Hier kun je inderdaad normaliter niks anders aan doen dan je proxy opnieuw genereren. Als je met een WCF server praat kunnen hier wel voorzieningen voor getroffen worden, waardoor er dus backwards compatibility is en het gewoon blijft werken, maar blijkbaar hebben ze dat aan de service kant niet gedaan.

Dat gezegd vermoed ik dat er meer veranderd is dan alleen 2 veldjes toegevoegd. Normaal zou dit namelijk niet voor zoveel problemen zorgen. Tenzij de velden niet aan het einde van de definitie hebben toegevoegd, maar ergens tussenin, of vooraan ofzo. (volgorde van velden is belangrijk bij deserialisatie).

Anoniem: 244685

Topicstarter
Zo te zien is inderdaad een veld ergens tussengevoegd. Ook al is daardoor de volgorde veranderd, via deserialisatie via XML zou het via de tag-namen van de velden toch weer goed gezet kunnen worden? Er zijn meerdere clients afhankelijk van die service, en die schijnen niet hetzelfde probleem te hebben (ik bespaar jullie de details). Is er niet ergens een deserialisatie-instelling waarmee je zegt te ordenen op naam i.p.v. volgorde en geen probleem te maken van nieuwe onbekende velden?

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 13:25

Haan

dotnetter

Ik heb het idee dat je het jezelf te moeilijk maakt. Als ik je startpost lees, kan je gewoon in Visual Studio in je projct voor 'Add Service Reference' kiezen, waarbij alles netjes voor je wordt gegeneerd (dit gebruikt onder water gewoon svcutil, dus geen reden om die tool handmatig te runnen). Vervolgens kan je "update service reference" doen, waarbij die reference weer opnieuw wordt gegenereerd.

Kater? Eerst water, de rest komt later


  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 07:41
Ik denk ook dat hier iets groters is veranderd. De namespaces van de types waarschijnlijk? Want normaal gesproken is een proxy gewoon backwards compatible.

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Volgorde maakt in principe niet uit. Als ik bijvoorbeeld de volgende XML:
XML:
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<Persoon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Woonplaats>Amsterdam</Woonplaats>
  <Naam>Pietje</Naam>
  <Leeftijd>35</Leeftijd>
</Persoon>

deserialiseer naar een object van dit type:
C#:
1
2
3
4
5
public class Persoon
{
    public String Naam;
    public int Leeftijd;
}

dan werkt dat gewoon. Onbekende velden worden dan door de XmlSerializer die ik gebruik genegeerd*. WCF gebruikt echter een andere serializer, namelijk de DataContractSerializer, maar die vertoont hetzelfde gedrag.

Sterker nog, wanneer ik een service maak en daar een client op genereer, en vervolgens een veld toevoeg aan de service maar de client niet bijwerk, blijft het ook gewoon werken en worden alleen de bekende velden gevuld (ongeacht de volgorde in de service, en het werkt ook zonder de IExtensibleDataObject* interface te implementeren in de client).

*: Onbekende velden worden, als je IExtensibleDataObject implementeert, opgeslagen in het ExtensionData-property van de klasse Persoon (standaardgedrag als je een service reference genereert).

My point being: waarschijnlijk is er wel meer veranderd en wordt het hele object daardoor niet gevuld. Krijg je geen exceptions?

[Voor 4% gewijzigd door CodeCaster op 01-06-2011 15:51]

https://oneerlijkewoz.nl
I have these thoughts / so often I ought / to replace that slot / with what I once bought / 'cause somebody stole my car radio / and now I just sit in silence


Anoniem: 244685

Topicstarter
Dank voor jullie hulp en uitleg zover. Ik ga proberen uit te zoeken wat het verschil is tussen de oude en de nieuwe service. Heb ik veel andere keuze dan handmatig de oude en de nieuwe proxy te vergelijken? De eerste exception die ik kreeg was toen ik een null-veld van een leeg object probeerde te gebruiken. Om m'n echte probleem nog even te vertalen naar m'n "Persoon"-voorbeeldje:
code:
1
2
3
Personen persons=service.geefPersonen();
foreach(Persoon p in persons.Items)
Console.WriteLine(p.naam);

"Personen" bevatte wel een array met een aantal Personen dat niet verschilde van de normale situatie (goed!), maar ieder Persoon-element in de array was leeg (fout). In het echt gebeurde op de plaats van Console.WriteLine iets dat een Exception gaf door de null-string p.naam.

Anoniem: 244685

Topicstarter
HA! Toen ik de twee verschillende proxies aan het vergelijken was, kwam ik deze attributes tegen:
[System.Xml.Serialization.XmlElementAttribute(Order = getal)]. Waarbij voor de twee proxies de getallen voor hetzelfde veld zo nu en dan verschilden. Op goed geluk heb ik ze allemaal uitgecomment, en bingo! Ik heb nu alleen wel een oplossing, alleen niet het gevoel dat het robuust is of dat ik er iets van begrijp...
Pagina: 1


Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee