NuGet Nugget: File-System Based Package Stores

A recent network “hiccup” posed a bit of a challenge to a demo that was built around showing how the Windows Azure Toolkit for Windows Phone (WATWP) NuGet packages make it easy to add Windows Azure cloud features to a Windows Phone 7 application.  So how do you access NuGet content when a network connection isn’t available?  What if you want to exert some management over the updates that are exposed to the developers in your enterprise, including exposing often-used or internal-use assets?

It turns out that NuGet offers some functionality that addresses these scenarios.  In addition to supporting the ability to set up your own package server (also known as Creating Remote Feeds in the NuGet documentation), there is the ability to consume packages collected in a directory – either a network share or a local file-system folder.  This is illustrated in the NuGet documentation under the subtopic “Creating Local Feeds” within the “Hosting Your Own NuGet Feeds” topic.

Populating a File-System Based Package Store

Any folder that contains NuGet .nupkg files can be set to be as a file-system based package server.  From my own use, folders that contain subfolders with .nupkg files will also work, allowing for organization and hierarchy.  If you already have a Visual Studio solution that has references to NuGet packages, moving these packages into such a local package store can be quite simple (especially for demos!)  Just locate the “packages” folder that is created when the NuGet packages are added

image

The entire package folder is not required, since the nupkg files are really Zip files that contain all of the necessary contents.  Search for files that end with the .nupkg extension. 

SNAGHTML9fbf7a

Simply copy all of these files into the folder you are using for your file-system based package store.  Note that a wider set of packages is available in your local package cache, which is normally maintained in <UserFolder>\AppData\Local\NuGet\Cache, and can be accessed from Visual Studio via Tools-Library Package Manager-Package Manager Settings, and click the “Browse” button in the General section of the Package Manager settings node.

Using File-Based Package Stores

To tell Visual Studio to consume file-based package stores, bring up the settings dialog (via Tools-Library Package Manager-Package Manager Settings or through the other accessors in Visual Studio) and select the Package Sources section of the Package Manager settings node.  Provide a name and type in the path or browse to the package location and click the Add button.  Note that the elements in the Available Package Sources list are shown in a check-list-box – they can be enabled or disabled.  Elements in the list can also be reordered in order to determine the precedence in which the sources are searched for matching packages.

SNAGHTMLab5b5b

When adding NuGet package references to your project in Visual Studio via the Manage NuGet Packages dialog, note that the newly named source now appears within the “Online” package listing section. 

SNAGHTMLb09c32

The new source is also available as a pulldown option in the Package Manager Console window.

SNAGHTMLb430e2

As I’ve been digging into NuGet more lately, I’ve been quite impressed by the functionality it exposes.  There’s much more to it than just a right-click menu item and a dialog box  that adds and updates project assembly references.  Some of my current favorites include managing package references at the solution level and visualizing NuGet package chains.  Be sure to check out the NuGet docs in case you have yet to discover your favorite.

Advertisement

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 Phone Camp Presentation Materials

I had a great time talking about the Windows Azure Toolkit for Windows Phone at the Windows Phone Camp event in Cambridge, MA earlier today.  I have posted the slide deck here for those who are interested in getting at the web links it contains.

If you missed the event and/or are interested in other Windows Phone Camp events, more information is available here.

Vermont Code Camp Presentation Materials

Many thanks to the organizers and attendees of this year’s Vermont Code Camp.   This event continues to set the bar for excellence, and a ton of credit is due to Julie Lerman, Rob Hale, and the rest of the volunteers who all clearly work quite hard to pull it all together.

I have uploaded the code and content from my “What’s New in Windows Phone 7.1 Silverlight Development”, and they can be downloaded from here.

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.

Creating Custom Ringtones in Windows Phone Mango

Now that I have upgraded my phone to the Windows Phone 7.1 Developers’ Preview, one of the features I’ve been anxious to try out is Custom Ringtones – the default tones and the ones provided by AT&T are “interesting”, but they’re just not “me.”  Windows Phone 7.1 (AKA Mango) supports custom ringtones – but how do you go about making that happen?

