Writing Custom Web Services for SharePoint Products and Technologies

 

Rahul Sakdeo
Rohit Puri
Brett Stallman
Microsoft Corporation

April 2004

Applies to:
    Microsoft® Windows® SharePoint™ Services
    Microsoft Office SharePoint Portal Server 2003

Summary: Learn to create custom Web services for Microsoft SharePoint Products and Technologies and how to use the SharePoint Products and Technologies infrastructure to create a document upload Web service for remote document access. The accompanying downloadable sample provides a Web service for working with documents remotely from an external application. (11 printed pages)

Note   The information in this article also applies to Microsoft Office SharePoint Portal Server 2003, which is built on the Windows SharePoint Services platform. The code samples can be used on SharePoint sites created in a portal context using SharePoint Portal Server.

Download ODC_WritingCustomWebServicesSampleSPPT.EXE.

Contents

Introduction
About the Web Service Sample
Writing a Custom Web Service
Creating a Sample Document Upload Web Service
Troubleshooting Guide
Conclusion

Introduction

You can build powerful solutions on the rich and robust platform of Microsoft® Windows® SharePoint™ Services. As a developer, you may want to use some of the capabilities of Windows SharePoint Services to create custom Web services of your own.

Note   Because of the enhanced security model used by Windows SharePoint Services, you need to take a couple extra steps. To create a Web service for Windows SharePoint Services using the ASP.NET Web Service template in Microsoft Visual Studio® .NET, you must create the Web service on a virtual server that uses a different port than the virtual server that is running Windows SharePoint Services. Additionally, you must be a member of the local Administrators group for the server that is running Windows SharePoint Services.

The following list summarizes the process for writing a custom Web service. The remainder of this article drills deeper into the details.

  • If your default Web site (port 80) hosts Windows SharePoint Services, create a virtual server that uses a different port. The new virtual server acts as the development Web server, and the virtual server that hosts Windows SharePoint Services acts as the deployment Web server.
  • Create a Web Service Project on the development virtual server.
  • Generate and modify a static discovery (.disco) file and a .wsdl file, save these files as .aspx pages, and then register the Microsoft.SharePoint namespace with the page directive.
  • Modify the .disco and .wsdl files to support service virtualization.
  • When you finish developing the Web service, deploy its files to the _vti_bin virtual directory and the _vti_bin\bin virtual directory, which are located on the physical path for the Windows SharePoint Services site.

Note   This article assumes that you have a solid understanding of Microsoft .NET Framework, ASP.NET, and a programming language such as C or Microsoft Visual Basic® .NET. For additional reference material not included in this article, see the Microsoft SharePoint Products and Technologies Software Development Kit (SDK).

About the Web Service Sample

The ODC_WritingCustomWebServicesSampleSPPT.EXE download provides a sample Web service for remote document access. This project implements some of the document access methods exposed by the Microsoft.SharePoint namespace, namely, SPFile.CheckIn, SPFile.CheckOut, SPFile.UndoCheckOut, and SPFileCollection.Add. Without this custom Web service, you must use Web Distributed Authoring and Versioning (WebDAV) or Microsoft Office FrontPage remote procedure call (RPC) requests to provide remote document access.

To use this service on a server running Windows SharePoint Services

  1. Download ODC_WritingCustomWebServicesSampleSPPT.EXE and extract its contents to the following directory on a front-end server running Windows SharePoint Services:

    Local_drive:\CreatingaCustomWebServiceSample
    
  2. Double-click the build.bat file to compile the project and install the Web service.

    The following files are copied to the Local_drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\isapi\ directory:

    • SPFiles.asmx
    • spfilesdisco.aspx
    • spfileswsdl.aspx

    The following files are copied to the Local_drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\isapi\BIN\ directory:

    • WSCheckOut.dll
    • WSCheckOut.pdb

Writing a Custom Web Service

The Visual Studio .NET integrated development environment provides an ASP.NET Web service template that makes it easy to create custom Web services for a computer running Windows SharePoint Services. To use the template, however, you must first create a virtual server in Internet Information Services (IIS) on a port different from the one on which Windows SharePoint Services is running.

