Walkthrough: Creating a Custom Web Service

This programming task provides an overview of how to create a custom Web service that operates within the context of Windows SharePoint Services 3.0. It steps through the process of creating a simple "Hello World" Web service and then shows how to modify the service so that it implements the Windows SharePoint Services 3.0 server-side object model to return site and list data.

Basic Steps for Creating a Web Service

  • Create an ASP.NET Web service in Microsoft Visual Studio 2005.

  • Create a class library within the Web service that defines the programming logic for the Web service.

  • Generate and edit a static discovery file and a Web Services Description Language (WSDL) file.

  • Deploy the Web service files to the _vti_bin directory.

  • Create a client application to consume the Web service.

Creating an ASP.NET Web Service in Visual Studio

The first step is to create an ASP.NET Web service Web site in Visual Studio 2005.

To create an ASP.NET Web service

  1. In Visual Studio, click File, point to New, and then select Web Site.

  2. In the Templates box of the New Web Site dialog box, select ASP.NET Web Service, select File System in the Location box, select a programming language and location for the project, and then click OK.

  3. Within the new Web service solution, create a separate class library project to contain the Web service logic. To create the project, click File, point to New, and then select Project.

  4. In the New Project dialog box, select a language in the Project types box, select Class Library in the Templates box, provide a name and location for the project, select Add to Solution in the Solution box, and then click OK.

  5. Add a reference to the System.Web.Services namespace in the class library project. Right-click the project in Solution Explorer, click Add Reference, select System.Web.Services in the Add Reference dialog box, and then click OK.

  6. Replace the default class file in the class library project with the default service class file that Visual Studio provides in the App_Code folder of the Web service.

    To replace the class file with the service class file

    1. In Solution Explorer, drag Service.cs or Service.vb to the top node in the class library project.

    2. Delete the Class1.cs or Class1.vb file, and also delete the Service.cs or Service.vb file that remains in the App_Code folder.

  7. Create a strong name for the class library:

    1. In Solution Explorer, right-click the class library project, and then click Properties.

    2. In the Properties dialog box, click Signing, select Sign the assembly, and then select <New> in the Choose a strong name key file list.

    3. In the Create Strong Name Key dialog box, provide a file name for the key, clear the Protect my key file with a password check box, and then click OK.

  8. To build only the class library project, right-click the project in Solution Explorer, and then click Build.

  9. To add your assembly to the global assembly cache (GAC), you can either drag the assembly into the %windows%\assembly directory using 2 instances of Windows Explorer, or use the command line utility gacutil.exe that is installed with the Microsoft .NET Framework SDK 2.0.

    To use gacutil.exe to copy the class library DLL into the GAC

    1. To open the Visual Studio command prompt, click Start, point to All Programs, point to Microsoft Visual Studio 2005, point to Visual Studio Tools, and click Visual Studio 2005 Command Prompt.

    2. At the command prompt type a command in the following form, and press ENTER:

      gacutil.exe -if "<Full file system path to DLL>".

  10. Now you are ready to modify the assembly information in the default Service.asmx file of the Web service with information for the DLL from the GAC. To get information from the GAC, open the %windows%\assembly directory in Windows Explorer, right-click your assembly, and click Properties.

  11. To open Service.asmx in Solution Explorer, right-click the file and click Open.

  12. Remove the CodeBehind attribute from the page directive in Service.asmx, and modify the contents of the Class attribute so that the directive matches the following format, where the assembly name "MyServiceAssembly" and the public key token are values specified in the Properties dialog box that you opened in step 10:

    <%@ WebService Language="C#" Class="Service, MyServiceAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8f2dca3c0f2d0131" %>

    In Visual Basic include the namespace to identify the class, for example, Class="MyServiceNamespace.Service, MyServiceAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8f2dca3c0f2d0131".

  13. Rename your .asmx file appropriately, and then save your changes.

Generating and Modifying Static Discovery and WSDL Files

To provide discovery and description for your custom Web service, you must create a .disco file and a .wsdl file. Because Windows SharePoint Services virtualizes its URLs (for example, http://MyServer/MySite/MySubsite becomes http://MyServer), you cannot use the autogenerated .disco and .wsdl files generated by ASP.NET. Instead, you must create a .disco page and a .wsdl ASPX page that provide the necessary redirection and maintain virtualization.

You can use ASP.NET to generate the .disco and .wsdl files by temporarily hosting your Web service in a virtual directory, such as /_layouts, and then using the .NET Framework Web Service Discovery tool (Disco.exe) to obtain the generated files.

To generate the static discovery and WSDL files

  1. In Windows Explorer, copy the .asmx file of your Web service to \\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS.

  2. 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://MyServer/_layouts/MyCustomWebService.asmx

  3. To register namespaces of the Windows SharePoint Services object model, open both the .disco and .wsdl files and replace the opening XML processing instruction -- <?xml version="1.0" encoding="utf-8"?> -- 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"; %>
  4. 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/" />
  5. 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); %> />
  6. Rename both files in the respective formats MyCustomWebServicedisco.aspx and MyCustomWebServicewsdl.aspx so that your service is discoverable through Windows SharePoint Services.

