简体   繁体   English

.Net消耗的iSeries Web服务

[英].Net consuming iSeries web service

I am trying to consume an iseries web service with .Net. 我正在尝试使用.Net使用iseries Web服务。 I have had success communicating with other web services on the iSeries, but with this particular one, I am having a very strange issue. 我已经成功地与iSeries上的其他Web服务进行通信,但是对于这个特定的服务,我遇到了一个非常奇怪的问题。

Here is the wsdl of the web service from the iSeries. 这是来自iSeries的Web服务的wsdl。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://example.com/ZCntInfFr/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ZCntInfFr"
targetNamespace="http://example.com/ZCntInfFr/">
<wsdl:types>
    <xsd:schema targetNamespace="http://example.com/ZCntInfFr/">
        <xsd:element name="GetContactInfoOperation">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element name="ShipToAcct" minOccurs="1"
                        maxOccurs="1">
                        <xsd:simpleType>
                            <xsd:restriction base="xsd:string">
                                <xsd:length value="6"></xsd:length>
                            </xsd:restriction>
                        </xsd:simpleType>
                    </xsd:element>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
        <xsd:element name="GetContactInfoOperationResponse">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element name="Contacts"
                        type="tns:ContactsType" minOccurs="1" maxOccurs="1">
                    </xsd:element>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
        <xsd:complexType name="ContactDataType">
            <xsd:sequence maxOccurs="unbounded" minOccurs="0">
                <xsd:element name="ContactType" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="5"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactTypeDesc" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="50"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactName" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="25"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactTitle" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="20"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactEmail" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="128"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactPhone" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="15"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactExtension" minOccurs="0"
                    maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="5"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ContactFax" minOccurs="0" maxOccurs="1">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:minLength value="0"></xsd:minLength>
                            <xsd:maxLength value="15"></xsd:maxLength>
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
    </xsd:sequence>
        </xsd:complexType>
        <xsd:complexType name="ContactsType">
            <xsd:sequence maxOccurs="unbounded" minOccurs="0">
                <xsd:element name="ContactData" type="tns:ContactDataType" maxOccurs="1" minOccurs="0"></xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:schema>
</wsdl:types>
<wsdl:message name="GetContactInfoOperationRequest">
    <wsdl:part name="parameters" element="tns:GetContactInfoOperation"></wsdl:part>
</wsdl:message>
<wsdl:message name="GetContactInfoOperationResponse">
    <wsdl:part name="parameters" element="tns:GetContactInfoOperationResponse"></wsdl:part>
</wsdl:message>
<wsdl:portType name="ZCntInfFr">
    <wsdl:operation name="GetContactInfoOperation">
        <wsdl:input message="tns:GetContactInfoOperationRequest"></wsdl:input>
        <wsdl:output message="tns:GetContactInfoOperationResponse"></wsdl:output>
    </wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ZCntInfFrSOAP" type="tns:ZCntInfFr">
    <soap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="GetContactInfoOperation">
        <soap:operation
            soapAction="http://example.com/ZCntInfFr/GetContactInfoOperation" />
        <wsdl:input>
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>
<wsdl:service name="ZCntInfFr">
    <wsdl:port binding="tns:ZCntInfFrSOAP" name="ZCntInfFrSOAP">
        <soap:address location="http://server:8181/myrxs/ZCntInfFr" />
    </wsdl:port>
</wsdl:service>

When I test this in SoapUI, here is the request/response I receive: 当我在SoapUI中对此进行测试时,这是我收到的请求/响应:

SoapUI Request: SoapUI请求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:zcn="http://example.com/ZCntInfFr/">
   <soapenv:Header/>
   <soapenv:Body>
      <zcn:GetContactInfoOperation>
         <ShipToAcct>099039</ShipToAcct>
      </zcn:GetContactInfoOperation>
   </soapenv:Body>
</soapenv:Envelope>

SoapUI Response: SoapUI响应:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:zcn="http://example.com/ZCntInfFr/">
   <soapenv:Header/>
   <soapenv:Body>
      <zcn:GetContactInfoOperationResponse>
         <Contacts>
            <ContactData>
               <ContactType>ADMIN</ContactType>
               <ContactTypeDesc>Administrator</ContactTypeDesc>
               <ContactName>Name</ContactName>
               <ContactTitle/>
               <ContactEmail>Email</ContactEmail>
               <ContactPhone/>
               <ContactExtension/>
               <ContactFax/>
            </ContactData>
         </Contacts>
      </zcn:GetContactInfoOperationResponse>
   </soapenv:Body>
</soapenv:Envelope>

The response is exactly how I would expect it. 响应正是我所期望的。 Notice I am getting back one contact, which is correct. 请注意,我正在找回一个联系人,这是正确的。

