2012-04-09 3 views
1

Я звоню веб-службу AXIS третьей стороны через решение .NetSOAP объект Response не заселен

Добавлена ​​служба Ссылку на мой VS Project с помощью следующих файлов WSDL (место службы было удалено, так как это ограниченное использование)

<?xml version="1.0" encoding="UTF-8"?> 
<wsdl:definitions 
    name="PremiumCharging" 
    targetNamespace="http://premiumcharging.verisign.com" 
    xmlns:pmg="http://types.premiumcharging.verisign.com" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:tns="http://premiumcharging.verisign.com" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <wsdl:types> 
    <xsd:schema 
     targetNamespace="http://types.premiumcharging.verisign.com" 
     xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
     xmlns:pmg="http://types.premiumcharging.verisign.com" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
     <xsd:complexType name="UserInfo"> 
     <xsd:sequence> 
      <xsd:element name="aggregatorId" type="xsd:int"/> 
      <xsd:element name="pwd" type="xsd:string"/> 
      <xsd:element name="version" type="xsd:string"/> 
     </xsd:sequence> 
     </xsd:complexType> 
     <xsd:complexType name="StatusInfo"> 
     <xsd:sequence> 
      <xsd:element name="errorCode" type="xsd:int"/> 
      <xsd:element name="errorDescription" type="xsd:string"/> 
      <xsd:element name="transactionId" type="xsd:int"/> 
     </xsd:sequence> 
     </xsd:complexType> 
    </xsd:schema> 
    </wsdl:types> 
    <wsdl:message name="chargeSubscriberResponse"> 
    <wsdl:part name="chargeSubscriberReturn" type="pmg:StatusInfo"/> 
    </wsdl:message> 
    <wsdl:message name="chargeSubscriberRequest"> 
    <wsdl:part name="user" type="pmg:UserInfo"/> 
    <wsdl:part name="mdn" type="xsd:string"/> 
    <wsdl:part name="productId" type="xsd:string"/> 
    <wsdl:part name="shortCode" type="xsd:string"/> 
    <wsdl:part name="carrierId" type="xsd:int"/> 
    <wsdl:part name="chargeId" type="xsd:string"/> 
    <wsdl:part name="msgtxid" type="xsd:string"/> 
    </wsdl:message> 
    <wsdl:portType name="PremiumChargingPortType"> 
    <wsdl:operation name="chargeSubscriber"> 
     <wsdl:input message="tns:chargeSubscriberRequest"/> 
     <wsdl:output message="tns:chargeSubscriberResponse"/> 
    </wsdl:operation> 
    </wsdl:portType> 
    <wsdl:binding name="PremiumChargingBinding" type="tns:PremiumChargingPortType"> 
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
    <wsdl:operation name="chargeSubscriber"> 
     <soap:operation/> 
     <wsdl:input> 
     <soap:body parts="user mdn productId shortCode carrierId chargeId msgtxid" use="literal"/> 
     </wsdl:input> 
     <wsdl:output> 
     <soap:body parts="chargeSubscriberReturn" use="literal" /> 
     </wsdl:output> 
    </wsdl:operation> 
    </wsdl:binding> 
    <wsdl:service name="PremiumCharging"> 
    <wsdl:port binding="tns:PremiumChargingBinding" name="PremiumChargingPort"> 
     <soap:address location="...location removed..."/> 
    </wsdl:port> 
    </wsdl:service> 
</wsdl:definitions> 

Я способен генерировать запрос и получить ответ (захваченное с помощью Fiddler), но реальный объект ответа (TypeOf StatusInfo) после вызова «chargeSubscriber» создается, но с нулевыми значениями (межд свойства) и пустую строку (для свойства строки.)

Это пример XML ответа захваченного в Скрипач:

<?xml version="1.0" encoding="utf-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <soapenv:Body> 
    <chargeSubscriberResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
     <chargeSubscriberReturn href="#id0"/> 
    </chargeSubscriberResponse> 
    <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns1:StatusInfo" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://types.premiumcharging.verisign.com"> 
     <errorCode href="#id1"/> 
     <errorDescription xsi:type="soapenc:string">Non-Carrier MIN</errorDescription> 
     <transactionId href="#id2"/> 
    </multiRef> 
    <multiRef id="id2" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">2216</multiRef> 
    <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">-105</multiRef> 
    </soapenv:Body> 
</soapenv:Envelope> 

Я прочитал, что некоторые пространства имен и имен ссылки несоответствие может быть проблемой, но я не могу найти который. Любая помощь приветствуется.

ответ

2

я был в состоянии управлять ответ путем создания клиента Message Inspector, как описано здесь:

How to Get Around WCFs Lack of a preview

Вместе с @SixtoSeaz предложил SO Ответ:

SO Answer