IMPORTANT – The information below is based on Windows Phone 7.1 (AKA Mango) Beta 2, with a phone and the related Zune software upgraded to use the Developer Preview.

The available ringtones on the phone are segmented into groups which can be seen by going to Settings / Ringtones + Sounds and/or Contact / Edit / Ringtone (the latter location is used to override the default ringtone and set a per-contact ringtone.)  The default collection of ringtones that are included by the phone OS, those provided by the carrier, and any custom ringtones installed by the user.  Custom and OEM-provided ringtones can be deleted (for pruning the available ringtone list) whereas the ringtones included with the Phone OS cannot.

Custom ringtones are audio files that are “registered” with the phone OS in a certain way – more on this in a moment.  However, in order to be registered, an audio file must meet the following criteria:

  • It must be either a WMA or an MP3 file
  • It must be 39 seconds or shorter in length
  • It must be smaller than 1MB in size
  • It cannot be copy protected / have DRM restrictions

Creating Custom Ringtone Files

So what do you need to create a custom ringtone file that fits this criteria?  While there are several tools that can be used, I’ll highlight 2 here – Expression Encoder and Audacity.  Expression Encoder is part of Microsoft’s Expression Suite.  As of this writing, there are both free and pro versions available, and while I happen to have Pro (available as part of my MSDN Subscription), the audio features should be part of both SKUs.  Expression Encoder succeeds the Windows Media Encoder, and although it is primarily targeted at video projects, it is usable for audio projects.

To get started with Expression Encoder, launch the application and select a “Transcoding Project” in the New Project dialog.  To load the audio file, select either Import from the File menu, or locate the file in Windows Explorer and drag it onto the application.  The file will be loaded into the editing timeline, and its metadata will be displayed.  Using the editing controls within Encoder, the section of interest for the ringtone can be isolated.  Since there is no waveform monitor within Encoder, this is exercise must largely be performed by ear and with an eye on the time displayed in the timeline.  (Note – a full discussion of editing within the Encoder product is beyond the scope of this discussion.)  Once the desired segment of audio has been isolated, the specific WMA format can be selected from the Encode toolstrip, and the Audio property panel can be used to set the target bitrate mode, bitrate, channel information, sample rate, and bit depth (these settings push and pull against each other to determine audio quality vs file size.  Remember, this is a ringtone, and there are limits to the file size.  Audio quality is probably negotiable here.)  The Metadata toolstrip can be used to set the clip;s metadata attributes (in particular, Title and Genre are important here), and the Output toolstrip can be used to determine the file output.  When ready, selecting Encode or Encode Selected Item from the File menu starts creating the new ringtone file.

SNAGHTML80d969d

Audacity is a free, open source, cross-platform sound editor.  In addition to downloading the Audacity application itself, for these purposes 2 add-ons should be considered – the LAME MP3 encoder (if MP3 files are the desired output), and the FFmpeg import/export library (if WMA files will be imported or exported.)  Links to these add-ons can be found at the Audactiy download site here.  To start editing a file, select Import from the File menu, or drag the file into the application.  Audacity does display a waveform synchronized to the timeline, making the audio editing experience more visual than in Expression Encoder.  Once the target section of the file has been isolated, Export or Export Selection can be selected from the File menu.  From here, the type of file being exported can be chosen (WMA or MP3 for ringtones), and depending on the selection, encoding options can be chosen.  Note that there are far fewer encoding options for WMA here than in Expression Encoder.  Once a target file location and options are selected, the metadata editor will be displayed, where metadata for the output file can be set. 

SNAGHTML8192f82

Regardless of what is set in the encoding applications above, the details tab in the file properties dialog can be used to set the metadata.  The Title property controls what is displayed when the file is shown in the Custom Ringtones group in the phone.  The Genre value is actually quite important – in order to use the Zune software to load the ringtone, it must be set to “Ringtone.”

SNAGHTML81f29f7

Adding Ringtones Using Zune Software

To manually transfer the ringtone, make sure the ringtone file that was just created is in one of the configured music folders within the Zune software, as pictured below. 

SNAGHTML822444a