When I call the iSeries web service from .Net here is the request/response I see when looking at Fiddler: 当我从.Net调用iSeries Web服务时,这是我在看Fiddler时看到的请求/响应:

.Net Request .Net请求

<?xml version="1.0" encoding="iso-8859-1"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetContactInfoOperation xmlns="http://www.mysitye.com/ZCntInfFr/">
            <ShipToAcct xmlns="">099039</ShipToAcct>
        </GetContactInfoOperation>
        </s:Body>
    </s:Envelope>

.Net Response .Net响应

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:zcn="http://example.com/ZCntInfFr/">
  <soapenv:Header/>
  <soapenv:Body>
    <zcn:GetContactInfoOperationResponse>
     <Contacts>
     </Contacts>
    </zcn:GetContactInfoOperationResponse>
  </soapenv:Body>
</soapenv:Envelope>

In this case, when I call it from .Net I receive an empty node. 在这种情况下,当我从.Net调用它时,我收到一个空节点。 No contacts. 没有联络人。

For completeness, here is proxy class I created from svcutil using: 为了完整起见,这是我使用以下方法从svcutil创建的代理类:

svcutil /n:*,Services.Web.Proxy.ISeriesContact /o:ContactProxy /s http://server:8181/ZCntInfFr.wsdl

Class: 类:

