Archives

Archives / 2011 / April
  • MediaWiki, WP7 and JSON Together Again For The First Time

    In another project that I’m working on (like I don’t have enough of them) I stumbled across the MediaWiki API. MediaWiki is the workhorse wiki software that powers such sites as Wikipedia. What you may (or may not) know is that the MediaWiki API is pretty slick, offering access to any content on a MediaWiki powered site.

    In this post we’ll walk through building a Windows Phone 7 app to browse the content on Wikipedia using JSON and the MediaWiki API.

    First create a new Windows Phone 7 app. Any app template will do but I find the Windows Phone Databound Application template to be useful as it creates a few useful things out of the box for you like a ViewModel class and adds it to the app. It’s nothing special that you can’t do yourself, but does save a little time.

    Next you’ll want to be able to read the data coming from Wikipedia. We’ll be using the MediaWiki API (no download required) which can serve data up in XML format but we’ll opt for using JSON. Rather than using the native JSON methods in .NET let’s use the Json.NET library, a wicked cool library by James Newton-King that makes serializing and deserializing JSON into .NET objects a breeze.

    Unfortunately at the time of this writing, the Nuget package for Json.NET doesn’t install properly on Windows Phone 7 projects so you have to download the file, unzip it, and add the references manually. Hopefully someone updates the Nuget package so this 5 minute task can be avoided in the future.

    The default app has a listbox with items to display that links to a detail page. For this sample, we’ll fill the list with categories and drill into the category to display the pages associated with it. The first task is to retrieve the categories from Wikipedia. The full documentation for the API is online here. To get the categories it’s a straight forward API call that looks like this:

    http://en.wikipedia.org/w/api.php?action=query&list=allcategories&format=json

    The first part is where the API page is located on Wikipedia (it may not be in this location on other WikiMedia sites so check with the site owner). Then we specify an action, in this case a query. We ask for a list of items specifying “allcategories” and we want it in JSON format.

    Here’s the output:

    {
        query: {
            allcategories: [
                {
                    *: "!"
                }
                {
                    *: "!!! EPs"
                }
                {
                    *: "!!! albumns"
                }
                {
                    *: "!!! albums"
                }
                {
                    *: "!!! songs"
                }
                {
                    *: "!!AFRICA!!"
                }
                {
                    *: "!910s science fiction novels"
                }
                {
                    *: "!928 births"
                }
                {
                    *: "!936 births"
                }
                {
                    *: "!946 poems"
                }
            ]
        }
        query-continue: {
            allcategories: {
                acfrom: "!949 births"
            }
        }
    }

    MediaWiki queries come back in two groups. First is the query results and then a section titled “query-continue” that contains the next value that you can use to start from on a subsequent query. You may need to do several queries if you want to get everything. MediaWiki supports up to 500 items per call but very often (especially with the size of Wikipedia) that number can be in the thousands. It’s up to you how to do the queries (all at once or as you go) but think of it as picking up where you left off. The default size is 10 which is fine for now.

    However the results are not very pretty and somewhat bizarre list of categories. First we’ll add some more data to the category with information about it. This is done by adding more parameters to the API call:

    http://en.wikipedia.org/w/api.php?action=query&list=allcategories&format=json&acprop=size&acprefix=A

    All we’ve done is add “&acprop=size&acprefix=A” to the call. This brings in number pages, files, sub categories into the mix (the size property is the sum of all those). We’ll also get categories that start with the letter “A” to avoid the categories named “!”. Here’s the results:

    {
        query: {
            allcategories: [
                {
                    *: "A"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E Network shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E Shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E Television Network shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E Television Networks"
                    size: 17
                    pages: 14
                    files: 0
                    subcats: 3
                }
                {
                    *: "A&E Television network shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E network shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E shows"
                    size: 66
                    pages: 66
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&E television network shows"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
                {
                    *: "A&M Records"
                    size: 0
                    pages: 0
                    files: 0
                    subcats: 0
                }
            ]
        }
        query-continue: {
            allcategories: {
                acfrom: "A&M Records EPs"
            }
        }
    }

    That looks better. Unfortunately there’s no way to include additional filters like “don’t include items with size = 0” so you’re going to have to make multiple calls and the filtering in your app (LINQ is great for this) but this is good enough to get started.

    Json.NET can deserialize these results into an object graph but you need to create the classes for it. One way to do this is to use the JSON C# Class Generator which is a pretty handy tool if you’re starting with JSON as your format and don’t have anything. It doesn’t know anything about the Json.NET library so it uses native C# calls for the structure and helpers and but will give you something to start from.

    We’ll just build our classes manually as there are only a few we need. Here’s the first cut (based on the JSON data above):

    public class MediaWiki
    {
        public Query Query { get; set; }
        public QueryContinue QueryContinue { get; set; }
    }
     
    public class Query
    {
        public Allcategory[] Allcategories { get; set; }
    }
     
    public class Allcategory
    {
        public int Size { get; set; }
        public int Pages { get; set; }
        public int Files { get; set; }
        public int Subcats { get; set; }
    }
     
    public class QueryContinue
    {
        public Allcategories Allcategories { get; set; }
    }
     
    public class Allcategories
    {
        public string Acfrom { get; set; }    
    }

    The class and property names here are not the most intuitive but we’ll fix that. First let’s make the call to the API to get our JSON then deserialize it into this object graph. Replace the LoadData method in the MainViewModel with this code:

    public void LoadData()
    {
        var address = @"http://en.wikipedia.org/w/api.php?action=query&list=allcategories&format=json&acprop=size&acprefix=A&aclimit=500";
        var webclient = new WebClient();
        webclient.DownloadStringCompleted += OnDownloadStringCompleted;
        webclient.DownloadStringAsync(new Uri(address));
    }

    This kicks off the download and sets up the callback to invoke when the download is complete (I also added “&aclimit=500” to the end of the query to get more than the default 10 results). When the string is downloaded we call this:

    foreach (var category in json.Query.Allcategories.Where(category => category.Size > 0))
    {
        Items.Add(
            new ItemViewModel
                {
                    LineOne = "Pages: " + category.Pages,
                    LineTwo = "Subcats: " + category.Size,
                });
    }

    This takes the result of the download and calls the JsonConvert method DeserializeObject. This is a generic method that we pass our MediaWiki class from above to. Then just loop over the Allcategories array to pluck out each category and create our ItemViewModel items manually. We use LINQ in the loop to filter out any categories with a size of 0.

    Here's the result on our phone:

    This isn’t too exciting because frankly we don’t know what the name of each category is. Remember the JSON?

    {
        *: "A&E Television Network shows"
        size: 0
        pages: 0
        files: 0
        subcats: 0
    }

    Hmmm.. how are we going to get that name into a property in our class? The Json.NET library matches up names of attributes in the markup with the name of a property in your class. We can’t create a property called “*” as that’s not valid in C#.

    The answer is to use the JsonPropertyAttribute on our class and introduce a new property called Title. Here’s our updated Allcategory class with the markup:

    public class Allcategory
    {
        [JsonProperty("*")]
        public string Title { get; set; }
        public int Size { get; set; }
        public int Pages { get; set; }
        public int Files { get; set; }
        public int Subcats { get; set; }
    }

    This tells Json.NET that when it comes across a value with the markup “*” to deserialize it into the Title property.

    Now we can update our LoadData method to use the title instead:

    private void OnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        var json = JsonConvert.DeserializeObject<MediaWiki>(e.Result);
        foreach (var category in json.Query.Allcategories.Where(category => category.Size > 0))
        {
            Items.Add(
                new ItemViewModel
                    {
                        LineOne = category.Title,
                        LineTwo = string.Format("Pages: {0} Subcats: {1}", 
                            category.Pages, category.Subcats),
                    });
        }
        IsDataLoaded = true;
    }

    Which now looks like this on the phone:

    That’s a little better.

    With the [JsonProperty] attribute we can also specify the name of the property in the JSON markup so that we’re not tied to that name when specifying the name in our C# class. This allows us to make our C# class a little more readable. Here’s an couple of examples:

    public class Query
    {
        [JsonProperty("allcategories")]
        public Allcategory[] Categories { get; set; }
    }
     
    public class Allcategory
    {
        [JsonProperty("*")]
        public string Title { get; set; }
        public int Size { get; set; }
        public int Pages { get; set; }
        public int Files { get; set; }
        [JsonProperty("subcats")]
        public int Categories { get; set; }
    }

    The JsonProperty will match whatever markup MediaWiki (or whomever is providing your JSON feed) and we can use a more friendlier name in our code (P.S. the class names can be whatever you want, it’s the properties that are important).

    The default app already has the function to display the DetailsPage when you tap on an item in the list. It passes the index of the array of ItemViewModel items to the page which retrieves it from the Items property of the ViewModel stored in the App class and sets up the title of the DetailsPage to the LineOne property of the ViewModel.

    This property is really the title of the category and the value we can use to get more information from the MediaWiki API. We’ll use the “categorymembers” action to get all pages in a given category. Here’s the url we’re going to use:

    http://en.wikipedia.org/w/api.php?action=query&list=categorymembers&format=json&cmtitle=Category:Zombies&cmprop=type|ids|title

    We’re going after all pages in the “Zombies” category and want to include the type of page, the id, and the title.

    Here’s the JSON from this call:

    {
        query: {
            categorymembers: [
                {
                    pageid: 8375
                    ns: 0
                    title: "Draugr"
                    type: "page"
                }
                {
                    pageid: 27279250
                    ns: 0
                    title: "Felicia Felix-Mentor"
                    type: "page"
                }
                {
                    pageid: 143895
                    ns: 0
                    title: "Jiang Shi"
                    type: "page"
                }
                {
                    pageid: 1776116
                    ns: 0
                    title: "Clairvius Narcisse"
                    type: "page"
                }
                {
                    pageid: 781891
                    ns: 0
                    title: "Philosophical zombie"
                    type: "page"
                }
                {
                    pageid: 7568400
                    ns: 0
                    title: "Zombie Squad"
                    type: "page"
                }
                {
                    pageid: 5048737
                    ns: 0
                    title: "Zombie walk"
                    type: "page"
                }
                {
                    pageid: 22328159
                    ns: 0
                    title: "Zombeatles"
                    type: "page"
                }
                {
                    pageid: 34509
                    ns: 0
                    title: "Zombie"
                    type: "page"
                }
                {
                    pageid: 6569013
                    ns: 14
                    title: "Category:Hoodoo"
                    type: "subcat"
                }
            ]
        }
        query-continue: {
            categorymembers: {
                cmcontinue: "subcat|31450932|ZOMBIES AND REVENANTS IN POPULAR CULTURE"
            }
        }
    }

    Note that we have a new attribute called “categorymembers” instead of “allcatgories” (but the top level attribute is still “query”). We’ll definitely need a class to handle the categorymembers array returned by the call but should it go into the existing Query class?

    Technically you could do it. Json will deserialize it for you and if it can match up the attribute with the C# property name (or find the property decorated with the JsonProperty attribute) it will and the other items will just be null.

    It’s up to you if you want to build a special query class for each type of query. I suggest you do (you can even create a generic MediaWikiQuery<T> class that takes in things like a CategoryMember class or AllCategory class) to keep things clean. Otherwise you’re violating a few SOLID principles and laying the foundation for a God class.

    For demo purposes I’ll just add the CategoryMember class to our Query class but like I said, it’s a demo only. Here’s the new CategoryMember class and the modified Query class:

    public class CategoryMember
    {
        public int PageId { get; set; }
        public string Title { get; set; }
        public string Type { get; set; }
    }
     
    public class Query
    {
        [JsonProperty("allcategories")]
        public Allcategory[] Categories { get; set; }
     
        [JsonProperty("categorymembers")]
        public CategoryMember[] Pages { get; set; }
    }

    Now when the DetailsPage loads we’ll figure out the index of the item based on the parameter passed in and call a new method on our MainViewModel to load the pages.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        string selectedIndex = "";
        if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
        {
            int index = int.Parse(selectedIndex);
            App.ViewModel.LoadPages(index);
            DataContext = App.ViewModel.SelectedCategory;
        }
    }

    Note that the LoadPages method is another call to the service so we’ll probably want to create a handler in our view to handle displaying a “Loading” indicator and respond to something like a property changed event on our ViewModel to remove it. Here we’ll just the binding in the ViewModel and the page will update (eventually) with the list of pages. It’s not the UX you want to build but this post is already getting long and I’m sure you’re pretty tired reading it.

    We also set the DataContext of our DetailsPage to a new property we added in the ViewModel call SelectedCategory. This way MainViewModel hangs onto whatever category the user selected so we can reference it (and it’s properties) later.

    To load the pages first we’ll call out to Wikipedia to fetch them based on our category. We could pass in the title we want but here we’ll pass the index to the title and fetch it in the method:

    public void LoadPages(int index)
    {
        SelectedCategory = Items[index];
        var address =
            string.Format(
                "http://en.wikipedia.org/w/api.php?action=query&list=categorymembers&format=json&cmtitle=Category:{0}&cmprop=type|ids|title",
                SelectedCategory.LineOne);
        var webclient = new WebClient();
        webclient.DownloadStringCompleted += OnDownloadPagesCompleted;
        webclient.DownloadStringAsync(new Uri(address));
    }

    This sets up SelectedCategory based on the index we passed in and crafts the url to the MediaWiki API to fetch all pages for whatever the category is (based on the title).

    Now we need to process the JSON when the download of the page list completes. For this we’re going to need a new ViewModel. Here’s a quick and dirty one that just uses the title and pageid property:

    public class PageViewModel : INotifyPropertyChanged
    {
        private int _pageid;
        private string _title;
     
        public int PageId
        {
            get { return _pageid; }
            set
            {
                if (value == _pageid) return;
                _pageid = value;
                NotifyPropertyChanged("PageId");
            }
        }
     
        public string Title
        {
            get { return _title; }
            set
            {
                if (value == _title) return;
                _title = value;
                NotifyPropertyChanged("Title");
            }
        }
     
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            var handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    We’ll display the Title to the user but the pageid needs to be stored because later we’ll want to retrieve all the details about a single page.

    In the ItemViewModel (our category) we have an ObservableCollection of PageViewModel objects called Pages. This mimics the Items property in the MainViewModel. Here’s the declaration:

    public ObservableCollection<PageViewModel> Pages { get; private set; }

    And here’s the constructor creating them:

    public ItemViewModel()
    {
        Pages = new ObservableCollection<PageViewModel>();
    }

    Back in the MainViewModel we deserialize the JSON and add the PageViewModel objects to our selected category:

    private void OnDownloadPagesCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        var json = JsonConvert.DeserializeObject<MediaWiki>(e.Result);
        foreach (var page in json.Query.Pages.Where(page => page.Type.Equals("page")))
        {
            SelectedCategory.Pages.Add(
                new PageViewModel
                    {
                        PageId = page.PageId, 
                        Title = page.Title
                    });
        }
    }

    Just like when we loaded the categories here we only select items where the page.Type is a “page”. In our Zombie example, one of the items is a “subcat”. In a real app, we would have something to handle constructing that and creating some kind of link to another category (since everything is a category, we could reuse a lot of this code for that).

    The last part is changing the DetailsPage.xaml to display a list of pages. Here’s the LayoutRoot grid updated:

    <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{Binding SelectedCategory}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
     
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="PageTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="ListTitle" Text="{Binding LineOne}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
     
        <!--ContentPanel contains details text. Place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock x:Name="ContentText" Text="{Binding LineThree}" TextWrapping="Wrap" Style="{StaticResource PhoneTextNormalStyle}"/>
            <ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Pages}" SelectionChanged="MainListBox_SelectionChanged">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin="0,0,0,17" Width="432">
                            <TextBlock Text="{Binding Title}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Grid>

    The result is a details page that shows our category as the title and a listbox full of pages.

    At this point you can add an additional handler to the listbox to drill down into the page itself. From there you can pluck out a list of images, links to other pages, and even the wiki content and sections.

    Check the MediaWiki API for more info on getting down into all of this stuff. It’s very cool being able to poke into MediaWiki and beats the hell out of screen scraping!

    A Call to Action!

    This just gives you an intro to accessing a resource like Wikipedia using the public API and deserializing results via JSON into a set of classes you can use to bind to a Windows Phone 7 app. I’m going to leave the rest up to you. A few ideas to think about if you were to build on this example:

    • Calling directly from the ViewModel isn’t a production practice, it was a demo only. You’ll probably want to create a MediaWikiService and inject it into your ViewModel
    • The call can take a few seconds so you’lll need to handle this in your service and update the UI accordingly
    • Drill down into a single page, pluck out the images and create a visual MediaWilki browser experience or something.
    • You can even post content *to* a MediaWiki wiki (after you login with a username/pass that has rights to) so not only can it be a browser experience but it can be an editing experience too.
    • This is just one example to use the MediaWiki API by fetching categories and page content but there are a lot of other type of queries you can make like getting a list of recent changes, comment history, or even random pages.

    Use your imagination and above all, have fun. If you get stuck feel free to leave questions in the comments section and I’ll do my best to answer them.

  • Custom SharePoint Ribbons and Current List Item in JavaScript

    I recently had to build a custom ribbon item displayed when a user viewed a list item. The ribbon button would whisk the user away to a view on another list, passing the current list item ID to the view to use as a query string filter. The secondary list has a field that references the first list (sort of a parent/child relationship).

    The challenge (besides creating a Ribbon item which is a Hell unto itself) was to get the current list item ID and pass it to the view via a query string so the view could be filtered. The SP.ClientConext class in the ECMAScript Class Library for SharePoint lets you get all kinds of things like retrieving lists and even list items from SharePoint through JavaScript. I didn’t find any way to get the current list item (it’s easy to get all list items for the current list but there didn’t seem to be a property like SP.ListItem.get_current()). Maybe I overlooked it.

    After posting a few pleas for help on Twitter (including one dude who told me to go trolling Stack Overflow because “several MVPs frequent” there, to which I replied “Yes I know. I’m one of them.”) I caved in and posted the question on Stack Overflow (well, the recently promoted SharePoint site on StackExchange).

    It got a few answers but nothing that really worked for my situation. Remember, I want to a) create a custom ribbon item that links to another view on another list and b) pass along the id of the current list item to that view for filtering (via a query string). Finally I stumbled over the answer buried deep on MSDN.

    So here’s the effect we’re going after. A ribbon button on the display form of a list item that links to an associated view:

    The Custom Group contains a series of Buttons, each of which links to a view in another list. Each view was created with a custom filter to only show items where a field in that list matched the value passed in.

    Normally you would open the list view in SharePoint designer, select the DataView and add a parameter to filter on a query string value. I’ll follow up with another blog post on how to do this programmatically without opening SharePoint Designer.

    When the user clicks on one of the custom buttons, we open another dialog and display that view.

    Like I said there were some good answers on the question from the SharePoint community. Brage Tukkensæter posted an answer that involved a custom action that iterated through each item selected and passed it along to a dialog. The problem with this was that you needed to have the user select at least one item in the list in tabular form (I’ve turned this function off in the view) and launching from the Display Form, the SP.ListOperation.Selection property he proposes to use is blank.

    Wouter van Vugt, another SharePoint MVP (Stack Overflow is just full of them), had another option. Grab the ID value from the query string of the list form and use it. That sounds like a fairly simple idea but it requires a few lines of JavaScript to grab the query string value. There are many examples on the web that you find to do this but they all require some kind of parsing, maybe some regular expressions, and it all feels awkward.

    I thought about using SPServices since we had that available but it meant that I would be relying on the JavaScript to call out to SPServices to do this and all of my buttons would have to be written to pass in something unique to a JavaScript method to do this. Again, more work than I think was necessary. I have the item up on the screen so I *know* SharePoint knows what the ID is. Why is it so freakin’ hard to get it.

    Well, it isn’t but it required some lucky digging and MSDN documentation from the previous version of SharePoint to surface it.

    Buried on this page in MSDN is a HOWTO on adding actions to the user interface. On that page there’s a list of URL Tokens.

    • ~site - Web site (SPWeb) relative link.
    • ~sitecollection - site collection (SPSite) relative link.
    • In addition, you can use the following tokens within a URL:
    • {ItemId} - Integer ID that represents the item within a list.
    • {ItemUrl} - URL of the item being acted upon. Only work for documents in libraries. [Not functional in Beta 2]
    • {ListId} - GUID that represents the list.
    • {SiteUrl} - URL of the Web site (SPWeb).
    • {RecurrenceId} - Recurrence index. This token is not supported for use in the context menus of list items.

    These are normally associated with a UrlAction element but there’s nothing to prevent you from using them in your CustomAction (in my case the CommandAction attribute of a CommandUIHandler since I was building a custom ribbon button).

    So I crafted my CommandAction like this:

    <CommandUIHandler CommandAction="javascript:viewDialog({ItemId});"/>

    I simply call my custom JavaScript method and pass it the {ItemId} token. Inside my JavaScript (which I added to my solution as another CustomAction in a mapped folder to Layouts) I have this snippet:

    function viewDialog(id) {  
        var options = {    
            url: "/sitename/Lists/ListName/ViewName.aspx?ID=" + id,    
            width: 800,    
            height: 600,  
        };  
     
        SP.UI.ModalDialog.showModalDialog(options);
    }

    This takes in an id as a parameter (the {ItemId} token) and builds up the options to pass to the showModalDialog method on the SP.UI object.

    The result is a custom button that links to another view passing it the id for the current item.

    What’s sad is that it was a bugger trying to find that piece of knowledge. A few people have written short blogs on it but it’s not very discoverable. The 2010 version of the MSDN documentation doesn’t include the URL Token section and frankly its misplaced IMHO. It seems you can use these tokens on any custom action whether it’s a UrlAction or CommandAction. I’m sure there are other uses for it and it’ll be handy in the future.

    Hopefully I didn’t kill any kitten or unicorns (or worse, zombies) in answering my own question on Stack Overflow.

    If the universe explodes later you’ll know why and you can freely blame me. In the meantime, enjoy this snippet of knowledge.

  • SharePoint Server 2010 Windows Phone 7 Mobile Edition

    It’s wonderful to end the week with two of my favorite passions, SharePoint and Windows Phone 7. The last few months I’ve been working on a special project that you can install on your Windows Phone 7 starting today.

    SharePoint Server 2010 running on Windows Phone 7.

    That’s right. Now you no longer need an IT shop to use SharePoint. You can just deploy it on your own phone and decide how to run it.

    screenshot_4-1-2011_6.41.58.946screenshot_4-1-2011_6.42.3.906

    Why would anyone deploy a server to your phone? Several reasons but mostly it’s because you can totally control your entire SharePoint environment even if you’re out of the office or offline.

    Scott Haack, Senior Principle Program Manager in Bellevue, Oregon said this about why this project came about:

    “It’s about choices. SharePoint Server 2010 on the mobile platform allows users to have choices about who runs their IT systems and decides how the system is configured without having to go through complicated business processes.”

    It’s all about competition too. Here’s what Phil Haanselman, Principle Platform Program Manager in Portland, Washington says about the platform:

    “With SharePoint Server 2010 on the Windows Phone 7 this pushes the platform to the edge and beyond. There is nothing like this on the iOS or WebOS and nobody is thinking in this space. It’s going to be game changing.”

    Bringing the Pieces Together

    I knew it was going to be a big job but I was up for it. There were so many pieces to get co-ordinated and I knew I would have a few challenges along the way. Here’s what it took to bring it all together.

    IIS Express to the Rescue

    Back in June when Scott Guthrie announced IIS Express I got thinking about SharePoint and the Mobile user. Wouldn’t it be great if they could run SharePoint on their phones! I knew Windows Phone 7 was coming up as I was currently in the beta and building Silverlight apps already. I knew SharePoint would run on Window 7 so why not combine the best of both worlds.

    IIS Express is a lightweight component that weighs in at under 10mb. It also does not require administrative access to run applications and has a full feature set including SSL, URL Rewrite, and other IIS 7.x modules. All packaged together that can be run from a single location and does not require any registration/configuration steps.

    It seemed like IIS Express was perfect to run on WP7.

    NoDo Delays

    Getting IIS Express onto the phone was going to be a bit of a challenge however with some work and co-ordination with high ranking figures at Microsoft I was able to get it to compile down into a single DLL file.

    To get it onto the phone I worked with top people on the Windows Phone team and packaged IIS Express into the next update, the infamous NoDo release. So as of right now, anyone with NoDo installed actually has web server available to them. There were several other updates we packaged into NoDo that were put there for SharePoint Server to run (mostly around Kerberos ticket support and background processing).

    So as a result this was the primary reason why NoDo was delayed. I do apologize to the community for the NoDo delays, but now you know the reason. It was so mobile users could run SharePoint.

    Getting past the NoDo release the Windows Phone 7 was now ready and enabled for serving up .aspx pages and SharePoint.

    Redesigning Central Administration

    The biggest challenge was having to rebuild the Central Administration site to work with the Metro look and feel. It was a lot of work but we’ve built all the screens as new using the Windows Phone 7 controls. This was done so you have good touch targets to hit. In early betas, we were just using the out of the box Central Admin web pages but it was hard to click on things and I was always zooming in and out. So I built the Metro screens to make it easier for you to work with Central Admin.

    Everything is all there and hopefully organized in a good way so you won’t be totally thrown back when using the WP7 version of SharePoint. Here’s Central Admin running on WP7.

    screenshot_4-1-2011_6.42.6.786screenshot_4-1-2011_6.42.9.724

    The Metro Way

    With the Metro overhaul of Central Admin we wired everything back up. Using MVVM was key in being able to have the UI respond to what you did so it was easy to show real-time information about the server.

    Here’s how you can create a new Web Application with Central Admin on the Windows Phone 7

    First select Web Applications from Application Management pivot. You’ll see this menu

    screenshot_4-1-2011_6.42.13.323

    Now click on Manage web applications. We couldn’t implement the Ribbon in Windows Phone 7 so from the list select Create New Web Application. You’ll be presented with a data entry screen to enter all the information for your new web app:

    screenshot_4-1-2011_6.42.16.90

    All of the options are there just like the current release of SharePoint. Unfortunately due to some last minute problems and trying to get this done by the end of the week we were not able to include Claims Based Authentication so only Classic Mode is available. Anyone would be a Fool to try to deliver something in April without testing it so this was why this decision was made.

    Complete Feature Set, Almost

    Not exactly. As I said we don’t support Claims Based Authentication and there are few other features in SharePoint 2010 we don’t support. Here’s a list of the current restrictions. These have been left out either due to time constraints or technical limitations on the phone platform. A few of these features will be available in the Mango release of Windows Phone 7 due out sometime in 2012.

    • Kerberos. Kerberos support is not fully implemented so it’s suggested to keep web sites running under NTLM (most of the system works under Kerberos but without a true integrated authentication on the Windows Phone 7 not everything works, yet)
    • Content Deployment. This isn’t implemented at all in this release due to time constraints. It’s planned for a future release. Hopefully this doesn’t hinder people too much.
    • InfoPath Forms Services. This was tricky but with some clever coding, we’re able to convert, on the fly InfoPath forms into Windows Phone 7 controls. However in some last minute testing we found that InfoPath forms with complex rules breaks the model. Simple forms work, complex forms will be delivered in Service Pack 1 due out later in the year.
    • Define blocked file types. Unfortunately as we don’t have complete control over access to the Windows Phone 7 sub-systems (like the registry) so we’re unable to control blocked file types. No word on when this feature might be available.

    Leveraging the Phone

    This release doesn’t just allow you to run SharePoint Server on your phone but we’ve also leveraged specific features of the WP7 platform as well. For example you can now hook up SharePoint Picture Libraries to the Windows Phone 7 Media Library and any picture taken on the your phone can instantly be available to anyone browsing the site.

    The other big integration point is Geolocation. Windows Phone 7 devices all have a built-in GPS. SharePoint Server 2010 leverages this by geotagging any content. A new feature in Document Libraries allows users to geotag documents with location information which can then be used to filter documents and lists based on locality and even plot document creation locations on a Bing Map using the built-in Bing Map Controls.

    It’s really up to the SharePoint web part developer to figure out how best to leverage these new capabilities. Like it was said before, this is game changing.

    Availability

    Most importantly when can you get this?

    Right now!

    Download the .xap file here directly and you can instantly sideload it onto your Windows Phone 7 (developer unlock required). If you’re not a developer then you’ll have to wait for the app to make it through Marketplace Certification which should be any day now.

    You do require the NoDo update to be able to run SharePoint Server 2010 on your phone so please make sure you have that installed first. The software will detect if IIS Express is installed or not and unfortunately fail if you don’t have the update yet.

    The software will be released on CodePlex in the next while under the Apache License so anyone can contribute to it. Please contact me offline if you’re interested.

    After MIX11 we’ll be making the server available as a NuGet package that can be deployed anywhere without the need to access the Windows Phone Marketplace. Stay tuned for news on this.

    Many Thanks

    Many thanks to all the wonderful people that made this project possible. Without their co-operation we wouldn’t be where we are today:

    • Geoffrey Chaucer
    • Eduard de Dene
    • John Aubrey
    • Sizdah Bedar
    • Joseph Boskin