Set the file (or fill folder) to be synced with the phone device.  The next time the phone is plugged in, the file will be placed on the phone.  Because its genre is set to “ringtone”, the files will not appear in the phone’s audio collection, and will appear in the list of custom ringtones.

image

Programmatically Adding Ringtones

If the ringtone files are not originating on the phone user’s desktop and/or using the Zune software is not practical, there is a mechanism for adding ringtones programmatically.  This would be useful, for example, to provide an application that allows ringtones to be selected from an internet site or related resource.  The SaveRingtoneTask takes center stage for programmatically setting ringtones.  For SaveRingtoneTask, the DisplayName property determines the name the ringtone will be displayed with in the Custom Ringtones section, and the Source property provides a Uri to the location of the ringtone file to be used.  This Uri typically points to a location in Isolated Storage, using the URI syntax for accessing Isolated Storage, as shown below (notice the similarity with the Uri used for the Connection String specified when accessing SQL CE databases in the WP 7.1 API.  There is some discussion that the Source Uri will also support the appdata prefix syntax that is available for read-only files that are included as part of the app’s payload in the Xap file, but I have yet to test this specific functionality.) 

   1: saveRingtoneChooser.DisplayName = "My Ringtone";

   2: saveRingtoneChooser.Source = new Uri(@"isostore:/myringtone.wma");

   3: saveRingtoneChooser.IsShareable = true;

   4: saveRingtoneChooser.Show();

Note that the file in Isolated Storage is “copied” to the internal ringtone location on the phone…if the application that ran the Chooser is subsequently uninstalled (which clears Isolated Storage for that application), the ringtone persists until it is explicitly deleted from the Custom Ringtone collection.  Also, in the case of the web-based ringtone provider example discussed above, it may be prudent to use the Background Transfer Service to queue the selected ringtone download, then process the file once it has been fully downloaded.

A Note About the Audio Files Used in this Example

The audio files used in this discussion are ripped from CD’s that are physically in my own personal collection (my taste in music notwithstanding.)  Please be sure to perform your own copyright research prior to launching any ringtone software / services.

Showing the Onscreen Keyboard in Silverlight OOB Applications

One of the “interesting” things about Silverlight apps running on Windows is that on touch/tablet systems, textboxes in Silverlight do not display a popup button to use for bringing up the Windows onscreen keyboard when they have focus, whereas native applications do.

image
WPF / Native Window following a “Touch” in a textbox

image
Silverlight OOB Window following a “Touch” in a textbox

The onscreen keyboard is actually present in the Silverlight case – it is usually just “conveniently” tucked against the left side of the screen – and experience has shown me that until you actually show or describe to someone where it is, they will usually not find it on their own.  Tap it once, and it “peeks” out a little bit.  Tap it again, and it is brought to the center of the screen.  Hit the close button, and it returns to its tucked away position on the side of the screen.

I have been asked several times for an option to show the onscreen keyboard from within a Silverlight application in a more consistent and user-friendly fashion.  It turns out that for Silverlight Out of Browser applications running with Elevated Trust, there is an option – COM Automation can be used to invoke the process that displays the onscreen keyboard, or Text Input Panel (TIP).

Locating the Process

As of Windows Vista, the TextInputPanel handles the Tablet Input Panel (TIP).  This is implemented in the file TabTip.exe, which exists in the directory <Program Files>\Common Files\Microsoft Shared\ink – this is true both in 64-bit and 32-bit versions of Windows.  (Note – I have verified this myself only on Windows 7.)  See the following site for more information about the TIP: http://msdn.microsoft.com/en-us/library/ms701746(VS.85).aspx.

Normally, to locate the needed path, the Environment.GetFolderPath method would be used.  However, when called on a 64-bit system from Silverlight with SpecialFolder.CommonProgramFiles as the parameter, it returns the path to the x86 Program Files directory…not the one that is needed in this case.  However, using the scripting shell’s ExpandEnvironmentStrings method can get the correct value, as follows:

   1: dynamic shell = AutomationFactory.CreateObject("WScript.Shell");

   2: String commonPath = shell.ExpandEnvironmentStrings("%CommonProgramW6432%");

   3:  

   4: // This path is the same for both 32 and 64-bit installs of Windows

   5: String filePath = System.IO.Path.Combine(commonPath, @"microsoft shared\ink\TabTip.exe");

