Saturday, May 24, 2008

Integrate ASP.NET Web Service based AJAX with MOSS 2007 or Windows SharePoint Services 3.0

Introduction:

As Windows SharePoint Services version 3 is built on ASP.NET 2.0, you can use most of ASP .Net Ajax functionalities in Sharepoint. There is two ways to use Asp .Net Ajax in a Solution:
  • by using an Update Pannel
  • by using an ASP .Net Ajax enabled Web Service
I have found nothing on the Web Service based method explaining how to exactly deploy it in a MOSS or Windows SharePoint Services application. So we did it by ourselves, and most of the following was done thanks to the work of François Michael Dain.

Tutorial:

Asp .Net Web Service Ajax enabled application, in Windows SharePoint Services 3.0

We are now going to build a simple Asp .Net Ajax Enabled Windows SharePoint Services Application based on Web Service method. We will build something simple, as an "Hello World" tutorial.

1 - Configuring the web Application web.config file.

First of all you have to configure your Web Application web.config file in order your SharePoint Application to be compliant with Asp .Net Ajax. There is excellent posts on doing that :

2 - Adding a Web Service to your Web Application.

After having configured your web.config properly, add a web service inside your SharePoint Web Application doing this :
Start Visual Studio and create a Class Library Project.
This is the solution in Visual Studio at the beginning, (We use WSPBuilder Project Template).



Under 12 hive, add "ISAPI" directory, then your Ajax Web Service Directory.



After having added your Web Service, your Solution should look like this :


Here is the code of HelloWorldService.asmx

<%@ WebService Language="C#" CodeBehind="HelloWorldService.asmx.cs" Class="WsAjaxEnabledWSSApplication.HelloWorldService" %>


Here is the code of HelloWorldService.asmx.cs

#region using

using System;

using System.ComponentModel;

using System.Web;

using System.Web.Script.Services;

using System.Web.Services;

 

 

#endregion

 

namespace WsAjaxEnabledWSSApplication

{

    ///

    /// Summary description for HelloWorldService

    ///

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [System.Web.Script.Services.ScriptService()]

    [ToolboxItem(false)]

    public class HelloWorldService : System.Web.Services.WebService

    {

        [WebMethod]

        public string HelloWorld(string userName)

        {

            return "Hello, " + userName;

        }

    }

}


3 - Building your Solution and adding your Web Service dll to the GAC.

Build your Solution, go to debug directory, copy WsAjaxEnabledWSSApplication.dll and paste it in the GAC (C:\windows\assembly).
If an "Access Denied" Pop Up message occurs, just paste it a second time and you will be succeed in pasting it.
Now you should do a IISReset, but it won't be necessary since we are going to modify the Web Application web.config file and this action will recycle the Web Application Pool.

4 - Adding your Solution dll referrence to the SafeControls section of the Web Application web.config file.

In the Gac (C:\windows\assembly), find your dll reference and right click it to display porperties. you can the copy name, culture, version and Public Key Token on a note pad and then build that line (change to suit your assembly and namespace etc...) :

<SafeControl Assembly="WsAjaxEnabledWSSApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9073b0a00e9670f8" 
Namespace="WsAjaxEnabledWSSApplication" TypeName="*" Safe="True" />

Make a back-up copy of your Web Application web.config file.
Open your Web Application web.config file and add the previous line in the SafeControls section
Don't forget to save the web.config file.

5 - Modyfying HelloWorldService.asmx file and deploying the Web Service.

Add this line at the top of your HelloWorldService.asmx file:

<%@ Assembly Name="WsAjaxEnabledWSSApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9073b0a00e9670f8" %>

Then, copy your AjaxWebService directory to ISAPI folder under the 12 hive. Here is a picture of the directory after copying.



6 - Testing your Web Service.

Open IIS mmc, locate your Web Service and right click it to browse it.



You should obtain that results:



If you enter the url of your Web Service followed by /js
(http://localhost:8080/_vti_bin/AjaxWebService/HelloWorldService.asmx/js)
You will be asked to save a js file.



Rename the file in AjaxWebService.js. Save the .js file on your server Desktop.



Edit AjaxWebService.js file and check that most of the lines are beginning by your namespace and WebService Name:
WsAjaxEnabledWSSApplication.HelloWorldService
The last line should show the complete call to your Web Service method :
WsAjaxEnabledWSSApplication.HelloWorldService.HelloWorld



7 - Creating a Windows SharePoint Services Applicative Page for consuming your web service

If it's not already done, create a site collection, for example : AjaxEnabledSite.
In your Visual Studio project, creat a new directory under 12 hive:
TEMPLATE\LAYOUTS
Add an .aspx page, asume we call it : AjaxHelloWorld.aspx
Your project should now look like this :



Here is the code of AjaxHelloWorld.aspx page :

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>

<%@ Page Language="C#"  MasterPageFile="~/_layouts/application.master"%>

 

<asp:Content ID="Content1" ContentPlaceHolderId="PlaceHolderMain" runat="server" >

test

</asp:Content >


Deploy your AjaxHelloWorld.aspx page with WSP Builder or just copy it in LAYOUTS directory.
Test your page by browsing it:



8 - Adding Ajax Code to your Applicative Page

In Visual Studio, add this code inside the asp:Content tag of AjaxHelloWorld.aspx :

   <script type="text/javascript">

        function sayHello(){

            WsAjaxEnabledWSSApplication.HelloWorldService.HelloWorld(document.getElementById("txt1").value, OnComplete, OnTimeOut, OnError);

        }

 

        function OnComplete(args){

            document.getElementById("txt2").innerText=args;

        }      

        function OnTimeOut(args){

            alert("Time Out");

        }      

        function OnError(args){

            alert("Error");

        }

 

    </script>

 

    <asp:ScriptManager ID="ScriptManager1" runat="server">

        <services>

                <asp:ServiceReference InlineScript="true" Path="../_vti_bin/AjaxWebService/HelloWorldService.asmx" />

         </services>

    </asp:ScriptManager>

 

    <input type="text" id="txt1"/>

    <br />

    <input type="button" value="Say Hello" onclick="JavaScript:sayHello();" />

    <br />

    <input type="text" id="txt2"/>



Deploy your page with WSP Builder or just copy it in LAYOUTS directory.

9 - Consuming your Ajax Web Service

You can now test your Ajax Web Service Based Applicative Page :



You have noticed that we didn't need any single line of server side code in our AjaxHelloWorld.aspx page.
Warnings :

This was a first step to roughly understand how to build and deploy an Web Service based AJAX web site in WSS or MOSS. The drawback of the present example is that you will be embarassed if you have several web sites that have to call the web service, since it will know as Context only one site : the site collection top level site. If you want to create and deploy several AJAX enabled web sites in WSS or MOSS see:
Create multiple Ajax enabled web sites in Windows SharePoint Services or MOSS 2007

2 comments:

Anonymous said...

hi,
I have come across with your blog and found informative. Thank you for input. Currently I am building Ajax enabled webpart for MOSS. I have been reading Ted& Daniels book. one thing it s not yet clear.. what is the point of having spweburl property. I mean when you creating a webservice in _vti_bin is not that discovery files take care of the redirecting..I mean like you can call the webservices from any where is not it? Please dont mind if I am talking totally out of context...dejaWoo

Marc Charmois said...

hi DejaWoo,

I'm glad you appreciated my post. You are not talking out of context, it is the exact topic of my 2 posts.


The post you left a comment on, is a tutorial roughly showing how to integrate web service based Ajax in SharePoint, but I didn't make the project be usable for several web sites. Especially you can't use SPContext object in the Web Service if there is several SharePoint Web Sites.
That's why I put a warning.

In order to expose a more complete project that can be usable for several Web Sites, I published a second post

http://mosshowto.blogspot.com/2008/06/create-multiple-ajax-enabled-web-sites.html


In this post, I used spweburl property like Daniel and Ted have implemented it in their book.
Daniel and Ted created the window spweburl porperty in server side programming doing this:


private const string WebInitScriptFormat = @"window.spWebUrl = '{0}';";

after that, they set this property value with the current SharePoint Web Site URL doing this:


string webInitScript = string.Format(CultureInfo.InvariantCulture, WebInitScriptFormat, SPContext.Current.Web.Url);
this.Page.ClientScript.RegisterClientScriptBlock(typeof(System.Web.UI.Page), WebInitScriptKey, webInitScript, true);



All that is done to be able to set the path to the Ajax web Service before calling it:
WsAjaxEnabledWSSApplication.HelloWorldService.set_path(window.spWebUrl + "/_vti_bin/AjaxWebService/HelloWorldService.asmx");
Doing that, the Web Service "will know" what SharePoint Web Site of the Site Collection is calling it. So you will be able to use SPContext object in the Web Service, and it will be the Context of the calling Web Site.


I hope I've answered to your question.

Marc