WCF, Silverlight, serialization en interfaces

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Knakker
  • Registratie: April 2000
  • Laatst online: 26-07 21:05
Ik ben mij sinds kort aan het verdiepen in WCF in combinatie met Silverlight als frontend. Deze combinatie is voor mij -in theorie- de oplossing voor het overgrote deel van mijn toepassingen: een service die allerlei berekeningen en simulaties uitvoert op een grote bak met data en een webclient waarmee ik berekeningen kan sturen en resultaten grafisch kan weergeven. Silverlight geeft me de responsiveness en interactie die ik bij ASP.NET niet heb, en de learning curve ervan is laag omdat de opbouw (voor mijn toepassingen) voor 90% dezelfde is als 'gewone' WPF applicaties. Tot nu toe ben ik zeer onder de indruk van de mogelijkheden en vooral ook het gemak waarmee zo'n constructie opgezet wordt.

In deze eerste kennismaking met WCF kom ik echter ook voor het eerst in aanraking met de problemen die bij serialisatie komen kijken; zaken waarbij ik tot voor kort nooit had stilgestaan (mede doordat ik vanuit de functionele hoek in de softwareontwikkeling gerold en dus geen 'gedegen' IT opleiding heb gehad).

Ik wil in mijn service de volgende interface gebruiken:

C#:
1
2
3
4
5
6
[ServiceContract]
public interface IService 
{ 
    [OperationContract]
    IReport GetReport(List<IField> Pivot); 
}


Ik heb een hele reeks klasses die IField implementeren. In de huidige definitie van de service kan ik deze niet zonder meer meegeven in mijn aanroep; van wat ik uit bronnen op internet heb begrepen is het probleem dat bij serialisatie de relatie tussen mijn contracten en IField niet wordt meegenomen. Laat ik voorop stellen dat ik niet snap waarom dit uberhaupt nodig is: in de definitie van de klassen aan zowel de service als de client kant staat gespecificeerd dat ze aan de IField interface voldoen...

Een oplossing is het toevoegen van een ServiceKnownType attribute aan mijn service voor elke klasse die IField implementeert, wat als gevolg heeft -als ik het goed heb begrepen- dat in de metadata wordt meegegeven dat bijvoorbeeld Obligatie IField implementeert. Afgezien van het feit dat ik vele tientallen van dit soort klasses heb, is dit een ernstige beperking: iedere keer wanneer ik een klasse toevoeg, moet ik de definitie van de service aanpassen. Dan kan ik net zo goed geen interfaces gebruiken.

Een andere oplossing die ik gevonden heb, is het gebruik van de NetDataContractFormatSerializer. Dit is een .NET-specifieke serializer (voor mijn situatie geen beperking), die allerhande relevante metadata wel meestuurt waardoor dit probleem zich niet meer voordoet. Deze is alleen weer niet in .NET subset van Silverlight (versie 3) opgenomen.

Het probleem is dat ik de mogelijke oplossingen en beperkingen van dit probleem op dit moment niet kan overzien, omdat ik het probleem niet echt begrijp - nu heb ik de klok horen luiden, maar de klepel weet ik nog niet te vinden. Is er iemand die meer licht kan schijnen op de ins en outs van dit probleem en mij wellicht in de goede richting kan duwen?

Alvast bedankt :)

[ Voor 7% gewijzigd door Knakker op 09-04-2010 10:50 ]

Geef mij maar een Warsteiner.


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 09-09 22:04

CodeIT

Code IT

