Wednesday, February 18, 2009

MOSS Custom Web Services

Alright, MOSS Web services is the least talked about topic.

So here I am blogging about getting custom web services work in the sharepoint environment. That means writing your own web services and deploying the the MOSS environment so its accessible like other WSS and MOSS services e.g. lists, Usergroup etc

1. The first step is to create an ASP.NET web service project in Visual Studio 2005. If you don't find a web service project template in visual studio, that means that you are still running an old version of Visual Studio 2005, the one without the service pack. You will have to download and install the Visual Studio 2005 Service Pack 1 Beta from Microsoft here.

2. In the Project Types box, select Visual C#.

3. In the Templates box, select ASP.NET Web Service Application.

4. In the Name box, type UploadService. In the Location box, type the following path: Local File System Folder:\WebService.

5. Click OK.

6. In the Solution Explorer, right-click Service1.asmx and rename the file CustomWS.asmx and then right click CustomWS.asmx and click View Code.

7. Add a reference to the assembly for Microsoft Office SharePoint Server 2007 (Microsoft.SharePoint.dll). This assembly is located in the following directory: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI. Please note that if you are developing on a machine that does not have SharePoint installed then you can copy the required files from the SharePoint machine to your development machine.

8. Make sure following using directives are included at the top:

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Net;


9. Change your class name from Service1 to CustomWS.

public class CustomWS: System.Web.Services.WebService


10. Comment out the web method definition. The commented out web method code will look like as follows:

//[WebMethod]
//public string HelloWorld()
//{
//return "Hello World";
//}


11. Add following code (web method) in the class:
/// Code here

12. Open CustomWS.asmx markup page. In Solution Explorer, right-click CustomWS.asmx and select View Markup. You will notice that the markup page has following line:

<%@ WebService Language="C#" CodeBehind="CustomWS.asmx.cs" Class="CustomService.CustomWS" %>


Change it to the following line:

<%@ WebService Language="C#" Class="CustomService.CustomWS" %>


13. Create a strong name for the class library. In Solution Explorer, right-click the web service project, and in the Properties dialog box, click Signing, select Sign the assembly, and select in the box for choosing a strong name key file.

14. In the Create Strong Name Key dialog box, provide a file name for the key, deselect Protect my key file with a password, and click OK.
15. Compile the web service project.

16. Now once you have signed and installed assembly in the GAC , open asmx file and change the markup to the following line:

<%@ WebService Language="C#" Class="Namespace.ClassName, AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8cee0c73157976c7" %>

This is the line I forgot to modify(including the publickeytoken and version number) and it bothered me for days.... duh!

17. As we are developing this web service on a machine that does not host SharePoint, therefore, we need to create a virtual directory in IIS. Click Start, point to Administrative Tools (You may have to go to the Control Panel first to select Administrative Tools), and then click Internet Information Services (IIS) Manager.
a. Expand the branch for the server computer to which you want to add a virtual directory. Under the server computer branch, expand the Web Sites folder, and right-click the Default Web Site and select New and then Virtual Directory.... If you don't want to use Default Web Site, you can create a new web site.

b. Click Next and enter an alias in the text box, for example, for this service you can enter UploadService.

c. Click Next and then click Browse... button to browse to the project folder (containing the .asmx file) and click Next.

d. Click Next again and then click Finish.


Note: In case you are developing the service on a SharePoint server,use following instructions:

18. Copy the Files.asmx to the following folder: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS

19. Run disco.exe at the command prompt from the LAYOUTS directory to generate .disco and .wsdl files.

Run a command in the following format to generate the files in LAYOUTS:

disco http://Site:port/_layouts/Files.asmx

Make sure you have entered the correct path in the command above otherwise you will get an error. If you created a virtual directory on a port other than the port 80, then you must mention the port number in the path (For example, http://localhost:8080/uploadservice/Files.asmx). This will generate the .disco and .wsdl files.

20. To register namespaces of the Windows SharePoint Services object model, open both the .disco and .wsdl files and replace the opening XML processing instruction -- -- with instructions such as the following:

<%@ Page Language="C#" Inherits="System.Web.UI.Page" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint.Utilities" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<% Response.ContentType = "text/xml"; %>

21. In the .disco file, modify the contract reference and SOAP address tags to be like the following example, which replaces literal paths with code generated paths through use of the Microsoft.SharePoint.Utilities.SPHttpUtility class, and which replaces the method name that is specified in the binding attribute:

<contractRef ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + "?wsdl"),Response.Output); %> docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>xmlns="http://schemas.xmlsoap.org/disco/scl/" /><soap address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns:q1="http://tempuri.org/" binding="q1:HelloWorld" xmlns="http://schemas.xmlsoap.org/disco/soap/" /><soap address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns:q2="http://tempuri.org/" binding="q2:ServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />

23. In the .wsdl file, make the following similar substitution for the SOAP address that is specified:

<soap:address location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> />

24. Rename both files in the respective formats CustomWSdisco.aspx and CustomWSwsdl.aspx so that your service is discoverable through Windows SharePoint Services.

Now let's copy the files to _vit_bin directory
25. The _vti_bin virtual directory maps physically to the Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI directory, which contains the default Web service files used in Windows SharePoint Services. Copy the new CustomWSwsdl.aspx and CustomWSdisco.aspx files, and also the CustomWS.asmx file, to the ISAPI folder.
From the _vti_bin directory, a Web service offers its functionality to the site that is specified when adding a Web reference for the service.
To verify that your custom Web service is discoverable, navigate to http://Server/_vti_bin/CustomWS.asmx

Now we need to list our web service files in the spdisco.aspx file for it to be available to applications:
26. To make your Web service discoverable in Visual Studio as a Web service alongside the default Windows SharePoint Services Web services, open the spdisco.aspx file located in \Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI and add the following code, specifying the .asmx file for your Web service.

<contractRef ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/MyCustomWebService.asmx?wsdl"), Response.Output); %>>
docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/MyCustomWebService.asmx"), Response.Output); %>
xmlns=" http://schemas.xmlsoap.org/disco/scl/ " />
<discoveryRef ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/MyCustomWebService.asmx?disco"),Response.Output); %>
xmlns="http://schemas.xmlsoap.org/disco/" />


WOO HOO and you'r done ! Just create a sample application to consume this web service just like you do to comsume other sharepoint web services

Happy web servicing !

No comments: