Wadliwy web serwis - debugowanie problemu z deserializacją

0

Mam do stworzenia aplikację w oparciu o wadliwy web serwis. Został on dla mnie w sporej mierze poprawiony, ale w dalszym ciągu nie działa tak jak powinien. Aktualnie za pomocą dotnet-svcutil.dll z udostępnionego opisu w WSDLu jestem w stanie wygenerować bez błędów klasy proxy, następnie połączyć się, zalogować, wysłać zapytanie i odebrać dane. Problem pojawia się przy deserializacji.

System.ServiceModel.CommunicationException: 'Wystąpił błąd podczas deserializacji treści komunikatu odpowiedzi dla operacji „getBillingForClient”.'
InvalidOperationException: Dokument XML zawiera błąd (2, 528).

Ludzie, którzy mi to poprawiają nie do końca mają czas i chciałbym we własnym zakresie trochę pomóc i znaleźć przyczynę (właściwość), z którą jest problem przy deserializacji. Czy da się jakoś dokładniej zdebugować ten problem, żeby uzyskać taką informację?

0

Nie jestem pewien jak to jest w przypadku XML ale chyba w samym XMLu masz błąd w wierszu 2 kolumna 528, albo odwrotnie. Przeważnie idzie się pogubić w miejscach zamykania elementu /> jeśli masz ukośniki w swoim XMLu na przykład trzymasz tam jakieś ścieżki które zawierają takie znaki to często można zauważyć że ten element nie jest poprawnie zamknięty. Druga opcja. Ja mam program który w XMLu trzyma zapytania SQLowe i znaki > < <= >= itp są niedozwolone podczas deserializacji trzeba je zamieniać na reprezentacje HTML &gt; = >

0

Przeanalizowałem dokładnie ten błąd i wychodzi mi, że deserializacja wysypuje się w miejscu poniżej, które zaznaczyłem (po przeczytaniu kolejnego znacznika "clients"). Klasę mam zdefiniowaną jak poniżej. Czy ktoś mógłby mi wytłumaczyć dlaczego to się sypie w tym miejscu?

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.example.org/ResellerAPI/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
	<SOAP-ENV:Body>
		<ns1:getClientsResponse>
			<getClientsResponse xsi:type="ns1:clientDetailsArray">
				<count xsi:type="xsd:int">70</count>
				<clients xsi:type="ns1:clientDetails">
					<clientID xsi:type="xsd:int">1266</clientID>
					<billingDetails xsi:type="ns1:clientBillingDetails">
						<firstname xsi:type="xsd:string"/>
						<name xsi:type="xsd:string">Klient - 793</name>
						<street xsi:type="xsd:string">brak danych</street>
						<house xsi:type="xsd:string"/>
						<apartment xsi:type="xsd:string"/>
						<zip xsi:type="xsd:string">00-000</zip>
						<city xsi:type="xsd:string">brak danych</city>
						<state xsi:type="xsd:string"/>
						<country xsi:type="xsd:string">Polska</country>
						<nip xsi:type="xsd:string">1234567819</nip>
						<bankaccount xsi:type="xsd:string"/>
						<tariffID xsi:type="xsd:int">203</tariffID>
					</billingDetails>
					<contactDetails xsi:type="ns1:clientContactDetails">
						<email xsi:type="xsd:string"/>
					</contactDetails>
					<resellerID xsi:type="xsd:int">76</resellerID>
					<externalID xsi:type="xsd:string">ATM</externalID>
				</clients>
				<clients xsi:type="ns1:clientDetails">   <<<<========================
					<clientID xsi:type="xsd:int">1267</clientID>
					<billingDetails xsi:type="ns1:clientBillingDetails">
						<firstname xsi:type="xsd:string"/>
						<name xsi:type="xsd:string">Klient - 793</name>
						<street xsi:type="xsd:string">brak danych</street>
						<house xsi:type="xsd:string"/>
						<apartment xsi:type="xsd:string"/>
						<zip xsi:type="xsd:string">00-000</zip>
						<city xsi:type="xsd:string">brak danych</city>
						<state xsi:type="xsd:string"/>
						<country xsi:type="xsd:string">Polska</country>
						<nip xsi:type="xsd:string">1234567819</nip>
						<bankaccount xsi:type="xsd:string"/>
						<tariffID xsi:type="xsd:int">203</tariffID>
					</billingDetails>
					<contactDetails xsi:type="ns1:clientContactDetails">
						<email xsi:type="xsd:string"/>
					</contactDetails>
					<resellerID xsi:type="xsd:int">76</resellerID>
					<externalID xsi:type="xsd:string">ATM</externalID>
				</clients>
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "0.5.0.0")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.SoapTypeAttribute(Namespace="http://www.example.org/ResellerAPI/")]
public partial class clientDetailsArray
{
    