Allereerst complimenten voor de uitgebreide startpost.
Doordat alle communicatie tussen je service en je client geserialiseerd wordt kunnen geen references worden gebruikt. Alles wat verstuurd wordt moet hard vastgelegd zijn, zodat deze als xml naar de client (en vice versa) verstuurd kan worden.
Je kunt dus niet met interfaces als parameter werken (met uitzondering van het gebruik van de NetDataContractSerializer).
Een oplossing is het toevoegen van een ServiceKnownType attribute aan mijn service voor elke klasse die IField implementeert, wat als gevolg heeft -als ik het goed heb begrepen- dat in de metadata wordt meegegeven dat bijvoorbeeld Obligatie IField implementeert. Afgezien van het feit dat ik vele tientallen van dit soort klasses heb, is dit een ernstige beperking: iedere keer wanneer ik een klasse toevoeg, moet ik de definitie van de service aanpassen. Dan kan ik net zo goed geen interfaces gebruiken.
Ik denk dat dit in jouw geval de enige mogelijkheid is.

[ Voor 41% gewijzigd door CodeIT op 09-04-2010 11:37 ]


Acties:
  • 0 Henk 'm!

  • Knakker
  • Registratie: April 2000
  • Laatst online: 26-07 21:05
Bedankt voor je reaktie! Ik snap het probleem alleen nog steeds niet. :P

De client weet dat Obligatie IField implementeert, want dat staat in haar definitie van het object. De compiler geeft daarom ook geen foutmelding. In de XML die van het object gegenereert wordt, staat als naam van het object 'Domain.Obligatie' vermeldt. De service houdt dat tegen zijn eigen definitie van Obligatie aan (die identiek is aan die van client), waarin staat dat deze IField implementeert. En dus is de aanroep legaal.

Wat is de reden dat het bovenstaande niet het geval is en niet werkt? Ik ben bijna in staat om een eigen serializer te schrijven die met behulp van reflectie mijn object serialiseert aan de clientkant en weer deserialiseert aan de service kant, want dan heb ik dit probleem niet. Of toch wel?

[ Voor 17% gewijzigd door Knakker op 09-04-2010 12:02 ]

Geef mij maar een Warsteiner.


Acties:
  • 0 Henk 'm!

  • TheNameless
  • Registratie: September 2001
  • Laatst online: 07-02 21:38

TheNameless

Jazzballet is vet!

Knakker schreef op vrijdag 09 april 2010 @ 10:44:
...
Een oplossing is het toevoegen van een ServiceKnownType attribute aan mijn service voor elke klasse die IField implementeert, wat als gevolg heeft -als ik het goed heb begrepen- dat in de metadata wordt meegegeven dat bijvoorbeeld Obligatie IField implementeert. Afgezien van het feit dat ik vele tientallen van dit soort klasses heb, is dit een ernstige beperking: iedere keer wanneer ik een klasse toevoeg, moet ik de definitie van de service aanpassen. Dan kan ik net zo goed geen interfaces gebruiken.
...
Dit lijkt me toch vrij logisch :?
Als je een nieuwe klasse definieer in je service, dan wil je deze toch ook kunnen gebruiken in de client?

Tip: kijk ook eens naar de overloads van de ServiceKnownTypeAttribute constructor: http://msdn.microsoft.com...s575141%28v=VS.90%29.aspx

Ducati: making mechanics out of riders since 1946


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 09-09 22:04

CodeIT

Code IT

Knakker schreef op vrijdag 09 april 2010 @ 11:59:
Bedankt voor je reaktie! Ik snap het probleem alleen nog steeds niet. :P

De client weet dat Obligatie IField implementeert, want dat staat in haar definitie van het object. De compiler geeft daarom ook geen foutmelding. In de XML die van het object gegenereert wordt, staat als naam van het object 'Domain.Obligatie' vermeldt. De service houdt dat tegen zijn eigen definitie van Obligatie aan (die identiek is aan die van client), waarin staat dat deze IField implementeert. En dus is de aanroep legaal.

Wat is de reden dat het bovenstaande niet het geval is en niet werkt? Ik ben bijna in staat om een eigen serializer te schrijven die met behulp van reflectie mijn object serialiseert aan de clientkant en weer deserialiseert aan de service kant, want dan heb ik dit probleem niet. Of toch wel?
De serializer serialiseert alleen je Obligatie, waardoor dus alle properties van IField verloren gaan. Er kan dus geen IField meer gemaakt worden. Hiervoor is juist het ServiceKnownType attribute voor uitgevonden. Deze specificeert dat, naast Obligatie, ook alles van IField geserialiseerd moet worden.

