SharePoint 2010 and AJAX – Part 2

This article follows my first one about SharePoint 2010 and AJAX. We saw how to create a simple WebPart with jQuery and Knockout in order to retrieve data with AJAX and use the MVVM pattern in our client-side code. You certainly noticed some hard-coded values in my examples. It’s not the kind of things I call “Best practices”. The goal of this article is to address this problem.

With server-side code we are used to stored the configuration needed by the components in different places : WebBrowsable Properties for a WebPart, web.config, Property Bag, Custom Database, SharePoint Lists, etc.

Here I’m proposing a solution to access your configuration client-side. I’m going to use jQuery and Knockout.js but the concept is generic.

I will use the same code than in the first part of this article. You can download it here : WawawumAjaxPatterns.zip

The Concept

The idea is very simple. Given that it’s easier to access the configuration with server code, the options needed by the View Model will be generated thanks to server code. All the configuration will be wrapped in an object passed into the constructor of the View Model.

The “options” will store different types of data:

  • Configuration values (the URL of the WCF Service for example)
  • Controls’ Client ID
  • Resources

Setting up the project

As said before we will start from the project available on the first part of this article. The WebPart contained inside this project has no configuration. All the parameters are hard-coded client-side. So we will update this project to add some properties to the WebPart.

Adding WebPart Properties

Open the TasksWebPart.cs file located into WebControls\TasksWebPart and add the following properties :

Add a constructor to initialize default values of these properties :

Override the Parent property in the Child Control

Accessing the Parent WebPart from the child User Control is a common problem when developing a Visual WebPart. Personnaly I always use the following piece of code that must be added into the TasksWebPartUserControl.ascx.cs file :

Don’t forget the new keyword in front of the Parent Property.

Updating the Business and Service Layers

These steps are not directly link to our problem. I just want to demonstrate how to serialize/deserialize different data types. What’s why I added the ItemsLimit property to the WebPart in order to have an integer. In the first part of this article, the number of items to retrieve cannot be set. So we have to update the business and service layers.

First update the TasksManager by adding a itemLimit parameter to the GetTasks method :

Then modify the signature of GetTasks in the ITaskService interface :

Finally implement the new version of the ITaskService interface in TasksService :

Creating the options object

What we want to generate is something like that :

We can achieve that by multiple ways :

  • Write a server-side method that will collect the settings and write them into a string formatted as JSON.
  • Write a Class which represents the settings and override the ToString method to write the instance of the object as JSON.
  • Write a Class which represents the settings and use the JSONDataContractSerializer or JSON.Net to serialize it as JSON.

The first two ones are obviously the easiest to implement but the most difficult to maintain. Each time a setting will be added, the corresponding code to format it will have to be written. Moreover, serializing complex types is a tedious work.

That’s why I prefer the solution of serializing an object representing the options thanks to the JSONDataContractSerializer or JSON.Net. Usually my advice is to use the native features of the .Net Framework rather than referencing third party libraries. This is true if the framework fits to your needs but in this case the JSONDataContractSerializer is quite limited.

The main limitations I found are :

  • No circular references : you cannot serialize an object having a property of its type (a Person with a Manager property of Person type for example).
  • Dictionaries cannot be serialized.

You can see a comparison table between JSONDataContractSerializer and JSON.Net here : http://james.newtonking.com/projects/json-net.aspx

Thus in this example I will use JSON.Net to serialize our object since I need a Dictionary to store the localizable resources and the Controls’ Client IDs.

Creating the Client Options Class

Add a class named “TasksClientOptions” into the TasksWebPart folder and put some properties which will be used to configure our View Model.

Serializing the Client Options

As said in the introduction of this section, I will use JSON.Net. You can download it here : http://json.codeplex.com/

Then reference the DLL into your project.

Here is the cool part. We will add a method that will be called directly from the ASCX. This method will create a new instance of the TasksClientOptions object, assign properties to it and then return a JSON representation of this object. That’s how the configuration retrieved server-side will be available client-side.

The following piece of code take care of these tasks :

See how it’s simple. The TasksClientOptions object is created and the ServiceUrl and ItemsLimit properties of the WebPart are retrieved thanks to the Parent Property we overriden before.

The Client ID of the div surrounding our controls is added to the Controls array. That will be usefull to get a reference to this control client-side thanks to document.getElementById or jQuery selectors.

Then ressources are added to the Dictionary. In this example my resources are hard-coded. In a real-world project these resources should be stored into RESX files.

Finally the serialization takes place in the last line of the function. JSON.Net makes us the task very easy. Calling the SerializeObject method will serialize the TasksClientOptions object into JSON and return it as string. Of course the serialization process can be configured.

Note that by default JSON.Net serialize all the public properties and fields. If you want to skip some of them you can :

  • Add the JsonIgnoreAttribute on the properties to skip
  • Add the DataContract attribute on the class to serialize and add the DataMember attribute to properties to serialize. This method is compatible with DataContractSerializer.

Retrieving the Client Options in the ASCX file

Now we have a method that generates our client options object in JSON. So we need to get this object client-side. We just need to update the ASCX file “TasksWebPartUserControl.ascx”. Search for the “initTasks” function and update it :

We use inline code to call the GenerateClientOptions that returns the object as JSON. Then this object is passed in the constructor of the View Model object.

After deploying the project we can inspect the generated HTML by viewing the page’s source :

If you want a more readable representation of the JSON generated you can copy / paste it into JSON Parser Online :

jsonoptions

The View Model

The last remaining step involves to refactor the View Model to take advantage of the options object. First, update the constructor to keep a reference to this object :

The lastUpdate observable will be used to display the time of the last refresh of the data.
This time the id of the container is not hard coded. So if you add more than one instance of this WebPart, the databinding with Knockout will work perfectly.

Then update the getData function to use the ServiceUrl, ListName and ItemsLimit properties of the options object :

Note that I added a callback when the AJAX call failed. Don’t forget to add it :

This callback uses both the Controls and Resources arrays.

Databinding

Finally we need to update the ASCX to correct the databinding :

Here I added the runat=”server” attribute to the outer container. I also put a message displaying the last update time. You can see how easy it is to access resources thanks to the options object.

The Result

If you deploy the project you should obtain a very ugly but working WebPart :

result

In this example I added two WebParts to show that they are independant. That’s cool but what are exactly the advantages of such a solution?

The advantages

Instead of using an object generated server-side then serialized into JSON you could use inline code to inject some dynamic values retrieved server-side into your JavaScript. Unfortunatly by doing this you can’t move your JavaScript code into a separate JS file since your inline code won’t be interpreted as expected.

That’s a major benefit of the solution exposed through this article. With a server-side generated object, you don’t have any reference to server-side code in your View Model. Only the initialization part must be put into your ASCX file.

Thus your code becomes more reusable since you can use your JavaScript file in multiple WebParts / Controls. Only the initialization will change.

Downloading

Here is the code of this demo :

WawawumAjaxPatterns – Part2.zip