Category Archives: Mashup

ScriptUtil.LoadAssemblyFromUrl() is Obsolete

The ScriptUtil.LoadAssemblyFromUrl method was marked obsolete in v10.2.1.0 HF32. A workaround for M3 scripts using the method is to replace with the following code:

var assembly = Assembly.Load(WebReader.GetRequestBinary(url));

In between version 10.2.1.0.333 (HF32) and 10.2.1.0.385 (HF42) the obsolete method will
fail in silence and just return null.

This has been changed in 10.2.1.0.389 (HF43) and an InvalidOperationException will be thrown when calling the method.

JSON support in REST data service – Part III

Create, Update or Delete a User

In the third post we continue to use the fake online REST service to add operations to create, update and delete a user.

Mashup_REST_JSON_DELPATCHPUT

We add three DataOperation declarations to create, update and delete a user and set the OutputType to be JSON to easily show the request response in a textbox as a text string. The online service will return a correct response but no changes will actually be done in the service database, this is just for testing purposes.

<mashup:DataOperation Name="CreateUserPost">
    <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users" />
    <mashup:DataParameter Key="REST.InputJsonTemplate" Value="{StaticResource PostTemplate}" />
    <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
    <mashup:DataParameter Key="REST.HttpMethod" Value="POST" />
    <mashup:DataParameter Key="REST.InputType" Value="json" />
    <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
</mashup:DataOperation>
<mashup:DataOperation Name="UpdateUserPost">
    <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/{id}" />    
    <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
    <mashup:DataParameter Key="REST.HttpMethod" Value="PUT" />
    <mashup:DataParameter Key="REST.InputType" Value="json" />
    <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
</mashup:DataOperation>
<mashup:DataOperation Name="DeleteUser">
    <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts/{id}" />
    <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
    <mashup:DataParameter Key="REST.HttpMethod" Value="DELETE" />
    <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
</mashup:DataOperation>

We also add a button for each operation with a trigger event. All the property values for the current item the DataPanel will be added in the request body, so just declare the Parameter bindings for values that may change.

<Button DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="5" Content="Update User">
   <Button.CommandParameter>
      <mashup:Events>
         <mashup:Event TargetName="UserDetails" SourceEventName="Click" TargetEventName="UpdateUserPost">
         <mashup:Parameter TargetKey="email" Value="{Binding ElementName=CEmail, Path=Text}" Type="String" />
         <mashup:Parameter TargetKey="website" Value="{Binding ElementName=CWebsite, Path=Text}" Type="String" />
         <mashup:Parameter TargetKey="phone" Value="{Binding ElementName=CPhone, Path=Text}" Type="String" />
         </mashup:Event>
      </mashup:Events>
   </Button.CommandParameter>
</Button>

 

Here is the Mashup code if you would like to try it out.

