Under the Hood with Windows Universal Projects

One of the main themes coming out of the keynotes and content at this year’s //Build 2014 conference was the continued convergence of the Windows Store and Windows Phone development platforms.  One exciting result of the fact that both these platforms now target very similar Windows Runtimes (WinRT and WinPRT, respectively) is the support for the new “Universal Apps” in Visual Studio 2013 Update 2.  (Another exciting result is that the “Programming the Windows Runtime by Example” book that Jeremy Likness and I wrote is even MORE relevant!) Projects created using the Universal App templates in Visual Studio include primary projects for each targeted platform as well as a shared project whose content “magically” gets included into each of the head projects.  Currently, only Windows 8.1 and Windows Phone 8.1 primary projects are supported, though apps targeting the Xbox One will one day be included, and Xamarin has indicated they’d be joining the fun soon. image
A Universal Apps Solution, showing Windows, Windows Phone, and Shared projects

I won’t spend a ton of time discussing the “how-to” aspect of Universal Apps projects – Jeff Prosise has published a series of blog posts that present the basics of working with those projects:

I want to focus on the mechanisms working behind-the-scenes that enables these things to work.  How does the Shared content make its way into the app projects in the solution, and why does it behave differently from other sharing mechanisms?  I find that understanding the inner workings of things leads to better decision making when employing them…perhaps that’s why I enjoy reading Jeff Richter’s books.

Where did they put the hood latch on this model?

So what is going on under the hood on these projects?  To understand that we need to get inside of the projects themselves.  Remember that most of the Visual Studio project files you work with (csproj, vbproj, etc) are actually MSBuild XML files.  You can examine this yourself by either opening the project files directly in a text editor (enhanced editors like Notepad++ or Sublime Text offer a better visual experience than good-old Notepad, but in a pinch, Notepad does work.)  You can also examine the inner content of a project file from Visual Studio itself with the following steps (or see here):

  • Right click on the project you want to work with in the Solution Explorer and select Unload Project
  • Right click on the project again and click Edit <ProjectName>

Regardless of what editor you choose to use, the content of your project files will follow the MSBuild Project File XML schema that is described here.  One of the jobs of the Visual Studio IDE is to properly maintain the various MSBuild schema elements as you add, remove, or rearrange items within your projects, but nothing prevents you from doing that manually, and there are actually a few MSBuild “tricks” that you can take advantage of that aren’t provided by the Visual Studio IDE.  Keith Rome has a blog post covering Wildcard Inclusions in C# Project Files that takes specific advantage of this capability.

Pay no attention to that man behind the curtain!

With one of the application project files open for XML editing, you can start to explore the magic of the Shared project.  Scroll down to the bottom of the file and locate the Import element that includes the attribute ‘Label = “Shared”’”:

<Import Project="..\UnderTheHood.Shared\UnderTheHood.Shared.projitems" 
Label="Shared" />

The purpose of the Import Element is to bring the contents of one project file into another project file, and a quick check of the MSDN docs suggests that it’s been around since at least .NET 2.0!  In this case, it is bringing in the contents of a file with a projitems extension from the shared project’s directory.  Note however that this file is NOT the shproj file that defines the Shared Project! (What gives?!) image
The Shared project extension is actually NOT what is referenced in the project files’ Import Element!

NOTE: You may also want to notice that there’s a Root Namespace property.  Setting this value determines the namespace that is given by default to new code files created within this shared project.

The projitems file is what the shared project creates/maintains.  If you open a File Explorer window to the Shared project file location, you will find this file.  Opening the file in a text editor (you can’t open it in Visual Studio while the shproj file is loaded, since it is already being referenced) will show that it is just another MSBuild file that includes the files that have been added to it  (if your text editor supports change notifications, add a new file to the Shared project while the projitems file is opened in the text editor and notice that when you save the project, the projitems file will be updated.)

So as you add, remove, or manipulate items in the shared project, the contents of the projitems file is updated, and this file’s contents in turn are simply incorporated into your app project files via the Import elements in their MSBuild XML.  This is why you can use #if declarations that are scoped to one project or another to differentiate behavior.

