I decided to write some tips about building a complete AJAX solution running on SharePoint 2010. There is no rocket science here but sometimes it’s not so simple to put all the pieces together to make a robust and easy to maintain solution. This post will give you some recipes to build AJAX components based on a layer architecture.
This first part deals about setting up your solution and deploy required clients libraries on your SharePoint environment.
Creating the projects
Create a new empty SharePoint project, choose a SharePoint site to deploy your solution and select the “Deploy as farm solution” option. Now add the following folders:
- Helpers
- Entities
- BL
- Services
- WebControls
You should obtain something like this :

Adding jQuery
I can’t work anymore without jQuery. It’s a very powerful way to traverse and manipulate the DOM of your page furtermore it provides AJAX helpers. SharePoint does not include jQuery so we have to add it to our solution and ensure that it will be available everywhere in our SharePoint site.
There are multiple solutions to this problem, the one I prefer is to use the delegate control AdditionalPageHead to register our scripts.
First thing to do is download the latest release of jQuery. So, go to http://jquery.com/ and grab the latest production (or development) version.
Then add the SharePoint mapped folder “Layouts” to your project. Visual Studio will add a folder with the name of your solution into it. Add another folder “Scripts” inside and save your version of jQuery here.
Thanks to that jQuery will be deployed into the SharePoint’s hive folder.
Now we will use a WebControl to register the script into the pages. In your project, add a new class named “AdditionalPageHead.cs” into the WebControls folder. Then make the class public and inherit from System.Web.UI.UserControl.

In this WebControl you can register the jQuery file thanks to the ClientScriptManager of the page. This can be implemented like this :
|
public class AdditionalPageHead : UserControl { protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); Page.ClientScript.RegisterClientScriptInclude(GetType(), "jquery", SPUtility.MakeBrowserCacheSafeLayoutsUrl("WawawumAjaxPatterns/Scripts/jquery-1.8.0.min.js", false)); } } |
I use the SPUtility.MakeBrowserCacheSafeLayoutsUrl in order to generate a URL that won’t be cached by the browser. It just adds a hash in the URL of the file (in a query string).
Now we have to use a Element file to register our Delegate Control. So let’s add a SharePoint Module named “AdditionalPageHead” to our project, delete the sample file of the module and edit the Element file :
|
<?xml version="1.0" encoding="utf-8" ?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Control Id="AdditionalPageHead" Sequence="10" ControlClass="WawawumAjaxPatterns.WebControls.AdditionalPageHead" ControlAssembly="WawawumAjaxPatterns, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2f55fcde3cc80692"/> </Elements> |
Don’t forget to update the ControlAssembly value and ControlClass with your own namespace and public key token.
Now rename the feature, I chose “WebControls” and set the scope to “Site”. Ensure that the AdditionalPageHead module is included into the feature:

We have a last thing to do in order to make this control work properly : add a Safe Control Entry. Opens the properties of the AdditionalPageHead module (right-click on it) and edit the “Safe Control Entries” attribute :

Now deploy the project to your test environment and you should see jQuery loaded into the Developer Toolbar of Internet Explorer :

