1

我正在通过 .Net 解决方案调用第三方的 AXIS Web 服务

通过以下 WSDL 文件向我的 VS 项目添加了服务参考(服务位置已被删除,因为它是一种受限使用)

<?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 捕获),但是在调用“chargeSubscriber”之后创建了实际响应对象(typeof StatusInfo),但值为零(对于 int 属性)和空字符串(对于字符串属性.)

这是在 Fiddler 中捕获的响应 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>

我已经读过某些命名空间和命名引用不匹配可能是一个问题,但我无法找到哪个。任何帮助表示赞赏。

4

2 回答 2

2

我能够通过创建一个客户端消息检查器来操纵响应,如下所述:

如何绕过 WCF 缺少预览

连同@SixtoSeaz 建议的 SO 答案:

所以回答

在客户端消息检查器的“AfterReceiveReply”方法中,我通过在引用 multiRef 项的每个节点上分配 InnerXml 来更改 SOAP 响应。然后,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);
        }
    }

}

然后将 Behavior 分配给 EndPoint(服务引用为 PMGReference)

MyBehavior behavior = new MyBehavior();
PMGReference.PremiumChargingPortTypeClient client = new PMGReference.PremiumChargingPortTypeClient();
client.Endpoint.Behaviors.Add(behavior);
于 2012-04-10T16:35:21.087 回答
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,该 XML 使用 WCF 序列化程序无法理解的 href/multiref 约定对。如果您能够更改服务配置,请查看此表单帖子以了解如何避免这种类型的编码。另一种选择可能是采用生成的服务数据合同并按照此SO 答案手动修改它们。

于 2012-04-09T20:23:44.390 回答