[C# .Net] door svcutil gegenereerde class als return type

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
Is er een mogelijkheid om svcutil classes te laten genereren die bruikbaar zijn als return type in een andere webservice?

Even de situatie: ik heb 2 webservices (A en B) en een client. De client doet calls naar webservice A en webservice A doet deze calls vervolgens weer bij webservice B. De reden hiervoor is dat webservice A en webservice B beiden over ipv6 met elkaar communiceren en de client niet perse ipv6 enabled is. Daarnaast wil ik wat centrale logging doen op webservice A. Webservice B draait overigens ook weer op een x aantal clients.

Nu krijg ik de volgende foutmelding als ik de door svcutil gegenereerde classes van webservice B in webservice A als return type wil aanbieden:
'System.ComponentModel.PropertyChangedEventHandler' cannot derive from special class 'System.MulticastDelegate'

Op zich niet heel vreemd als je ziet wat voor code hij bouwt, maar ik vraag me dus af of het mogelijk is om met svcutil classes te genereren die WEL bruikbaar zijn in een andere webservice. Anders zou ik in webservice A een identieke class moeten gaan designen, alle properties overhevelen na iedere call en zodra er iets wijzigt in de wsdl van webservice B deze code weer moeten updaten. Niet echt handig dus...

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
De meest voor de hand liggende oplossing is om 1 schema assembly te bouwen, waarin alle benodigde types (1 keer) worden gedefinieerd. Deze schema assembly reference je vervolgens vanuit beide webservices zodat je op beide plekken dezelfde types hebt.

Let op: je moet dan wel voorkomen dat svcutil deze types zelf ook nog een keer genereert aan de hand van de wsdl. Dit kan door gebruik te maken van de /reference switch (zie o.a. hier en hier).

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
MrBucket schreef op vrijdag 19 juni 2009 @ 17:45:
De meest voor de hand liggende oplossing is om 1 schema assembly te bouwen, waarin alle benodigde types (1 keer) worden gedefinieerd. Deze schema assembly reference je vervolgens vanuit beide webservices zodat je op beide plekken dezelfde types hebt.

Let op: je moet dan wel voorkomen dat svcutil deze types zelf ook nog een keer genereert aan de hand van de wsdl. Dit kan door gebruik te maken van de /reference switch (zie o.a. hier en hier).
Dan zit ik nog steeds met hetzelfde probleem. Ik kan wat ik genereer met svcutil niet zo maar 1 op 1 aanbieden in een andere webservice. Dit omdat svcutil allemaal code genereert waar ik niet op zit te wachten. Bij mij gaat hij hier op z'n bek omdat de gegenereerde class INotifyPropertyChanged implementeert en hij dat event wat bij die interface komt niet kan serializen. Ik heb dus meer een "/nofuzz" optie nodig in svcutil ;) Ik kan wel handmatig die interface gaan verwijderen maar zodra er dan iets veranderd in webservice B en ik de proxy dus opnieuw moet genereren kan ik weer van voren af aan beginnen.

Acties:
  • 0 Henk 'm!

  • HeSitated
  • Registratie: April 2009
  • Laatst online: 03-12-2024
Hardcell schreef op vrijdag 19 juni 2009 @ 21:09:
[...]


Dan zit ik nog steeds met hetzelfde probleem. Ik kan wat ik genereer met svcutil niet zo maar 1 op 1 aanbieden in een andere webservice.
En als die klasses een interface implementeren? Dan hoef je niet de klasses te sharen, maar alleen de interfaces...

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ik begrijp dat de types die door webservice A aangeboden worden niet door jou worden gedefinieerd, maar dat je afhankelijk bent van de wsdl? Dat verandert de zaak wel enigzins, alhoewel het me een beetje vreemd lijkt dat je svcutil niet kan vertellen dat 'ie geen INotifyPropertyChanged moet implementeren, aangezien je met /edb 'm kunt vertellen dat 'ie 't wel moet doen 8)7.
'k Heb hier alleen geen .NET 3.5 omgeving bij de hand om het te testen...

Ik heb trouwens je post nog eens doorgelezen, en die webservice B (die alleen maar calls forward) is eigenlijk een beetje een vreemde eend in de bijt. Volgens mij zou je die niet als een 'normale' webservice willen implementeren met z'n eigen service en data contracts, maar eigenlijk als een soort van pass-through service die elk bericht slikt en 'm forward naar webservice A.

Het artikel Extending WCF with Custom Behaviors kan je hier wellicht verder mee helpen.

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
HeSitated schreef op vrijdag 19 juni 2009 @ 21:38:
[...]


En als die klasses een interface implementeren? Dan hoef je niet de klasses te sharen, maar alleen de interfaces...
Ik snap niet helemaal wat je bedoelt. Het probleem zit hem niet in het sharen maar in de autogenerated code. Ik kan inderdaad een interface bouwen, maar dan moet ik nog steeds een 2de class bouwen die die interface implementeerd en handmatig het result van webservice B in zo'n class wrappen en die dan weer terugsturen van webservice A naar de client. Dat handwerk wil ik juist voorkomen. Die interface komt er niet vanzelf en zal dus ook geupdate moeten worden iedere keer als de wsdl van webservice B verandert en daarnaast die 2de class dus ook.

