As soon as the RTM version of ASP.NET AJAX framework was published few weeks ago, I have been looking for how to use it with Windows SharePoint Services 3.0 web sites. After some days of testing, [Halleluiah !] I found a solution.
I would like now to share with you the result of this work, for you to be able to use « UpdatePanels » and other novelties of the ASP.NET AJAX framework into WSS 3.0 (either on .aspx pages or on web parts)
Before using ASP.NET AJAX framework, we must first install it on the WSS 3.0 server. You can download AJAX framework from the following URL:
http://www.microsoft.com/downloads/details.aspx?FamilyID=ca9d90fa-e8c9-42e3-aa19-08e2c027f5d6&displaylang=en
In this article I am working with US versions. The default WSS installation folder is: “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12”.
I will refer later to a sub folder (“Template\Layouts\1033\”) of the WSS installation folder, which contains WSS 3.0 JavaScript files. For a better understanding, I will call it “WSS scripts folder”.
On my server, I also have complete installations of Visual Studio 2005 Team Suite and SharePoint Designer 2007.
Everyone’s ready? So, let’s go!
First of all, I create a new WSS web application using WSS administration tool. The site collection is based on the “empty site” template. Here is below a screenshot of the site homepage:
The next step will be now to include the ASP.NET AJAX framework configuration into the web.config file of my WSS web site.
For those of you who already know the ASP.NET AJAX framework, you must have noticed that it is necessary to add many pieces of information in the configuration file of a standard ASP.NET site. If not, AJAX won’t work.
For those of you who don’t know, the screenshot below shows a default web.config file of an ASP.NET AJAX site.

