4 out of 17 rated this helpful - Rate this topic

Walkthrough: Creating a Custom ASP.NET Web Service

Published: May 2010

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

Important noteImportant

Custom ASP.NET Web services will function in SharePoint Foundation 2010, but it’s recommended that you instead create custom WCF services. For more information about WCF services, see WCF Services in SharePoint Foundation 2010. For a walkthrough that shows how to create a custom WCF service, see Walkthrough: Creating and Implementing a Custom WCF Service in SharePoint Foundation.

  • Create a Microsoft ASP.NET Web service in Microsoft Visual Studio.

  • 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.

  • Make your Web Service discoverable by listing it in Spdisco.aspx

  • Create a client application to consume the Web service.

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

The first step is to create a Microsoft ASP.NET Web service Web site in Visual Studio.

To create an ASP.NET Web service

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

  2. In the New Web Site dialog box, select .NET Framework 3.5 as the target framework, select Visual Basic or Visual C# as the programming language under Installed Templates, select the ASP.NET Web Service template, select File System in the Web location box, specify a 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, expand either Visual Basic or Visual C# under Installed Templates, select Class Library as the template, 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 on the .NET tab of 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 the Service.cs or Service.vb file 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 two instances of Windows Explorer, or use gacutil.exe, the command-line utility that is installed with theMicrosoft .NET Framework 2.0 Software Development Kit.

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

    1. To open the Visual Studio command prompt, click Start, click All Programs, click Microsoft Visual Studio 2010, click Visual Studio Tools, right-click Visual Studio Command Prompt (2010), and click Run as administrator.

    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 by using information about the DLL that can be found in 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.

To provide discovery and description for your custom Web service, you must create a .disco file and a .wsdl file. Because SharePoint Foundation virtualizes its URLs (for example, http://MyServer/MySite/MySubsite becomes http://MyServer), you cannot use the .disco and .wsdl files that are autogenerated 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 by using the Microsoft .NET Framework Web Service Discovery tool (Disco.exe) to obtain the generated files.

To generate and edit the static discovery and WSDL files

  1. In Windows Explorer, copy the .asmx file of your Web service to %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\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 SharePoint Foundation 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=14.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 SharePoint Foundation.

The _vti_bin virtual directory maps physically to the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI directory, which contains the default Web service files that are used in SharePoint Foundation. 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.

To make your Web service discoverable in Visual Studio as a Web service along with the default SharePoint Foundation Web services, open the spdisco.aspx file that is located in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\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/" />

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, 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 Forms 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 Service Reference.

  5. In the Add Service Reference dialog box, click Advanced, and in the Service Reference Settings box, click Add Web Reference.

  6. In the address bar of the Add Web Reference browser, type the URL for the site to apply the service to, as follows,

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

    and then press ENTER.

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

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

  9. 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.

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

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

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

To implement the SharePoint Foundation object model

  1. Add a reference to the Microsoft.SharePoint assembly. Right-click the class library project in Solution Explorer, click Add Reference, select SharePoint Foundation, 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.

    Imports Microsoft.SharePoint
    Imports Microsoft.SharePoint.Utilities
    

    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.

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

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

    If your code modifies SharePoint Foundation data in some way during an HttpGet request, 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 that 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.

Date

Description

Reason

May 2010

Initial publication

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Alternate walkthrough
There seem to be several people having troubles following this walkthrough so I created an alternate version on my blog. I think it is a little easier to follow. $0$0 $0 $0http://msmvps.com/blogs/windsor/archive/2011/11/04/walkthrough-creating-a-custom-asp-net-asmx-web-service-in-sharepoint-2010.aspx$0


Can recommend it, 100% better and clear than MSDN article
can't even add class library
When I try to add class library - I don't see "Add to Solution in the Solution box" at all and it creates separate solution with library instead. What am I missing??
Steps to do again on production environment ?
Hi,

I want to develop a custom web service for SharePoint 2010.

Can you tell me if these steps have to be done another time by the administrator of the production (or final) system of my client ?

thank you
Are there possible conflicts between a generic web service and SharePoint?
I need to publish data in a SharePoint server, in a web service.  However, I do not need to access to any SharePoint data.  Q1) Do I still have to undergo the above procedure?  Should I beware of any sort of possible conflict at all?  Q2: I guess it is possible to use another IP port to make the generic web service independent from SharePoint, right?
Terrible Article
I really hope that creating a web-service with VS 2010 is not so difficult and if it is then the product itself is a failure. I totally lost it after seeing hello world.
How to see exact error message for "HTML document does not contain Web service"
When you run Disco.exe against your asmx file you may experience very inconvenient message "HTML document does not contain Web service discovery information". In my case it was very important to see the exact error message. Please find answer at malcan.com/EN/Lists/Tips%20and%20tricks/DispForm.aspx?ID=25
Quality check
Going forward, please don't have the author create any more documentation by his or herself, perhaps citing from memory after gulping a six pack of Jolt. Please assign a Quality Assurance Engineer and/or Business Analyst who can quality check this writer's documentation STEP-BY-STEP to ensure no step was left out or, are/is vague.

For example, the step, "rename your asmx file appropriately".  It's easy to understand and anybody worth their computing salt can do a, rename. The confusing part is, rename it to what? Exactly? It's vague. Should the renamed file be namespace.service? alphabet.soup? bird.migration.from.nirvana.to.san.francisco? What??

In VS 2010, the default name of the project web site is website1. Notice the absence of a little blurb explaining that VS 2010 creates the project folder outside of the defined, default location for "regular" projects. It's two dots up and in a different folder named, websites. The default name for a Class Library project is ClassLibrary1. This also happens to be the named plugged in as the default NameSpace.

There. See? How expensive was it to include little FYI's in technical documentation? Was the writer late for a root canal and simply didn't have time? I'm not buying it whatever the reason is. There simply is no excuse for poor technical documentation. Especially, coming from a world class organization as Microsoft. Your success in the Windows 3.0/3.1 decade was largely dependent on world class documentation.


This step confused me
"Rename your .asmx file appropriately, and then save your changes"

IF my assembly is XYZ would this be XYZ.asmx?
Great article!
I was trying to achieve this for a long time, this article helped achieve my target. Thanks again
Good example but...
The walkthrough was great till I reached "Implementing the SharePoint Foundation Object Model". $0I was able to view the "Hello World" string but after replacing the code with SP object model, I am getting "The request failed with HTTP status 401: Unauthorized."$0 $0Also the example should show how to do simple debugging of the service library, e.g. do I need to attach to w3p process or what?$0
Could not load type from assembly

ERROR
I was facing an error below Could not load type 'Service' from assembly 'ListItemFetch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=782bb1324eff5bd5'. 


SOLUTION:
Note: My assembly is in GAC ( properly signed) and there is no other same assembly in any Bin directory of my site that might override the one in GAC. Moreover i tried this also without signing it.

So after an hours I resolved it by giving  "fully qualified name" to class in Web Service directive

<%@ WebService Language="c#" Class="ListItemFetch.Service, ListItemFetch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=782bb1324eff5bd5" %>

How about ADMISAPI
Can I drop my web service in ADMISAPI instead? I only want this particular web service to be available through the Central Admin URL and to Farm Admin users (basically just like admin.asmx). What other implications/protections would this give me by using the ADMISAPI instead?

UPDATE: I've done some test and it seems to work fine, it makes sense, but I've never found it documented anywhere.
Yikes
This is terrible !   Visual Studio is suppose to make life easy !
Code not updated from SharePoint 2007 article
The code to register the namespaces of the SharePoint Foundation object model need to be:

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