Copying the Web Service Files to the _vti_bin Directory

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 MyCustomWebServicewsdl.aspx and MyCustomWebServicedisco.aspx files, and also the MyCustomWebService.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://MyServer/_vti_bin/MyCustomWebService.asmx.

List the New Web Service in spdisco.aspx

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/" />
Creating a Windows Application to Consume the Web Service

After you copy the Web services files to the _vti_bin directory, the next step is to create a Windows Application to consume the Web service.

To create a Windows Application that consumes the Web service

  1. Open Visual Studio 2005, and on the File menu, point to New, and then click Project.

  2. In the New Project dialog box, select Visual C# or Visual Basic, and then select the Windows Application template.

  3. Type a name for the application in the Name box, specify a location for the project files in the Location box, and then click OK.

  4. In Solution Explorer, right-click the project, and then click Add Web Reference.

  5. In the address bar of the Add Web Reference browser, type the URL for the site to apply the service to, as follows, and then press ENTER:

    http://Server_Name/[sites/][Site_Name/]_vti_bin/MyCustomWebService.asmx

  6. Click Add Reference to download the service contract for the Web service.

  7. Open Form1 in Design view, display the Toolbox, and then drag a button onto the form.

  8. Double-click the Button1 control on Form1 to display the code-behind file in the code editor, and add the following code that calls your custom method.

    Visual Basic
    Dim MyCustomService As New Web_Reference_Folder.MyServiceClass()
    MyCustomService.UseDefaultCredentials = True
    MessageBox.Show(MyCustomService.HelloWorld())

    C#
                                Web_Reference_Folder.MyServiceClass MyCustomService = new Web_Reference_Folder.MyServiceClass();
    MyCustomService.UseDefaultCredentials = true;
    MessageBox.Show(MyCustomService.HelloWorld());
  9. Press F5 to compile and run the project and see a message box that displays "Hello World".

Implementing the Windows SharePoint Services Object Model

Now you are ready to try out types and members of the Windows SharePoint Services object model in the class library of your Web service.

To implement the Windows SharePoint Services object model

  1. Add a reference to the Microsoft.SharePoint assembly. Right-click the class library project in Solution Explorer, click Add Reference, select Windows SharePoint Services, and then click OK.

  2. In your project Service.cs or Service.vb file, you must import the appropriate namespaces in the object model. For example, to use types and members of the Microsoft.SharePoint and Microsoft.SharePoint.Utilities namespaces, add the following directives:

    Visual Basic
    Imports Microsoft.SharePoint
    Imports Microsoft.SharePoint.Utilities

    C#
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
  3. Rename the method in Service.cs or Service.vb. For example, change the name from HelloWorld to GetSiteListCount.

  4. Add the following code to display the name of the Web site and the number of lists that it contains.

    Visual Basic
    Dim myWebSite As SPWeb = SPContext.Current.Web
    Dim lists As SPListCollection = myWebSite.Lists
    
    Return myWebSite.Title + " contains " + lists.Count.ToString() + 
    " lists."

    C#
    SPWeb myWebSite = SPContext.Current.Web;
    SPListCollection lists = myWebSite.Lists;
    
    return (myWebSite.Title + " contains " + lists.Count.ToString() + 
    " lists.");
    Note Note:

    If your code modifies Windows SharePoint Services data in some way, you may need to allow unsafe updates on the Web site, which you can do by setting the AllowUnsafeUpdates property.

  5. To rebuild the class library DLL and copy it to the GAC, repeat steps 8 and 9 in "To create an ASP.NET Web service."

  6. Reset Internet Information Services (IIS) for changes in the DLL to take effect.

  7. To generate new versions of the .disco and .wsdl files, repeat the steps in "To generate the static discovery and WSDL files," but change the method binding name in the .disco file as appropriate, for example, to GetSiteListCount.

  8. Copy the new versions of the MyCustomWebServicedisco.aspx and MyCustomWebServicewsdl.aspx files to the ISAPI folder.

  9. Open the Windows application you created previously, delete the previous Web service reference for the Hello World example, change the method name as appropriate, and add a new Web reference to the revised Web service.

  10. Press F5 to compile and run the project and see a message box that displays the Web site name and the number of lists that it contains.