To create a virtual server on a different port

  1. Click Start, point to Administrative Tools, and then click Internet Information Services (IIS) Manager.

  2. Expand the branch for the server computer to which you want to add a virtual server. Under the server computer branch, right-click the Web Sites folder, point to New, and then click Web site.

  3. In the Name box, type a name for the new Web site.

  4. In the Description box, type the description of your virtual server, and then click Next.

  5. In the Enter the IP address to use for this Web site box, select the IP address that you want to use, or use the default value (All Unassigned).

  6. In the TCP port this Web site should use box, type the port number to assign to the virtual server, and then click Next.

    Note   Verify that this port number is not currently in use. You do not need to assign a host header because Windows SharePoint Service handles hosting.

  7. In the Path box, browse or type the path to the location on your hard disk where you want to store your projects.

  8. If you do not want to permit anonymous access to your virtual server, clear the Allow anonymous access to this Web site check box, and then click Next.

  9. On the Web Site Access Permissions panel, select the permissions that you want to use, and then click Next.

    Note   For best results in most cases, accept the default permissions. By default, the Read permission and the Run Scripts (such as ASP) permission are selected. Windows SharePoint Services automatically adds the Execute (such as ISAPI applications or CGI) permission to the appropriate folders.

  10. Click Finish.

To create a Web Service Project in Visual Studio .NET

  1. On the File menu, point to New, and then click Project.

  2. In the Project Types box, select Visual Basic Projects or Visual C Projects, depending on which language you prefer.

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

  4. In the Location box, type the following path:

    http://Server_Name:port/Project_Name
    
  5. Click OK.

    Note   On a remote computer, you receive a "Web Access Failed" error message, which tells you that the path does not correspond to the URL that you specified in the New Project dialog box. If this occurs, follow these steps:

    Under What would you like to do?, verify that the Retry using a different file share path check box is selected, and then type the following path in the Location box:

    \\Server_Name\NewVirtualRootPath
    

    Click OK.

    Completing this step creates an empty ASP.Net Web Service project that includes a Service1.asmx file.

  6. In Solution Explorer, right-click Service1.asmx, and then click View Code.

  7. Remove the comments in the following lines:

    '<WebMethod()> Public Function HelloWorld() As String
    '    HelloWorld = "Hello World"
    ' End Function
    
  8. Compile the project**.**

You can now deploy your service to the virtual server running Windows SharePoint Services.

To bind against a custom Web service for Windows SharePoint Services, Visual Studio .NET requires a special set of .aspx pages based on the static discovery (.disco) file and the .wsdl file for your Web service. Use the command line utility installed with Visual Studio .NET to generate a static discovery (.disco) file and a .wsdl file, as described in the following procedure.

To create and edit a .disco file and a .wsdl file

  1. At the Visual Studio .NET command prompt, type the following line, and then press ENTER to create a Service1.disco file and a Service1.wsdl file in the current folder:

    Disco http://server_name:New_Port/Project_Name/Service_1.asmx
    
  2. Open the Service1.disco file and locate the following line:

    <?xml version="1.0" encoding="utf-8"?>
    

    Replace the preceding line with the following lines:

    <%@ Page Language="C#" Inherits="System.Web.UI.Page"
    %> <%@ Assembly Name="Microsoft.SharePoint, Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint.Utilities" %> <%@ Import Namespace="Microsoft.SharePoint" %>
    <% Response.ContentType = "text/xml"; %>
    
  3. Save the file as Service1disco.aspx.

  4. Repeat steps 2 through 4 to modify the Service1.wsdl file and save it as Service1wsdl.aspx.

To modify the Service1disco.aspx file and the Service1wsdl.aspx file to support service virtualization

Note   The following code examples, and subsequent ones, include extra line breaks to facilitate online display. To use these examples, please remove the extra line breaks.

  1. Open the Service1disco.aspx file, and then locate the following tag:

    <contractRef ref="http://server_name:New_Port/Project_Name/Service1.asmx?wsdl" docRef=
    "http://server_name:New_Port/Project_Name/Service1.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
    
  2. Make the following changes in the <contractRef> tag:

    <contractRef ref=<% SPEncode.WriteHtmlEncodeWithQuote(Response, SPWeb.OriginalBaseUrl(Request)
     + "?wsdl", '"'); %> docRef=<% SPEncode.WriteHtmlEncodeWithQuote(Response,
     SPWeb.OriginalBaseUrl(Request), '"'); %> xmlns="http://schemas.xmlsoap.org/disco/scl/" />
    
  3. Locate the following tag:

    <soap address="http://server_name:New_Port/Project_Name/Service1.asmx" xmlns:q1=
    "http://tempuri.org/" binding="q1:Service1Soap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
    
  4. Change the <soap address> tag as follows, and then save the changes:

    <soap address=<% SPEncode.WriteHtmlEncodeWithQuote(Response, SPWeb.OriginalBaseUrl
    (Request), '"'); %> xmlns:q1="http://tempuri.org/" binding="q1:Service1Soap" xmlns=
    "http://schemas.xmlsoap.org/disco/soap/" />
    
  5. Open the Service1wsdl.aspx file, and then locate the following line:

    <soap:address location="http://server_name:New_Port/Project_Name/Service1.asmx" />
    
  6. Make the following changes to the soap:address line, and then save the changes:

    <soap:address location=<% SPEncode.WriteHtmlEncodeWithQuote(Response,
     SPWeb.OriginalBaseUrl(Request), '"'); %> />
    