But wait, there’s (partially) more!

Remember that there’s more that you can do to affect your shared files’ integration behavior than simply throwing a bunch of #if and #else blocks throughout the shared code (ew!).  Don’t forget about partial classes and their often-overlooked cousins, partial methods. Partial methods first came on to the scene as a tool to allow developers to introduce code that strategically extended designer-generated files without having to worry about designer regeneration obliterating their code without having to create subclasses and override virtual methods.  When a partial class includes a partial method, private methods can call into that partial method, and partial extensions can choose whether or not to provide an implementation of the partial method. Wait…what?  Perhaps an example. I’ve added a new class to the shared project:

namespace UnderTheHood
{
    public partial class PartialClass
    {
        public void DoSomethingInteresting()
        {
            DoSomethingPlatformSpecific();
        }

        partial void DoSomethingPlatformSpecific();
    }
}

Note the lack of implementation for the DoSomethingPlatformSpecific method. Now in the Windows 8.1 project I’ve provided an implementation of the DoSomethingPlatformSpecific method:

namespace UnderTheHood
{
    public partial class PartialClass
    {
        partial void DoSomethingPlatformSpecific()
        {
            Debug.WriteLine("I am a Windows 8.1 implementation.");
        }
    }
}

And a slightly different implementation in the Windows Phone 8.1 project:

namespace UnderTheHood
{
    public partial class PartialClass
    {
        partial void DoSomethingPlatformSpecific()
        {
            Debug.WriteLine("I am a Windows Phone 8.1 implementation.");
        }
    }
}

Now calling the public DoSomethingInteresting method will call into whatever platform-specific DoSomethingPlatformSpecific implementation is in the current project, allowing for platform-specific customizations to occur in the platform-specific projects, rather than mixing them in the shared projects with #if and #else statements.  If new platforms are added to the Universal Project “universe” (sorry), you don’t have to worry about the #if statements becoming these big messes that include a lot of code that is greyed out by Visual Studio depending on which project it thinks is currently in scope. Bear in mind that partial methods differ from abstract methods in that they do not have to be overridden/implemented.  If no implementation is provided, the call into the partial method won’t fail or cause any negative side effects…it is simply a no-op.  As a consequence, there are a few rules to follow when working with partial methods:

  • They must return void (if they had return types, an implementation would be required)
  • That can have ref parameters, but not out parameters (if no implementation is provided, the ref parameter is unmodified)
  • Partial methods are inherently private in scope.
  • They can be static, and can be generic.
  • Delegates can only refer to implementations of static methods.

The bottom line

So hopefully now you have a better understanding of how these magical new shared projects work in Visual Studio.  Much of the technology they use has been in the DNA of our project files for a while.  Visual Studio 2013 Update 2 has been enhanced to include some nice new IDE updates in order to surface these features in a way that makes them very useful for writing reusable code.  This new compile-time reusability combines quite nicely with the post-compile reusability that is offered by Portable Class Libraries. If you want to learn more about them, Jeff Prosise will be delivering a session on universal apps at the Software Design & Development conference in London next month. The talk will delve into what universal apps are and how they’re structured, and he promises to have plenty of samples to share as he goes over the ins and outs of writing apps that target separate but similar run-times.  You might also benefit from watching Jeff’s video entitled Introduction to WinRT on WintellectNOW. If you’re not already a subscriber, you can sign up with the promo code Garland-13 and enjoy two weeks of access for free. Also, did I happen to already mention that Jeremy Likness and I had written a book about using the Windows Runtime?

Managing Windows Azure Mobile Services (WAMS) Server Scripts with Microsoft Visual Studio Tools for Git

Windows Azure Mobile Services (WAMS) has come a long way in a few short months.  At the 2013 Build conference in San Francisco, Microsoft announced more than the service’s General Availability date – it also showed that the service had been integrated into the Visual Studio 2013 Preview in several key places.  These included a “Connected Services Manager” that will augment an existing project to connect with a new or preexisting WAMS instance, an entry for WAMS in the Server Explorer panel that allows viewing and editing the server-side data table business logic scripts (with access to the other WAMS script elements expected to be added over time), and a Push Notification Wizard that facilitates connecting an existing Windows Store app to a WAMS instance.  These features are detailed in this post on the Visual Studio Blog.  The expectation is that these integration points are expected to be enhanced as Visual Studio 2013 is updated to its RTM version.