Als ik gewoon svcutil zover krijg dat hij niet iedere class een INotifyPropertyChanged meegeeft dan ben ik er (volgens mij) al. Die PropertyChanged gebruik ik toch niet want ik ga niets databinden in die webservice. Het is maar een doorgeefluik in dit geval.

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
MrBucket schreef op vrijdag 19 juni 2009 @ 21:56:
Ik begrijp dat de types die door webservice A aangeboden worden niet door jou worden gedefinieerd, maar dat je afhankelijk bent van de wsdl? Dat verandert de zaak wel enigzins, alhoewel het me een beetje vreemd lijkt dat je svcutil niet kan vertellen dat 'ie geen INotifyPropertyChanged moet implementeren, aangezien je met /edb 'm kunt vertellen dat 'ie 't wel moet doen 8)7.
'k Heb hier alleen geen .NET 3.5 omgeving bij de hand om het te testen...

Ik heb trouwens je post nog eens doorgelezen, en die webservice B (die alleen maar calls forward) is eigenlijk een beetje een vreemde eend in de bijt. Volgens mij zou je die niet als een 'normale' webservice willen implementeren met z'n eigen service en data contracts, maar eigenlijk als een soort van pass-through service die elk bericht slikt en 'm forward naar webservice A.

Het artikel Extending WCF with Custom Behaviors kan je hier wellicht verder mee helpen.
Je wisselt volgens mij A en B om ;) Anyway, het is niet ALLEEN pas-through wat er gebeurd op webservice A. Het endpoint bevat ook enkele calls die niet doorgestuurd worden naar webservice B, naarnaast krijg webservice A een id mee waarmee hij het ipv6 adres van webservice B moet resolven uit een database en verder doet hij ook nog wat logging..

Maar thnx voor die /edb tip ;) Ik had deze proxy voor het gemak even via die "Add Service Reference" gebouwd en ik ben bang dat daar ook de issue zit, dat die automatisch die /edb optie erachter knalt. Ik ga die reference eens even vanuit de command prompt genereren. :P

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Hardcell schreef op vrijdag 19 juni 2009 @ 22:09:
[...]


Je wisselt volgens mij A en B om ;)
Eh ja, dat realiseerde ik me op een of andere manier net pas. Nevermind ;)
Het endpoint bevat ook enkele calls die niet doorgestuurd worden naar webservice B, naarnaast krijg webservice A een id mee waarmee hij het ipv6 adres van webservice B moet resolven uit een database en verder doet hij ook nog wat logging..
Zolang die extra taken (adres resolven, logging) voor alle webservice calls eigenlijk hetzelfde zijn kun je dit ws. beter als een behavior implementeren, zodat je de benodigde code maar 1 keer hoeft te schrijven en de webservice niet stuk gaat als de achterliggende webservice verandert.
Zie het MSDN Magazine artikel wat ik eerder postte over op welke punten je in kunt haken en wat er mogelijk is.
Maar thnx voor die /edb tip ;) Ik had deze proxy voor het gemak even via die "Add Service Reference" gebouwd en ik ben bang dat daar ook de issue zit, dat die automatisch die /edb optie erachter knalt. Ik ga die reference eens even vanuit de command prompt genereren. :P
Zie de links in mijn eerste post. De 2e omschrijft alle mogelijke commandline switches, en je kunt aardig wat configureren (volgens mij kunnen ook lang niet alle opties via de wizard gezet worden) :)

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
MrBucket schreef op vrijdag 19 juni 2009 @ 22:20:
[...]

Eh ja, dat realiseerde ik me op een of andere manier net pas. Nevermind ;)

[...]

Zolang die extra taken (adres resolven, logging) voor alle webservice calls eigenlijk hetzelfde zijn kun je dit ws. beter als een behavior implementeren, zodat je de benodigde code maar 1 keer hoeft te schrijven en de webservice niet stuk gaat als de achterliggende webservice verandert.
Zie het MSDN Magazine artikel wat ik eerder postte over op welke punten je in kunt haken en wat er mogelijk is.

[...]

Zie de links in mijn eerste post. De 2e omschrijft alle mogelijke commandline switches, en je kunt aardig wat configureren (volgens mij kunnen ook lang niet alle opties via de wizard gezet worden) :)
Ik ken de extensibility features van wcf ;) Het leek me alleen niet nodig om zo low-level te gaan in dit geval. Sowieso moeten de calls toch in de wsdl komen dus een class die de interface (het servicecontract) implementeert kom ik niet onder uit lijkt mij?

Verder heb ik dan:
code:
1
2
3
delegate TResponse callDelegate<TRequest, TResponse>(TRequest request);

private TResponse makeCall<TResponse, TRequest>(int id, TRequest request, callDelegate<TRequest, TResponse> call)

waar de makeCall dus de response teruggeeft bij succes, een FaultException gooit bij error en de nodige logging doet. (En er is uiteraard nog een helpfunctie om het ipv6 adres bij het opgegeven id op te zoeken)

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Hardcell schreef op vrijdag 19 juni 2009 @ 22:33:
[...]


Ik ken de extensibility features van wcf ;) Het leek me alleen niet nodig om zo low-level te gaan in dit geval. Sowieso moeten de calls toch in de wsdl komen dus een class die de interface (het servicecontract) implementeert kom ik niet onder uit lijkt mij?
Nou, ik weet dat het mogelijk moet zijn om een soort van catch-all service te maken door gebruik te maken van de Message class. Zoals hier te lezen is: For example, you might want to use the Message class (...) when you need to deal with messages in a general way regardless of message contents (for example, when routing or forwarding messages when building a router, load-balancer, or a publish-subscribe system).

Ik heb er zelf geen ervaring mee, maar 't klinkt wel aardig in de richting van wat jij zoekt, volgens mij.

Acties:
  • 0 Henk 'm!

  • HeSitated
  • Registratie: April 2009
  • Laatst online: 03-12-2024
Hardcell schreef op vrijdag 19 juni 2009 @ 22:00:
Ik kan inderdaad een interface bouwen, maar dan moet ik nog steeds een 2de class bouwen die die interface implementeerd en handmatig het result van webservice B in zo'n class wrappen en die dan weer terugsturen van webservice A naar de client. Dat handwerk wil ik juist voorkomen. Die interface komt er niet vanzelf en zal dus ook geupdate moeten worden iedere keer als de wsdl van webservice B verandert en daarnaast die 2de class dus ook.
Je hoeft dan toch alleen dan de interface te wijzigen als er iets wijzigt in de zaken die webservice A gebruikt?

Maar die moest je dan toch al wijzigen! Toch?

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
Nu de class met svcutil gegenereert. Wat een gare shit is dat WCF toch af en toe zeg. Wat doet hij nu, hij raised alleen het event niet, het event niet en hij implementeerd niet die INotifyChanged interface. Er staat wel nog steeds een:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace System.ComponentModel
{
    using System;
    
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.SerializableAttribute()]
    public partial class PropertyChangedEventHandler : System.MulticastDelegate
    {
        
        public PropertyChangedEventHandler(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : 
                base(info, context)
        {
        }
    }
}

PropertyChangedEvent dus gedefinieerd in m'n autogenerated code en iedere class heeft ook nog steeds die property en private field:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private System.ComponentModel.PropertyChangedEventHandler PropertyChangedField;

[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
public System.ComponentModel.PropertyChangedEventHandler PropertyChanged
{
    get
    {
          return this.PropertyChangedField;
    }
    set
    {
          this.PropertyChangedField = value;
    }
}


Het lijkt er dus op dat ik zelf een tool aan het schrijven kom die de autogenerated code stript van onnodige crap.. :(

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
HeSitated schreef op vrijdag 19 juni 2009 @ 22:51:
[...]


Je hoeft dan toch alleen dan de interface te wijzigen als er iets wijzigt in de zaken die webservice A gebruikt?

Maar die moest je dan toch al wijzigen! Toch?
Nee, webservice B bouw ik niet zelf, die krijg ik via een externe partij aangeboden, vandaar de behoefte aan iets wat code genereert.
MrBucket schreef op vrijdag 19 juni 2009 @ 22:47:
[...]

Nou, ik weet dat het mogelijk moet zijn om een soort van catch-all service te maken door gebruik te maken van de Message class. Zoals hier te lezen is: For example, you might want to use the Message class (...) when you need to deal with messages in a general way regardless of message contents (for example, when routing or forwarding messages when building a router, load-balancer, or a publish-subscribe system).

Ik heb er zelf geen ervaring mee, maar 't klinkt wel aardig in de richting van wat jij zoekt, volgens mij.
Als het echt alleen pass-through zou zijn zou dat een mooiere oplossing zijn ja. Alleen bevat dit endpoint naast die pass-through functionaliteit ook een zwik calls die code bevatten die gewoon op webservice A uitgevoert wordt.

Acties:
  • 0 Henk 'm!

Verwijderd

Hardcell schreef op vrijdag 19 juni 2009 @ 22:53:
Het lijkt er dus op dat ik zelf een tool aan het schrijven kom die de autogenerated code stript van onnodige crap.. :(
Vreemd als ik svcutil op de volgende manier start (de meest eenvoudige) dan krijg ik niets te zien wat met notify property changed te maken heeft.
code:
1
svcutil http://testserver:3924/Service/Service.svc

Hoe ziet de command line voor svcutil eruit die jij gebruikt?

Acties:
  • 0 Henk 'm!

  • Hardcell
  • Registratie: November 2004
  • Laatst online: 03-02-2023
Nu werkt het wel. Ik moest gegenereerde file eerst deleten voor hem opnieuw te laten genereren. Hij laat die zooi gewoon staan als je eerst met /edb genereert en daarna zonder. Problem solved! :)
Pagina: 1