Using Multiple Properties Or The Entire Object In a Converter Class for Windows Phone and WinRT

Kind of a long wordy title, what does it really mean?  When you are creating a custom converter for Windows Phone or WinRT, you create a class that inherits from IValueConverter and implement a Convert method.  In that method you’re given (among other things) the value that has been bound (bind-ed sounds too funky, sorry) to your element and optionally a converter parameter that you can use to help you decide what your Convert method should return.  For example, your parameter could return “true”, “backwards”, “Blazers”, or whatever you want.  The main limitation as you may be noticing here is that you can only pass a single value back.  So what happens when you need to look at multiple properties of the item that is being used in the data binding in order to decide what to pass back from Convert? 

Here’s a simple example from something I was working on.  I’m binding to an item that has an “IsMine” and “IsOpen” property.  If the current item has “IsMine” equal to true, then I will return different values depending on whether IsOpen is true or false.  This obviously is not possible if you are just passing a single string back as your converter parameter.  The trick is to not assign a value to the binding; when you do that, the entire item is passed in as the “bind-ed” value.  So assume you’ve written a custom Convert method called MyColorConverter.  You want to use that for the background color of a Border element, so you would configure the binding for it like this:

 

<BorderBackground=”{Binding Converter={StaticResource DataItemsColorConverter}}”>

 

Notice that usually you would say what field you are binding too like this:  {Binding myField, Converter={blah}.  By omitting a specific field for the binding value, you get access to the entire object.  Then in my Convert method I can work with it like this:

 

    public class DataItemsColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {

            SharePointData.DataItem di = (SharePointData.DataItem)value;

 

            if (di.IsMine)
            {
                if (di.IsOpen)
                    return “#FF41719C”;
                else
                    return “#FFED7D31”;
            }
            else
                return “#FF7030A0”;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            //not going to be converting back
            return value;
        }
    }

 

 

How To Send An Authenticated Message to the Windows Phone Push Notification Service

The Push Notification Service is a cool feature of Windows Phone that lets you do things like send toast messages, update a Live Tile, etc. for your Windows Phone application.  You can use the service without any additional transmission security protocols, but if you do you are limited to a maximum of 500 messages per day.  If you use SSL to set up a mutually authenticated session to the Push Notification Service however, you can send an unlimited number of messages.  This makes securing your conversation that much more appealing.  The actual process for doing so is unfortunately documented about as poorly as anything I’ve ever seen.  Fortunately the social forums in the Windows Phone App Hub are quite useful so you can piece it together from reading through them.  To save you the time though of trying to hunt down all of the pieces needed to do this, I thought I would bring it all together here in one simple document.  You know, kind of like the product team should have done.  🙂  So here goes:

  1. You can read about the requirements for the certificate that’s used for establishing this secure communication here:  http://msdn.microsoft.com/en-us/library/ff941099(v=vs.92).  To make it simple though, I found that if you have an SSL certificate from one of the supported certificate authorities, it works just fine.  To see the list of supported certificate authorities, see here:  http://msdn.microsoft.com/en-us/library/gg521150(v=vs.92).
  2. You need to take this certificate and upload it to the App Hub.  You don’t need the PFX with the private key, just the public version of the certificate (i.e. the .cer file).  To upload it, sign into the App Hub, sign-in and then click on your account name in the upper left corner.  When you go into the account management page you will see a link called Certificates under the My Account banner.  Click on that and follow the instructions there to upload the certificate.
  3. In your Windows Phone application you create a HttpNotificationChannel class instance.  When you create the new HttpNotificationChannel, use the common name (CN) of the SSL certificate as the second parameter for the new channel.  You can find the common name of your certificate by double-clicking on the .cer file top open it, click on the Details tab, and then click on the Subject property.  You will see values displayed in the window below and the first one should be something like “CN = www.contoso.com“; you want to use just the “www.contoso.com” in this example.  So when you created your new channel it would look something like this:  pushChannel = new HttpNotificationChannel(“myChannelName”, “www.contoso.com“);
    1. NOTE:  If you have already created channels for different devices, then you will need to find your channel using the HttpNotificationChannel.Find method, then .Close and .Dispose the channel.  Then you need to recreate it so you can associate your common name with the connection.
  4. Where run your server side code, you need to install the certificate, including the private key (so the .pfx file).  You also need to ensure that the account for your application pool has access to the private keys for that certificate.  To do that, open the MMC tool and add the Certificates snap-in for the Local Computer.  After you’ve installed your certificate into the Personal node, right-click on the certifcate in the MMC and select All Tasks…Manage Private Keys.  You then need to add the account for the application pool your application is using and grant it at least Read rights to the keys.
    1. NOTE:  If you are using the new built in accounts in IIS 7.5, like ApplicationPoolIdentity, then you need to grant access to IIS apppool\ASP.NET v4.0, where “ASP.NET v4.0” is the name of your app pool.
  5. In the code where you are sending the message to the Push Notification Service you need to add the certificate to the HttpWebRequest object.  You would typically do this by opening up the X509 Store, getting the certificate collection for the My store, doing a Find on the collection by thumbprint, where you need to copy and paste the certificate’s thumbprint from the certificate properties to your code, and then using the first certificate in the collection it returns (i.e. myCollection[0]).  Once you have the certificate you can add it to your request like this:  myRequest..ClientCertificates.Add(mySslCertificate);