namespace Services.Web.Proxy.ISeriesContact
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace = "http://example.com/ZCntInfFr/", ConfigurationName = "Services.Web.Proxy.ISeriesContact.ZCntInfFr")]
    public interface ZCntInfFr
    {
        // CODEGEN: Parameter 'Contacts' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
        [System.ServiceModel.OperationContractAttribute(Action = "http://example.com/ZCntInfFr/GetContactInfoOperation", ReplyAction = "*")]
        [System.ServiceModel.XmlSerializerFormatAttribute()]
        [return: System.ServiceModel.MessageParameterAttribute(Name = "Contacts")]
        Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse GetContactInfoOperation(Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest request);

        [System.ServiceModel.OperationContractAttribute(Action = "http://example.com/ZCntInfFr/GetContactInfoOperation", ReplyAction = "*")]
        System.Threading.Tasks.Task<Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse> GetContactInfoOperationAsync(Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest request);
    }

    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://example.com/ZCntInfFr/")]
    public partial class ContactDataType
    {

        private string[] itemsField;

        private ItemsChoiceType[] itemsElementNameField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("ContactEmail", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactExtension", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactFax", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactName", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactPhone", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactTitle", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactType", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute("ContactTypeDesc", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
        public string[] Items
        {
            get
            {
                return this.itemsField;
            }
            set
            {
                this.itemsField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("ItemsElementName", Order = 1)]
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public ItemsChoiceType[] ItemsElementName
        {
            get
            {
                return this.itemsElementNameField;
            }
            set
            {
                this.itemsElementNameField = value;
            }
        }
    }

    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
    [System.SerializableAttribute()]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://example.com/ZCntInfFr/", IncludeInSchema = false)]
    public enum ItemsChoiceType
    {

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactEmail")]
        ContactEmail,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactExtension")]
        ContactExtension,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactFax")]
        ContactFax,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactName")]
        ContactName,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactPhone")]
        ContactPhone,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactTitle")]
        ContactTitle,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactType")]
        ContactType,

        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute(":ContactTypeDesc")]
        ContactTypeDesc,
    }

    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://example.com/ZCntInfFr/")]
    public partial class ContactsType
    {

        private ContactDataType[] contactDataField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("ContactData", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
        public ContactDataType[] ContactData
        {
            get
            {
                return this.contactDataField;
            }
            set
            {
                this.contactDataField = value;
            }
        }
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    [System.ServiceModel.MessageContractAttribute(WrapperName = "GetContactInfoOperation", WrapperNamespace = "http://example.com/ZCntInfFr/", IsWrapped = true)]
    public partial class GetContactInfoOperationRequest
    {

        [System.ServiceModel.MessageBodyMemberAttribute(Namespace = "http://example.com/ZCntInfFr/", Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string ShipToAcct;

        public GetContactInfoOperationRequest()
        {
        }

        public GetContactInfoOperationRequest(string ShipToAcct)
        {
            this.ShipToAcct = ShipToAcct;
        }
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    [System.ServiceModel.MessageContractAttribute(WrapperName = "GetContactInfoOperationResponse", WrapperNamespace = "http://example.com/ZCntInfFr/", IsWrapped = true)]
    public partial class GetContactInfoOperationResponse
    {

        [System.ServiceModel.MessageBodyMemberAttribute(Namespace = "http://example.com/ZCntInfFr/", Order = 0)]
        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public Services.Web.Proxy.ISeriesContact.ContactsType Contacts;

        public GetContactInfoOperationResponse()
        {
        }

        public GetContactInfoOperationResponse(Services.Web.Proxy.ISeriesContact.ContactsType Contacts)
        {
            this.Contacts = Contacts;
        }
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public interface ZCntInfFrChannel : Services.Web.Proxy.ISeriesContact.ZCntInfFr, System.ServiceModel.IClientChannel
    {
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class ZCntInfFrClient : System.ServiceModel.ClientBase<Services.Web.Proxy.ISeriesContact.ZCntInfFr>, Services.Web.Proxy.ISeriesContact.ZCntInfFr
    {

        public ZCntInfFrClient()
        {
        }

        public ZCntInfFrClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public ZCntInfFrClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ZCntInfFrClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ZCntInfFrClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
        Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse Services.Web.Proxy.ISeriesContact.ZCntInfFr.GetContactInfoOperation(Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest request)
        {
            return base.Channel.GetContactInfoOperation(request);
        }

        public Services.Web.Proxy.ISeriesContact.ContactsType GetContactInfoOperation(string ShipToAcct)
        {
            Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest inValue = new Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest();
            inValue.ShipToAcct = ShipToAcct;
            Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse retVal = ((Services.Web.Proxy.ISeriesContact.ZCntInfFr)(this)).GetContactInfoOperation(inValue);
            return retVal.Contacts;
        }

        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
        System.Threading.Tasks.Task<Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse> Services.Web.Proxy.ISeriesContact.ZCntInfFr.GetContactInfoOperationAsync(Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest request)
        {
            return base.Channel.GetContactInfoOperationAsync(request);
        }

        public System.Threading.Tasks.Task<Services.Web.Proxy.ISeriesContact.GetContactInfoOperationResponse> GetContactInfoOperationAsync(string ShipToAcct)
        {
            Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest inValue = new Services.Web.Proxy.ISeriesContact.GetContactInfoOperationRequest();
            inValue.ShipToAcct = ShipToAcct;
            return ((Services.Web.Proxy.ISeriesContact.ZCntInfFr)(this)).GetContactInfoOperationAsync(inValue);
        }
    }
}

I have enabled WCF tracing and nothing is sticking out in the .svclog file. 我已启用WCF跟踪,.svclog文件中没有任何内容。 I have been googling like mad and have seen that there might be some issues with minOccurs in the WSDL. 我一直在疯狂地搜寻,并且发现WSDL中的minOccurs可能存在一些问题。 My thought is that perhaps it is something to do with the deserialization process in .Net. 我的想法是,这可能与.Net中的反序列化过程有关。

As a side note, and an exercise, I was able to call the SOAP service using the WebClient object and I retrieved the correct raw XML with the contact in it. 作为附带说明和练习,我能够使用WebClient对象调用SOAP服务,并且检索了其中包含联系人的正确原始XML。 This also leads me to my thought that something is going on with deserialization. 这也使我想到反序列化正在发生。

I also tried to generate the proxy with wsdl.exe but I still go back an empty clients node. 我也尝试使用wsdl.exe生成代理,但是我仍然返回一个空的客户端节点。

One other thing I should mention is that when I add the reference to the iSeries web service to Service References in my project, I get exactly the same results: No contacts. 我应该提到的另一件事是,当我将对iSeries Web服务的引用添加到项目中的“服务引用”时,得到的结果完全相同:没有联系。

Any help, nudge, advice, or direction would be greatly appreciated. 任何帮助,推动,建议或指导将不胜感激。 I have been working on this for two days and I am still not fully understanding what is going on here. 我已经为此工作了两天,但我仍然没有完全了解这里发生的情况。

Your help is greatly appreciated. 非常感谢您的帮助。

Thanks. 谢谢。

So a shout out to bvstone. 所以向bvstone大喊。

It turns out that the iSeries developer was hand parsing the requests. 事实证明,iSeries开发人员正在手工解析请求。 So even though the request generation from SoapUI and from .Net were functionally equivalent, the structure was different. 因此,即使从SoapUI和.Net生成请求在功能上是等效的,其结构也不同。 This was not handled properly in the iSeries code. 在iSeries代码中未正确处理。

I'm no expert on the iSeries but I have suggested that we use standard xml libraries, if they exist for the iSeries to parse xml requests correctly. 我不是iSeries方面的专家,但是我建议我们使用标准xml库,如果iSeries可以使用它们来正确解析xml请求。

Thanks, bvstone for pointing me in the right direction. 谢谢bvstone向我指出正确的方向。

I have developed many services exposing and consuming data in iSeries and I seriously recommend Scott Klement HTTPAPI for this job. 我已经开发了许多服务,可以在iSeries中公开和使用数据,并且我强烈建议对此工作使用Scott Klement HTTPAPI Give it a try you won't regret it. 试试看,您不会后悔的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM