Develop and deploy Silverlight + SharePoint 2010 Solutions

I had the pleasure of presenting at the Australian SharePoint Conference on Develop and deploy Silverlight + SharePoint 2010 Solutions.  I had a blast, thank you guys for all the work organizing everything.

While the PowerPoint slides will be made available shortly, I just want to take the time and share the key points of the presentation in detail for people to reference:

Download the zipped solution of what I built on stage here

Part 1 is about getting started.  How do you start if you have some dev skills and aren't afraid of code.  Where do you start?  You'll see how things begin to come together.

 

WHAT DO YOU NEED?

  • Visual Studio .NET 2010 (you can use Visual Web Developer 2010 Express)
  • Silverlight 4 runtime (you probably already have this via Windows Update)
  • Silverlight 4 SDK included in Silverlight 4 Tools for Visual Studio 2010 (free)
  • Silverlight 4 Toolkit April (free)
  • Of course, it would be quite nice to actually have SharePoint 2010 somewhere so you can test this :-)  You can do this demo with SharePoint Foundation 2010 (free), but you will need to have a Windows Server 2008 / 2008 R2 (not free) as well as the x64 hardware to run this server (not free)
  • For IT PRO, it is possible to compile the Silverlight application with the above tools and deploy this to your SharePoint 2010 my-site server just to see how it works.  Let me know how this goes!

If you aren't sure where to grab these, use the Microsoft Web Platform Installer 2.0 - it figures out everything for you.

image

 

THE GOAL

The goal here is to show a Silverlight application working with SharePoint by consuming SharePoint data. 

image

Here's a Silverlight web part, using the Chart from Silverlight toolkit, but pulling data from a SharePoint list live.

 

SETTING UP THE PROJECTS

In VS.NET 2010, create a Silverlight project, accept the suggestion that it wants to add an additional ASP.NET Web Application project for hosting the Silverlight project.

image

I specifically targets Silverlight 4 because I have the Silverlight 4 toolkit installed on my machine.  I've previously build this demo with Silverlight 3 and Silverlight 3 toolkit.

 