    private int countField;
    
    private clientDetails[] clientsField;
    
    /// <remarks/>
    public int count
    {
        get
        {
            return this.countField;
        }
        set
        {
            this.countField = value;
        }
    }
    
    /// <remarks/>
    public clientDetails[] clients
    {
        get
        {
            return this.clientsField;
        }
        set
        {
            this.clientsField = value;
        }
    }
}
0

Ok, po dokładniejszym zdebugowaniu znalazłem taki błąd:

Nie można przypisać obiektu typu clientDetails do obiektu typu clientDetails[]

czyli, że format tego co zwraca web serwis po deserializacji nie jest typem tablicowym na jaki powinien być rzutowany. Jako, że nie znam się na SOAPie i nie za bardzo w obecnych czasach chce mi się to zgłębiać to prosiłbym kogoś o wskazanie jak powinna wyglądać powyższa odpowiedź, żeby się to poprawnie deserialozowało jako tablica clientDetails.

1

To nie jest bezpośrednio problem z SOAP tylko z serializacją do xml i bynajmniej w dzisiejszych czasach to ciągle jest potrzebna wiedza, bo json'a wszędzie się nie wepchnie.
WCF korzysta z DataContractSerializer, a on serializuje kolekcje w następujący sposób:

<kolekcja>
   <item></item> 
   <item></item>
   <item></item>
</kolekcja>

czyli wewnątrz elementu kolekcji są tylko te same tagi, natomiast u Ciebie wewnątrz elementu "getClientsResponse" są dwa rodzaje elementów "count" i "clients" .

<getClientsResponse >
     <count></count>
     <clients></clients>
     <clients></clients>
</getClientsResponse >

więc jeśli problem ma być rozwiązany po stronie serwisu, to albo trzeba się pozbyć elementu count z getClientsResponse (ale wtedy też wsdl sie zmieni) , albo opakować wszystkie elementy clients w dodatkowy element.

0

Ok, dzięki za pomoc. Teraz już wiem z czym muszę walczyć.

0

Trochę powalczyłem z problemem i doszedłem do momentu, w którym już nie wiem co dalej robić.

  1. Mam web serwis, z którego generuję klasy proxy.
  2. Poprawiam sobie te klasy zgodnie z tym co zasugerował mi neves, żeby zgadzały się z tym co dostaję w odpowiedzi na requesty.
  3. Jeżeli teraz wyślę odpowiednio spreparowane zapytanie za pomocą WebClienta, wytnę z odpowiedzi SOAP Envelope, a ciało odpowiedzi próbuję deserializować za pomocą wygenerowanych klas proxy to wszystko działa poprawnie.
  4. Natomiast jeżeli zrobię to po bożemu i użyję klienta z wygenerowanej klasy proxy to XmlSerilizerReader do deserlializacji tablicy clientDetails[] generuje taką metodę, którą zamiast deserilizować tablicę zwraca null:
        object Read610_Array() {
            // dummy array method
            UnknownNode(null);
            return null;
        }

Jak przeszukałam google to znalazłem tylko coś takiego https://referencesource.microsoft.com/#System.Xml/System/Xml/Serialization/XmlSerializationReader.cs,2259 czyli tak jakby przy SOAPie i tablicach zaiast generować kod do deserializacji generowało "dummy array method" i nie wiedziało co z tym robić.
Ma ktoś pomysł co robię źle, bo nie wierzę, że tego się nie da zrobić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1