Calling a Web Service using WS and REST Data Services

In Lawson Smart Office 9.1.3 we introduced the REST data service for mashups. In version 10.0.0 we introduced support for SOAP based web services. In 10.0.1 we introduced some new configuration options that will help you to connect to the web services out there.

There are different options available when consuming SOAP web services in Mashups.

1. Data Service and WS
2. Data Service and REST
3. Process Server with TriggerPanel

Data Service and WS is the use of generated proxy code combined with WCF in order to call web services. The advantage with using generated proxy code is that typing comes for free. Any result will be in form of objects according to the service definition. Using Data Service and REST involves using a XML template of the complete SOAP request with replacement variables and submitting the template XML as one request. The template XML can easily be extracted from a WSDL using a free tool such as SoapUI.

I recently recieved an email with two web services that was hard to consume via the WS Data Service. One problem was related to an issue in the configuration tool and the other web service was hard to consume becuase it returned a string that was XML. XML? Isn’t web services always xml? I’ll step you through the process of testing the web service using a tool and the data controls for Mashups.

The WSDLs are:
1. http://www.webservicex.net/CurrencyConvertor.asmx?WSDL
2. http://www.webservicex.net/stockquote.asmx?WSDL

Currency Converter
I usually start my testing by launching the Web service test tool available within Lawson Smart Office, tool://wstest.

I start by loading the WSDL and select the operation to test. Both web services are publically available. I enter the input USD and SEK and press test.

In LSO 10.0.0 you would have seen a message that the result object has no properties. And then you would have seen some strange data. Don’t dispair. It’s an issue with the test tool. In LSO 10.0.1 you will see that there is only one thing that is returned and that is a Double.

Anytime I get into trouble with testing the Web Service I turn to my favorite Web Service test tool – SoapUI. This is a must have if you are testing different REST and SOAP based services or developing your own services. It’s open source and free so just install it. In SoapUI you create a test project and point to the WSDL.

The result from testing ‘Request 1’ is shown in the image below. There you can see that the returned object is the convertion rate.

The convertion rate is returned and it is not wrapped in any result object. This means that the result will be available in the Mashup DataPanel as the Data property, the result from the operation. In many cases you can simply use the DataContext of the control and bind to {Binding .} or when you are interested in a property on the result then it is {Binding Path=PropertyName} or you bind to the DataPanel and it’s result using:

<!– detailPanelNameis the name of the DataPanel, list or detail–>
<Label Name="result" Content="{Binding Path=Data, ElementName=detailPanelName}" />

Here is what the final result looks like:

And here is the complete XAML:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI">
  <Grid.Resources>
  </Grid.Resources>

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <mashup:DataPanel Name="detail">
    <mashup:DataPanel.DataService>
      <mashup:DataService Type="WS">
        <mashup:DataService.Operations>
          <mashup:DataOperation Name="Read">
            <mashup:DataParameter Key="WS.Wsdl" Value="http://www.webservicex.net/CurrencyConvertor.asmx?WSDL" />
            <mashup:DataParameter Key="WS.Address" Value="http://www.webservicex.net/CurrencyConvertor.asmx" />
            <mashup:DataParameter Key="WS.Operation" Value="ConversionRate" />
            <mashup:DataParameter Key="WS.Contract" Value="CurrencyConvertorSoap" />
        <!--    <mashup:DataParameter Key="FromCurrency" Value="USD" />
            <mashup:DataParameter Key="ToCurrency" Value="ALL" />-->
          </mashup:DataOperation>
        </mashup:DataService.Operations>
      </mashup:DataService>
    </mashup:DataPanel.DataService>
    <Grid Margin="8">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <TextBlock Text="From Currency:" />
      <TextBox Grid.Column="1" Name="fromCurrency" />
      <TextBlock Grid.Row="1" Text="To Currency:" />
      <TextBox Grid.Row="1" Grid.Column="1" Name="toCurrency" />

      <TextBlock Grid.Row="2" Text="Result:" />
      <Label Grid.Row="2" Grid.Column="1" Name="result" Content="{Binding Path=Data, ElementName=detail}" />

      <Button Grid.Row="3" Grid.ColumnSpan="2" Margin="5" Content="Get convertion rate" Width="160" HorizontalAlignment="Right" Name="button">
        <Button.CommandParameter>
          <mashup:Events>
            <mashup:Event SourceEventName="Click" TargetEventName="Read" TargetName="detail" Debug="False">
              <mashup:Parameter TargetKey="ToCurrency" Value="{Binding Path=Text, ElementName=toCurrency}" />
              <mashup:Parameter TargetKey="FromCurrency" Value="{Binding Path=Text, ElementName=fromCurrency}" />
            </mashup:Event>
          </mashup:Events>
        </Button.CommandParameter>
      </Button>

    </Grid>
  </mashup:DataPanel>

  <ui:StatusBar Name="StatusBar" Grid.Row="2" Grid.Column="0" />
