lula / ngx-soap

Simple SOAP client for Angular
MIT License
66 stars 61 forks source link

Build error TypeError: Cannot read property 'elements' of undefined #9

Open minau87 opened 6 years ago

minau87 commented 6 years ago

Hey Lula,

so, I'm getting this error:

Build error TypeError: Cannot read property 'elements' of undefined at MessageElement.postProcess (wsdl.js:1211) at OperationElement.postProcess (wsdl.js:1822) at PortTypeElement.postProcess (wsdl.js:1864) at BindingElement.postProcess (wsdl.js:1906) at ServiceElement.postProcess (wsdl.js:1980) at eval (wsdl.js:160) at ZoneDelegate.invoke (zone.js:388) at Object.onInvoke (core.js:4733) at ZoneDelegate.invoke (zone.js:387) at Zone.run (zone.js:138)

followed by:

Error: Uncaught (in promise): Error: TypeError: Cannot read property 'options' of undefined Error: TypeError: Cannot read property 'options' of undefined at eval (soap.js:9)

I do receive a proper response, namely a WSDL document from my service.

Any ideas? Let me know if you need additional information.

Thanks in advance.

lula commented 6 years ago

hello @minau87 can you please share your code ? At least part of it where you get the WSDL and you call the operation.

minau87 commented 6 years ago

Sure. I basically do exactly what you do in your example.

ngOnInit() {
    // 1. Get WSDL content
    this.http.get('http://localhost:8080/ws/highscore?wsdl').subscribe(response => {
      if (response && response.text()) {
        // Here I can even log the response.text()/WSDL to the console...
        // 2. Create the SOAP-client
        this.soap.createClient(response.text()).then((client: Client) => {
          this.client = client;
        });
      }
    });
}

That's all I do at the moment. I'm not even calling operations yet.

lula commented 6 years ago

I had to test it with the proxy, but I guess it doesn't matter that much. Changed the example app in order to get WSDL from http://www.dneonline.com/calculator.asmx?WSDL (/calculator is the proxy):

this.http.get('/calculator/calculator.asmx?WSDL').subscribe(response => {
      if (response && response.text()) {
        this.soap.createClient(response.text()).then(client => {
...

It worked for me. So probably the WSDL has something that breaks the parsing, or it isn't well formed.

minau87 commented 6 years ago

Thank you for your response.

So probably the WSDL has something that breaks the parsing, or it isn't well formed.

That's what I suspected to be the problem. Do you mind having a look at the WSDL?

<!--
 Published by JAX-WS RI (http://jax-ws.java.net). RI's version is Metro/2.3.1 (UNKNOWN_BRANCH-false; 2015-01-15T16:53:43+0100) JAXWS-RI/2.2.10 JAXWS-API/2.2.11 JAXB-RI/2.2.10-b140802.1033 JAXB-API/2.2.12-b140109.1041 svn-revision#unknown. 
-->
<!--
 Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is Metro/2.3.1 (UNKNOWN_BRANCH-false; 2015-01-15T16:53:43+0100) JAXWS-RI/2.2.10 JAXWS-API/2.2.11 JAXB-RI/2.2.10-b140802.1033 JAXB-API/2.2.12-b140109.1041 svn-revision#unknown. 
-->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://snakegame/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://snakegame/" name="HighscoreImplService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://snakegame/" schemaLocation="http://localhost:8080/ws/highscore?xsd=1"/>
    </xsd:schema>
  </types>
  <message name="highscore">
    <part name="parameters" element="tns:highscore"/>
  </message>
  <message name="highscoreResponse">
    <part name="parameters" element="tns:highscoreResponse"/>
  </message>
  <portType name="Highscore">
    <operation name="highscore">
      <input wsam:Action="http://snakegame/Highscore/highscoreRequest" message="tns:highscore"/>
      <output wsam:Action="http://snakegame/Highscore/highscoreResponse" message="tns:highscoreResponse"/>
    </operation>
  </portType>
  <binding name="HighscoreImplPortBinding" type="tns:Highscore">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="highscore">
    <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="HighscoreImplService">
    <port name="HighscoreImplPort" binding="tns:HighscoreImplPortBinding">
      <soap:address location="http://localhost:8080/ws/highscore"/>
    </port>
  </service>
</definitions>

Is there anything that could cause the issue?

Thanks again for your time!

lula commented 6 years ago

I believe the problem is the import of the schema, that means more than a simple file parsing. The wsdl is basically a string which is then parsed and used. Everything needed must be on the same wsdl, as of now. In the future, having more time to work on it, this can be something to think about though.

As I can see the schema in on localhost anyway, can you perhaps try to build a wsdl which is just in one file?

minau87 commented 6 years ago

Hey, that's exactly what I was trying to check. I tried to build the client from a different WSDL file and it worked just fine, with the schema being within that same file. In my case, as you already pointed out, the schema is in a seperate file.

I'll try and figure out how to do that with the tool (jax-ws, Metro) I'm using and report back.

Thanks again!

lula commented 6 years ago

Thanks to you! Cheers!

minau87 commented 6 years ago

So, the tool I'm using (again, that's jax-ws and Metro for anyone seeing this at a later point in time) supports a -inlineSchemas parameter for it's WSDL generation process. It does exactly what was needed here in this case, but unfortunately the WSDL doesn't get served in that form for whatever reason.

What I ended up doing was the following:

ngOnInit() {
    // 1. Get WSDL content
    this.http.get('http://localhost:8080/ws/highscore?wsdl').subscribe(response => {
      if (response && response.text()) {
        // 2. Get the schema
        this.http.get('http://localhost:8080/ws/highscore?xsd=1').subscribe(schemaResponse => {
          if (schemaResponse && schemaResponse.text()) {
            // 3. Extract schema. Necessary because ngx-soap currently doesn't work with referenced schemas.
            const schema = this.extractSchema(schemaResponse.text());
            // 4. Replace the reference to the schema with the actual schema
            const wsdl = this.replaceSchema(response.text(), schema);
            // 5. Create the SOAP-client
            this.soap.createClient(wsdl).then((client: Client) => {
              this.client = client;
            });
          }
        });
      }
    });
  }

I basically wrote two methods. One for extracting the schema needed from the specific ressource referenced. The second method simply replaces the reference with the schema. That's not necessarily beautiful, but works for now.

TrimA74 commented 6 years ago

I am having the same issue with my custom soap service

My WSDL :

<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI (http://jax-ws.java.net). RI's version is Metro/2.4.0 (wsit240-7e98ff4; 2017-08-03T21:19:54+0200) JAXWS-RI/2.3.0 JAXWS-API/2.3.0 JAXB-RI/2.3.0 JAXB-API/2.3.0 svn-revision#unknown. --><!-- Generated by JAX-WS RI (http://javaee.github.io/metro-jax-ws). RI's version is Metro/2.4.0 (wsit240-7e98ff4; 2017-08-03T21:19:54+0200) JAXWS-RI/2.3.0 JAXWS-API/2.3.0 JAXB-RI/2.3.0 JAXB-API/2.3.0 svn-revision#unknown. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://example/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://example/" name="DistanceService">
<types>
<xsd:schema>
<xsd:import namespace="http://example/" schemaLocation="http://localhost:8080/TD1_war_exploded/services/Distance?xsd=1"/>
</xsd:schema>
</types>
<message name="distance">
<part name="parameters" element="tns:distance"/>
</message>
<message name="distanceResponse">
<part name="parameters" element="tns:distanceResponse"/>
</message>
<message name="price">
<part name="parameters" element="tns:price"/>
</message>
<message name="priceResponse">
<part name="parameters" element="tns:priceResponse"/>
</message>
<portType name="Distance">
<operation name="distance">
<input wsam:Action="http://example/Distance/distanceRequest" message="tns:distance"/>
<output wsam:Action="http://example/Distance/distanceResponse" message="tns:distanceResponse"/>
</operation>
<operation name="price">
<input wsam:Action="http://example/Distance/priceRequest" message="tns:price"/>
<output wsam:Action="http://example/Distance/priceResponse" message="tns:priceResponse"/>
</operation>
</portType>
<binding name="DistancePortBinding" type="tns:Distance">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="distance">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="price">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="DistanceService">
<port name="DistancePort" binding="tns:DistancePortBinding">
<soap:address location="http://localhost:8080/TD1_war_exploded/services/Distance"/>
</port>
</service>
</definitions>

@minau87 What code is behind your this.extractSchema and this.replaceSchema functions ?

YassineNachti commented 6 years ago

@minau87 could you please share your two methods: extractSchema(); replaceSchema(); I would greatly appreciate the help.

liuxh0 commented 6 years ago

Hi @lula,

We also encountered a problem when using wdsl with import. Is it planned to support this?

Since I am new to wsdl, I don't know if it is complicated to add the support. Does node-soap support this? If so, I'd really like to help.

Thanks.

lula commented 6 years ago

Hey guys, sorry for embarassing late reply. I'm afraid implementing this feature might not be so easy. Moreover, lately I have been very busy at work and still I have no time for anything else.

So @liuxh0, if you want to help that would be very appreciated 😄 . I haven't checked already if node-soap support this but that would probably be the first thing to look into.

liuxh0 commented 6 years ago

Let me have a try. It may take some time since I'm not very familiar with SOAP...

BTW I am not really a fan of SOAP :(

minau87 commented 6 years ago

@YassineNachti @TrimA74 Sorry guys, was pretty inactive the last couple of months. Unfortunately I can't seem to find the code. Did this for a course at university a while back and I might have deleted it after submitting, dunno. Seeing that the ticket is still open though, this might still be relevant to you or someone else, here's what I did:

What you can see me doing first is

// 1. Get WSDL content
    this.http.get('http://localhost:8080/ws/highscore?wsdl').subscribe(response => {

this. Here I'm basically just getting the WSDL. Within that, the schema is only referenced. Right now, this is what doesn't work.

I worked around the issue by making a (second) seperate http-call (notice the different URLs) where I get only the schema (the one that's just referenced in the response above):

this.http.get('http://localhost:8080/ws/highscore?xsd=1').subscribe(schemaResponse => {

Then I simply took what was needed from that (thus the extractSchema() method) and replaced it with the part where the schema is referenced in the original response/WSDL (the replaceSchema() method). Like, I basically replaced the text. I don't have exactly in mind how I did that, but the last part shouldn't be hard to figure out. I think there was a little bit of trial and error involved until I had a well-formed WSDL, but that's it.

Hope this helps.

lula commented 6 years ago

Hello everyone!

I worked a little on the repo during the weekend and I eventually decided to recreate the project almost from scratch with Angular 6 CLI:

It seems to work with the usual basic example but I haven't yet tried with more complex ones. Please check it out and share know your outcome: just follow the simple instructions on this doc to download and locally test the new branch.

@liuxh0 thanks!

BTW I am not really a fan of SOAP :(

Ahahah!! Me neither, but alas sometimes I have to deal with SOAP at work. So, rather for fun then for a real need, here I am 😄!

lula commented 6 years ago

Guys, you can check the latest version from npm.

Cheers!

jjdarias commented 5 years ago

Hi everybody! Does anyone have the solution for access to methods in JAX-WS Metro ?? I as @TrimA74 and @minau87 have a different structure in WSDL than calculator.wsdl example. I appreciate your help!

Seems like this code is the solution: // 3. Extract schema. Necessary because ngx-soap currently doesn't work with referenced schemas. const schema = this.extractSchema(schemaResponse.text()); // 4. Replace the reference to the schema with the actual schema const wsdl = this.replaceSchema(response.text(), schema);

Anybody could replicate it?

Thanks in advance!