One of the more recent features added to WAMS itself has been the integration of Git-based source control for the server scripts (as of this writing, this feature is currently in Preview.)  This integration provides several advantages for managing a WAMS service’s scripts.  First, it allows for scripts to be edited locally /offline using desktop file editing tools, including Visual Studio.  Changes can be managed through the local Git repository until they are ready to be synchronized to the server.  What’s more, this arrangement also allows access to some of the WAMS script-related content that is not (presently) available through the WAMS management portal (though access to these files can also be obtained from the command-line management tools.)

To mostly round out the collection of the tools will be discussed here, the Team Foundation Server Power Tools team at Microsoft has released the Visual Studio Tools for Git, which is an extension that allows Visual Studio’s Team Explorer to integrate with Git.  This integration includes using the Team Explorer GUI to manage and connect to local repositories, as well as to track changed elements in a selected repo, and managing branches, commits, and syncs in that repo.  As of this writing, the extension is at version 0.9.5.

This post will explore how the new integrated Visual Studio tools for Git can be used to provide GUI-based source-controlled management for client-side editing of the scripts belonging to a Windows Azure Mobile Services instance.

Enabling Source Control in a WAMS Instance

The first step in the process is to enable Git Source Control for the account which owns the WAMS instance, if it has not already been set up for that account.  This process is documented here.  Basically, the steps entail:

  • – If this is the first time a Mobile Service Git repository is being set up for the current Azure subscription:
    • – From the WAMS Management Portal “Dashboard” page for the desired service, select “Set up source control”
    • – Provide a username and password to be used for access to mobile service Git repositories within the subscription.  These credentials can be changed later by selecting the “Reset your source control credentials” link on a WAMS Dashboard page for any Mobile Service attached to the same subscription.
  • – Copy the Git URL from the service instance’s Configure tab.

image

Connect to the Git Repository from Visual Studio

The next step is to connect to the server-side repository that was just created and clone it to the local machine.  This (and many of the remaining steps) can be accomplished via several Git tools, including the command line, but the focus here is on using Visual Studio (for the most part, I prefer to leave the command line to build scripts and for hacking into the Matrix.)  Once the Visual Studio Tools for Git extension has been downloaded and installed, open Visual Studio 2013 and select the Team Explorer pane (if necessary, it can be found in the View menu.) 

Select Connect (the icon looks like a the male end of a 2-prong extension cord)

image

In the ensuing Connect dialog, select Clone to do the initial setup of the local repo as a clone of the server repository.  This will show a couple of text boxes – the top one is used to provide the URL to the remote repository – paste the URL that was copied earlier from the WAMS Management Portal.  In the second one, type in or browse to the local directory path into which the repository should be cloned.

image

When you press the Clone button, you will be prompted for your server-side Git repository credentials.

image

…and after entering these credentials, you will have a local clone of the WAMS repository.

Examining the WAMS File Structure and Script Files

If you right-click on the new repository entry in the Team Explorer Connection Panel, you will see context menu options which include one for opening the repository in File Explorer.

image

 

The folder you open will contain a file and single subfolder titled “service”.  Within the service folder are the folders that contain the WAMS script content.  These folders and their purpose are listed below:

  • api: contains 2 files per Custom API defined in the WAMS portal.  The first file is a JavaScript (api name.js) file containing the script itself and the second is a JSON metadata file (api name.json) that describes the permission level required for each custom api script action.
  • scheduler: contains a JavaScript file (scheduled job name.js) for each defined scheduler script.
  • shared: contains scripts and/or Node.js modules that can be reused by other scripts in the service instance.  Note that there is no browser in the portal (at present) for files in this folder.
  • tables: contains between 1-5 files per defined table in the WAMS instance.  These files minimally include a JSON metadata file (table name.json)  For any modified table action script (read, insert, update, delete), there is also a corresponding JavaScript file (table name.operation.js)

