In this article I am going to show you how to integrate ASP.NET Ajax 1.0 with SharePoint 3.0. We will create a new Ajax WebPart from scratch and then we will deploy it into SharePoint 3.0 site. Moreover, I will demonstrate how to add that webpart into SharePoint Page.
To create a web part class, open your visual studio, create a new Class Library Project and name it as "TestAbdelHaqWebpart." Then add a new class and name it "MyAjaxWebPart."
First of all, you have to add some references to the project which are listed below:
· System.Web
· System.Web.Extensions
· System.Web.Extensions.Design
In addition, you need to inherit the WebPart class.
Take a look at listing 1; it is our Ajax WebPart class.
Listing 1
Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Text Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Web.UI.WebControls.WebParts Imports System.Data Imports System.Data.SqlClient Public Class MyAjaxWebPart Inherits WebPart Private _grdSearch As GridView Private _txtSearch As TextBox Private _btnSearch As Button Private _lblMsg As Label Private _updatePanel As UpdatePanel Private _updateProgress As UpdateProgress Private Shared ReadOnly EventSubmitKey As New Object() Public NewAjaxWebPart12() Public Sub New() Me.ExportMode = WebPartExportMode.All End Sub <WebBrowsable(True), _ Personalizable(PersonalizationScope.Shared), _ Category("AbdHaq Property") _ > _ Public Property LoadingImageURL() As String Get Dim _obj As Object = ViewState("LoadingImageURL") If _obj Is Nothing Then Return String.Empty Else Return DirectCast(ViewState("LoadingImageURL"), String) End If End Get Set(ByVal value As String) ViewState("LoadingImageURL") = value End Set End Property Public Custom Event Submit As EventHandler AddHandler(ByVal value As EventHandler) Events.AddHandler(EventSubmitKey, value) End AddHandler RemoveHandler(ByVal value As EventHandler) Events.RemoveHandler(EventSubmitKey, value) End RemoveHandler RaiseEvent(ByVal sender As Object, _ ByVal e As System.EventArgs) CType(Events(EventSubmitKey), _ EventHandler).Invoke(sender, e) End RaiseEvent End Event Private Sub _btnSearch_Click(ByVal source As Object, ByVal e As EventArgs) _grdSearch.Visible = False System.Threading.Thread.Sleep(1500) '//Create DataTable Structure Dim Dtable = New DataTable("tmpTable") '//User_ID Col Dtable.Columns.Add("User_ID", GetType(Integer)) Dtable.Columns("User_ID").AutoIncrement = True Dtable.Columns("User_ID").AutoIncrementSeed = 1 '//User_Name Col Dtable.Columns.Add("User_Name", GetType(String)) '//User_Department Col Dtable.Columns.Add("User_Department", GetType(String)) Dim dr As DataRow dr = Dtable.NewRow dr("User_Name") = "Abdulla Abdelhaq" dr("User_Department") = "Technical" Dtable.Rows.Add(dr) dr = Dtable.NewRow dr("User_Name") = "Noura Ahmad" dr("User_Department") = "Technical" Dtable.Rows.Add(dr) dr = Dtable.NewRow dr("User_Name") = "Oday Mohammad" dr("User_Department") = "Production" Dtable.Rows.Add(dr) Dim _searchFor As String = "%" If _txtSearch.Text <> String.Empty Then _searchFor = _txtSearch.Text End If Dim dtView As New DataView(Dtable) dtView.RowFilter = "User_Name LIKE '%'+'" & _searchFor & "'+'%'" If dtView.Count > 0 Then _grdSearch.Visible = True _grdSearch.AutoGenerateColumns = True _grdSearch.DataSource = dtView _grdSearch.DataBind() _lblMsg.Text = String.Empty Else _lblMsg.Text = "<font color='red'>Sorry, No Data Found!.</font>" _grdSearch.Visible = False End If End Sub Protected Overrides Sub CreateChildControls() Controls.Clear() _updatePanel = New UpdatePanel With _updatePanel .ID = "UpdatePanel1" .ChildrenAsTriggers = True .UpdateMode = UpdatePanelUpdateMode.Conditional End With _updateProgress = New UpdateProgress _updateProgress.ID = "UpdateProgress1" Dim _templateHTML As String If LoadingImageURL = String.Empty Then _templateHTML = "<span>Loading ...</span>" Else _templateHTML = "<div><img alt='Loading...' src='" & _ LoadingImageURL.Trim & "'/></div>" End If _updateProgress.ProgressTemplate = New ProgressTemplate(_templateHTML) _updateProgress.AssociatedUpdatePanelID = _updatePanel.ClientID Me.Controls.Add(_updatePanel) _grdSearch = New GridView _grdSearch.ID = "GrdSearch" _txtSearch = New TextBox _txtSearch.ID = "txtSearch" _btnSearch = New Button _btnSearch.Text = "Search" _btnSearch.ID = "BtnSearch" _lblMsg = New Label _lblMsg.ID = "lblMsgError" AddHandler _btnSearch.Click, AddressOf _btnSearch_Click _updatePanel.ContentTemplateContainer.Controls.Add(_txtSearch) _updatePanel.ContentTemplateContainer.Controls.Add(_btnSearch) _updatePanel.ContentTemplateContainer.Controls.Add(_grdSearch) _updatePanel.ContentTemplateContainer.Controls.Add(_lblMsg) _updatePanel.ContentTemplateContainer.Controls.Add(_updateProgress) End Sub Protected Overrides Sub OnInit(ByVal e As EventArgs) MyBase.OnInit(e) 'get the existing ScriptManager if it exists on the page Dim _AjaxManager As ScriptManager = ScriptManager.GetCurrent(Me.Page) If _AjaxManager Is Nothing Then 'create new ScriptManager and EnablePartialRendering _AjaxManager = New ScriptManager() _AjaxManager.EnablePartialRendering = True 'Fix problem with postbacks and form actions (DevDiv 55525) Page.ClientScript.RegisterStartupScript(Me.GetType, Me.ID, _ "_spOriginalFormAction = document.forms[0].action;", True) 'tag:"form" att:"onsubmit" val:"return _spFormOnSubmitWrapper()" 'blocks async postbacks after the first one 'not calling "_spFormOnSubmitWrapper()" breaks all postbacks 'returning true all the time, somewhat defeats the purpose of the '_spFormOnSubmitWrapper() which is to block repetitive postbacks, 'but it allows MS AJAX Extensions to work properly If Not Me.Page.Form Is Nothing Then Dim formOnSubmitAtt As String = Me.Page.Form.Attributes("onsubmit") If Not String.IsNullOrEmpty(formOnSubmitAtt) And _ formOnSubmitAtt = "return _spFormOnSubmitWrapper();" Then Me.Page.Form.Attributes("onsubmit") =_ "_spFormOnSubmitWrapper();" End If 'add the ScriptManager as the first control in the Page.Form Me.Page.Form.Controls.AddAt(0, _AjaxManager) End If End If End Sub Protected Overrides Sub RenderContents(ByVal writer As _ System.Web.UI.HtmlTextWriter) _updatePanel.RenderControl(writer) End Sub End Class 'Class for Building progress tempales Public Class ProgressTemplate : Implements ITemplate Private template As String Public Sub New(ByVal temp As String) template = temp End Sub Public Sub InstantiateIn(ByVal container As Control) Implements _ Web.UI.ITemplate.InstantiateIn Dim ltr As New LiteralControl(Me.template) container.Controls.Add(ltr) End Sub End Class
I have read many articles that talked about adding the Script Manager to the SharePoint manually; that you have to go to the master page of your SharePoint page, and then write a script manager tag to the HTML code manually!
Actually, I do not prefer this way. As a developer, I would like to add it dynamically by the code.
Go back to Listing 1 and take a look on OnInit subroutine. Here we will add the script manager dynamically. We are checking if there is an existing script manager on the page. If it is not, then we will create a new script manager and we will add it in the page controls.
Dealing with UpdatePanel and UpdateProgress
If you try to add controls to UpdatePanel programmatically, you will notice that the UpdatePanel requires you to add server controls only. So you need to choose the proper server control that matches your requirement after rendering time. For example, if you want to add HTML div inside the UpdatePanel, you should add the panel control instead of the HTML div element.
Since the UpdateProgress control is a template control, you have to create a template class that represents the container of the UpdateProgress controls. Listing 1 contains a public class called ProgressTemplate, I have created an instance from that class in CreateChildControls subroutine and then I have added the loading animation image inside the UpdateProgress using that instance.
To make our Ajax webpart more reusable, there is a public property called LoadingImageURL which enables you to set path of the loading animation image. So you can upload the image you want into your Sharepoint site, and then you can use it as loading image by using LoadingImageURL public property.
Deploying DLL file into SharePoint bin folder
After you have built the project successfully, all you need is to get the DLL file from the bin folder of your project. We are going to deploy that DLL file into the SharePoint site; you can do that simply by copying that DLL and pasting it into the bin folder of the SharePoint site. Or you can change the build output path of the webpart project into the bin folder of the SharePoint site so that it will deploy the DLL file automatically after any build operation.
To change the build output path, use the following steps:
1. From the Solution Explorer, right click over the Solution name, and click on Properties.
2. New window will be opened, click on Compile tab, and then click on browse button in the
Build output path.
3. Find out the bin folder of your SharePoint site, and then set it as "Build output path" for the webpart project.
Now if you rebuild the project again, it will deploy the project DLL file into the bin folder of the SharePoint site.
Adding SafeControl to the SharePoint Web.Config file
The second step in deploying webpart project into SharePoint site is to add the SafeControl of our webpart project into the SharePoint web.config file.
So you have to navigate to the following path:
C:\InetPub\wwwroot
And open your SharePoint Site folder, then you will find a web.config file in the root of the SharePoint site. Open it and add a new SafeControl element as shown in Listing 2.
Listing 2
<SafeControl Assembly="TestAbdelHaqWebPart" Namespace=" TestAbdelHaqWebPart" TypeName="*" />
That is it; you have deployed a webpart project into a SharePoint site.
Extending SharePoint web.config files with ASP.NET AJAX requires that you interleave some Ajax registration entries in-line with WSS registration entries. To do this you will need to edit your SharePoint web.config file.
1. Add a <sectionGroup>element to the <configSections>tag:
Listing 3
<configSections> <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/> <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" /> <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" /> <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" /> </sectionGroup> </sectionGroup> </sectionGroup> </configSections>
2. Add a <controls> section as a child of the <system.web>/<pages> tag.
Listing 4
<pages> <controls> <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </controls> </pages>
3. Add the following tag to the <assemblies> tag, within <compilation>.
Listing 5
<assemblies> <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </assemblies>
4. Add some new registrations to the end of the <httpHandlers> section.
Listing 6
<httpHandlers> <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/> </httpHandlers>
5. Add a new registration to the HttpModules section beneath any existing registrations.
Listing 7
<httpModules> <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules>
6. Add a SafeControl entry for the System.Web.UI namespace from Microsoft Ajax Extensions, within the <SharePoint>/<SafeControls>section.
Listing 8
<SafeControls> <SafeControl Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TypeName="*" Safe="True" /> </SafeControls>
7. Finally, add the following configuration tags at the bottom of web.config, near the bottom before the end <configuration> tag.
Listing 9
<system.web.extensions> <scripting> <webServices> <!-- Uncomment this line to enable the authentication service. Include requireSSL="true" if appropriate. --> <!-- <authenticationService enabled="true" requireSSL = "true|false"/> --> <!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and writeAccessProperties attributes. --> <p class=Code-GenericCxSpMiddle> <!-- <profileService enabled="true" readAccessProperties="propertyname1,propertyname2" writeAccessProperties="propertyname1,propertyname2" /> --> </webServices> <!-- <scriptResourceHandler enableCompression="true" enableCaching="true" /> --> </scripting> </system.web.extensions> <system.webServer> <validation validateIntegratedModeConfiguration="false"/> <modules> <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </modules> <handlers> <remove name="WebServiceHandlerFactory-Integrated" /> <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </handlers> </system.webServer>
To add a WebPart to the SharePoint site, you have to add it first to the SharePoint WebPart Gallery.
Adding New WebPart to the SharePoint WebPart Gallery
To do this, follow the subsequent steps.
1. Click Site Actions tab, and select Site Settings. The Site Settings page will appear.
2. Under gallery column, click on web parts link. This takes you to the WebPart Gallery page.
3. Click on the New button as shown in Figure 1, it will move you to a new page that displays all WebParts that are included in the sharepoint webconfig file.
Figure 1
4. Check your webpart project name which is "TestAbdelHaqWebPart" and then click on Populate Gallery button as illustrated in Figure 2, which adds the WebPart to the WebPart gallery so that you can add it later to the page.
Figure 2
Now let us go and add our new WebPart to the home page.
Adding WebPart to SharePoint page
To add our new WebPart to the home page, follow the subsequent steps.
1. From the home page, click on Site Actions tab and select choose Edit Page.
Figure 3
2. Click on Add a Web Part as shown in Figure 4
Figure 4
3. From the popup page, check "MyAjaxWebPart" and then click on Add button.
Figure 5
4. Click Exit Edit Mode.
And that is it; we have added our new WebPart to the home page of our SharePoint website.
Type the name that you want to search and click the search button. Notice that the Loading image will be displayed and the result will be represented inside the GridView.
So no post back, no flashing on the page, which is what we are talking about, "Ajax WebPart." It represents what is called Progress Indicator, which helps in maintaining the user's attention and communicates that the system is still alive even if a response has not yet occurred.
Figures 6 and 7 show you how Ajax WebPart works on the page.
Figure 6
Figure 7
[Download Sample]
In this article, an overview about how to create a new Ajax WebPart and deploy it into SharePoint 3.0 site was explained. In addition, we learned how to add Script Manager Element dynamically inside SharePoint page; also I illustrated how to deal with UpdatePanel and UpdateProgress controls programmatically. And finally, we have added our new Ajax WebPart into SharePoint site.
I encourage you to download the source code so that you can learn what we have done in a more detailed manner. If you have any questions or wish to share your comments, do not hesitate to contact me.
I hope that you have found this tutorial as informative as possible.