И в методе "AfterReceiveReply" из Cli инспектор сообщений Я изменил ответ SOAP, назначив InnerXml на каждом узле, который ссылается на элемент multiRef. Затем объект Response StatusInfo получал правильные значения, заполненные по мере необходимости.

Поведение и ClientMessageInspector:

public class MyBehavior : IEndpointBehavior 
{ 
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     clientRuntime.MessageInspectors.Add(new MyMessageInspector()); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
    } 
} 

public class MyMessageInspector : IClientMessageInspector 
{ 
    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.LoadXml(reply.ToString()); 

     List<XmlElement> items = new List<XmlElement>(); 
     Dictionary<string, XmlElement> multiRefs = new Dictionary<string,XmlElement>(); 

     InspectNodes(doc.DocumentElement, items, multiRefs); 

     FixNodes(items, multiRefs); 

     MemoryStream ms = new MemoryStream(); 

     XmlWriter writer = XmlWriter.Create(ms); 
     doc.WriteTo(writer); 
     writer.Flush(); 
     ms.Position = 0; 

     XmlReader reader = XmlReader.Create(ms); 
     reply = Message.CreateMessage(reader, int.MaxValue, reply.Version); 
    } 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     return null; 
    } 

    private static void InspectNodes(XmlElement element, List<XmlElement> items, Dictionary<string, XmlElement> multiRefs) 
    { 
     string val = element.GetAttribute("href"); 
     if (val != null && val.StartsWith("#id")) 
      items.Add(element); 
     else if (element.Name == "multiRef") 
      multiRefs[element.GetAttribute("id")] = element; 

     foreach (XmlNode node in element.ChildNodes) 
     { 
      XmlElement child = node as XmlElement; 
      if (child != null) 
       InspectNodes(child, items, multiRefs); 
     } 

    } 


    private static void FixNodes(List<XmlElement> items, Dictionary<string, XmlElement> multiRefs) 
    { 
     // Reverse order so populate the id refs into one single element. This is only a solution in relation to the WSDL definition. 
     for (int x = items.Count - 1; x >= 0; x--) 
     { 
      XmlElement element = items[x]; 

      string href = element.GetAttribute("href"); 
      if (String.IsNullOrEmpty(href)) 
       continue; 

      if (href.StartsWith("#")) 
       href = href.Remove(0, 1); 

      XmlElement multiRef = multiRefs[href]; 

      if (multiRef == null) 
       continue; 

      element.RemoveAttribute("href"); 
      element.InnerXml = multiRef.InnerXml; 

      multiRef.ParentNode.RemoveChild(multiRef as XmlNode); 
     } 
    } 

} 

А затем присвоить поведение на конечную точку (Service Reference является PMGReference)

MyBehavior behavior = new MyBehavior(); 
PMGReference.PremiumChargingPortTypeClient client = new PMGReference.PremiumChargingPortTypeClient(); 
client.Endpoint.Behaviors.Add(behavior); 
1

Это определение XML схемы:

<xsd:complexType name="StatusInfo"> 
    <xsd:sequence> 
     <xsd:element name="errorCode" type="xsd:int"/> 
     <xsd:element name="errorDescription" type="xsd:string"/> 
     <xsd:element name="transactionId" type="xsd:int"/> 
    </xsd:sequence> 
    </xsd:complexType> 

должен производить XML, который выглядит следующим образом (и что WCF ожидает):

<StatusInfo> 
     <errorCode>-105</errorCode> 
     <errorDescription>Non-Carrier MIN</errorDescription> 
     <transactionId>2216</transactionId> 
    </StatusInfo> 

Служба Java создает XML, который использует конвенционную пару href/multiref, который не понимается сериализатором WCF. Посмотрите на это form post, чтобы узнать, как избежать такого типа кодирования, если вы можете изменить конфигурацию службы. Другим вариантом может быть взять сгенерированные контракты данных услуг и вручную изменять их по линии этого SO answer.

+0

У меня нет доступа к службе AXIS (третья сторона), чтобы избежать ответы, отправляющие multiRef, как предлагает ваш форум. Поэтому, к сожалению, это не то решение, которое мне нужно. – Quintium

+0

В этом случае вам придется бороться с ручной модификацией ваших сгенерированных классов контрактов данных, чтобы «понять» соглашение multiRef по строкам ссылки, добавленной в мой ответ. Я не думаю, что использование привязки специально для Axis из коллекции [WCF Express Interop] (http://wcf.codeplex.com/wikipage?title=WCF%20Express%20Interop%20Bindings) поможет, но это может стоить попробуйте. –

+0

Также см. Http://www.tomergabel.com/GettingWCFAndApacheAxisToBeFriendly.aspx.Можете ли вы спросить у провайдера, есть ли у них конечная точка, которая предоставляет Document/Literal вместо RPC-кодированного SOAP? – JamieSee