Entries from June 1, 2010 - July 1, 2010

Tuesday
Jun292010

Windows Live Photo Gallery (beta)

The nastiest part of the whole Windows Live Wave 4 Beta experience so far has been concentrated on the installer - though not all Microsoft's fault, I did have some dodgy settings in my Internet Options.

Today, I flicked open the new Windows Live Photo Gallery, and this is a really nice application.

THE GOOD

  1. Automatically detected iPhone and offer to import pictures
    image
  2. Import offers to just grab everything, or group (and mass-tag) pictures based on the time they were taken.  Aka "afternoon trip", "evening dinner @ rocks"
    image
  3. Default view sorted pictures by Month
  4. Automatically detected the picture orientation and rotated them around.  Unlike…  a certain other company's software.  http://johnliu.net/blog/2010/4/15/apple-iphone-drivers-are-pos.html


    iPhone crap drivers.

    image
    Windows Live Photo Gallery import (automatically fixed orientation)
  5. Lovely Ribbons interface

THE AWESOME

  1. Panoramic photo stitching!IMG_3067 Stitch

    Long Zheng has a much better comparison
  2. Mass tagging, mass image adjustments
  3. Mass upload to Skydrive, Flickr or Facebook
  4. Extensible (this will make it even more awesome)
Tuesday
Jun292010

Windows Live Wave 4 Beta - Error 0x8104000b WaitForCatalog

0x8104000b
Source: WaitForCatalog.
Couldn't setup the installer. Check to make sure you are connected to the internet.

 

Had this nasty installer bug that hit me when installing Windows Live Wave 4 beta.  After a good deal of looking around, I ended up http://windowslivehelp.com/thread.aspx?threadid=ccb7680f-260f-4ebb-acf5-e2247a7aefe3 where various users were discussing their problems and Microsoft is trying to help.

My Particular problem was due to an old manual configuration script for my IE Proxy settings.  It had been un-ticked, but the address field wasn't blanked out.  So I had to tick it, enter <space> to blank it out, OK to save, then re-open the dialog to make sure the old proxy script is indeed gone.

Then run the installer from Microsoft again.

Check out the entire thread for other possible problems and fixes.  And if you see it asking you to download an exe from a non-Microsoft source, always exercise caution and double-check it with Microsoft Security Essentials first.

 

Len (MS)

We have identified a bug that occurs when your IE proxy settings point to a proxy script that is invalid or not reachable.  We are working on a permanent solution to this problem but in the meantime have come up with this workaround.

1) Open Internet Explorer.

2) Click Tools, then click Internet Options.

3) Click the Connections tab, and then click the LAN settings button.

4) Select the check box for Use automatic configuration script.

5) Copy the URL that is shown in the Address box below the check box. Paste it somewhere that you can retrieve it from later (in case you want to restore this setting when you are done installing Windows Live)

6) Delete the URL currently shown in the Address box, and replace it with a space character

7) Click OK in Local Area Network (LAN) settings dialog.

8) Click the LAN settings button again.

9) Now clear the check box for Use automatic configuration script.

10) Click OK in Local Area Network (LAN) settings dialog.

11) Click OK in the  Internet Options dialog.

12) Run the installation of Windows Live Essentials again.

Monday
Jun282010

Develop and deploy Silverlight + SharePoint 2010 Solutions (part 3 - light it up)

A quick summary of part 2:

  1. How to attach debugger, check network traffic with Fiddler
  2. Do your VIEWFIELDS, FILTER and SORT on the server
  3. LINQ is converted to CAML beneath the hood - but you can avoid CAML…  almost
  4. Trim your service call

Part 3 is all where we Light up SharePoint and take it beyond the browser.  And see why SL + SP is just pure awesome.

 

OUT OF BROWSER

There's one change in Code necessary for Out-of-browser.

        public SharePointChart()
        {
            InitializeComponent();
            sharepointContext = ClientContext.Current;

            if (sharepointContext == null)
            {
                sharepointContext = new ClientContext("http://colt-sp2010/sites/Home/");
            }

            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 5);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

When you are running Out of Browser you don't have a ClientContext.Current.  No worry, we create one by giving it the Site URL.

(NOTE: this will disable our "mock-data" code, since sharepointContext won't be null anymore)

 

image

Tools in VS.NET 2010 has really improved on this front.  Making Silverlight work out of browser is simply just ticking this one check box.

Which is great - because it means I can pack more stuff into my demo :-)

image

I don't actually need to change any Out-of-Browser settings.  But the one to take note is the "Require elevated trust".  Some features of Silverlight will require full trust in OOB.

Anyway, compile the solution again, and XAP-Deploy to SharePoint document library again.

 

image

Right click to install to computer.

image

Run this from the Computer.

 

DEPLOYMENT CONSIDERATIONS

While XAP-document-library-deployment looks awesome in a demo, there are drawbacks that must be taken into consideration:

  1. Do you leave your end-users to manage versions?  Will they copy your SharePoint Silverlight component and deploy it to 20 document libraries, leaving you no way to centrally upgrade them as a single unit?
  2. In many cases, it is much better for developers to build Silverlight + SharePoint solutions as Sandbox Solutions.  You do this by adding a SharePoint project into your VS.NET, and then configure the xap file to be added to SharePoint as a feature module
  3. Finally, if you want to grant Silverlight additional capabilities that involves additional services deployed on the server, you may need to go back to full Farm-Solutions.  I don't see this as a common scenario.

So the summary version:

XAP document library deployment:

Great for IT PRO who doesn't have permissions.
Not great for version control.

 

Sandbox Solutions:

Great for site collection administrators.
Centralized deployment and good version control capabilities.

 

Farm Solutions:

Useful if you need to deploy server-side stuff, like an extra WCF service.
Build to target Sandbox.

 

SILVERLIGHT INIT-PARAMS

A question in the question time:  Can parameters be specified for Silverlight so that I don't have to hard-code the list internal name.

Yes it can:

Silverlight has a property initParam (think of void Main(string[] args))

The way you access it in code is during the Silverlight app startup.

image

In the application startup event - read the initialization parameters.

image

SharePoint web part configuration lets end-users specify the InitParams in this settings box.

 

This concludes the 3-part Silverlight + SharePoint solutions blog-series.  Let me know what you guys think and if I've made any blunders in the blog.

 

FUTURE IDEAS

A quick brain dump of the future of Silverlight + SharePoint

Silverlight Features

  • Local storage
  • Access Groove as offline storage
  • Camera or mic
  • Local event notification
  • COM access

SharePoint + Silverlight Features

  • "SharePoint-Repair" Silverlight tools
  • Dynamic Language Runtime + SharePoint <- this is going to be super awesome
  • Adding additional farm services

Development (unfortunately not written yet)

  • Full Sandbox Solutions demo
  • Full REST interface demo
  • Full old-WCF services demo
Thursday
Jun242010

SharePoint: Do you turn off auto update on your SharePoint servers?

Cross Posted from Do you turn off auto update on your SharePoint servers?

A recent Security Hotfix has broken SharePoint WSS3 stand-alone installations.  This has prompted Microsoft SharePoint team to quickly release information regarding how to fix the issue.
http://blogs.msdn.com/b/sharepoint/archive/2010/06/22/installing-kb938444.aspx
This again reminds us that it is always not a good idea to have Windows Update automatically updating your servers.  There are a few reasons.

  1. The previously mentioned problem - where the hotfix could bring down a production environment. 
  2. In fact, even in a development environment this could be hours of lost work as the development team struggles to understand why only some of the developers' SharePoint magically and mysteriously broke overnight.
  3. Windows Update could restart your server, or put your server in a state where it requires restarting - preventing any urgent MSI installs without bringing down the server.

Windows Update remains the best thing for end-users to protect their systems.  But in a server, especially a production server environment - Windows Update patches are just like any new versions of the software that's built internally.  It should be tested and then deployed in a controlled manner.
So recommendations:

  1. Windows Updates may be critical and should be kept relatively up to date.
  2. Have a plan where your awesome Network Admins schedule time to keep the servers up to date - including testing that the servers still perform its functions.
  3. Turn off Automatic Windows Update on Windows Servers
Wednesday
Jun232010

SharePoint MOSS 2007 - Style Library - File Not Found

A client called up - after they performed a site collection export and import (in order to duplicate a site), the Publishing features we developed for them stopped working.  The site looks wrong.