</Grid>

Stock quote
Time to check the other SOAP web service. I’ll open the Web service test tool and load the WSDL.
Now I can’t search for LWSN anymore so lets check out the stocks from Microsoft, MSFT.

Here is the result in the Web Service test tool.

My screenshot is from a 10.0.1 version of LSO. If you have something else you can bind to the Data property of the DataPanel and you will see the string. Seeing XML in a SOAP request means that they are returning a xml as a string and that string is defined as a string in the WSDL and not as different complex types. Now I want to know exactly what the response is so I test this service as well in SoapUI.

Here you can see a CDATA block and the beginning of the XML returned. Now this kind of SOAP web service is rather common. The developer use SOAP but as the result they have arbitrary XML. This xml cannot be converted to types and is there for not a good match for the WS data service. Here I have to use REST. However since it returns XML in a CDATA block I might be into trouble. When XML is parsed the value within the CDATA block is eqvivalent with the value of a text node. This means that the XML string will continure to be just and XML string within a XML document.

In version 10.0.1 we added a way to set the XPath to the element that has the XML string and then by setting REST.XPathNodeIsXmlDocument to true in the configuration. We also added the configuraiton option to set ContentType. This web service does not work with content type application/xml so you will not be able to run this mashup in previous versions of LSO (10.0.1 is required).

But if you find yourselft with a web service that returns a CDATA block you should try and set the REST.XPath to the node that has the CDATA block and then set REST.RemoveNamespace to true. This might create a XMLDocument from the node text.

My plan is to use the REST data service with a XML template where I specify the input XML. I could have used the exact same approach for the first web service. Becuase it has a simple structure I was only interested in getting the response as data. I do not care about it’s type for further processing in Mashup events.

If you care about performance you should use REST whenever possible. The reason is that the WS data service has two limitations. The WSDL has to be available and there is one download of the WSDL per LSO session. For REST the template XML is already embedded in the Mashup XAML.

Here is my template as a static resource:

<Grid.Resources>
 <x:String x:Key="templateStock">
  <![CDATA[
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET/">
   <soapenv:Header/>
   <soapenv:Body>
      <web:GetQuote>
         <web:symbol>{symbol}</web:symbol>
      </web:GetQuote>
   </soapenv:Body>
  </soapenv:Envelope>
  ]]>
 </x:String>
<Grid.Resources>

Note the {symbol} in the template. I’m going to send in an event parameter for symbol that will be automatically replaced in the XML.

Since I use REST I need to use XPaths for dealing with the data. I usually test my XPaths in this online test tool..

There are probably more efficeint ways to write the XPaths but I this case I also wanted to demonstrate how to find a node using the local name even if the node is in a default namespace.

Here is the result:

And the XAML:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI">
  <Grid.Resources>
    <x:String x:Key="templateStock">
         <![CDATA[
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET/">
   <soapenv:Header/>
   <soapenv:Body>
      <web:GetQuote>
         <web:symbol>{symbol}</web:symbol>
      </web:GetQuote>
   </soapenv:Body>
</soapenv:Envelope>
]]>
      </x:String>
  </Grid.Resources>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <!-- Form-->
      <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
    <TextBlock Text="Stock Quote" FontSize="18" Margin="8" />