XAML

  1. Add a Silverlight User Control to your project SharePointChart.xaml, compile project so VS.NET recognizes there's a new user control.
  2. Drag and drop the SharePointChart.xaml component from the toolbox into the MainPage.xaml
  3. Remove any positioning or alignment attributes, so that the SharePointChart snaps to the width and height of the parent (MainPage.xaml).
  4. I then add a file to the project, this file contains two classes:
    an Entity that implements INotifyChanged and a Collection that inherits from ObservableCollection
  5. using System.Collections.ObjectModel;
    using System.ComponentModel;
    //REMEMBER: namespace
    namespace SLSPTest
    {
        /// <summary>
        /// Two interfaces for easy databinding in Silverlight:
        /// INotifyPropertyChanged - for entity - raise event when a property is updated and tells the UI
        /// ObservableCollection - for collections - raises event(s) when elements add/removed, provides enumerator
        /// </summary>
        public class PollItem : INotifyPropertyChanged
        {
            private string surveyChoice = "";
            private int surveyCount = 0;
            public PollItem(string Choice, int Count)
            {
                surveyChoice = Choice;
                surveyCount = Count;
            }
            /// <summary>
            /// A Choice in this survey
            /// </summary>
            public string SurveyChoice
            {
                get { return surveyChoice; }
                set
                {
                    surveyChoice = value;
                    OnPropertyChanged("SurveyChoice");
                }
            }
            /// <summary>
            /// Number of votes for this choice
            /// </summary>
            public int SurveyCount
            {
                get { return surveyCount; }
                set
                {
                    surveyCount = value;
                    OnPropertyChanged("SurveyCount");
                }
            }
    
            #region Implement INotifyPropertyChanged interface
            public event PropertyChangedEventHandler PropertyChanged;
            void OnPropertyChanged(string propertyName)
            {
                // check event handlers exists
                if (PropertyChanged != null)
                {
                    // raise event
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
            #endregion
        }
    
        public class PollCollection : ObservableCollection<PollItem>
        {
            // just a strongly typed observable collection
        }
    }
  6. The reason that I create these two classes isn't particularly clear - but basically, I wanted to:
    • Keep the example simple
    • I don't want to have ANY UI-update code - want to utilize Silverlight databinding
    • I can quickly get the Silverlight part up and running with mock data
    • These simple objects can be changed to your strongly typed entity and lends well to a REST-based method call as well.
  7. Go back to the SharePointChart.xaml - I gutted the XAML and replaced it with:
  8. <UserControl x:Class="SLSPTest.SharePointChart"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:SLSP="clr-namespace:SLSPTest"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
        <UserControl.Resources>
            <SLSP:PollCollection x:Name="Collection" />
        </UserControl.Resources>
        
        <Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
            <toolkit:Chart Name="pollChart" Title="Favourite Languages" >
                <toolkit:Chart.Axes>
                    <toolkit:LinearAxis Interval="1" Orientation="X" />
                </toolkit:Chart.Axes>
                <toolkit:BarSeries Title="Poll" IndependentValueBinding="{Binding Path=SurveyChoice}" DependentValueBinding="{Binding Path=SurveyCount}" ItemsSource="{Binding Source={StaticResource Collection}}" />
            </toolkit:Chart>
        </Grid>
    </UserControl>
  9. The key points in the XAML are:
    • Namespace in Silverlight (xmlns)
    • Variables in Silverlight (UserControl.Resources)
    • Databinding of ItemSource, and set Idenpendent/DependantValueBinding
    • It is also VERY IMPORANT that I didn't want to show any more XAML after this point.  SharePoint developers are easily scared by scary looking XML-like code.  May be because it reminds them of CAML.
  10. Time to write some code - in the user control's Loaded event, I add a method call to GetData(), then UpdateCollection();
  11. using System.Windows;
    using System.Windows.Controls;
    namespace SLSPTest
    {
        public partial class SharePointChart : UserControl
        {
            public SharePointChart()
            {
                InitializeComponent();
            }
            private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
            {
                GetData();
            }
            private void GetData()
            {
                UpdateData();
            }
            private void UpdateData()
            {
                PollCollection collection = this.Resources["Collection"] as PollCollection;
    
                collection.Add(new PollItem("C#", 1));
                collection.Add(new PollItem("VB.NET", 10));
                collection.Add(new PollItem("SQL", 5));
            }
        }
    }
  12. Notes for this step:
    • I split the data call into two functions GetData and UpdateData - this is important because the SharePoint client object model (as well as most ways Silverlight actually calls a web service) is always asynchronous, so you prepare the request and make the service call, then expect a callback to fire when it is successful.  This is not just in SharePoint, but with REST, WCF, RIA as well.
    • Still doing sample set up right now - add a couple of items to the collection
    • Notice there are no UI update code - F5, and Silverlight will run.  Silverlight automatically binds to the mock data collection.

 

BRIEF BREAK IN SHAREPOINT

  1. Back in SharePoint, create a list "Football", add 1 column "FavouriteCountry"
  2. Add a few rows of data, otherwise it won't be much fun

 

BACK TO VS.NET

  1. We currently have a running Silverlight application, but it is just displaying mock data. 
  2. Add the Microsoft official Silverlight Client Object Model from the 14Hive/SharePoint root.
    \Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin\
    image
  3. Modify the code to
  4. using System.Windows;
    using System.Windows.Controls;
    using Microsoft.SharePoint.Client;
    using System;
    using System.Collections.Generic;
    namespace SLSPTest
    {
        public partial class SharePointChart : UserControl
        {
            ClientContext sharepointContext;
            public SharePointChart()
            {
                InitializeComponent();
                sharepointContext = ClientContext.Current;
            }
            private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
            {
                if (sharepointContext == null)
                {
                    GetData();
                }
                else 
                {
                    QueryDataFromSharePoint();
                }
            }
            private void GetData()
            {
                UpdateData();
            }
            private void UpdateData()
            {
                PollCollection collection = this.Resources["Collection"] as PollCollection;
    
                collection.Add(new PollItem("C#", 1));
                collection.Add(new PollItem("VB.NET", 10));
                collection.Add(new PollItem("SQL", 5));
            }
    
            private const string ListName = "Football";
            private const string InternalFieldName = "FavouriteCountry";
            private ListItemCollection listItems;
    
            private void QueryDataFromSharePoint()
            {
                Web web = sharepointContext.Web;
                // get our list
                List list = web.Lists.GetByTitle(ListName);
                // get items in our list
                listItems = list.GetItems(CamlQuery.CreateAllItemsQuery());
                // tell context we want to load them
                // we don't actually need to load the list - just need a reference to get to the list item
                // sharepointContext.Load(list);
                sharepointContext.Load(listItems);
    
                // execute the load asynchronously
                sharepointContext.ExecuteQueryAsync(SucceededCallback, FailedCallback);
            }
    
            private void FailedCallback(object sender, ClientRequestFailedEventArgs e)
            {
                throw new NotImplementedException();
            }
    
            private void SucceededCallback(object sender, ClientRequestSucceededEventArgs e)
            {
                this.Dispatcher.BeginInvoke(UpdateDataFromSharePoint);
            }
    
            private void UpdateDataFromSharePoint()
            {
                // loop through the list from sharepoint - update my dictionary with count
                Dictionary<string, int> summary = new Dictionary<string, int>();
                foreach (var listitem in listItems)
                {
                    string language = listitem[InternalFieldName].ToString();
                    if (!summary.ContainsKey(language))
                    {
                        summary[language] = 1;
                    }
                    else
                    {
                        summary[language]++;
                    }
                }
    
                PollCollection collection = this.Resources["Collection"] as PollCollection;
                // loop through collection - update any count
                foreach (var item in collection)
                {
                    if (summary.ContainsKey(item.SurveyChoice))
                    {
                        item.SurveyCount = summary[item.SurveyChoice];
                        summary.Remove(item.SurveyChoice);
                    }
                    else
                    {
                        item.SurveyCount = 0;
                    }
                }
    
                // add any new entries
                foreach (var item in summary)
                {
                    collection.Add(new PollItem(item.Key, item.Value));
                }
            }
        }
    }
  5. Notes:
    • Client Object Model uses the ClientContext class from Microsoft.SharePoint.Client - this is where all the magic happens.  Start from: ClientContext.Current
    • If we don't have a current context - use our mock data, otherwise query SharePoint
    • Use the various methods on the ClientContext to get to the list or list item that you want, then call ClientContext.Load
    • Client object model does not actually talk to the server until you call ExecuteQueryAsync
    • Need 2 callbacks - I don't take care of the failure
    • On success callback - need to redirect back to the UI thread.  Very common in Silverlight and WinForm multi-threading applications.  SharePoint or ASP.NET developers might have never seen a dispatcher in their life!
    • Back on the UI thread, and updating the collection.  My long-winded version does:
      1. count the list items into a dictionary of team/votes
      2. Go through each item of the current collection (remember, already databound), and update the numbers - the cool effect of this is that when the number changes the chart will respond and grow automatically via the animation storyboard.
      3. Finally add any new dictionary pair to the collection (will appear on chart)

 

EASIEST DEPLOYMENT EVER

  1. Compile your Silverlight application, look for the compiled XAP file in the web application's clientbin folder.  This XAP file is a zip file of all the Silverlight dll and XAML files in one package.
    image 
  2. To deploy, upload this into a document library in your SharePoint, copy the URL
    image
  3. Create a new page, insert a Silverlight Web Part, which will ask you for the URL to a XAP file, paste the URL from your earlier uploaded XAP file (in the document library).


RE-DEPLOYMENT(S)

  1. If you build a new version of your Silverlight XAP file, just upload over the old version in the same document library
  2. Go back to the pages with the Silverlight Web Part and refresh (F5), the browser will reload the new version of your Silverlight

 

NEXT UP

This is getting pretty long and I'll stop for now.  I'll continue later with:

  • Re-query
  • Debugging
  • Tunning the performance of your client object query calls
  • Further discussions regarding XAP-deployment, Sandbox Solutions or Farm Solutions
  • REST interface
  • Silverlight initParam
  • Out of Browser

Part 2 is now up next

Silverlight + SharePoint: helper classes

While composing my earlier blog about Silverlight + SharePoint +CAML best practices, it dawns on me that it would be quite possible to build a helper library to assist the user in cleaning up the LINQ statements before sending it off to the server, similar to how the client object model tries to convert LINQ to CAML beneath the hood.

Similarly, there are a few useful properties in the Server object model that is missing in the client object model.  These could be provided via a helper class as well.

This would make a nice little weekend project.

Silverlight + SharePoint + CAML - best practices

I was reviewing http://microsoftpdc.com/Sessions/PR07 regarding SharePoint client object model tonight, in consideration of how the client object model should be used with Silverlight to build Silverlight SharePoint solutions.

I really liked slide 20, but I think it needs a bit more expanding:

  • Use .Where method to:
    • Filter down items retrieved in a collection
  • Use .Include method to:
    • Explicitly select properties or child objects to retrieve
    • You own specifying what you want!
    • (use .IncludeWithDefaultProperties for default + custom properties)
  • Use .Take method to:
    • Restrict overall number of items retrieved

 

The object model provides (through LINQ query), these three ways of filtering down the objects that you want to return from SharePoint. 

There's a little bit more that wasn't mentioned - the gem (or curse, if you hate everything related to CAML…) that is

var query = new CamlQuery();
ListItemCollection items = list.GetItems(query);

 

Yes, CAML is far from dead.  And LINQ is not the answer to everything.

The basic issue is that the LINQ syntax is converted into CAML to be passed to SharePoint to execute on the server.  In particular:

  • .Include - dictates the View.Fields that are returned from the service call

WARNING

  • .Take
  • .Where - these two may seem intuitive enough, but actually they are hidden pitfalls here.  The reason is that these parts of the LINQ statement are not translated to CAML.  So you are actually performing these operations on the client side, using essentially LINQ on an unfiltered objects collection. 

Bad performance, and quite possibly bad logic!

If you are really after paging behaviour - SharePoint 2010 has this built into the object model.  A skip and a take is done via:

CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
                @"<View>
                    <ViewFields>
                      <FieldRef Name='Title'/>
                      <FieldRef Name='Category'/>
                      <FieldRef Name='Estimate'/>
                    </ViewFields>
                    <RowLimit>10</RowLimit>
                  </View>";
camlQuery.ListItemCollectionPosition = itemPosition; 

Skip is done via paging - see CamlQuery.ListItemCollectionPosition property.
Take is done via CAML <RowLimit>, or alternatively, you can do this via CamlQuery.RowLimit property.

I'll throw in one more, in CAML you can additionally perform Order By - this is one additional area where the order will affect the records returned by the query significantly - especially if you are using paging on top.

 

Guidance

In Silverlight, you should never query ListItems without some safeguards around the Query's RowLimit, as well as possibly handle paging.  On the server side, SharePoint will impose a limit of (default) 2000 items per query.

See more references here

I once read that CAML is compared to the butcher knife, and LINQ is the pocket carving knife (sorry forgot which blog I read this on - let me know).  I agree whole-heartedly: both are tools to control the slice of data you want from SharePoint, but you must keep performance in mind!

For the love of SharePoint

Did quite a bit of blog reading tonight, mostly related to SharePoint, and it has prompted me to reflect the last 3 years and how my attitude towards SharePoint has gradually shifted. 

Here is a journey of a .NET developer who stumbled upon a technology called SharePoint, and finally made some sense of it.

2004: Does the world really need another Portal Software?

It was 2004 when I first head about this SharePoint portal server.  At the time where everyone was busy building first .NET applications, then ASP.NET applications.  The world was different then, perhaps a bit more black and white and mostly in code.

Everyone is out there building portals with web technologies, and failing that… build an engine for other people to build their portal upon.  Community Server, DotNetNuke, DasBlog… and these were the good ones.

So here’s this silly product from Microsoft, called SharePoint.  Immediately dismissed as a DotNetNuke –ish portal software and promptly forgotten.

2007: Many software seems to be built on top of the SharePoint platform, what is it?

I was working elsewhere in 2007.  Happily working on ASP.NET with nhibernate and spring.net.  SharePoint, unsubtly, crawled in front of the view screen again.

What intrigued me then was that Microsoft was refusing to let SharePoint die.  What surprised me was that it was no longer the portal software that I had in mind.  It had become a platform.

Still, I wouldn’t have given up my freedom with writing my own code to live within the confines of another platform that isn’t built by me.  (the "not invented here" syndrome)

So, performance point and BI flew past me.  Though in hindsight, I’m still pretty sure I wasn’t interested in that type of work…  May be in another decade I’d say differently.

2008: Jumping in the deep end.  The wars between SharePoint vs. Developer

I jumped into SharePoint some point in early 2008 – we were working on a heavily customized SharePoint publishing site, and there are a few areas where we needed the ASP.NET muscles to force SharePoint to bend to our will.  Considering myself an ASP.NET blackbelt, I jump in to sumo wrestle with the giant that is SharePoint.

I won.  Most of the time.  But SharePoint made me pay for my victories.  Years later, there are battle scars and silent tears for the hours that was thrown in to fight SharePoint.

It is in those hours that I learned:

2009: Seeing SharePoint for what it really is.

Perhaps my lessons came later.  Perhaps it’s seeing the unnecessary wounds that I earned from wrestling, that got me to sit down, and work out what is SharePoint.  And what is the right thing to do.

So half way through 2008 and throughout all of 2009, I tell myself OK.  I’m going to give myself and this thing one chance and really work out what SharePoint is.

The Internet does not fail, and SharePoint knowledge is out there, free for you to find and to read.  The funny thing is that all these information has always been available.  But perhaps I was just too stubborn to turn my head to have a good look at SharePoint. 

If you want a reading list, this is the biggest list I could find:
http://www.dynamicevents.com/MCM/MCMSharePointPre-Reads.pdf
Recommended reading list for Microsoft SharePoint Certified Masters.  There are 81 articles and some are reference books.  You will probably never finish reading before SharePoint 2010 comes out with more required reading.

2010: At the edge of my seat.

As SharePoint became fun, I come to enjoy working in this platform.  Around mid 2009 after prompting from boss Adam Cogan, I wrote a brief presentation of 8 things I really wish SharePoint 2007 could do better, for me as a developer.  And presented it in Adelaide and Sydney SharePoint user groups.

As Microsoft show its hands with SharePoint 2010, I worked to update the same presentation to see if MS has addressed my wishes.

Somewhat surprisingly, Microsoft addressed almost all my annoyances.  From CAML, packaging, debugging, BCS, search, and even a much cleaner DOM for our designers.

And even added more that I wasn’t too worried about: Silverlight, OData, ribbons and enterprise taxonomy.

Looking back over the last 3 years, our internal SharePoint installation has turned from an “oh we have a SharePoint running here somewhere” service, to an “essential production” service.  There was a time where if mail wasn’t available people would complain within 10 minutes, but SharePoint may be down for extended periods of time without people noticing or caring.  Not anymore.  Now, if SharePoint is unavailable for just 5 minutes due to a feature upgrade, you will hear people complain.

Too much writing, time to wrap it up

There’s still plenty more things to do in SharePoint, and plenty more things to do with SharePoint.  I’m glad I jumped on this path.  No idea where I’ll be in another 10 years, but I think I’ll always look back on 2010 with much fondness.

SharePoint 2010 CAML List Joins

SharePoint 2010, you can finally do List Joins in CAML.  This would be a great boon to the type of views that you can create in SharePoint and in code.

http://msdn.microsoft.com/en-us/library/ee539975(office.14).aspx

There is a catch – it looks like the field that you can use for joins must be a Lookup type field to the foreign list.

Join type can be LEFT or INNER.

Given that LINQ to SharePoint sits on top of CAML – all the LINQ join statements will translate properly as well.

 

 

When I first started developing with SharePoint, I really hated CAML. 

In time, I’ve learnt to live with CAML, the lack of good tools drives me crazy.  But it is a necessary evil when you work in SharePoint.