So I pull out my detective hat and get to work.

  1. IE Developer Tools quickly showed that there's a problem getting the CSS files from Style Library, where our feature deploys the CSS files
  2. Jumping into the Style Library - things look in place.  Click on the CSS file itself -> File Not Found
  3. Times like this one just LOVES SharePoint.  The main trap here really is that a whole number of files could be "not found".  And that error doesn't actually mean an awful lot.
  4. Tried the simplest: knowing this file is part of the site definition, I deleted the file and re-activated our package.  SharePoint says file is back.  But again, clicking on it leads to the File Not Found error, again
  5. Quick check of the 12 Hive on the Web Front Ends (WFE) quickly determined that the file does exist in \FEATURES\
  6. Imagining that it may be customized somehow, I tried Reset to Site Definition.  Still no good.
  7. On the edge of going to the log files… 
  8. When I remembered that we can try to see what the real error is.  So take a detour to the web.config
    1. CustomError="Off"
    2. CallStack="True"
  9. Ah ha.  Site <guid> not found.  Stacktrace says Blobcache is involved.
  10. This actually makes a lot of sense and confirms we weren't just mad.  Yes there is a file missing - the cache file!  Our file is actually fine sleeping in the content database.
  11. Confirmed with customer they did switch on Blobcache a few month ago.  But obviously it's now interfering with the export/import routine. 
  12. Switched BlobCache off via web.config
  13. Refresh (F5) the site - everything's running just fine again :-)

All in about 50mins work.  In hindsight…  jump to the Stack Trace right away to save guess work.

In SharePoint 2010 - errors will be displayed with a Correlation ID, allowing admins to quickly jump to the error stack trace in the log files.

Tuesday
Jun222010

Develop and deploy Silverlight + SharePoint 2010 Solutions (part 2)

A quick summary of part 1:

  1. Environment (tools)
  2. Creating Silverlight project
  3. Creating XAML
  4. Hooking up Silverlight databinding to mock data
  5. Implement real SharePoint query via Microsoft's Client Object Model
  6. Quick discussion of the deploy to document library deployment strategy - I dubbed this XAP-deployment

Part 2 is all about Debugging and Tuning our service calls and see how much fine-grained control we have in talking to SharePoint.  Read on - it's really awesome. 

 

TIMER UPDATE (RE-QUERY)

First problem we have is that the Silverlight application does not re-query the service.  It runs, queries SharePoint once, and then stops.

  1. Let's make it query SharePoint on a periodic basis.  There are various timers available in Silverlight, the easiest to use is the System.Windows.Threading.DispatcherTimer:
  2.         public SharePointChart()
            {
                InitializeComponent();
                sharepointContext = ClientContext.Current;
    
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = new TimeSpan(0, 0, 5);
                timer.Tick += new EventHandler(timer_Tick);
                timer.Start();
            }
            private void timer_Tick(object sender, EventArgs e)
            {
                if (sharepointContext == null)
                {
                    GetData();
                }
                else
                {
                    QueryDataFromSharePoint();
                }
            }
  3. Notes:
    • Create a DispatcherTimer, set it to tick every 5 seconds
    • On each tick - query data from SharePoint
    • By magic of the earlier work we did with databinding in XAML - there is no UI update code required.  The code (controller) updates the data (model) and the UI (view) updates automatically.  This is best practice to move towards full MVVM in Silverlight, and the least amount of headaches down the road.

DEBUGGING SILVERLIGHT

As Silverlight is running in the Browser, debugging the Silverlight application can be done via Attaching the debugger to a running browser process.

image

image

In the list of processes - look for the browser process that has Silverlight run time loaded.

image

You can attach to other browsers as well.

Key notes:

  • Client side debugging Silverlight is superior:
  • Managed Code - not Javascript
  • Browser-independent - no fiddling with different DOM or browser behaviours
  • Server-independent - you could be talking to your development, test, UAT or Production server, the server could be on-premise or in-the-cloud (SharePoint Online).  You are still, debugging the Silverlight that's running on your own machine, calling the server via published services.

 

TUNING SILVERLIGHT

Let's see what Silverlight is doing under the hood.  Run our favourite HTTP sniffer Fiddler 2 (you can also use FireBug or Wireshark - whichever you are familiar with):

image

Since our Silverlight is faithfully re-polling the server every 5 seconds, we see this particular HTTP connection repeating - for as long as the Silverlight app is running (close browser window to stop it)

image

Notice the return traffic is 1.3K - relatively tiny in the scheme of things.  By comparison:

image

  • Full page reload starts at 30k for bare page
  • AJAX web parts are about 20k (rough estimates)

 

Digging in a bit more on the traffic

image

 

 

 

The request is XML

image

The response is gzipped-compressed JSON (Javascript Object Notation)

 

TWEAKING THE QUERY IN LINQ

This next part is tricky but interesting.  The code first.

        private const string ListName = "Football";
        private const string InternalFieldName = "FavouriteCountry";
        private ListItemCollection listItems;
        private IEnumerable<ListItem> listItems2;

        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());

            
            // still need the earlier syntax to tell sharepoint where to get it
            listItems2 = sharepointContext.LoadQuery(
                listItems.Include(
                    item => item["Title"],
                    item => item[InternalFieldName])
                );

            // but don't actually load it!
            //sharepointContext.Load(listItems);

            // execute the load asynchronously
            sharepointContext.ExecuteQueryAsync(SucceededCallback, FailedCallback);
        }