Acties:
  • 0 Henk 'm!

  • Knakker
  • Registratie: April 2000
  • Laatst online: 26-07 21:05
Dit lijkt me toch vrij logisch :?
Als je een nieuwe klasse definieer in je service, dan wil je deze toch ook kunnen gebruiken in de client?
Klopt. Maar die zit in een aparte (gedeelde) library, dus dat gaat automatisch. De server interface daarentegen niet, omdat de service interface aan de (web)client kant asynchroon moet zijn opgebouwd (dus met callbacks etc). Bovendien is het voor die service helemaal niet relevant wat voor implementatie van IField het is, zolang de door de interface gedefinieerde methodes maar beschikbaar zijn.
De serializer serialiseert alleen je Obligatie, waardoor dus alle properties van IField verloren gaan. Er kan dus geen IField meer gemaakt worden. Hiervoor is juist het ServiceKnownType attribute voor uitgevonden. Deze specificeert dat, naast Obligatie, ook alles van IField geserialiseerd moet worden.
Maar mijn obligatie heeft toch juist alle properties van IField? Anders zou het de IField interface niet kunnen implementeren... toch?

Klok, klepel.... bedankt tot zover ;)

[ Voor 47% gewijzigd door Knakker op 09-04-2010 14:19 ]

Geef mij maar een Warsteiner.


Acties:
  • 0 Henk 'm!

  • CodeIT
  • Registratie: Juni 2002
  • Laatst online: 09-09 22:04

CodeIT

Code IT

Knakker schreef op vrijdag 09 april 2010 @ 14:16:

Maar mijn obligatie heeft toch juist alle properties van IField? Anders zou het de IField interface niet kunnen implementeren... toch?

Klok, klepel.... bedankt tot zover ;)
Daar heb je gelijk in, mijn verhaal ging meer over inheritance, dat is namelijk hetzelfde probleem.
In het geval van een interface is het zo dat alle properties wel overgestuurd kunnen worden, maar dat de definitie ontbreekt, omdat deze (deels) wordt gespecificeerd in je interface.
Omdat WCF gebruikt kan worden door meer dan .NET alleen, wordt alleen de data overgestuurd en geen taalspecifieke metadata. De service is dan taalonafhankelijk te gebruiken.

De NetDataContractSerializer maakt van je WCF service ook een .NET only WCF service.

Acties:
  • 0 Henk 'm!

  • TheNameless
  • Registratie: September 2001
  • Laatst online: 07-02 21:38

TheNameless

Jazzballet is vet!

Knakker schreef op vrijdag 09 april 2010 @ 14:16:
...
Klopt. Maar die zit in een aparte (gedeelde) library, dus dat gaat automatisch. De server interface daarentegen niet, omdat de service interface aan de (web)client kant asynchroon moet zijn opgebouwd (dus met callbacks etc). Bovendien is het voor die service helemaal niet relevant wat voor implementatie van IField het is, zolang de door de interface gedefinieerde methodes maar beschikbaar zijn.
...
Ik denk dat dit ook direct een rede is waardoor je er tegen aanloopt.

Stel dat je service een webservice is (dus via SOAP).
Hoe wil je hier dan een JAVA client van genereren?
Dat kan alleen via een WSDL (de metadata die WCF genereert), maar als deze niet alle beschikbare implementaties van een interface definieert, dan kunnen er rare dingen gebeuren :)

In jou geval is dit probleem er niet, omdat de specifieke implementaties via een andere weg beschikbaar is (een andere assembly).

Misschien is dit de reden dat WCF het gewoon niet toelaat (just guessing)?

Ducati: making mechanics out of riders since 1946

Pagina: 1