CEJson: https://ardjson.codeplex.com 
This link includes the before and after projects (full source) as a zip file.




Previous:
Ardjson – Part 1: A New IOT Project on Codeplex

The Sensor/Telemetry app as presented in Part 1 of this series could have been developed as new projects and developed from the ground up. With a functioning ToDo Tasks app communicating with Microsoft Azure Mobile Services, it was decided instead to “morph” the existing app into the new one.

A file compare app such as Beyond Compare (the one I use) is a useful tool for seeing the "wood for the trees". The tool was used to make a comparison of the before and and after solution projects. A screen capture of the files that were modified is:

image

  • Many of the changes were incremental.
  • Some functionality was extended, other functionality was added
  • Config.xml was added to the Shared project.
  • ToDo.cs was renamed TelemetryItem.cs and modified.
  • There was some renaming of programming entities.

[1] Customization of the Mobile Web Service Configuration

The first change involved using an XML configuration file to specify the Mobile Service name and its app key, which [1]means they could be changed without the apps being recompiled. To do this the file Config.xml was added the Shared project and code was added to App.xaml.cs to read those values in using Linq to XML. The instantiation of the mobile service class then uses those values. Note that this initialization must be placed after InitializeComponent() in the App constructor.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <service>telemetrysvc/service>
   <appKey>KKKKKKKKKKKKKKKKKKKK</appKey>
</configuration>

Config.xml
The service and appKey values  in Config.xml for the specific Mobile Service (can be changed there).

class Config
{
public string Service;
public string AppKey;
}
The Config class that is read from the config file
XDocument doc = XDocument.Load("Config.XML");
var configs = (from xElem in doc.Descendants("configuration")
select new Config
{
Service = xElem.Element("service").Value,
AppKey = xElem.Element("appKey").Value
}).ToList();

// Should only be one configuration
if (configs.Count == 1)
{
service = service.Replace("telemetrymobileservice", configs[0].Service);
appKey = configs[0].AppKey;
}

MobileService = new MobileServiceClient(
service,
appKey
);
Code in the App constructor to use the configuration in the configuration XML file.

[2] Namespace

A number of the subsequent changes involve name changes such as for the solution Namepace. The original namespace is sportronicsdj and was changed to TelemetryMobileService. One might be tempted to just do a simple bulk textual substitution of the former by the latter but that would lead to a corruption in the source code because the original namespace text is used in other contexts in the solution in full and as part of symbolic names. The change in namespace was effected by Refactoring it to the new name throughout the solution. Refactoring was then used for a number of other symbolic names throughout the solution code.

[3] ToDoItem.cs

This file was renamed to TelemetryItem.cs. The class name was changed to Telemetry using refactoring as was the  renaming of the Text property to Sensor. The Value property was added. File comparison tools are useful for identifying the changes between projects at file level.


public class TodoItem
{
     public string Id { get; set; }

   
     public string Text { get; set; }

    [JsonProperty(PropertyName = "complete")]
     public bool Complete { get; set; }
}



public class Telemetry
{
     public string Id { get; set; }

   
     public string Sensor { get; set; }

    [JsonProperty(PropertyName = "complete")]
     public bool Complete { get; set; }

    [JsonProperty(PropertyName = "value")]
     public int Value { get; set; }

}

Changes to the data class, which is passed between the app and Azure.
The app uses the public Pascal cased property names. The service uses the lowercase Json propertynames.

[4] UI Changes wrt the Class change

The changes in the code with respect to (wrt) the data classes above were in the main automatically taken care of throughout the solution using refactoring. Some required changes were embedded within strings and needed manually editing. Also because there is an extra property in the class a UI element needed to be added to both the input and output part of the UI.

 

In the desktop and phone projects, the TexttInput was renamed SensorInput, again using refactoring. This was done in the MainPage.xaml file in both projects in the TexBlock control immediately before the Save button control.

In MainPage.cs in the Shared project the Save method:
private async void ButtonSave_Click(object sender, RoutedEventArgs e)
{
var todoItem = new TodoItem { Text = TextInput.Text };
await InsertTodoItem(todoItem);
}
was changed to:
private async void ButtonSave_Click(object sender, RoutedEventArgs e)
{
var telemetryItem = new Telemetry { Sensor = SensorInput.Text, Value = int.Parse(ValueInput.Text) };
await InsertTelemetryItem(telemetryItem);
}
The TextInput to SensorInput was done using Refactoring first.
Note that the name change in the local variable toDoItem to telemetryItem is covered later.

 

In MainPage.cs is both projects in the Output UI (In a StackPanel in the ListView toward the bottom of the file):
<CheckBox Name="CheckBoxComplete" IsChecked="{Binding Complete, Mode=TwoWay}" Checked="CheckBoxComplete_Checked" Content="{Binding Text}" Margin="10,5" VerticalAlignment="Center"/>
was changed to
<CheckBox Name="CheckBoxComplete" IsChecked="{Binding Complete, Mode=TwoWay}" Checked="CheckBoxComplete_Checked" Content="{Binding Senssor}" Margin="10,5" VerticalAlignment="Center"/>
In this part of the UI a TextBlock was added to accommodate the Value property:
<TextBlock x:Name="ValueTextBlock" Text="{Binding Value}" VerticalAlignment="Center"  />

 

The Input UI was reworked to improve its layout: (Desktop version shown)
<StackPanel Orientation="Horizontal" Margin="72,0,0,0">
<TextBlock VerticalAlignment="Center">Sensor: </TextBlock>
<TextBox x:Name="SensorInput" Margin="5" MinWidth="300" VerticalAlignment="Center"/>
<TextBlock VerticalAlignment="Center">Value: </TextBlock>
<TextBox x:Name="ValueInput" Margin="5" MinWidth="75" VerticalAlignment="Center" InputScope="Number"/>
<Button x:Name="ButtonSave" Click="ButtonSave_Click" IsEnabled="False" Content="Save"/>
</StackPanel>

 

And the ListView Output UI was reworked to improve its layout: (Desktop version shown)
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="125"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Name="CheckBoxComplete" IsChecked="{Binding Complete, Mode=TwoWay}" Checked="CheckBoxComplete_Checked" Content="" Margin="10,5" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" x:Name="SensorTextblock" Text="{Binding Sensor}" VerticalAlignment="Center" />
<TextBlock Grid.Column="2" x:Name="ValueTextBlock" Text="{Binding Value}" VerticalAlignment="Center" TextAlignment="Right" Width="100" />
</Grid>

</DataTemplate>
</ListView.ItemTemplate>

[5] Some Cosmetic Changes

These actions are rather cosmetic in that they aren't required  from a functional perspective but make for good coding. They involve changing any remaining toDo references in symbol names to telemetry. They are largely local variable and parameter names within procedures in MainPaige.cs in the Shared project.  Again reflection is used rather than bulk substitution so as to make these changes safely.

Project File Method Focus Original Replacement
Shared MainPage.cs Global within class 1st declaration in class items telemetryItems
      2nd declaration in class toDoTable telemetryTable
    InsertTodoItem Rename method InsertTodoItem InsertTelemetryItem
Parameter todoItem TodoItem todoItem
Actually by now it is:
Telemetry todoItem
Telemetry telemetryItem
RefreshTodoItems Rename method  RefreshTodoItems RefreshTelemetryItems
      local variable name todoItem .Where(todoItem => todoItem.Complete == false) .Where(telemetryItem => telemetryItem.Complete == false)
      local variable name items ListItems.ItemsSource = items; ListItems.ItemsSource = telemetryItems;
CheckBoxComplete local variable name Item             TodoItem item = cb.DataContext as TodoItem;

Telemetry telemetryItem = cb.DataContext as Telemetry;

Note that with some of the changes above there is more than one instance of the variable name to be changed. By using refactoring in one location all instances are changed together. Bulk substitution can be quite erroneous .. I've tried it!

[6] One more cosmetic change

When the sensor names are entered, it makes sense to always capitalise the first letter in the anme (Pascal case). This was implement in the Shared project when the data is submitted to the service in MainPage.cs:

A new functiuon Noarmalise() was added, which is called in the Save method:
//Clean up of Sensor names.
private string Normalise(string strn)
{
string strnTemp ="";
if (strn != "")
{
strnTemp = strn.Substring(1).ToLower();
strnTemp = strn.ToUpper()[0].ToString() + strnTemp;
}
return strnTemp;
}


private async void ButtonSave_Click(object sender, RoutedEventArgs e)
{
//var telemetryItem = new Telemetry { Sensor = SensorInput.Text, Value = int.Parse(ValueInput.Text) };
var telemetryItem = new Telemetry { Sensor = Normalise(SensorInput.Text) , Value = int.Parse(ValueInput.Text)};
await InsertTelemetryItem(telemetryItem);
}



Coming: A Video of the comparison of the two projects

Next:  Command line Manipulation of the Mobile Service through Curl.

<Watch this space>



Footnote:

I tried to create a template for the second solution but the actions fails in what appears to be a known bug not yet resolved. Discussion points the Phone app being the source of the problem.

---------------------------
Export Template Wizard
---------------------------
Template export failed for the following reason: Illegal characters in path.
---------------------------
OK  
---------------------------