Note : instead of creating a class inheriting from UserControl you can add a User Control directly from the Add new item window of Visual Studio. This will create an ASCX file and the code-behind. The benefit of this method is that you don’t have to add the Safe Control Entry. It’s up to you.
Adding Knockout.js
The main problem when you build an AJAX control is to bind the data with the UI. Server-side we have a lot of controls to do such a thing : Repeater, DataList, GridView… Client side is an other story, it can be such a pain to create controls dynamically and bind data to them. Knockout solves this problem by applying the MVVM pattern in JavaScript. It enables you to declare templates and bind them to your data. Your UI can be automatically refreshed when the View Model changes. Through this article I’ll try to explain the basics of Knockout but I strongly suggest you reading the official documentation if you want to go further : http://knockoutjs.com/
Start by downloading the last version of Knockout and the Knockout Mapping plugin and add them to the Layouts/Scripts folder we created before. Then add a RegisterClientScriptInclude call into the AdditionalPageHead UserControl to register the script files :
|
public class AdditionalPageHead : UserControl { protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); Page.ClientScript.RegisterClientScriptInclude(GetType(), "jquery", SPUtility.MakeBrowserCacheSafeLayoutsUrl("WawawumAjaxPatterns/Scripts/jquery-1.8.0.min.js", false)); Page.ClientScript.RegisterClientScriptInclude(GetType(), "knockout", SPUtility.MakeBrowserCacheSafeLayoutsUrl("WawawumAjaxPatterns/Scripts/knockout-2.1.0.js", false)); Page.ClientScript.RegisterClientScriptInclude(GetType(), "knockout.mapping", SPUtility.MakeBrowserCacheSafeLayoutsUrl("WawawumAjaxPatterns/Scripts/knockout.mapping-2.3.2.js", false)); } } |
Redeploy the project and check if the knockout.js file is loaded.
Creating the Entity and the Business Layer
I’ll take a very simple example for the business layer. We will return the items of a SharePoint Tasks list. This is not very useful but accessing the data is not the point of this article so I let you adapt the code to your needs. You can query items on a list, search results or even data stored into an external database, this won’t change the rest of the solution.
Creating the Entity “Task”
Start by adding a class “Tasks” into the Entities folder and add some basic fields and constructors :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
[DataContract] public class Task { #region Properties [DataMember] public int Id { get; set; } [DataMember] public string Title { get; set; } [DataMember] public TaskStatus Status { get; set; } #endregion #region Constructors public Task() { } public Task(SPListItem item) { Id = item.ID; Title = item.Title; Status = (TaskStatus)ChoiceFieldValueAttribute.ConvertToEnum(typeof(TaskStatus), item["Status"].ToString()); } #endregion #region Methods public void CopyTo(SPListItem item) { item["Title"] = Title; item["Status"] = ChoiceFieldValueAttribute.GetValue(Status); } #endregion } public enum TaskStatus { [ChoiceFieldValue("Not Started")] NotStarted, [ChoiceFieldValue("In Progress")] InProgress, [ChoiceFieldValue("Completed")] Completed, [ChoiceFieldValue("Deferred")] Deferred, [ChoiceFieldValue("Waiting on someone else")] WaitingOnSomeoneElse } |
Two important things here :
– You must apply the DataContract to the Task Entity because it will be serialized / deserialized by the DataContractSeralizer when sending and receiving messages through the WCF Service.
– You must apply the DataMember attribute to each field of the Task Entity you want to serialized.
You noticed that I added an enumeration to store the value of the task’s status. I put this enumeration in the same file that the Task class.
When a Task will be instantiated from an SPListItem we will have to convert the SPFieldChoiceValue to a TaskStatus enumeration. In order to achieve this conversion I use a custom class : ChoiceFieldValueAttribute. You can find all the explanations on my blog : SharePoint Choice Field, CAML and Enum.
Here I’ll just give you the steps to add it to our project. Add a new class “ChoiceFieldValueAttribute” into the Entities folder and copy the following lines of code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
public class ChoiceFieldValueAttribute : Attribute { /// <summary> /// Gets or sets the SharePoint Value associated to the Enumeration field. /// </summary> public string Value { get; set; } public ChoiceFieldValueAttribute(string value) { Value = value; } /// <summary> /// Converts the string value to an Enumeration of the specified type depending of the ChoiceFieldValueAttribute set on the enumeration's fields. /// </summary> public static object ConvertToEnum(Type enumType, string value) { FieldInfo[] fields = enumType.GetFields(); foreach (FieldInfo field in fields) { object[] customAttributes = field.GetCustomAttributes(typeof(ChoiceFieldValueAttribute), false); if (customAttributes.Length > 0) { ChoiceFieldValueAttribute choiceAttribute = (ChoiceFieldValueAttribute)customAttributes[0]; if (choiceAttribute.Value.Equals(value)) { return Enum.Parse(enumType, field.Name); } } } throw new ArgumentException(); } /// <summary> /// Converts the specified enumeration value to its string value depending of the ChoiceFieldValueAttribute set on the enumeration's fields. /// </summary> public static string GetValue(Enum enumValue) { FieldInfo field = enumValue.GetType().GetField(enumValue.ToString()); object[] customAttributes = field.GetCustomAttributes(typeof(ChoiceFieldValueAttribute), false); if (customAttributes.Length > 0) { ChoiceFieldValueAttribute choiceAttribute = (ChoiceFieldValueAttribute)customAttributes[0]; return choiceAttribute.Value; } throw new ArgumentException(); } } |
Creating the TaskManager
Now we have to create a class to retrieve the data from SharePoint. Add a class “TasksManager” to the BL folder :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
public class TasksManager : IDisposable { #region Fields private bool _isDisposed; private bool _webIsContext; #endregion #region Properties public string ListName { get; set; } public SPWeb Web { get; private set; } #endregion #region Constructors and Destructors /// <summary> /// Initializes a new instance of the TasksManager class based on the specified list name. /// </summary> /// <param name="listName">The name of the SharePoint List that will be used by this instance to retrieve / add items.</param> public TasksManager(string listName) { Web = SPContext.Current.Web; ListName = listName; _webIsContext = true; } /// <summary> /// Initializes a new instance of the TasksManager class based on the specified Web URL and list name. /// </summary> /// <param name="webUrl">The SharePoint Web Site URL used by this instance to retrieve the specified list.</param> /// <param name="listName">The name of the SharePoint List that will be used by this instance to retrieve / add items.</param> public TasksManager(string webUrl, string listName) { Web = SPContext.Current.Site.OpenWeb(webUrl); ListName = listName; } ~TasksManager() { Dispose(false); } #endregion #region Methods /// <summary> /// Retrieves all the Task of the List of the Current Context. /// </summary> public IEnumerable<Task> GetTasks() { SPQuery query = new SPQuery(); query.ViewFields = string.Concat( "<FieldRef Name='Title' />", "<FieldRef Name='Status' />"); SPListItemCollection items = Web.Lists[ListName].GetItems(query); List<Task> tasks = new List<Task>(items.Count); tasks.AddRange(from SPListItem item in items select new Task(item)); return tasks; } /// <summary> /// Add a Task to the List of the Current Context. /// </summary> /// <param name="task">The Task entity to add.</param> public Task AddTask(Task task) { SPListItem item = Web.Lists[ListName].AddItem(); task.CopyTo(item); item.Update(); return new Task(item); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose(bool disposing) { if (!_isDisposed) { if (disposing && !_webIsContext) // Warning : do not dispose the Web coming from SPContext.Current.Web ! { Web.Dispose(); } _isDisposed = true; } } #endregion } |
I won’t explain this piece of code because there is nothing special here about creating an AJAX component, it’s not rocket science. You can implement your business layer as you want. I often use LinQ to SharePoint to retrieve strongly-typed entities but in this example I’ve decided to get these with the classic SharePoint Object Model and CAML.
All you need is a method GetTasks returning all the tasks of a SharePoint list and a AddTask method to create new items in this list. All the other stuff deals about the disposal mecanism.
Creating the WCF Service
Here is the tricky part if you never have created a WCF Service hosted in SharePoint. It’s pretty easy actually because SharePoint handles all the configuration itself (you don’t have to specify endpoints and all of these XML stuffs).
The WCF Service Contract
Let’s begin by adding an interface “ITasksService” in the Service folder of our project. This interface will define the contract of the WCF Service.
|
[ServiceContract] [ServiceKnownType(typeof(Task))] public interface ITasksService { [OperationContract] [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)] IEnumerable<Task> GetTasks(string listName); [OperationContract] [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)] Task AddTask(Task task, string listName); } |
- ServiceContract : specifies that this interface is a Service Contract.
- ServiceKnownType : add this attribute for each type that may be serialized / deserialized when a Service method is called. In this example we are only working with Task entities so this is the only type to define.
- OperationContract : add this attribute on each service method.
- WebInvoke : this attribute specifies that the decorated method can be called in REST. Moreover you can configure if the method should be called with a POST or GET request.
The Service Implementation
Now we have to implement our contract. Add a “TasksService” class into the “Services” folder and implement the ITasksService interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] [BasicHttpBindingServiceMetadataExchangeEndpoint] public class TasksService : ITasksService { public IEnumerable<Task> GetTasks(string listName) { using (TasksManager manager = new TasksManager(listName)) { return manager.GetTasks(); } } public Task AddTask(Task task, string listName) { using (TasksManager manager = new TasksManager(listName)) { return manager.AddTask(task); } } } |
- BasicHttpBindingServiceMetadataExchangeEndpoint : tells to SharePoint to enable a MEX endpoint
The SVC file
The last step is to create the svc file that will define our service’s type and which SharePoint service factory to use.
The svc file must be deployed to the SharePoint ISAPI folder, right-click on your project è Add è SharePoint Mapped Folder and choose the ISAPI folder. Then add a file named “TasksService.svc” into this folder. The file type does not matter, it can be an empty text file.
Add the following content :
|
<%@ServiceHost Language="C#" Debug="true" Service="WawawumAjaxPatterns.Services.TasksService, WawawumAjaxPatterns, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2f55fcde3cc80692" Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> |
The service attribute must sepcify our service implementation. Replace my assembly full name by yours. Usually you can use the token $SharePoint.Project.AssemblyFullName$ that should be replaced by Visual Studio when packaging your project. In my case it didn’t work on this project so I just put my assembly full name myself.
The factory can be one of the following SharePoint Factories :
- MultipleBaseAddressBasicHttpBindingServiceHostFactory = SOAP service
- MultipleBaseAddressWebServiceHostFactory = REST service
- MultipleBaseAddressDataServiceHostFactory = ADO .Net Data Service
Since jQuery works well with REST services we choose the second one.
Creating the WebPart
The last step is about creating the WebPart which will consume our WCF Service. I’m suggesting you to first create a very basic WebPart calling the Service without displaying anything. You should be able to see thanks to a tool like Fiddler if the service is actually returning the data. Then you add the databinding with knockout.js.
Adding the WebPart
Add a new Visual WebPart “TasksWebPart” into the WebControls folder of the project and ensure that the WebPart belongs the WebControl feature. Then add the following content into the ASCX file of the WebPart :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
<div id="TasksContainer"></div> <script type="text/javascript"> function TasksManager() { } TasksManager.prototype.getData = function () { var data = { listName: "Tasks" }; $.ajax({ url: "/_vti_bin/TasksService.svc/GetTasks", contentType: 'application/json', data: JSON.stringify(data), type: 'POST', dataType: 'json', cache: false, context: this, success: this.getDataSucceeded }); }; TasksManager.prototype.getDataSucceeded = function(result) { if(result != null) { var container = $("#TasksContainer"); for(var i in result.GetTasksResult) { container.append("Title : " + result.GetTasksResult[i].Title + "<br/>"); } } }; function initTasks_<%= ClientID %>() { $(document).ready(function() { var manager = new TasksManager(); manager.getData(); }); } initTasks_<%= ClientID %>(); </script> |
This piece of code will enable you to test your service. Deploy the project to a SharePoint development environment and add the WebPart in a page. The WebPart should display the list of your tasks :