Notes:

  • We still need a reference to the ListItems Collection via List.GetItems(CamlQuery.CreateAllItemsQuery());
  • We use it as a reference point to begin our LINQ Query
  • The SharePoint ClientContext has a separate LoadQuery method, that returns a new ListItems collection - listItems2, we start from the CAML definition, and further refine it to ONLY include the Title and FavouriteCountry fields.
  • But we don't actually ever call Load on ListItems

Result:

image

We've shrunk the data load from 1.7k down to 359 bytes!

image

The returned JSON object is a lot lighter - and contains only a few of the required fields (ID, ObjectType, ObjectVersion), as well as our Title and FavouriteCountry.

 

MAKE YOUR SERVER DO WORK

Imagine the list is thousands of items.  We don't always want to bring back every list item.  What we should always consider is how to use SharePoint to do much of the work for us, and keep our connection traffic low.

            listItems2 = sharepointContext.LoadQuery(
                listItems.Include(
                    item => item["Title"],
                    item => item[InternalFieldName])                    
                .Where(
                    // add where clause for server to execute
                    item => (string)item["Title"] == "john")
                );

Notes:

  • I'm inserting here a Where clause to my LINQ query.  The Query is to be executed on the server.
  • IMPORTANT: do not use Where clause on the Load method - because that is a LINQ to objects filter and is very bad:  imagine bringing down 1000 items and then do your filtering in memory on the client side…

Result:

image

Only pulling back 1 record.

image

Check out the Request XML - includes the Where clause filter.

SUMMARY

  • How to attach debugger, check network traffic with Fiddler
  • Do your VIEWFIELDS, FILTER and SORT on the server
  • LINQ is converted to CAML beneath the hood - but you can avoid CAML…  almost
  • Trim your service call
  • You probably don't need to poll the server every 5 seconds as well

 

NEXT UP

Wrapping up in the next part for:

  • Deployment considerations
  • Out of Browser
  • REST interface
  • Silverlight initParam

Update: Part 3 (final) is now up.

Friday
Jun182010

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

Wednesday
Jun092010

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.

Wednesday
Jun092010

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!

Thursday
Jun032010

MCTS exams - what are these certification trying to solve exactly?

Just walked out of a MCTS exam, the one in question is actually 70-630, after 30minutes.  The exam was allocated 2hours.  I'm full of mixed feelings.  Relief, but highly puzzled and unsatisfied by the whole exam.

The format is a series of questions - of the contents I can't comment, but of the quality of the questions…  Imagine something like this:

You need to do something in SharePoint, what do you need to do?

  • Fiddle with Active Directory and do A
  • Play with SQL Server and do B
  • Configure SharePoint and do C
  • Run Exchange Server and do D

No surprises which is the right answer.  Even if you don't know jack about SharePoint.  Repeat these questions for half an hour.

I try to justify why such exams (and by association, certifications) are necessary.

  1. It proves you have experience with the technology, or at least, can find your way around in that technology, and use it to Actually Solve Problems
  2. It proves that you have a good overall understand of the technology and product, and that you can be relied on to Implement Solutions with the technology
  3. It makes the companies sponsoring you to do the test happy that they've got another certified professional, which they can then tell their clients

I then, try to justify, and fail badly, at understanding why the questions were give away…  Pay the money for the examination, most of it is a tax write-off anyway.  No previous training or experience necessary.  Pass the test.  Pat on the back.

  1. Perhaps…  and this I can somewhat understand, it's just hard to write "good but wrong" answers.  You start with a question, with an answer.  Then you try to put in the typical two way-off answers, and one really close answer.
  2. Perhaps the problem is with the multiple-choice format.  Itself, which lends to the traditional 4-answer format.

Suggestion

  1. Make the exam harder.  Make people sweat, make them unsure whether they should submit the exam, or pause and go back and review one more time
  2. Or get rid of the multiple choice format.  How about this:

Each question's answer is made up of a sentence with dropdown boxes where you can select keywords.  Imagine something like this:

You need to do something in SharePoint, what do you need to do?

[Fiddle/Play/Configure/Run] [Active Direcotry/SQL Server/SharePoint/Exchange Server] and do [A/B/C/D]

(imagine [xxx] is a drop down box).  You can even give partial answers for getting "really close" to the "right answer" but no cigar.

and do as well as