Information about the CommonProgramW6432 Environment Variable can be found at this link: http://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx.

Showing the Onscreen Keyboard

Now that the necessary program has been located, it simply needs to be run to show the keyboard (or to bring it up onscreen, in case the keyboard app is running, but “hidden” along the margin, as pictured above.  To do this, simply call ShellExecute, passing in the path calculated above:

   1: dynamic application = AutomationFactory.CreateObject("Shell.Application");

   2: application.ShellExecute(filePath, "", "", "open", 1);

The full code listing for a ShowKeyboard helper method is shown below:

   1: public static class KeyboardHelper

   2: {

   3:     public static void ShowKeyboard()

   4:     {

   5:         if (AutomationFactory.IsAvailable)

   6:         {

   7:             try

   8:             {

   9:                 // Ensure Windows 7 or Windows Server 2008 R2

  10:                 // OS Version # - http://msdn.microsoft.com/en-us/library/ms724832(VS.85).aspx

  11:                 if (Environment.OSVersion.Platform == PlatformID.Win32NT

  12:                     && Environment.OSVersion.Version >= new Version(6, 1))

  13:                 {

  14:                     // Get the path to the Common Program Files directory (not the x86 version...)

  15:  

  16:                     // Environment.GetFolderPath returns the wrong path (x86 branch on 64-bit systems.)

  17:                     // String commonPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);

  18:  

  19:                     dynamic shell = AutomationFactory.CreateObject("WScript.Shell");

  20:                     String commonPath = shell.ExpandEnvironmentStrings("%CommonProgramW6432%");

  21:  

  22:                     // This path is the same for both 32 and 64-bit installs of Windows

  23:                     String filePath = System.IO.Path.Combine(commonPath, @"microsoft shared\ink\TabTip.exe");

  24:  

  25:                     // Bring up the TIP - http://msdn.microsoft.com/en-us/library/ms701746(VS.85).aspx

  26:                     dynamic application = AutomationFactory.CreateObject("Shell.Application");

  27:                     application.ShellExecute(filePath, "", "", "open", 1);

  28:                 }

  29:             }

  30:             catch (Exception ex)

  31:             {

  32:                 Debug.WriteLine(ex);

  33:             }

  34:         }

  35:     }

  36: }

What’s Next?

I have shown how to programmatically show the TIP…as far as how to get there, that is left as an exercise for the reader.  In some cases, adding a launcher (such as a “show keyboard” button) somewhere in the UI may be an acceptable option – it is certainly the simplest.  To approximate the behavior seen in native applications, more work is required.  This includes showing a UI control to display the TIP, which is only displayed if the user accesses the textbox control via touch input.  This can be determined by using the Silverlight Multitouch Input APIs, or a helper library such as LightTouch or the Native Extensions for Silverlight

CT Code Camp 4 Presentation Materials

I have uploaded the content from my talk at the Connecticut .Net Developers’ Group Code Camp 4 from today (6/18/2011).  The code and content  from my “What’s New in Windows Phone 7.1 Silverlight Development” are available here.

Many thanks to SB Chatterjee and his team for putting together the event.  Also thank you to the attendees for some great questions and discussion during and after the session (and yes, I did make it back home in time to attend my daughter’s recital.)

NH .Net Code Camp 3 Presentation Materials

I have uploaded the content from my 2 talks at the NH .Net Code Camp 3 event from yesterday (6/4/2011). 

  • The code and material for my first talk – Introduction to Windows Phone 7 Development with Silverlight – are available here.
  • The code and material for my second talk –  What’s New in Windows Phone 7.1 Silverlight Development – are available here.

As is usually the case, the code has been sanitized, which involves the removal of my personal Bing Maps developer key.  For information on how to obtain your own map key, please check out the Bing Maps Developer Portal.

Many thanks to Patty, Udai, and Pat for hosting another fun event.