If you start fiddler you can explore the result of the AJAX Call thanks to the JSON inspector. If you don’t have installed Fiddler already I suggest you to do it right now. This tool is essential to debug this sort of components. It enables you to see in details the HTTP requests made by Internet Explorer and to inspect the answers of SharePoint.

In the bottom right section of this screenshot of fiddler, you can see the result as JSON. You will notice that the result is always wrapped into an object which name is the concatenation of the service method and the constant “Result”.
DataBinding with Knockout.js
If you have never worked with Knockout.js before I suggest you to read the official documentation here : http://knockoutjs.com/documentation/introduction.html
The three points : Observables, Computed Observables and Observable Arrays are the main concepts to begin with this framework.
There are multiple ways to create the View Model which will be used by Knockout. First the entities returned by the WCF Service can be stored either into a native JavaScript array either in an observable array. The last one is useful when refreshing the View Model. If you want to refresh the WebPart without a postback by making another call to the WCF Service, it is very easy to refresh the whole view thanks to an observable array. Moreover if you support adding new items directly within the WebPart it will make the work straightforward.
Then each field of the entities can be converted to observables. It can be useful if the entities themselves are refreshed.
For this example we will use the most powerful and flexible solution : an observable array of observable entities (not a suprise isn’t it?).
Using the mapping plugin
The WCF service returns JSON objects that must be converted into observable objects. We can do this manually by assigning each field into observables or use the Mapping plugin of Knockout which has been added in the “Adding Knockout.js” part of this article.
First of all we need to add a field into our TasksManager to store the data. Add a “tasks” field into the constructor :
|
function TasksManager() { this.tasks = ko.observableArray(); } |
We use Knockout to create an empty observable array and assign it to the new field.
Then we need to convert the JSON objects into observables. Update the for loop in the getDataSucceeded callback function :
|
for(var i in result.GetTasksResult) { var task = ko.mapping.fromJS(result.GetTasksResult[i]); this.tasks.push(task); } |
The fromJS function of the Knockout Mapping plugin enables to convert the JSON into observables. Note that the converted objects are not observables themselves, only their fields are now observables. So you can’t databind the View on a Task for example but you can do it on a Task’s Title field.
By doing this we bind our Model to the View Model.
Here you can see the content of the mapped object when debuging with the developer tools of Internet Explorer :