Tags :


Community Content

Colin Brown MVP
Information regarding the WSDL file ammendments is incorrect.

Within the section "To generate the static discovery and WSDL files", item 4 gives the following code :-

<contractRef ref=<% SPEncode.WriteHtmlEncodeWithQuote(Response, SPWeb.OriginalBaseUrl(Request) + "?wsdl", '"'); %>  docRef=<% SPEncode.WriteHtmlEncodeWithQuote(Response, SPWeb.OriginalBaseUrl(Request), '"'); %>  xmlns=" http://schemas.xmlsoap.org/disco/scl/ " />
<soap address=<% SPEncode.WriteHtmlEncodeWithQuote(Response, SPWeb.OriginalBaseUrl(Request), '"'); %>  xmlns:q1=" http://tempuri.org/ " binding="q1:HelloWorld" xmlns=" http://schemas.xmlsoap.org/disco/soap/ " />

This is infact incorrect, the initial call to SPENCODE should actually be a call to "SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode"

Therefore the example code should actually read :-

  <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/ " />

 

Colin Brown
Microsoft MVP

Tags : contentbug

cakriwut
List the new service in spdisco.aspx

The walkthrough is missing a step to list the new service in spdisco.aspx.

1. Open spdisco.aspx in Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI
2. Add following contract ref and soap address reference inside <discovery> tag. (Note** replace MyCustomWebService.asmx with appropriate name)

   <contractRef ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/MyCustomWebService.asmx?wsdl"), Response.Output); %> docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/ServiceClass.asmx"), Response.Output); %> xmlns="   http://schemas.xmlsoap.org/disco/scl/   " />
   <soap address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(spWeb.Url + "/_vti_bin/MyCustomWebService.asmx"), Response.Output); %> xmlns:q1="   http://schemas.microsoft.com/sharepoint/soap/   " binding="q1:VersionsSoap" xmlns="   http://schemas.xmlsoap.org/disco/soap/   " />

 

-Riwut Libinuko-

Tags : contentbug

chicagogrooves
Using/Imports not resolving without reference to Microsoft.SharePoint.dll
In my example it was needed to add a reference from the classlibrary project to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.SharePoint.dll in order to pickup the namespaces mentioned in the using/Imports statements.
Tags :

Chris Boyd
gacutil Typo

There is a small typo in the instuctions on how to register the DLL in the GAC.

gacutile.exe -iF "<Full file system path to DLL>".

Should be:

gacutil.exe -iF "<Full file system path to DLL>".

 

Tags : contentbug

HaloX_69
Weird Language error failure in VB.net ,success in C#.

I cannot get this working in VB.net 2005 , I can successful get these steps working in C#.
In vb.net i can get my web service running only if I do not separate my service.vb form app_code folder.
for some reason if I separate the service.vb form app_code folder and do exactly as the above article says i get a Type error.
Could not load type 'class1 from
assembly 'Create_Site_ECS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12bef56a6427b4cc'

<%@ WebService Language="vb" Class="Class1, 'Create_Site, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12bef56a6427b4cc" %>
I think this is wired , did any one try this in VB.net , I converted the web service to c# , but I like VB.net more that C#.

HI - I resolved this issue with a VB.net service by prefixing the class name in the .asmx file with the assembly namespace, eg

<%@ WebService Language="vb" Class="Create_Site.Class1, 'Create_Site, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12bef56a6427b4cc" %>

HTH

Actually it isn't the assembly name, but the project default namespace. It just happened that it worked for you because the default namespace is the project name unless changed.

ciao

Tags :

mrtrombone
Autogenerate WSDL and Disco Files
Here is a really helpful tool to autogenerate your wsdl and dicso files automatically:
http://paulhorsfall.co.uk/archive/2007/04/20/SharePoint-Web-Service-DISCO-and-WSDL-Generator.aspx
Tags :

Brian Bedard
Additions don't stay to true form of WSDL and DISCO documents

I made the changes suggested. There's just one problem. When I ran them, the substitutions that were made included the source file, one of the aspx files. Thats not what the XML indicates when running disco.exe on the asmx. It includes the asmx not the aspx's.

What I propose is a quick change to the baseUrl to remove the source file and replace the correct asmx file.

<% string baseUrl = SPWeb.OriginalBaseUrl(Request); baseUrl = baseUrl.Remove(baseUrl.LastIndexOf("/")+1); %>

Tags :

Marius Mans
Visual Studio 2008

