Minulý týden jsem potřeboval použít v AX2009 jednu webovou službu poskytovanou třetí stranou. Vytvořil jsem referenci v AOT, takže AX vygenerovala potřebný kód a konfiguraci a já jsem byl okamžitě schopný získat data z webové služby. Skvělé.
Ale nepsal bych o tom, pokud by to bylo všechno. Ta daná webová služba se bude používat interaktivně – zadáte nějaký vstup, zavolá se webová služba, zobrazí se data a tak dále. Někdy také zadáte špatný vstup a služba vrátí speciální zprávu s kódem chyby a textem popisujícím vzniklý problém.
Očekával jsem, že dostanu FaultException, kterou bych odchytil a nějak zpracoval. Namísto toho jsem dostal tuto chybu:
Type ‘System.ServiceModel.Channels.ReceivedFault’ in assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’ is not marked as serializable.
Zkusil jsem hledat na webu a očividně nejsem první, kdo se s tímto problém setkal, ale nenašel jsem žádné užitečné vysvětlení nebo řešení.
Tak jsem se podíval do použité implementace a zjistil jsem, že proxy vygenerovaná Axaptou dědí od třídy Microsoft.Dynamics.IntegrationFramework.WebService.WebReferenceBase (v Microsoft.Dynamics.IntegrationFramework.dll). Tato třída vytvoří pro každou webovou službu novou aplikační doménu, což umožňuje – když nic jiného – nahrát soubor app.config, ale hranice aplikační domény očividně způsobuje problém s instancí ReceivedFault.
Nenapadá mě žádný způsob, jak použít referenci generovanou Axaptou a zároveň se vyhnout chybě v serializaci. Reference na služby mají v AX pěkně integrovanou konfiguraci, ale v mém případě je náležité zpracování výjimek důležitější. Takže jsem vytvořil samostatnou knihovnu tříd, která referencuje danou webovou službu, nastavuje binding a adresu endpointu a volá webovou službu.
Pominu-li konfiguraci a validaci vstupu, vypadá celá implementace takto jednoduše:
public static Object GetData(string input) { using (var client = new MyService_SoapClient( new BasicHttpBinding(), new EndpointAddress("http://somewhere/service.ws"))) { return client.GetData(input); } }
ReceivedFault je korektně transformována na FaultException, která je pak poslána do AX, kde je možné ji bez problému odchytit.
Sice jsem nezkoušel použít stejnou webovou službu v AX2012, ale nepředpokládám, že by tam byl stejný problém. AX2012 totiž řeší webové služby podstatně jinak než AX2009.