Note : To access to the Id field’s value we would write : task.Id() and not task.Id given that this field is an observable.
Creating the view
Replace the div with the id “TasksContainer” by this one and its content :
|
<div data-bind="foreach: tasks" id="TasksContainer"> <div data-bind="text: Title()"></div> </div> |
Then update the constructor of TasksManager :
|
function TasksManager() { this.tasks = ko.observableArray(); ko.applyBindings(this, document.getElementById("TasksContainer")); } |
Only the last line has been added to this constructor. The applyBindings function is like the “DataBind” method in .Net. It binds your View Model to the View.
The first argument is very important : it’s the View Model. And yes we are using the whole TasksManager object as the View Model.
So when we specify the token “tasks” into the “foreach” binding in the div element, we are refering to the “tasks” field of the TasksManager object.
The “Title()” token refers to the “Title” field of the current data item iterated by the foreach.
The second argument enables you to use multiple Views and View Models on the same page. If you don’t specify a DOM element when calling applyBindings, Knockout tries to bind the specified View Model at the page level. This doesn’t work if you have multiple views.
That’s why we target on which view the View Model is bound thanks to this second argument.
Deploy the changes and you should see your tasks.
Refreshing the data
Ok that’s fine but nothing new here. We can also get the list of tasks without Knockout and all this View Model stuff. That’s true but remember that in the first example we just write a list of Tasks. In a real-world example you will need to display plenty of data and add some events and behaviors. To illustrate how knockout can make your developer life easy, we will add a button to refresh our view model.
Modify the HTML markup to add an outer container around the existing one and a button, then updates the ID attributes :
|
<div id="TasksWebPartContainer"> <div data-bind="foreach: tasks" id="TasksList"> <div data-bind="text: Title()"></div> </div> <input type="button" value="Refresh" data-bind="click: getData"/> </div> |
Now we need to bind the View Model to the outer container “TasksWebPartContainer” instead the “TasksContainer” we just delete :
|
ko.applyBindings(this, document.getElementById("TasksWebPartContainer")); |
That’s all we need to refresh our data. If a new item is added to the SharePoint list, the WCF service will return it and thanks to the “tasks” observable array, the new results will be displayed with the new item. It is the same thing if an existing tasks is modified.
Next…
As you can see in this post’s title, you are reading the first part of a post series about AJAX and SharePoint. So stay tuned if you want more about generating dynamic client options for your AJAX components and some other tips.
Update : you can now read the next part of this article here:
SharePoint 2010 and AJAX – Part 2
Download
Here is the code of this demo :
WawawumAjaxPatterns.zip