未填充SOAP响应对象

时间:2012-04-09 20:03:14

标签: c# wcf wsdl axis

我通过.Net解决方案呼叫第三方的AXIS网络服务

通过以下WSDL文件为我的VS Project添加了服务引用(服务位置已被删除,因为它是受限制的用法)

<?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>

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

2 个答案:

答案 0 :(得分:2)

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

How to Get Around WCFs Lack of a preview

与@SixtoSeaz一起建议SO答案:

SO Answer

在Client Message Inspector的方法“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);
        }
    }

}

然后将行为分配给EndPoint(服务参考是PMGReference)

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

答案 1 :(得分: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服务正在创建使用WCF序列化程序无法理解的常规href / multiref对的XML。如果能够更改服务配置,请查看此form post以了解如何避免此类编码。另一个选择是获取生成的服务数据合同,并按照SO answer.

的方式手动修改它们