If you used Visual Studio 2008 to edit the wsdl and disco files, be careful as the editor insists on inserting quotes when you paste XML, see below:

if you insert
<%@ Page Language="C#" Inherits="System.Web.UI.Page" %>

it becomes
<%@ Page="" Language="C#" Inherits="System.Web.UI.Page"%> WRONG, won't work.

The web service will still work if you call it from a test app as in this article, but Infopath, for example, will not bind to the broken WSDL file.

Tags :

IT Chavan
Port no of Sharepoint Central admiisrtation site Required
While Generating and Modifying Static Discovery and WSDL Files in step 2.

One must include port no of sharepoint central administration in disco command. if it is other than 80 or 8080.The port no can be obtained from Administrative tools->IIS->websites>sharepoint central administration v3->properties web site tab and no in against TCP Port.
Tags : contentbug

Kevin Mi
403 Error
Just wanted to write a quick note about the 403: Forbidden error.

I faced this down for about 6 hours the other day. I was using a lab setup with 3 virtual servers: AD, SQL and SharePoint. I have VS 08 installed on the SP VM where I do my dev work. I was logged in as a regular user that was assigned admin privileges in SharePoint, but not the SP VM or the domain. I was able to get the Hello World web service installed in the ISAPI folder (/_vti_bin/) but it wasn't showing up correctly in the _layouts folder. I added myself as a domain admin and everything started working correctly. I haven't checked to see if it's domain admin or local admin that's required, but that's how I fixed the 403: Forbidden error.

Hope that helps.
Tags : 403 forbidden

Sasa Popovic
The HTML document does not contain Web service discovery information
If you get "The HTML document does not contain Web service discovery information." error message while trying to generate disco and wsdl files then it probably means that you didn't set correct value for Class attribute of WebService directive.

I was getting that error message because I didn't have namespace in front of name of my class.
Tags :

Shash30
The HTML document does not contain Web service discovery information
I also got the same error while running disco.exe and the problem was copy pasting :). i Copied the Web Service Directive code containing the FQN but forgot to update the Quotes (").You will find the quotes to be diffrent after copying the code.
Tags :

VijayGande
avoid having '.' in the class project names

Exception of type 'System.Web.HttpParseException' was thrown in the webserver.asmx

Resolved by removing the '.' in the project name.

e.g.
Before: CompanyName.Project.Bll
After: CompanyNameProjectBll

Tags :

linda_h
Error when trying to add the Web Reference to a Web App that consumes the Web Service

I'm using VB, so I removed the semicolons from all of the '<%' code render blocks where we're using the 'Response' object.


I completed the walkthrough steps up through listing the Web Service in the spdisco.aspx file. I am able to browse to my Web Service in the _vti_bin directory, http://MyServer:port/_vti_bin/MyService.asmx.

To consume the Web Service, I created a Web application and I'm trying to 'add web reference,' but I'm getting an error. I enter http://MyServer:port/_vti_bin/MyService.asmx in the URL of the Add Web Reference window. It finds it, but in the right-hand side of the Add Web Reference window, I'm getting the following error:
The document at the url http://MyServer:port/_vti_bin/MyService.asmx was not recognized as a known document type.
The error message from each known type may help you fix the problem:
- Report from 'http://MyServer:port/_vti_bin/MyService.asmx' is 'The document format is not recognized (the content type

That's it! The message gets chopped off!

The ContentType in both the MyServicewsdl.aspx and MyServicedisco.aspx files is: <% Response.ContentType = "text/xml" %>



Any ideas?

Tags :

Excalibur
Use from SharePoint Designer 2007?

I've followed the directions in this article and created the ws. When opening the .asmx in IE I get the wsdl and all lookes ok.
But when I try to open it from SharePoint Designer I get the error: "http://server/_vti_bin/wstest.asmx did not return a valid description of an XML Web Service. Please check the address and try again". How to use it from SD???

Thomas Lee
What a pain!
I think this is a huge pain in the arse. Especially when the project you're working with references several web services. There should be an automated way to deal with using a web service from within SharePoint
Tags : comment

Teena Sharma
Trap for "The HTML document does not contain Web service discovery information " Error.

Make sure before running command disco http://MyServer/_layouts/MyCustomWebService.asmx that the disco.exe should present at path \Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS. if not either u have to copy it first into \layouts folder or should place the copy of "MyCustomWebService.asmx" file at the path where disco.exe file exists on the system. genrally it should be available at path C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin in your system.

Tags :

Moustafa Arafa
I'm getting an exception when i am trying to navigate to my web service
here is the solution:

http://moustafa-arafa.blogspot.com/2010/02/sharepoint-tip-creating-custom-web.html

Page view tracker