To copy the Web service files to the _vti_bin virtual directory

  1. Copy the Service1wsdl.aspx file, the Service1disco.aspx file, and the Service1.asmx file to the _vti_bin virtual directory. This is the directory where all default Web services are stored.

  2. Copy the corresponding assembly (.dll) file to the _vti_bin/bin virtual directory.

    Note   The _vti_bin/bin virtual directory is mapped to the \\Server_Name\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ISAPI directory.

Next, you must include the service in the list of default Windows SharePoint Services Web services that is displayed in the Add Web Reference browser of Visual Studio .NET.

To include the Web service in the list of Web services on the server

  1. In Notepad, open the spdisco.aspx file of the Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\ISAPI folder.

  2. Add the following lines to the end of the file within the discovery element and save the file:

    <contractRef ref=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Service1.asmx?wsdl",
     '"'); %> docRef=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Service1.asmx", '"');
     %> xmlns="http://schemas.xmlsoap.org/disco/scl/" /><soap address=<%
     SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Service1.asmx", '"'); %>
     xmlns:q1="http://schemas.microsoft.com/sharepoint/soap/directory/" binding="q1:Service1Soap"
     xmlns="http://schemas.xmlsoap.org/disco/soap/" />
    

    Note   The text appearing before

    "Soap"

    in the binding attribute of the soap element (in this example,

    binding="q1:Service1Soap"

    ) specifies the name of the class that is defined in the Web service.

Using the Web Service

You are ready to use your custom Web service by creating a Windows application in Visual Studio .NET.

To use the custom Web Service

  1. On another computer, open Visual Studio .NET.

  2. On the File menu, point to New, and then click Project.

  3. In the Project Types box, select Visual Basic Projects or Visual C Projects, depending on which language you prefer.

  4. In the Templates box, select Windows Application.

  5. Specify a name and path for the project, and then click OK.

  6. On the default form, add a command button to invoke the new Web service.

  7. Add a Web reference to the Web service:

  8. Right-click the project, and then click Add Web Reference.

  9. In the wizard, type the following URL, and then click Open to download the service contract for the Web service:

    http://Server_name/_vti_bin/Service1.asmx
    

    Name this reference WSSServer.

  10. Add the following using directive to the project:

    using System.Net;
    
  11. In the Click event for the new button, add the following lines of code:

    WSSServer.Service1 _svc = new WSSServer.Service1();
    //to use the following line use System.Net in the using section
    _svc.Credentials = CredentialCache.DefaultCredentials;
    string _Retval = _svc.HelloWorld();
    MessageBox.Show(_Retval);
    
  12. Compile the project and run it, and then click the button to test the Web service.

Creating a Sample Document Upload Web Service

You can use the method described earlier in this article to create a Web service that uploads documents into the Shared Documents document library on the computer that is running Windows SharePoint Services. This Web service uses service virtualization to determine the site context, and then uploads the document to the Shared Documents document library folder.

To create the Upload service

  1. Use the method described in the previous section to create a Web service project. Name the project UploadSvc and name the Web service class and constructor UploadFile.

  2. In Solution Explorer, right-click Service1.asmx and rename the file UploadFile.asmx.

  3. Add a reference to the assembly for Windows SharePoint Services (Microsoft.Sharepoint.dll). By default, this assembly is listed with the other assemblies in the global assembly cache. The assembly for Windows SharePoint Services is also located in the following directory:

    C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\ISAPI
    
  4. Add the following Web method to the UploadFile.asmx.cs file as a member of the UploadFile class:

    [WebMethod]
    public string UploadDocument(string fileName, byte[] fileContents, string pathFolder)
    {
        if ( fileContents == null)
        {
            return "Null Attachment";
        }
        try
        {
            SPWeb site = SPControl.GetContextWeb(Context);
            SPFolder folder = site.GetFolder(pathFolder);
            string fileUrl = fileName;
            SPFile file = folder.Files.Add(fileUrl, fileContents);
            return file.TimeCreated.ToLongDateString()+ "::" + file.Title;
        }
        catch (System.Exception ee)
        {
            return ee.Message + "::" + ee.Source;
        }
    }
    
  5. Add the following using directives to the project:

    using System.IO;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    
  6. Compile the Web service project.

  7. Create and modify the .disco and .wsdl files and modify the spdisco.aspx file as described in previous sections, but replace Service1 with UploadFile. Save the files as UploadFiledisco.aspx and UploadFilewsdl.aspx respectively.

  8. Copy the .asmx file and the .aspx versions of the .disco and .wsdl files to the _vti_bin virtual directory, and copy the corresponding assembly to the _vti_bin/bin virtual directory.