<Grid Margin="15,10,15,15" 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" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms" xmlns:sys="clr-namespace:System;assembly=mscorlib">
   <Grid.RowDefinitions>
      <RowDefinition Height="1*" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="1*" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="1*" />
      <ColumnDefinition Width="10" />
      <ColumnDefinition Width="1*" />
   </Grid.ColumnDefinitions>
   <Grid.Resources>
      <x:String x:Key="PostTemplate"><![CDATA[      
               { 
                 "name": "{name}",
                 "username": "{username}",
                 "email": "{email}",
                 "address": {
                    "street": "{street}",
                    "suite": "{suite}",
                    "city": "{city}",
                    "zipcode": "{zipcode}",
                    "geo": {
                       "lat": "0.0",
                       "lng": "0.0"
                    }
                 },
                 "phone": "{phone}",
                 "website": "{website}",
                 "company": {
                    "name": "{companyName}",
                    "catchPhrase": "{companyCatchPhrase}",
                    "bs": "{companyBs}"
                 }                 
               }
            ]]></x:String>
   </Grid.Resources>
   <mashup:DataListPanel DockPanel.Dock="Top" Name="UsersList" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3">
      <mashup:DataListPanel.DataService>
         <mashup:DataService Type="REST">
            <mashup:DataService.Operations>
               <mashup:DataOperation Name="List">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/" />
                  <mashup:DataParameter Key="REST.OutputType" Value="DataItem" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
               </mashup:DataOperation>
            </mashup:DataService.Operations>
         </mashup:DataService>
      </mashup:DataListPanel.DataService>
      <mashup:DataListPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup" TargetEventName="List" />
            <mashup:Event SourceName="UsersList" TargetName="UserDetails" SourceEventName="CurrentItemChanged" TargetEventName="Get">
               <mashup:Parameter SourceKey="id" TargetKey="userId" Type="Numeric" />
            </mashup:Event>
         </mashup:Events>
      </mashup:DataListPanel.Events>
      <DockPanel LastChildFill="False">
         <ListView DockPanel.Dock="Top" Name="ListViewCompany" ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
            <ListView.View>
               <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
                  <GridView.Columns>
                     <GridViewColumn Header="Company" DisplayMemberBinding="{Binding [company].[name]}" />
                     <GridViewColumn Header="City" DisplayMemberBinding="{Binding [address].[city]}" />
                     <GridViewColumn Header="Name" DisplayMemberBinding="{Binding [name]}" />
                     <GridViewColumn Header="Email" DisplayMemberBinding="{Binding [email]}" />
                     <GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
                     <GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
                  </GridView.Columns>
               </GridView>
            </ListView.View>
         </ListView>
      </DockPanel>
   </mashup:DataListPanel>
   <mashup:DataPanel Grid.Row="0" Grid.Column="2" Grid.RowSpan="1" Name="UserDetails">
      <mashup:DataPanel.DataService>
         <mashup:DataService Type="REST">
            <mashup:DataService.Operations>
               <mashup:DataOperation Name="Get">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/{userId}" />
                  <mashup:DataParameter Key="REST.OutputType" Value="DataItem" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
               </mashup:DataOperation>
               <mashup:DataOperation Name="CreateUserPost">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users" />
                  <mashup:DataParameter Key="REST.InputJsonTemplate" Value="{StaticResource PostTemplate}" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
                  <mashup:DataParameter Key="REST.HttpMethod" Value="POST" />
                  <mashup:DataParameter Key="REST.InputType" Value="json" />
                  <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
               </mashup:DataOperation>
               <mashup:DataOperation Name="UpdateUserPost">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/{id}" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
                  <mashup:DataParameter Key="REST.HttpMethod" Value="PUT" />
                  <mashup:DataParameter Key="REST.InputType" Value="json" />
                  <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
               </mashup:DataOperation>
               <mashup:DataOperation Name="DeleteUser">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts/{id}" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
                  <mashup:DataParameter Key="REST.HttpMethod" Value="DELETE" />
                  <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
               </mashup:DataOperation>
            </mashup:DataService.Operations>
         </mashup:DataService>
      </mashup:DataPanel.DataService>
      <mashup:DataPanel.Events>
         <mashup:Events></mashup:Events>
      </mashup:DataPanel.Events>
      <Grid Margin="10,0,10,0">
         <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="24" />
            <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
         <DockPanel Grid.Row="1" LastChildFill="False">
            <TextBlock DockPanel.Dock="Left" Text="Company" Width="55" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CCompany" Width="220" Margin="5" Text="{Binding [company].[name]}" />
         </DockPanel>
         <DockPanel Grid.Row="3">
            <TextBlock DockPanel.Dock="Left" Text="Name" Width="55" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CName" Width="220" Margin="5" Text="{Binding [name]}" />
            <TextBlock DockPanel.Dock="Left" Text="UserName" Width="60" Margin="0,0,10,0" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CUserName" Margin="5" Text="{Binding [username]}" />
         </DockPanel>
         <DockPanel Grid.Row="5">
            <TextBlock DockPanel.Dock="Left" Text="Email" Width="55" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CEmail" Width="220" Margin="5" Text="{Binding [email]}" />
            <TextBlock DockPanel.Dock="Left" Text="Website" Width="60" Margin="0,0,10,0" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CWebsite" Margin="5" Text="{Binding [website]}" />
         </DockPanel>
         <DockPanel Grid.Row="7" LastChildFill="False">
            <TextBlock DockPanel.Dock="Left" Text="Phone" Width="55" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CPhone" Width="220" Margin="5" Text="{Binding [phone]}" />
         </DockPanel>
         <DockPanel Grid.Row="9">
            <TextBlock DockPanel.Dock="Left" Text="Catch" Width="55" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CCatch" Width="220" Margin="5" Text="{Binding [company].[catchPhrase]}" />
            <TextBlock DockPanel.Dock="Left" Text="BS" Width="60" Margin="5" VerticalAlignment="Center" />
            <TextBox DockPanel.Dock="Left" Name="CBS" Margin="5" Text="{Binding [company].[bs]}" />
         </DockPanel>
         <DockPanel Grid.Row="11">
            <Button DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="5" Content="Add User">
               <Button.CommandParameter>
                  <mashup:Events>
                     <mashup:Event TargetName="UserDetails" SourceEventName="Click" TargetEventName="CreateUserPost">
                        <mashup:Parameter TargetKey="name" Value="{Binding ElementName=CName, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="companyName" Value="{Binding ElementName=CCompany, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="userName" Value="{Binding ElementName=CUserName, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="email" Value="{Binding ElementName=CEmail, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="website" Value="{Binding ElementName=CWebsite, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="phone" Value="{Binding ElementName=CPhone, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="companyCatchPhrase" Value="{Binding ElementName=CCatch, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="companyBs" Value="{Bindng ElementName=CBS, Path=Text}" Type="String" />
                     </mashup:Event>
                  </mashup:Events>
               </Button.CommandParameter>
            </Button>
            <Button DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="5" Content="Update User">
               <Button.CommandParameter>
                  <mashup:Events>
                     <mashup:Event TargetName="UserDetails" SourceEventName="Click" TargetEventName="UpdateUserPost">
                        <mashup:Parameter TargetKey="email" Value="{Binding ElementName=CEmail, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="website" Value="{Binding ElementName=CWebsite, Path=Text}" Type="String" />
                        <mashup:Parameter TargetKey="phone" Value="{Binding ElementName=CPhone, Path=Text}" Type="String" />
                     </mashup:Event>
                  </mashup:Events>
               </Button.CommandParameter>
            </Button>
            <Button DockPanel.Dock="Top" HorizontalAlignment="Right" Margin="5" Content="Delete User">
               <Button.CommandParameter>
                  <mashup:Events>
                     <mashup:Event TargetName="UserDetails" SourceEventName="Click" TargetEventName="DeleteUser">
                        <mashup:Parameter TargetKey="id" Value="{Binding ElementName=UsersList, Path=CurrentItem[id]}" />
                     </mashup:Event>
                  </mashup:Events>
               </Button.CommandParameter>
            </Button>
         </DockPanel>
      </Grid>
   </mashup:DataPanel>
   <DockPanel Grid.Row="1" Grid.Column="2" Grid.RowSpan="2" VerticalAlignment="Stretch">
      <TextBlock DockPanel.Dock="Top" Text="Server Response:" Width="140" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Left" />
      <TextBox Name="ServerResponse" DockPanel.Dock="Top" Text="{Binding ElementName=UserDetails, Path=DataContext[json]}" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Top" TextWrapping="Wrap" AcceptsReturn="True" />
   </DockPanel>
</Grid>

 

JSON support in REST data service – Part II

Post the User Post with a JSON Template

In the previous part we used the REST data service to fetch a set of users in JSON format and present them in a list view and as a JSON text string. In this example we call the same service to get related user information and send a request to add new information. The fake online service we use returns a correct JSON response but will not create anything in the database of the service. Smart Office 10.2.1.0.367 HF38 is required.

 

Mashup_REST_JSON_POST

First we define another data operation to create a user post by sending a JSON request,

<mashup:DataOperation Name="CreateUserPost">
    <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts" />
    <mashup:DataParameter Key="REST.InputJsonTemplate" Value="{StaticResource PostTemplate}" />
    <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
    <mashup:DataParameter Key="REST.HttpMethod" Value="POST" />
    <mashup:DataParameter Key="REST.InputType" Value="json" />
    <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
</mashup:DataOperation>

and we also add a Send button containing an event that collects required values and trigger the CreateUserPost operation.

<Button DockPanel.Dock="Top" HorizontalAlignment="Right" Margin="5" Content="Send">
   <Button.CommandParameter>
            <mashup:Events>
                 <mashup:Event TargetName="PostComment" SourceEventName="Click" TargetEventName="CreateUserPost">
                 <mashup:Parameter TargetKey="title" Value="{Binding ElementName=PostTitle, Path=Text}" />
                 <mashup:Parameter TargetKey="body" Value="{Binding ElementName=PostBody, Path=Text}" />
                 <mashup:Parameter TargetKey="userId" Value="{Binding ElementName=UsersList, Path=CurrentItem[id]}" />
             </mashup:Event>
         </mashup:Events>
    </Button.CommandParameter>
</Button>

A press of the Send button collects the parameters and creates a JSON parameter body to be part of the server request. The body will look like this.

{
   "title": "test",
   "body": "test",
   "userId": "2",
}

Notice that the userId is a string but for the service we call, assume it must be a numeric value. Imagine that we need to customize the body for the service request since the default one will not do the trick.

Let’s create a template for the body that will result in the following JSON.

{
   "title": "test",
   "body": "test",
   "userId": 2,
}

First we add the template as a resource in the Mashup code within a CDATA block.

<Grid.Resources>   
      <x:String x:Key="PostTemplate"><![CDATA[      
               { 
                 "title": "{title}",
                 "body": "{body}",
                 "userId": {userId}
               }
            ]]></x:String>
   </Grid.Resources>

Next step is to add a template reference in the data operation declaration using the InputJsonTemplate parameter .

<mashup:DataOperation Name="CreateUserPost">
    <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts" />
    <mashup:DataParameter Key="REST.InputJsonTemplate" Value="{StaticResource PostTemplate}" />

Done! This is all that is needed to customize the server request body instead of getting the default one generated.

The full Mashup code if you would like to try it out.

<Grid Margin="15,10,15,15" 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" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms" xmlns:sys="clr-namespace:System;assembly=mscorlib">
	<Grid.RowDefinitions>
		<RowDefinition Height="1*" />
		<RowDefinition Height="10" />
		<RowDefinition Height="1*" />
		<RowDefinition Height="Auto" />
	</Grid.RowDefinitions>
	<Grid.ColumnDefinitions>
		<ColumnDefinition Width="1*" />
		<ColumnDefinition Width="10" />
		<ColumnDefinition Width="1*" />
	</Grid.ColumnDefinitions>
	<Grid.Resources>
		<x:String x:Key="PostTemplate"><![CDATA[		
					{ 
					  "title": "{title}",
					  "body": "{body}",
					  "userId": {userId}
					}
				]]></x:String>
	</Grid.Resources>
	<mashup:DataListPanel Name="UsersList" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3">
		<mashup:DataListPanel.DataService>
			<mashup:DataService Type="REST">
				<mashup:DataService.Operations>
					<mashup:DataOperation Name="List">
						<mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/" />
						<mashup:DataParameter Key="REST.OutputType" Value="DataItem" />
						<mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
					</mashup:DataOperation>
				</mashup:DataService.Operations>
			</mashup:DataService>
		</mashup:DataListPanel.DataService>
		<mashup:DataListPanel.Events>
			<mashup:Events>
				<mashup:Event SourceEventName="Startup" TargetEventName="List" />
			</mashup:Events>
		</mashup:DataListPanel.Events>
		<ListView Name="ListViewCompany" ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
			<ListView.View>
				<GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
					<GridView.Columns>
						<GridViewColumn Header="Company" DisplayMemberBinding="{Binding [company].[name]}" />
						<GridViewColumn Header="City" DisplayMemberBinding="{Binding [address].[city]}" />
						<GridViewColumn Header="Name" DisplayMemberBinding="{Binding [name]}" />
						<GridViewColumn Header="Email" DisplayMemberBinding="{Binding [email]}" />
						<GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
						<GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
					</GridView.Columns>
				</GridView>
			</ListView.View>
		</ListView>
	</mashup:DataListPanel>
	<mashup:DataPanel Grid.Row="0" Grid.Column="2" Grid.RowSpan="3" Name="PostComment">
		<mashup:DataPanel.DataService>
			<mashup:DataService Type="REST">
				<mashup:DataService.Operations>
					<mashup:DataOperation Name="ListUserPost">
						<mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts/?userid={userId}" />
						<mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
					</mashup:DataOperation>
					<mashup:DataOperation Name="CreateUserPost">
						<mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/posts" />
						<mashup:DataParameter Key="REST.InputJsonTemplate" Value="{StaticResource PostTemplate}" />
						<mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
						<mashup:DataParameter Key="REST.HttpMethod" Value="POST" />
						<mashup:DataParameter Key="REST.InputType" Value="json" />
						<mashup:DataParameter Key="REST.OutputType" Value="application/json" />
						<!-- Change to DataItem to use return data -->
					</mashup:DataOperation>
				</mashup:DataService.Operations>
			</mashup:DataService>
		</mashup:DataPanel.DataService>
		<mashup:DataPanel.Events>
			<mashup:Events>
				<mashup:Event SourceEventName="Startup" TargetEventName="List" />				
			</mashup:Events>
		</mashup:DataPanel.Events>
		<Grid Margin="10,0,10,0">
			<Grid.RowDefinitions>
				<RowDefinition Height="Auto" />
				<RowDefinition Height="10" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="10" />
				<RowDefinition Height="Auto" />
			</Grid.RowDefinitions>
			<DockPanel Grid.Row="0">
				<TextBlock DockPanel.Dock="Left" Text="Post a comment as" Margin="0,0,5,0" />
				<TextBlock DockPanel.Dock="Left" Text="{Binding ElementName=UsersList, Path=CurrentItem[name]}" />
			</DockPanel>
			<DockPanel Grid.Row="2">
				<TextBlock DockPanel.Dock="Top" Text="Title" Margin="5" />
				<TextBox DockPanel.Dock="Top" Name="PostTitle" Margin="5" />
				<TextBlock DockPanel.Dock="Top" Text="Content" Margin="5" />
				<TextBox DockPanel.Dock="Top" Name="PostBody" Margin="5" />
				<Button DockPanel.Dock="Top" HorizontalAlignment="Right" Margin="5" Content="Send">
					<Button.CommandParameter>
						<mashup:Events>
							<mashup:Event TargetName="PostComment" SourceEventName="Click" TargetEventName="CreateUserPost">
								<mashup:Parameter TargetKey="title" Value="{Binding ElementName=PostTitle, Path=Text}" />
								<mashup:Parameter TargetKey="body" Value="{Binding ElementName=PostBody, Path=Text}" />
								<mashup:Parameter TargetKey="userId" Value="{Binding ElementName=UsersList, Path=CurrentItem[id]}" />
							</mashup:Event>
						</mashup:Events>
					</Button.CommandParameter>
				</Button>
			</DockPanel>
			<DockPanel Grid.Row="4">
				<TextBlock DockPanel.Dock="Top" Text="Server Response:" Width="140" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Left" />
				<TextBox Height="120" DockPanel.Dock="Top" Text="{Binding [json]}" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" VerticalContentAlignment="Top" TextWrapping="Wrap" AcceptsReturn="True" />
			</DockPanel>
		</Grid>
	</mashup:DataPanel>
</Grid>

 

JSON support in REST data service – Part I

In Smart Office 10.2.1.0.367 HF38 there is support for JSON when calling a REST data service from a Mashup. In this blog post I’m going to use a fake online REST service to demonstrate how it’s done.

The response data from the REST service call can be converted into a DataItem hierarchy or as a JSON string. This example will fetch a listing of users from the service and present them in a Mashup ListView and in a TextBox as a JSON string, side-by-side.

Mashup_REST_JSON_LIST

The Mashup XAML syntax will be the same as before when doing a REST service call. All you need to do now is set the REST.AcceptHeader parameter to application/json.
The REST.OutputType determines if the data response is available to the Mashup as an object hierarchy or as a JSON string. Use the value ‘DataItem’ to get DataItem hierarchy or set ‘application/json’ for a JSON string. If REST.OutputType is not set the default will be a DataItem hierarchy.

<mashup:DataListPanel.DataService>
    <mashup:DataService Type="REST">
        <mashup:DataService.Operations>
            <mashup:DataOperation Name="List">
                <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/" />
                <mashup:DataParameter Key="REST.OutputType" Value="DataItem" />
                <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
            </mashup:DataOperation>
        </mashup:DataService.Operations>
    </mashup:DataService>
</mashup:DataListPanel.DataService>

To set the first column in the ListView to the company name use the binding below.

DisplayMemberBinding="{Binding [company].[name]}"

To access the JSON string when that is set as output type simply bind to ‘json’.

Text="{Binding [json]}"

Here is the complete Mashup code if you would like to try it out.

<Grid Margin="15,10,15,15" 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" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms" xmlns:sys="clr-namespace:System;assembly=mscorlib">
   <Grid.RowDefinitions>
      <RowDefinition Height="1*" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="1*" />
      <ColumnDefinition Width="10" />
      <ColumnDefinition Width="1*" />
   </Grid.ColumnDefinitions>
   <mashup:DataListPanel DockPanel.Dock="Top" Name="UsersList" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3">
      <mashup:DataListPanel.DataService>
         <mashup:DataService Type="REST">
            <mashup:DataService.Operations>
               <mashup:DataOperation Name="List">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/" />
                  <mashup:DataParameter Key="REST.OutputType" Value="DataItem" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
               </mashup:DataOperation>
            </mashup:DataService.Operations>
         </mashup:DataService>
      </mashup:DataListPanel.DataService>
      <mashup:DataListPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup" TargetEventName="List" />
         </mashup:Events>
      </mashup:DataListPanel.Events>
      <DockPanel LastChildFill="False">
         <ListView DockPanel.Dock="Top" Name="ListViewCompany" ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
            <ListView.View>
               <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
                  <GridView.Columns>
                     <GridViewColumn Header="Company" DisplayMemberBinding="{Binding [company].[name]}" />
                     <GridViewColumn Header="City" DisplayMemberBinding="{Binding [address].[city]}" />
                     <GridViewColumn Header="Name" DisplayMemberBinding="{Binding [name]}" />
                     <GridViewColumn Header="Email" DisplayMemberBinding="{Binding [email]}" />
                     <GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
                     <GridViewColumn Header="Longitude" DisplayMemberBinding="{Binding [address].[geo].[lng]}" />
                  </GridView.Columns>
               </GridView>
            </ListView.View>
         </ListView>
      </DockPanel>
   </mashup:DataListPanel>
   <mashup:DataPanel Grid.Row="0" Grid.Column="2" Name="JsonString">
      <mashup:DataPanel.DataService>
         <mashup:DataService Type="REST">
            <mashup:DataService.Operations>
               <mashup:DataOperation Name="List">
                  <mashup:DataParameter Key="REST.BaseAddress" Value="https://jsonplaceholder.typicode.com/users/" />
                  <mashup:DataParameter Key="REST.AcceptHeader" Value="application/json" />
                  <mashup:DataParameter Key="REST.OutputType" Value="application/json" />
               </mashup:DataOperation>
            </mashup:DataService.Operations>
         </mashup:DataService>
      </mashup:DataPanel.DataService>
      <mashup:DataPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup" TargetEventName="List" />
         </mashup:Events>
      </mashup:DataPanel.Events>
      <Grid Margin="10,0,10,0">
         <TextBox Text="{Binding [json]}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" AcceptsReturn="True" VerticalContentAlignment="Top" TextWrapping="Wrap" />
      </Grid>
   </mashup:DataPanel>
</Grid>

Mashup Converter with Zero Focus

In Smart Office 10.2.1.0.367 HF 38 there is a new value converter that converts a number to a string label focusing on zero; equals, above or below.

Mashup_Converter_Zero

The default behavior for the value converter is:

value < 0 returns NA
value = 0 returns No
value > 0 returns Yes
otherwise for non numeric input it returns an empty string

 Text="{Binding ElementName=InputValue, Path=Text, Converter={utils:AboveBelowZeroConverter}}"

 

The return labels for negative, zero and positive values can be customized by adding the ConverterParameter in the data binding containing three strings separated by _ or – characters. If the parameter is incorrect formatted the converter falls back to the default values and logs the issue if the log is in DEBUG mode.

Setting the following ConverterParameter will change the return labels to become Negative, Zero, Positive.

 Text="{Binding ElementName=InputValue, Path=Text, Converter={utils:AboveBelowZeroConverter}, ConverterParameter=Negative_Zero-Positive}"

 

Here is a the full code for you to try the converter out.

<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" xmlns:utils="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI">
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
   </Grid.ColumnDefinitions>
   <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="10" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
   </Grid.RowDefinitions>
   <TextBlock Grid.Row="0" Text="Test of AboveBelowZeroConverter. Default: Return NA for negative values, No for zero and Yes for positive values, otherwise empty string" Margin="10" />
   <DockPanel Grid.Row="2" Margin="10" LastChildFill="False">
      <TextBlock DockPanel.Dock="Left" Text="Enter a value:" Margin="5" />
      <TextBox DockPanel.Dock="Left" Name="InputValue" Height="24" Width="60" VerticalAlignment="Top" HorizontalAlignment="Stretch" />
      <TextBlock DockPanel.Dock="Left" FontSize="16" Foreground="Green" Text="{Binding ElementName=InputValue, Path=Text, Converter={utils:AboveBelowZeroConverter}}" Margin="5" />
   </DockPanel>
   <DockPanel Grid.Row="3" Margin="10" LastChildFill="False">
      <TextBlock DockPanel.Dock="Top" Text="Custom return value. Set binding 'ConverterParameter=negative zero-positive' (Three strings separated by _ or - character, if invalid converter falls back to default)" Margin="5" />
      <TextBlock DockPanel.Dock="Top" FontSize="16" Foreground="Green" Text="{Binding ElementName=InputValue, Path=Text, Converter={utils:AboveBelowZeroConverter}, ConverterParameter=Negative_Zero-Positive}" Margin="150,5,5,5" />
   </DockPanel>
</Grid>

 

 

 

Snooping my Mashup for Missing Data

Sometimes when you’re developing a Mashup it happens that the data you’re expecting to appear in a databound control is not showing up. There’s a small developer tool named Snoop that will help you examine the runtime visual tree of a Windows Presentation Foundation (WPF) user interface.

Snoop WPF Spy utility

Download

Launch Smart Office and open the Mashup Designer. In this post we use an example from the Help menu named Document found in the Infor Document Management category.

ISOIDMMashupEx

Run the example, save it and search for any Document Type e g CLM_Document. Depending on the available data, it will look something like this in the running Mashup.

ISOIDMMashupExRunning

Now it’s time to launch the Snoop utlitity tool. It has a slim and narrow window. ISOSnoop

Drag the Snoop hair-cross (marked yellow) and drop it on your Mashup window. A new window will open and present the visual tree representation of the user interface in the left-hand panel and the details of the selected UI element in the right-hand panel. Below the details panel there’s a preview panel to render and show the selected UI element (if actived with the power button).

Press down the CTRL- and SHIFT- key simultaneously while you drag the mouse over the Mashup window. The control beneath the mouse will be selected and decorated with a red border and the corresponding element in the Snoop visual tree view will be highlighted and selected. Navigation can also be done directly in the tree-view by selecting UI element nodes.

ISO IDM Snoop

ISOIDMMashupExAttrSelected

Let’s examine the bound data for the document attribute panel. Use the mouse or locate and select the LangAttrList (ListBox) in the visual tree. Scroll down in the Properties list until you find ItemsSource property for the ListBox control.

ISO IDM Snoop ItemsSource

It’s now possible to drill-down into the data collection with a double-click on the value of ItemsSource, in this example [System.Windows.Data.CompositeCollection]. Now you see that the collection contains 1 item: this[0]. You can continue to drill-down with a double-click on the value this[0] to see the details of the item or navigate back up by clicking the up-arrow button (marked yellow).

ISO IDM Snoop Drill-down and up

In this case the ListBox will apply a template for each document attribute found in a collection item. Select the attrTemplate under the ListBoxItem to show its properties. In most template cases the data will be in the DataContext property of the element. Select the Data Context tab for a dedicated view of the property, in this case the DataContext is a piece of XML.
Note that there’s a Binding Errors column in the properties list that will show an error message if the data binding declaration for a UI element property is wrong and the data source can’t be found.

ISO IDM Snoop Data Context

We’ve only scratched the surface of the Snoop tool functionality but it’s the basics needed to investige why your data is not showing up.

MIPanel enhancements for the Mashup Designer

Smart Office Hot Fix 12 was just released (10.2.0.88). We have some new features and in this post I’ll cover a changes to the MIPanel that will make it easier to chain calls together. The new features for the MIPanel are:

  • New events: CompletedSuccessfully and CompletedWithError
  • New properties: ShowMessagesInDialog and ShowMessagesInStatusBar
  • New result property that you can bind to: MIPanel.ErrorInfo. This property will contain error information from the first failed transaction. It has ErrorMessage, ErrorCode, ErrorField, Transaction and Program.

Properties

For those of you who have use conditions on events you can now consider using the new events. An example scenario would be updating item information and if that transaction is successful you would like to run another transaction. In that case you can trigger the second update based on CompletedSuccessfully instead of UpdateCompleted.

Item update

Please note that I have some hard coded values in the example. I did have to configure MandatoryInputFields since I’m not changing the item number as the behavior of the MIPanel is to only send updated data to an MITransaction. The use of the event is pretty straight forward. For numeric input I used the NumericTextBox. You will not find it in the Designer UI but it is part of Smart Office so you can use it if you edit the XAML. Here is 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" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms">
	<Grid.ColumnDefinitions>
		<ColumnDefinition Width="1*" />
	</Grid.ColumnDefinitions>
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto" />
		<RowDefinition Height="1*" />
		<RowDefinition Height="Auto" />
		<RowDefinition Height="Auto" />
	</Grid.RowDefinitions>
	<m3:MIPanel Name="ItemDetail" Grid.Row="0" Margin="0,15,0,0">
		<m3:MIPanel.Events>
			<mashup:Events>
				<mashup:Event SourceEventName="Startup" TargetEventName="Get">
					<mashup:Parameter TargetKey="ITNO" Value="AC-001" />
					<mashup:Parameter TargetKey="FACI" Value="010" />
				</mashup:Event>
			</mashup:Events>
		</m3:MIPanel.Events>
		<Grid>
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="Auto" />
				<ColumnDefinition Width="10" />
				<ColumnDefinition Width="200" />
				<ColumnDefinition Width="15" />
				<ColumnDefinition Width="*" />
			</Grid.ColumnDefinitions>
			<Grid.RowDefinitions>
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="10" />
				<RowDefinition Height="Auto" />
			</Grid.RowDefinitions>
			<Label Content="Item number:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="15" Text="{Binding [ITNO]}" IsEnabled="false" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Name:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="30" Text="{Binding [ITDS]}" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Description 2:" Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="60" Text="{Binding [FUDS]}" Grid.Row="4" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Avergage cost:" Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<ui:NumericTextBox MaxLength="10" Name="inputAPPR" Text="{Binding [APPR]}" Grid.Row="6" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Button Name="SaveButton" Content="Update" Grid.Row="8" Grid.Column="2" HorizontalAlignment="Right">
				<Button.CommandParameter>
					<mashup:Events>
						<mashup:Event TargetName="ItemDetail" SourceEventName="Click" TargetEventName="Update" Debug="True">
							<mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
							<mashup:Parameter TargetKey="FUDS" Value="{Binding [FUDS]}" />
							<mashup:Parameter TargetKey="ITDS" Value="{Binding [ITDS]}" />
						</mashup:Event>
					</mashup:Events>
				</Button.CommandParameter>
			</Button>
		</Grid>
		<m3:MIPanel.DataSources>
			<m3:MIDataSourceList>
				<m3:MIDataSource Program="MMS200MI" Transaction="Get" Type="Get" InputFields="ITNO" OutputFields="ITNO,ITDS,FUDS" />
				<m3:MIDataSource Program="MMS200MI" Transaction="GetItmFac" Type="Get" InputFields="FACI,ITNO" OutputFields="APPR" />
				<m3:MIDataSource Program="MMS200MI" Transaction="UpdItmBasic" Type="Update" InputFields="ITNO,ITDS,FUDS" MandatoryInputFields="ITNO" />
			</m3:MIDataSourceList>
		</m3:MIPanel.DataSources>
	</m3:MIPanel>
	<m3:MIPanel Name="SecondUpdatePanel">
		<m3:MIPanel.Events>
			<mashup:Events>
				<mashup:Event SourceName="ItemDetail" SourceEventName="CompletedSuccessfully" TargetEventName="Update" Debug="True">
					<mashup:Event.Conditions>
						<mashup:Conditions>
							<mashup:Condition SourceValue="{Binding ElementName=inputAPPR, Path=Text}" TargetValue="{Binding ElementName=ItemDetail, Path=[MMS200MI.GetItemFac.APPR]}" Operator="NotEqual" />
						</mashup:Conditions>
					</mashup:Event.Conditions>
					<mashup:Parameter SourceKey="ITNO" />
					<mashup:Parameter TargetKey="FACI" Value="010" />
					<mashup:Parameter SourceKey="APPR" />
				</mashup:Event>
			</mashup:Events>
		</m3:MIPanel.Events>
		<m3:MIPanel.DataSource>
			<m3:MIDataSource Program="MMS200MI" Transaction="UpdItmFac" Type="Update" InputFields="FACI,ITNO,APPR" />
		</m3:MIPanel.DataSource>
	</m3:MIPanel>

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

Unfortunately the Documentation in the Mashup Designer is not updated with the new properties etc as there has been no update to the Mashup Designer. You can always find the latest API documentation in the Smart Office SDK.

Please note that these events applies to update transactions. You set the type of the transaction on the MIDataSource. We will automatically try and determine the type based on the transaction name.

For a full listing of changes made on this release, refer to Lawson KB 1626878 / M3 KB 1623430.