Windows Phone Resiliency – do more

In the last three posts in this series, I showed you how to write your apps in a way that will allow you to future proof them to an extent.

There are a few tips & tricks I wanted to discuss with regards to XPath and, to a lesser extent, Javascript, that will help you solve issues faster and more elegantly.

XPath

As I said in the XPath post of this series, the XPath we implemented is not standard – it should do a good job working with valid XPath expressions, but it also supports more advanced functions and capabilities.

Return values

When writing your customized code, consider the value you need to get back. Since our XPath processor supports the ability to return discrete types such as String, Boolean and Numbers, you can use that to simplify programming. For example, in the weather examples in previous posts, the temperature result is actually numeric. If you end up storing that value in memory as a number, you can forgoe the whole string to number processing in managed code and keep that as the responsibility of the XPath.

Here’s a modified version of an XPath that will return the temperature as a number:

number(//yweather:condition[@unit=’{0}’]/@temp)

The attribute temp is of type string. By passing it into the number() function, we are instructing the processor to return it as a numeric value. In C#, you can then do the following:

Code Snippet
  1. var tempResult = doc.Root.SelectNodes(xpath).FirstOrDefault();
  2. if (tempResult != null)
  3. {
  4. this.Temperature = (double)tempResult.ToObject();
  5. }

All three discrete types (String, Number and Boolean) can support the ToObject() method – which returns the relevant value (System.String, System.Double and System.Boolean respectively).

Context Change

Our XPath functionality lets the developer write localized expressions on a different context. The way XPath works is that with each Axis change, the processor changes the context you work in to be the relevant one. However, what if you have a complicated expression you want to write as part of an if() function? In that cases, you can use the se-contextchange() function to create a localized context to work in. Consider a prior example we used to return Fahrenheit and Celsius from a single node:

if (‘{0}’=’F’, Number(//yweather:condition[@unit=’F’)]/@temp), (5/9) * (Number(//yweather:condition[@unit=’F’)]/@temp) – 32)))

In this case, we have the same expression being used twice:

Number(//yweather:condition[@unit=’F’)]/@temp)

This expression could have been even more complicated – it is unfortunate that you need to write it multiple times to get the full XPath expression to work… Well – you don’t necessarily need to do that:

se-contextchange(Number(//yweather:condition[@unit=’F’)]/@temp), if (‘{0}’=’F’, ., (5/9) * (. – 32))))

The se-contextchange() function takes as the first parameter, the expression you want to use from now on as the “current” expression (or context). The result of the expression in the second parameter will be used as the return value of se-contextchange() and you can see that I am using the dot character (.) to access the context. This can greatly simplify complex expressions.

Stopping XPath Evaluation

In some cases, your XPath will return too many results (for example, in the case of an RSS feed, you may want to stop processing the XPath once you hit certain text in an item – as would be the example where the bottom 2-3 elements in the feed are ads you are not interested in).

For this, you can sue the se-stopif() function. When encountered, the processor will evaluate the first parameter and, if true, it will simply stop processing further (the entire expression will terminate). The result of the function is always true so you can put it as part of other Boolean expressions.

Regular Expressions

While I am not a fan of regular expressions and reading even moderately complicated ones makes me bleed from my eyes, I do recognize how powerful they are at parsing text. With our XPath processor, you can get the best of both worlds – use XPath to reach that piece of text you are interested in and then use RegEx to parse it via the se-regex() function:

se-regex(//div[@id=’userinfo’], ‘ (?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]‌​)\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-‌​9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})’)

This will return a US phone number inside the text of an div element with the id attribute set to ‘userinfo’.

Getting HTML fragments

When parsing HTML documents, you may wish to extract an HTML fragment out of the full HTML document (for example, so you can put it inside a WebBrowser control). This is easily achievable by using the se-outerhtml() and se-innerhtml():

se-innerhtml(//div[@id=’userinfo’])

This expression will return a string that represents the HTML that’s inside the aforementioned div element.

Implementing your own XPath

The XPath functionality is abstracted in a way that should allow you to create your own XPath parsers from any hierarchical data such as JSON, CSS, XAML (WPF forms) etc. It takes a total of 5 or 6 files to allow the parser to work over other data structures – take a look at the HapHelper folder under the library provided in the samples to see an example of how to build it.

Javascript

Since Javascript is fairly well understood and is pretty open-ended, there aren’t really a lot of tips I feel are needed to be supplied about actual coding. I would want to touch on a few topics with regards to using it though.

JSON

Don’t feel like you need to use .NET to unwrap JSON expressions when inside your Javascript code – if one of the calls you make returns a JSON string, you can simply evaluate it to get the actual JS object right into your code:

var json = “(“ + response + “)”;

var obj = eval(json);

// You can now use obj as you would any JSON deserialized object in a browser.

Assembly loading

It is important to note that the CLR parts your JS code will get access to are limited by the assemblies that are currently loaded into memory.

For example, if you run JS code in the constructor of your Application derived class (usually called App) and you do not use the System.Xml.Linq before the JS code executes, the js code will not have access to the various XML Linq classes.

This can cause somewhat nuanced issues when you have different code paths calling into your JS code and in some of them parts of the CLR is not yet loaded.

Threading

JINT is meant to execute on one thread (and maybe the same thread). While callbacks work, make sure you do not run JS code on different threads at the same time.

I have not spent a lot of time figuring out the exact limitations – we mostly just execute the code on the UI thread.

Debugging

While the infrastructure is there, sadly, debugging is not well designed when executing functions on an existing program in JINT. When coding, I end up using the tried and true “alert” method of debugging. It’s very annoying. We may end up doing some work on enabling this later, if it’s not enabled by the good people of JINT.

Be careful with anonymous functions

Especially when using LINQ, make sure that you resolve all returned collections. In other words, conside the following Linq call which finds all the MyClass instances that have IsVisible turned on:

Code Snippet
  1. var result = System.Linq.Enumerable.Where{MyApp.MyClass} (otherCollection, function(x) { return x.IsVisible; });

If you actually return this from a JS function and enumerate the result, you will probably find yourself crashing and burning.

For each time you go and call MoveNext() on the enumerator (thru foreach for example), you will find yourself running the anonymous JS function and JINT does not look kindly at that.

Instead, do the following:

Code Snippet
  1. var result = System.Linq.Enumerable.Where{MyApp.MyClass} (otherCollection, function(x) { return x.IsVisible; });
  2. result = System.Linq.Enumerable.ToArray{MyApp.MyClass}(result);

This will fully “realize” the IEnumerable and turn it into an array that does not require more calculations.

Combining JS with XAML

The Silverlight version running in Windows Phone allows you to take a XAML file and instantiate it into an object.

That in turn means that, with some work, you can not only create customized code that runs, but actually full-fledged UI elements that are fully customizable. Instead of just returning the JS to run, you also return the XAML to instantiate before hand, passing a reference to it to the JS object and allowing it to hook events, run code, etc.

This can be incredibly powerful and depending on the reception of this series, I may write another blog post about that.

Advertisements
This entry was posted in Dev, Javascript, Resilient, WindowsPhone. Bookmark the permalink.

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