The other important things to note:

  • Your certificate that you upload in only used for four months.  If you don’t submit an application for certification to the marketplace that uses the certificate then it will need to be uploaded again.  When you submit your app for certification to the marketplace you will have an opportunity to select a certificate for it from the list of certificates that you have uploaded.  Just select the certificate that you uploaded for these communications and you are set.
  • How do you know if this works?  Well, when you create the HttpNotificationChannel class instance on the Windows Phone client, you will get back a notification channel Uri that send your messages to.  Look at that Uri – if you are not using an authenticated connection, then you will see “throttledthirdparty” in the path.  However if you created your class instance correctly, the path will contain “unthrottledthirdparty”; in addition the protocol it shows will be HTTPS instead of HTTP.  Now of course, to really make sure it works, after you get that Uri back you need to successfully send a message.  If it arrives at your device okay then you know it worked.

Using Compression on Windows Phone 7.5

As I’m sure many of you know who have done development on Windows Phone, there isn’t built in support for compression and decompression.  Many folks have pointed to the SharpCompress project on CodePlex, and this is what I ended up using for it as well.  The BIG thing that was missing from it though has been any documentation whatsoever for decompressing files on the phone.  I had quite a bit of code I had written for a winform application that used the WriteAllToDirectory method to decompress a zipped file on Windows.  However, that method doesn’t exist in the assembly for Windows Phone.  In addition, you can’t just provide the path to which you can unzip when using the Windows Phone assembly for SharpCompress, you have to give it a stream object.