Note #1: Each folder also includes a text md file that describes the intended contents of the folder and any layout constraints for each file. 

Note #2: For the most part, with the exception of the “shared” folder, the files should be “seeded” by creating the desired named item server-side and then syncing the repository.  WAMS often has to spin up other infrastructure elements in addition to just the scripts, such as database tables and entries for the scheduler. 

For Table scripts, the table can be created in the Visual Studio Server Explorer, but the individual table operation script files won’t be brought down by a Sync operation until the corresponding scripts is modified in some way – the change can be as simple as adding a comment.  Once the file has been altered and saved to the server, using Sync will fetch the file to the local repository.  The WAMS instance context menu (with the Create Table option) in the Server Explorer is shown below, along with a script that has been modified with nothing but a comment.

image              image

The screenshot below shows after the file above has been saved to the server from within the Server explorer, after doing a Sync of the Git repositories, the local folder has been updated with the table’s corresponding read script file.

image

Note that generating files this way is probably best left only for initially “seeding” the files, thus leaving day-to-day editing to an operation that is covered by source control and includes change tracking, etc.

Working with the Visual Studio Git Tools

From the Connections panel, opening one of the repositories (double-click or right-click and select Open) displays the Home panel for the selected repository.

image

Once the necessary files have been synced to the local repository, the files within the folders in the repository can be edited on the local machine and the changes will be tracked by Git.  These changes can be seen in Visual Studio by bringing up the Changes Panel.  In the illustration below, the “read” script file for the “blogdemo” table has been modified locally (in fact, it was opened in Visual Studio and edited there to take advantage of Visual Studio’s JavaScript editing tools.  Any text editor could have been used, however.)

image

Note that there’s also an entry for “demosharedcontent.js” in the Untracked Files listing.  To include the file, simply drag it (or its containing folder) up and drop it in the “Included Changes” section:

image

Once the collection of changed files that is to be committed to the local repository is ready, a commit message (comment) can be entered and the Commit button can be pressed.  Pressing the Commits link from this panel, returning to the home panel and selecting the Commits button, or selecting the Commits pulldown at the top of the TFS explorer will show the current set of outgoing and incoming Commits available for Syncing with the Server.

image

Pressing the Sync button once again synchronizes the script changes with the WAMS service.  Examining the table script in the WAMS Management Portal shows that the change in fact has been uploaded to the server:

image

If the Sync results in conflicts that Git cannot resolve, (the same word was changed both in the client and the server, for example) the Sync will indicate so, and a list of conflicts will be displayed:

image

The conflicts can be examined in detail and adjusted using the 3-way merge tool that comes with Visual Studio (with apologies for my typos):

image

Once the Merge is committed, it can be synced to the server.

The final working panel that hasn’t been shown yet is the Branches panel, which allows management of branches in the selected local repository.

image

Wrapping Up

While Windows Azure Mobile Services currently benefits from several points of integration into the Visual Studio 2013 IDE, the addition of the Visual Studio Tools for Git offers an additional tool to help with the management of server-side scripts.  For what it’s worth, the Visual Studio Tools for Git also works with Visual Studio 2012, and supports the same kinds of source control management as was shown here in Visual Studio 2013 Preview, except that Visual Studio 2012 lacks the additional WAMS integration points such as the entry in the Server Explorer.  Nonetheless, look for the integration of these tools to become even richer as WAMS, Visual Studio 2013 , and even the Visual Studio Tools for Git are enhanced over the next few months.

Using the New Caller Information Attributes for Reliable Property Change Notifications

As anyone who has implemented the INotifyPropertyChanged interface knows, the fact that the PropertyChangedEventArgs takes a property name as a string means that you are one fat-fingered mistake away from a bug that can sometimes be difficult to track down.  If the property name supplied in the string doesn’t match the actual property name, the data binding (or other operations) that relies on this interface doesn’t work properly.

   1: public Int32 MyProperty

   2: {

   3:     get { return _myProperty; }

   4:     set

   5:     {

   6:         if (_myProperty != value)

   7:         {

   8:             _myProperty = value;

   9:             OnPropertyChanged("MyProperty");

  10:         }

  11:     }

  12: }