<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="8,8,0,8">
<TextBlock Text="Symbol:" />
<TextBox Width="150" Name="textBoxSymbol" />
<Button Content="OK" Name="okButton">
      <Button.CommandParameter>
        <mashup:Events>
          <mashup:Event TargetName="detail" SourceEventName="Click" TargetEventName="Read">
             <!-- Here I pass in the symbol that is the replacement variable in template XML-->
            <mashup:Parameter TargetKey="symbol" Value="{Binding Path=Text, ElementName=textBoxSymbol}" />
          </mashup:Event>
        </mashup:Events>
      </Button.CommandParameter>
    </Button>
</StackPanel>
  <mashup:DataPanel Name="detail" Grid.Row="3">
    <mashup:DataPanel.DataService>
      <mashup:DataService Type="REST">
        <mashup:DataService.Operations>
          <mashup:DataOperation Name="Read">
            <mashup:DataParameter Key="REST.InputType" Value="XML" />
            <mashup:DataParameter Key="REST.InputXmlTemplate" Value="{StaticResource templateStock}" />
            <mashup:DataParameter Key="REST.HttpMethod" Value="POST" />
            <mashup:DataParameter Key="REST.BaseAddress" Value="http://www.webservicex.net/stockquote.asmx" />
            <mashup:DataParameter Key="REST.AcceptHeader" Value="text/xml" />
            <mashup:DataParameter Key="REST.RemoveNamespace" Value="false" />
            <mashup:DataParameter Key="REST.XPath" Value="//*[ local-name() = 'GetQuoteResponse']" />
            <mashup:DataParameter Key="REST.ContentType" Value="text/xml" />
            <mashup:DataParameter Key="REST.XPathNodeIsXmlDocument" Value="true" />
          </mashup:DataOperation>
        </mashup:DataService.Operations>
      </mashup:DataService>
    </mashup:DataPanel.DataService>
    <Grid Margin="8">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      <!-- Form-->
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Name:" />
      <!--<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding XPath=//Name/text()}" />-->
      <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding XPath=//Name/text()}" />
      <TextBlock Grid.Row="2" Grid.Column="0" Text="Last:" />
      <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding XPath=//Last/text()}" />
      <TextBlock Grid.Row="3" Grid.Column="0" Text="Date:" />
      <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding XPath=//Date/text()}" />
      <TextBlock Grid.Row="4" Grid.Column="0" Text="Change:" />
      <TextBlock Grid.Row="4" Grid.Column="1" Text="{Binding XPath=//Change/text()}" />
      <TextBlock Grid.Row="5" Grid.Column="0" Text="Returns:" />
      <TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Path=Data.InnerXml, ElementName=detail}" Height="100" Width="500" VerticalAlignment="top" HorizontalAlignment="Left" />
    </Grid>
  </mashup:DataPanel>
  <ui:StatusBar Name="StatusBar" Grid.Row="4" Grid.Column="0" />
</Grid>

Note that REST.XPathNodeIsXmlDocument is new in 10.0.1. For 9.1.3 and 10.0.o try and set REST.RemoveNamespace to true.

Check the code documentation (available under the help menu in the Mashup Designer) for RestDataService and WSDataService for more information on how to configure Data Service panels for REST or WS.