To use the Upload service

  1. Open Visual Studio .NET, and then create a standard Windows application.

  2. Add a Web reference to the Web service that you created in the preceding procedure. Name the Web reference WSSServer.

  3. Add a button and two text boxes to the default form in the Windows application, one text box in which to enter the path of the file to upload and another text box in which to specify the destination document library (for example, http://Server_Name/sites/Target_Site/Document_Library).

  4. Add the following lines of code to the Click event for the button.

    WSSServer.UploadFile svcDocLib = new WSSServer.UploadFile();
    svcDocLib.Credentials = CredentialCache.DefaultCredentials;
    
    string strPath = textBox1.Text;
    string strFile = strPath.Substring(strPath.LastIndexOf("\\") + 1);
    string strDestination = textBox2.Text;
    
    FileStream fStream = new FileStream(strPath, System.IO.FileMode.Open);
    byte[] binFile = new byte[(int)fStream.Length];
    fStream.Read(binFile, 0, (int)fStream.Length);
    fStream.Close();
    
    string str = svcDocLib.UploadDocument(strFile, binFile, strDestination);
    MessageBox.Show(str);
    
  5. Add the following using directives to the project:

    using System.Net;
    using System.IO;
    
  6. Compile the project and run it.

Troubleshooting Guide

Obtaining the SharePoint Site Context

At run time, if your custom Web service cannot use the GetContextWeb function to obtain the SharePoint site context successfully, you receive the following error message when you try to use the Web service:

System.ArgumentException: Value does not fall within the expected range. At Microsoft.SharePoint.SPSite

When you create a custom Web service for your SharePoint site, you must retrieve an instance of the SPWeb class by invoking the GetContextWeb function on the SPControl object. To successfully invoke GetContextWeb, your custom Web service must run within the same AppDomain as your SharePoint site. To do this, move your .asmx file to the _vti_bin virtual directory, and move the assembly for the Web service into the _vti_bin/bin virtual directory.

Testing your Custom Web Service

After you deploy your .asmx file and your assembly, test your Web service. To test your Web service successfully, you must create a test application in Visual Studio .NET that uses SOAP to invoke the Web service methods. By default, custom Web services for Windows SharePoint Services only honor SOAP requests from their clients. If you try to test your Web service using a protocol other than SOAP, you receive the following error message:

Microsoft.SharePoint.SPException: The security validation for this page is invalid and might be corrupted. Please use your Web browser's Back button to try your operation again.

Adding a Web Reference to your Custom Web Service from Visual Studio .NET

To bind against a custom Web service for Windows SharePoint Services, Visual Studio .NET requires a special set of .aspx pages. If you add a Web reference to the .asmx file for the service without the required .aspx pages, you receive the following error message:

"File not found" when adding a Web reference to the ASMX file from Visual Studio.NET.

After you use the .disco file and the .wsdl file to create the two new .aspx files and move them to the appropriate _vti_bin virtual directory, you can successfully add a Web reference to the Web service from Visual Studio .NET. Be sure to add the Web reference to the .asmx file for the Web Service. Do not add the Web reference to either of the newly created .aspx files. If you do so, the Web service may appear to work in Visual Studio .NET, but at run time you receive the following error message:

Additional information: Possible SOAP version mismatch: Envelope namespace http://schemas.xmlsoap.org/wsdl/ was unexpected. Expecting http://schemas.xmlsoap.org/soap/envelope/.

Conclusion

By employing the techniques covered in this article, you can effectively create custom Web services that extend and enhance the power of Windows SharePoint Services for your own SharePoint-based solutions. Use the sample download to upload documents to a library and to check files in to or out from a remote application.