Lambda expressions and Expression Trees in .Net 3 brought a solution to the problem, where the compile-time checking could help ensure that a correct value was provided.  I blogged about this back in 2010 (https://blog.dotnetgator.com/2010/06/21/finding-binding-trouble/), and even cited my (then-future) coworker Jeremy Likness’s treatment of the same topic (http://csharperimage.jeremylikness.com/2010/06/tips-and-tricks-for-inotifypropertychan.html).

   1: public Int32 MyProperty

   2: {

   3:     get { return _myProperty; }

   4:     set

   5:     {

   6:         if (_myProperty != value)

   7:         {

   8:             _myProperty = value;

   9:             OnPropertyChanged(() => MyProperty);

  10:         }

  11:     }

  12: }

Now there’s a new feature in .Net 4.5 that provides yet another opportunity to ensure that INotifyPropertyChanged is implemented correctly – possibly in a simpler fashion than ever before, and with better performance than the Expression Tree/Lambda expression approach.

.Net 4.5 includes 3 new “Caller Information” attributes  – CallerFilePathAttribute, CallerLineNumberAttribute, and CallerMemberNameAttribute.  These three attributes are scoped to individual method parameters, and when used, they apply the indicated value from the CALLING METHOD to the called method’s attributed parameter at run time.  In our case, we’re interested in the CallerMemberName attribute, which we can use to automatically retrieve the property that is trying to raise the property change notification:

   1: private void OnPropertyChanged([CallerMemberName] String caller = null)

   2: {

   3:     var handler = PropertyChanged;

   4:     if (handler != null)

   5:     {

   6:         handler(this, new PropertyChangedEventArgs(caller));

   7:     }

   8: }

Note that the Caller Information attributes require a default value be supplied.

This reduces the overhead of a property in the class that provides this method to the following:

   1: public Int32 MyProperty

   2: {

   3:     get { return _myProperty; }

   4:     set

   5:     {

   6:         if (_myProperty != value)

   7:         {

   8:             _myProperty = value;

   9:             OnPropertyChanged();

  10:         }

  11:     }

  12: }

Of course, one important question is how does this method perform in comparison to either just providing a string, or using the Lambda/Expression Tree approach?  In my tests with iterations of between 1,000-500,000 property changes I saw between ~10-30% performance improvement over the Lambda/Expression Tree approach, and performance between ~20-30% lower than using a directly supplied string.

Note that the latest version of the MSDN documentation illustrating the implementation of the INotifyPropertyChanged interface (as of this writing) show the use of the CallerMemberName attribute – http://msdn.microsoft.com/en-us/library/ms229614(v=vs.110).aspx

DevBoston (Waltham) Presentation Content

Many thanks to the attendees of my presentation tonight covering Developing Cloud Enabled Windows Phone Applications with Windows Azure.  I apologize once again for the technical network-related gremlins that decided to attack us tonight…hopefully the workaround covered the necessary ground and everyone was able to see the concepts I was trying to show.

As promised, I have posted the content for the presentation here.  This includes the slide deck with the various resource links, as well as the final project.  As I mentioned, I have “sanitized” the configuration of the project to omit my specific Access Control (ACS) settings.  This involved changing the AccessControlResources.xaml file in the phone project and the Web.config file in the web role project.  Look for the text [your-xxx-here] for where to substitute your own ACS information.

Because the network issues prevented us from accessing the NuGet site or repository, I wanted to be sure to list the packages that were used in these projects:

Phone.Storage Adds support in the phone project to access Azure Storage.
WindowsAzure.Storage.Proxy.AccessControl Adds support in the server-side MVC3 based web role to field secured storage requests using ACS to generate the authentication token
Phone.Storage.AccessControl Adds support in the phone project for interacting with ACS-secured storage, including a login page with the ACS-aware login control.
WindowsAzure.Notifications Adds support in the server-side MVC3 based web role to handle registration & storage for Push Notification endpoints
Phone.Notifications.BasePage Adds support in the phone project (including a UI page) for enabling notifications in the application and registering with server-side push notification endpoint.
MPNSRecipe Adds the MPNS Recipe, used in the worker role project.

Boston .Net Code Camp Presentation Content

I would like to thank the organizers and attendees of the recent 16th (wow!) Boston Code Camp where I did a talk on Developing Cloud-Enabled Windows Phone Applications with Windows Azure – and special thanks to everyone who stuck it out once the snow started falling in order to catch my talk.  Obviously, it took longer than expected to get this content posted – Nashua got hit especially hard by the storm, including a 75% city-wide power outage the day following the Code Camp event, along with accompanying telecom and even cellular outages.  I am happy to say that I finally got my power turned back on mid-week, and am slowly but surely digging out of the mountain of backlog that piled up during the multi-day outage.

The content can be found here.  Because I demoed ACS, some of the items that are placed in the project would normally reference my “real” Azure account…they have been removed and replaced with the phrase “YOUR CONTENT HERE.”  You will need to replace these values with your own from the Azure ACS management portal in order to be able to run the provided code.  Also, in order to use the Azure Emulator, be sure to run Visual Studio in Admin mode when working with this project.

Boston Azure User Group Presentation Materials

Many thanks to the organizers and attendees of the Boston Azure User Group where I had the chance to speak this past week on Developing Cloud-Enabled Windows Phone Applications with Windows Azure.  I hope everyone who attended enjoyed the presentation as much as I enjoyed doing it.  I certainly appreciate everybody having stuck through considering the A/C glitch causing the room temperature to get a little uncomfortable.

Speaking of weather, I think my house is now as prepared as it is going to be for the upcoming arrival of hurricane Irene to New Hampshire…I really didn’t think I’d be dealing with these anymore after my 15 years in Florida – that we “paid our dues” in New England with our annual rounds of Nor’easters and other winter “fun.”  Nonetheless, the slide deck and code from the presentation have been posted, and can be found here.

The sample code is broken into 5 parts across 4 solutions as follows:

  1. Membership (Windows Azure Toolkit for Windows Phone)
  2. Storage (Windows Azure Toolkit for Windows Phone)
  3. Notification Services (Windows Azure Toolkit for Windows Phone)
  4. AppFabric Service Bus
  5. OData (Azure Data Marketplace and SQL Azure)

Key “markers” have been placed into the code files as comments that start with the word “NOTE” (a handy way to see *most* of them is to make use of the Visual Studio Task List pane, however, there are a few in the config files that don’t get picked up by this pane.)  The code has been sanitized to point to local storage and/or to remove any keys I had put in that were specific to the sites and accounts I was using for the demo.  Please substitute your own private values where necessary.

New England Code Camp 15 Presentation Materials

I have uploaded the content from my talks at yesterday’s (5/7/2011) New England Code Camp 15.  I had two talks – Introduction to Windows Phone 7 Development with Silverlight and Advanced Windows Phone 7 Development with Silverlight.  The content for my first talk can be found here, and the content for the second talk can be found here.  The content includes:

  • Presentation slides, which include the reference links I mentioned during the talk.
  • The sample code.  In the second presentation I discussed the Bing Maps control.  I have removed my Map Key and replaced it with the text “YOUR_KEY_HERE.”  To remove the licensing warning that appears when running the project, be sure to get an application key from the Bing Maps Developer Portal and replace the temporary text.

After having done various phone talks over the past year, I decided I needed to overhaul the content prior to this presentation.  This was done both in order to relate the contents of the presentation to something that more closely resembled an actual app, as well as in anticipation of including the upcoming “Mango” content.  I think the presentation got closer on those fronts, but it still needs some tuning (especially the first half, which ran a bit long…my apologies to the attendees for having to rush through some of the material.)

I have also discovered an interesting defect in the application that occurred after adding the code to handle saving page-state when the app is tombstoned.  What happens is that the closing of the DatePicker control (from the Silverlight for Windows Phone Toolkit) sets the value of the property before an OnNavigatedTo event is called, which resets the value to what was serialized when the control first appears.  The net result is that the DatePicker control ceases to change the date.  I included a quick fix for this in the code published above, and will be taking a deeper look at this control in the coming days, with a more thorough post to follow.