13 thoughts on “Calling a Web Service using WS and REST Data Services

  1. Jon

    Hi
    I try to figure out how to use POST to add a ticket in a application through the REST api and from a mashup form. Is this possible? How to build the xml to be sent?

    Reply
    1. karinpb Post author

      Hi,
      Sorry for the late reply. I must have missed your comment.
      It is possible to use a POST and submit the XML to be sent.
      You did not mention if your service requires authentication so I assume it’s accessable for everyone.
      You need to set REST.HttpMethod to POST. Then you can set an REST.InputXmlTemplate for example by adding it to the resources like below:

      Then you create replacement variables for the data that you would like to send and you specify those as parameters in the event which means that the MashupDataPanel will fill in the values from the event into your XMLTemplate and fill the form. If the code below is not visible check the API Documentation for RestDataService.KeyInputXmlTemplate

      <Grid.Resources>
          <x:String x:Key="EmployeeRequestTemplate">
          <![CDATA[        
              <Request Action="Load">
                  <Employee Number={EmployeeNumber}" />
              </Request>
          ]]>
          </x:String>
      <Grid.Resources>
      
      <mashup:DataParameter Key="REST.InputXmlTemplate" Value="{StaticResource EmployeeRequestTemplate}" />
      
      

      As for the MashupDataPanel it does not have to wrap the input form – it just has to exist on the Mashup – hidden – but accessible for events. Check out the API Documentation in the Mashup Designer and search for RestDataService. It is possible that you need to specify ContentType or AcceptHeader.

      Reply
  2. Jon

    Hi and thanx for your reply!

    I’ve found out how to POST, but as you commented, I need to validate access through at API-key. So far haven’t found a way to post a API-key, but thorugh fiddler, I see that my XML is correct. The workaround so far is to let the mashup call a script to POST the data to the REST-service. I try to create a ticket in the osTicket service system 😉

    Reply
  3. ZaherElShamy

    thanks for that helpful Post ,,, i want to know how to Call WS (which retrieves one row and two columns as a result ) with a button and then write the first Column in a Text Field on the Grid… here is my code
    i tested the WebService with the Tool and it is Working well

    Reply
    1. ZaherElShamy

      thanks for that helpful Post ,,, i want to know how to Call WS (which retrieves one row and two columns as a result ) with a button and then write the first Column in a Text Field on the Grid… here is my code
      i tested the WebService with the Tool and it is Working well

      Reply
      1. ZaherElShamy

        when i write that Code … with the click it takes the Value ” getItemNameResponseType”
        Label Grid.Row=”2″ Grid.Column=”1″ Name=”result” Content=”{Binding Path=Data, ElementName=detail}”

      2. karinpb Post author

        I’m sorry but there isn’t enough information. Try and get the binding to a ListView or DataGrid two work first. Then use index to get just the first row.

      3. karinpb Post author

        You should search for the tag to use to escape code. I can’t print it out so google it. And remember that tool://wstest will show you tips for bindings.

  4. Priyanka Nadgouda

    Hi,
    I am new to M3 Web Services(MWS) for M3 version 13.2 and still in the learning phase.

    Requirement: I want to edit values in textboxes in display program PPS200/E by calling it through Web service. Also, I want to store the modified values back into M3 database.

    My work so far: I have created a web service for display program PPS200 in MWS and deployed it on our local server. I have validated the Web service through SoapUI. I created dynamic web project in eclipse, but when I try to create web service client for it, I get the following error: “IWAB0237W The sample JSP client does not support arrays{0}:PPS200″. Kindly advise how to resolve the same.

    Question: How can we call M3 Web Services externally using Java and Tomcat server? If not, then how can we achieve this requirement through any other java-based applications?

    Thanks in advance.

    Reply
    1. karinpb Post author

      Hi,
      This is a question that is not related to Smart Office but I’ll try with what I know.
      The sample JSP is not suited for Web services that has arrays as input. If I remember the WSDL format for MWS you would need to make sure the WS is called correctly. The issue you have is eclipse specific and not related to the MWS. I would recommend generating java client stub classes and checking the WSDL for information on how to call it.

      Since MWS is like any standard SOAP WS you can call it from any client that supports SOAP web services so Java and Tomcat is fine.

      I thinke the input is an array where the first entry is the actual input. The documentation for MWS should have a code example or you should contact Infor Support. I recommend analyzing the example since any MWS M3 script would be similar.

      Reply
  5. HeikoM

    Hi,
    I am calling a M3 “Update” API by sending a GET query to the REST service:
    GET https://./m3api-rest/execute/OIS017MI/UpdBasePrice?PRRF=MYLIST&CUCD=EUR&FVDT=20170101&ITNO=MYITEM&SAPR=1.40 .

    This works fine when I have a value for my updated field, in this case SAPR (sales price)

    But is there any way to remove/blank out a field value (replace it with a zero-length string) ?

    I can not add a parameter like ‘XXXX=’ without a value, I retrieve the error message:
    ‘Xxxx ? does not exist’.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s