Well, I know that it is not easy to read but that is not the aim. The aim is for you to understand that the work is not easy. In the article sources, you will find the “Ajax, default web.config” file which is the readable version of this screenshot. :D
In short, you know what you can expect. The second step is to merge our WSS site configuration file with the default web.config of an ASP.NET AJAX site (see the files “Wss, original web.config” and “Wss, final web.config” in the article sources). We need to open the two configuration files (the default AJAX config.file and our WSS site config. file) and:
· Copy the whole sectionGroup from configuration\configSections section of the AJAX configuration file and paste it in the configuration\configSections section of the WSS config. File.
· Copy the whole controls from configuration\system.web\pages section of the AJAX configuration file and paste it in the configuration\system.web\pages section of the WSS config. File.
· Copy all the add sections from the configuration\system.web\compilation\assemblies section of the AJAX configuration file and paste it in the configuration\system.web\compilation\assemblies section of the WSS configuration file. Be careful as one of the line (“<add assembly=”Microsoft. SharePoint…/>”). It already exists in the native WSS configuration file; so, you must delete this pasted line.
· Copy all the add sections from the configuration\system.web\httpHandlers section of the AJAX configuration file and paste it in the configuration\system.web\httpHandlers section of the WSS configuration file. Be careful: the lines must be pasted after the remove line.
· Copy the add line from the configuration\system.web\httpModules section of the AJAX configuration file and paste it in the configuration\system.web\httpModules section of the WSS configuration file. Be careful: the line must be pasted after the clear line.
· Copy the system.webServer sections from the configuration section of the AJAX configuration file and paste it in the configuration section of the WSS configuration file.
Yes, we did it. Now to be sure that your WSS site still works, you have to save these changes made on your WSS configuration file. Then run IISRESET command, and finally connect to your WSS site… it should work correctly.
Our WSS site configuration is ready to work with the ASP.NET AJAX framework. Now we have to use AJAX in our WSS site.
All the web pages meant to use the AJAX controls must contain a ScriptManager control. For me to ease the work and to manage the ScriptManager presence only once, I have decided to add it directly into the default master page of my WSS site. How can we do that? It is very simple, you will see.
Open your WSS site with SharePoint Designer 2007. Edit the default.master page in the _catalogs\masterpage folder and go into the code of this page, as in the following screenshot.
We are going to declare our ScriptManager in the same way the masterpage declares a WebPartManager which is necessary to manage Web Parts. So we add the following line straight above the WebPartManager declaration:
<asp:ScriptManager ID="mainScriptManager" runat="server"/>
You should obtain:
Save the modifications and log on your WSS site to test that it works. Alas, no! a WSS error shows that the System.Web.UI.ScriptManager control is not safe.
How to solve this problem? Once again, this is not difficult. We only have to specify in our site configuration file that our System.Web.Extension assembly is safe (the AJAX Assembly is the one which declares the ScriptManager control). We must edit our web.config file and add the following line into the configuration/SharePoint/SafeControls section:
<SafeControl Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TypeName="*" Safe="True" AllowRemoteDesigner="True" />
Save modifications and restart IIS Service using IISRESET command. Test your WSS site again: the problem is solved. We can go on…
We can now create a Web Part using the AJAX controls. Mine here is not extraordinary: All its work is updating time without refreshing all the page. This will allow us to check it works correctly.
I am creating a new “Class Library” project with Visual Studio. Then I am going to add references to the assemblies :
· Microsoft.SharePoint (WSS)
· System.Web.Extensions (AJAX Controls)
· System.Web (Standard ASP .NET Controls)
I then create a class I will name WebPartHeure that inherited of Microsoft.SharePoint.WebPartPages.WebPart. In my class header I add the using System.Web.UI and using System.Web.UI.WebControls directives. My Web Part is going to build up a label in charge of displaying time and a button allowing time updating. In order to do it with AJAX, these two controls will be included into an UpdatePanel. Here is the Web Part entire code.
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Bewise.Wss3.Sample.AjaxEtWss
{
public class WebPartHeure :
Microsoft.SharePoint.WebPartPages.WebPart
{
private Label hour;
private Button refreshHour;
private UpdatePanel updatePanel;
private AsyncPostBackTrigger refreshHourTrigger;
protected override void CreateChildControls()
{
// Label
hour = new Label();
hour.ID = "hour";
// Show datetime
hour.Text = DateTime.Now.ToString();
// Button
refreshHour = new Button();
refreshHour.ID = "refreshHour";
refreshHour.Text = "Refresh !";
// Trigger
refreshHourTrigger = new AsyncPostBackTrigger();
refreshHourTrigger.ControlID = refreshHour.ID;
refreshHourTrigger.EventName = "Click";
// UpdatePanel
updatePanel = new UpdatePanel();
updatePanel.ID = "updatePanel";
updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
// Add trigger to UpdatePanel
updatePanel.Triggers.Add(refreshHourTrigger);
// Add Childs controls
updatePanel.ContentTemplateContainer.Controls.Add(hour);
updatePanel.ContentTemplateContainer.Controls.Add(refreshHour);
// Add all controls to te Web Parts
this.Controls.Add(updatePanel);
}
protected override void Render(HtmlTextWriter writer)
{
// Ensure childs controls are created
this.EnsureChildControls();
// Render updatePanel and childs controls
updatePanel.RenderControl(writer);
}
}
}
Don’t forget to sign your assembly otherwise you won’t be able to refer it in WSS. Afterwards let’s create a .dwp file to register our Web Part in WSS. Here is the file content of my example:
<?xml version="1.0" encoding="utf-8" ?>
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
<Assembly>Bewise.Wss3.Sample.AjaxEtWss, Version=1.0.0.0, Culture=neutral, PublicKeyToken=995401eda3d8bd0c</Assembly>
<TypeName>Bewise.Wss3.Sample.AjaxEtWss.WebPartHeure</TypeName>
<Title>WebPartHeure AJAX</Title>
<Description>Show hour and refresh using AJAX</Description>
</WebPart>
As our Web Part is ready by now, we’ll have to register it on our WSS Site in order to be able to test it. Copy the .dwp file as well as our assembly into the bin folder of our WSS web site. Then we will edit the site configuration file to declare our assembly safe. Add the following line into the configuration/SharePoint/SafeControls section and save modifications.
<SafeControl Assembly="Bewise.Wss3.Sample.AjaxEtWss, Version=1.0.0.0, Culture=neutral, PublicKeyToken=995401eda3d8bd0c" Namespace="Bewise.Wss3.Sample.AjaxEtWss" TypeName="*" Safe="True" AllowRemoteDesigner="True" />
Afterwards, open your WSS site and go to the Web Part Gallery. Download your .dwp file. You should see it in the Web Parts list as shown below:
Go back to the site home page and edit it. Add your web Part and at last, exit the edit mode. You should see something similar to:
Let’s test once again. A thousand times Alas! In a correct test, you will notice that the first time you click on the “Refresh” button, it works, but the next times nothing happens. Why?
Why can it work the first time and not the next times? After many hours I tried to find the origin of the problem, I finally found the reason. If we edit the master page again with SharePoint Designer, we can see these two following lines:
<BODY scroll="yes" onload="javascript:if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();">
And
<form runat="server" onsubmit="return _spFormOnSubmitWrapper();">
The second line means that every time a WSS page is submitted, the _spFormOnSubmitWrapper() JavaScript method is called. This method is declared in the INIT.JS file of the WSS scripts folder (see Introduction to find this folder). Here is the code of this function:
function _spFormOnSubmitWrapper()
{
if (_spSuppressFormOnSubmitWrapper) {
return true;
}
if (_spFormOnSubmitCalled) {
return false;
}
if (typeof(_spFormOnSubmit)=="function") {
var retval=_spFormOnSubmit();
var testval=false;
if (typeof(retval)==typeof(testval) && retval==testval) {
return false;
}
}
RestoreToOriginalFormAction();
_spFormOnSubmitCalled=true;
return true;
}
What is this function doing? On top of turning into true or false according to some conditions, the function also updates _spFormOnSubmitCalled variable in true. Looking further on, we find this variable turned into false when applied with the _spBodyOnLoadWrapper() method. This last method also is called at each loading of a WSS page (see first line). But what is the problem?
Usually, when loading a WSS page without AJAX, the _spFormOnSubmitCalled variable is set to false by the _spBodyOnLoadWrapper() method. Then, when the page is submit, the method _spFormOnSubmitWrapper() set the variable to true, but , this variable is reset to false when the page is reloaded. Now, what is the difference when we use AJAX? When loading a WSS page, the _spFormOnSubmitCalled variable is always set to false by the _spBodyOnLoadWrapper() method. Next, when we click on “Refresh” button, the _spFormOnSubmitWrapper() is call and set the variable to true. But, here is the difference: with AJAX, the page is not reloaded: so, the variable is not reset to false.
To solve the problem, we have to update spFormOnSubmitWrapper() to be sure that, when a submit is done by an AJAX control, the spFormOnSubmitCalled is set to false. Here is the new code for the spFormOnSubmitWrapper() function. The modifications are on Italic. To be able to restore the original file, make a copy of INIT.JS file before applying modifications.
function _spFormOnSubmitWrapper()
{
if (_spSuppressFormOnSubmitWrapper) {
return true;
}
if (_spFormOnSubmitCalled) {
return false;
}
if (typeof(_spFormOnSubmit)=="function") {
var retval=_spFormOnSubmit();
var testval=false;
if (typeof(retval)==typeof(testval) && retval==testval) {
return false;
}
}
if((typeof(Sys) != 'undefined' ) &&
(typeof(Sys.WebForms) != 'undefined' ) &&
(Sys.WebForms.PageRequestManager.getInstance() != null) &&
(Sys.WebForms.PageRequestManager.getInstance()._postBackSettings.panelID != ''))
_spFormOnSubmitCalled=false;
else
_spFormOnSubmitCalled=true;
RestoreToOriginalFormAction();
_spFormOnSubmitCalled=true;
return true;
}
What does the code we have added do? It check:
· if the “Sys” and “Sys.WebForm” types proper to AJAX framework are defined
· if a declared ScriptManager exists in the page (require to work with AJAX)
· if the panel ID which has submitted is registered on the ScriptManager (in that case, the submit has been made by an AJAX control)
If all these conditions are fulfilled, it means that it’s an AJAX control that has made submit. In this case, the variable at the origin of the problem is set false, if not we keep the default treatment.
Finally, after all these steps, everything should perfectly work.
I hope this article will help you to improve your WSS Solutions. Do not hesitate to make me share of your remarks and comments.
See you soon for a next article.