This ultimately worked, but requires you to do things quite a bit differently from when you use this on the full version of Windows.  Here are some tips to get you through this:

    1. Enumerate through the Entry collection of the IReader  you get from the Reader factory:

      //”sr” is a stream reader object from previous code that contains the byte array of the actual zip file

      using (var reader = ReaderFactory.Open(sr))

      {

      while (reader.MoveToNextEntry())

      {

         //IsDirectory always returns false in everything I’ve seen so far

         if (!reader.Entry.IsDirectory)

         {

            //process the entry, described next

         }

         else

         {

             //do not know of a scenario where we can end up here

             Debug.WriteLine(reader.Entry.FilePath);

         }

      }

      }

        2.       Create the directory(s) for the files, then get an IsolatedStorageFileStream instance to which you can write:

        //IsDirectory always returns false in everything I’ve seen so far

        if (!reader.Entry.IsDirectory)

        {

               IsolatedStorageFileStream theFile = GetLocalFile(reader.Entry.FilePath);

        }

         

        private IsolatedStorageFileStream GetLocalFile(string fullPath)

        {

           IsolatedStorageFileStream fs = null;

         

           try

           {

               //get isolated storage so we can create directories and decompress

               IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

         

               //trim everything from the last index of /, which is the file

               //name, i.e. it will look like folder/folder/folder/filename.txt

               string dirPath = fullPath.Substring(0, fullPath.LastIndexOf(“/”));

         

               //what’s nice is you can create the full folder path in one call

               if (!storage.DirectoryExists(dirPath))

                  storage.CreateDirectory(dirPath);

         

               //now that all the directories exist, create a stream for the

               // file – again, cool because you can just give the full path

               fs = storage.CreateFile(fullPath);

           }

           catch (Exception ex)

           {

               Debug.WriteLine(ex.Message);

           }

         

           return fs;

        }

          3.       Now that you have a stream, you can write the individual file out use the WriteEntryTo method:

            if (!reader.Entry.IsDirectory)

            {

               IsolatedStorageFileStream theFile = GetLocalFile(reader.Entry.FilePath);

             

               if (theFile != null)

                   reader.WriteEntryTo(theFile);

            }

             

            Hope this helps someone, the lack of documentation was troublesome so I just had to puzzle through it.

            Deciphering NullReferenceException or Binding Reference Cycle Errors in Windows Phone 7.1

            I recently ran across a very, very difficult problem to diagnose and fix, and I couldn’t find this issue going on anywhere else so I thought I’d write about it here in case it comes up again for anyone else.  In a Windows Phone 7.1 (i.e. Mango) application, you have a service reference – in my case, a WCF application.  What I was seeing is that frequently yet randomly, it would throw an exception just creating the WCF proxy.  What I mean by that is this line of code:

            MyService.MyClass foo = new MyService.MyClass(“myConfigSettings”);

            Would throw an exception.  While that’s kind of inherently crazy, what was more puzzling and frustrating about it is that the exception it would throw wasn’t always the same.  It would throw one of these two exceptions – no rhyme or reason as to which it would throw when:

            • NullReferenceException – absolutely no details here, no message, no inner exception nothing.
            • A binding reference cycle was detected in your configuration. The following reference cycle must be removed: basicHttpBinding/BasicHttpBinding_IMyAppInterface

            One of the (many) nutty things about this, is that the exception would only be thrown when the method was invoked from some code that ran during application start up; invoke that method any other time and there’s no problem.  Also, if you just step through the exception handling code and then drag the next line of execution back up to create the proxy instance, it always worked.  There were other really strange and weird things that had varying degrees of success, but what finally kind of tipped it off to me was the fact that in the application start up code, there was another chunk of code that executed and it also created an instance of that WCF proxy and it NEVER failed.  So in trying to figure out why one always worked and one frequently failed, it finally occurred to me to look at how the code was being invoked.  As it turns out, I had two different background threads being created, and each one was running a different chunk of code.  Each thread was both calling different methods that contained code that would instantiate an instance of the WCF proxy.  Well this, as it turns out, was the downfall and cause of this little problem.  By reconfiguring the code so that all the app startup tasks run on a single background thread, the weird exceptions magically disappeared.

            It was pure luck of course figuring this out (along with a lot of trial and error) so I thought I would share this little nugget in case you find yourself in a similar predicament.

            Windows Phone 7 and Other Mobile Device Access to SharePoint 2010 SAML Sites After Applying SP1 and June 2011 CU

            As I alluded to in an earlier post, there have been some changes in SP1 and June CU that impact the ability of Windows Phone 7 (both RTM and Mango) and other mobile devices to access SharePoint sites that use SAML authentication.  I described in a different post how to change the compat.browser file to essentially change the behavior when entering a SAML site so that it treats a mobile browser as a regular desktop browser (http://blogs.technet.com/b/speschka/archive/2010/11/21/some-windows-phone-7-and-sharepoint-2010-tips.aspx).  That at least lets you authenticate with the site, and then you can use the normal browser views of the site or you can manually navigate to the mobile pages.

            When SP1 and June CU came out however, the method of modifying the compat.browser file to allow authentication quit working.  Since that time a number of folks have looked at this and for now there is a new work-around that will provide the same behavior as before.  To do this, you need to modify the web.config file for each web application that you intend to use your mobile devices on.  To get this behavior add the following snippet in the system.web section of the web.config of your Web Application:

            <browserCaps>

            <result
            type=”System.Web.Mobile.MobileCapabilities, System.Web.Mobile,
            Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” />

            <filter>isMobileDevice=false</filter>

            </browserCaps>

            Making this change should allow most mobile devices to access a SAML secured site.  It does not, however, enable the Office Hub application in Windows Phone 7 to work with the site.  If or when the story changes on mobile support I’ll update the blog with another post.

            Connecting to an SSL WCF Service with Windows Phone 7 Emulator

            Had lots of fun earlier trying to figure out why my Windows Phone 7 application could not connect to my WCF endpoint.  I had tested things out thoroughly with a standard winforms client application and everything worked great, but whenever I tried hitting the same endpoint from my WP7 emulator I’d get the annoying error along the lines of “no endpoint listening” and if you look at the inner exception it was something like a 404 not found response.  Of course this was completely silly, the endpoint was there.  There were two things that I learned to resolve this:

            1. The error really meant that the phone emulator did not have the root certificate authority for the SSL cert in its list of trusted certs.  Unfortunately even with the WP7 1.1 (i.e. Mango SDK), there does still not appear an easy way to do this.  What you really need to do is put the root CA .cer file into a zip file somewhere, and then put it up on a web site where you can download it.  It could be a local development server, you can email it to yourself at something like HotMail, etc.  Navigate to that file from within the emulator and it will download it then show you the contents of the zip file.  If you click on the .cer file then it will offer to install it for you.  Take it up on this offer and it will put it in the list of trusted certificate authorities and you are good to go.  Or so it may seem… (see the next item)
            2. The steps I described in #1 work great…until you stop and restart the emulator.  It has no persistent state it seems so everytime you happen to stop it (or the many times it gets stopped itself and/or disconnected from Visual Studio) you have to repeat step 1 all over again.  Every time.  Painful as heck.  Not sure if this is on the fix radar or not but I guess we’ll see.

            FBA Sites with Office Hub in Windows Phone 7

            Hey all, just wanted to give a quick but important update to the post on integrating SharePoint 2010 with Windows Phone 7 (http://blogs.technet.com/b/speschka/archive/2010/11/21/some-windows-phone-7-and-sharepoint-2010-tips.aspx).  After playing around with this some more and reviewing some of the tips left in the comments by our friend Tomislav, I got the right combination of things to get the Office Hub in Windows Phone 7 to open an FBA site. 

            There were two keys to making this work as it turns out:

            1. You must secure your FBA site with SSL.  If you don’t have SSL then you won’t have joy.
            2. You must use a fully-qualified domain name for the zone.  For example, https://foo will NOT work.  However, https://foo.contoso.com WILL work.  This was the important distinction I found in my testing.

            Hope this clears up some of the ongoing confusion around Office Hub support for FBA sites in SharePoint 2010.  Thanks to all the folks who commented on the previous thread; I think it’s been very helpful to everyone that’s trying to figure this all out right now.