Friday, November 6, 2009

SharePoint: Create custom web service

This post will describe how to create a custom web service and deploy it in SharePoint. I have divided this post into two parts mainly. The first part will describe how to develop the web service and the second part will describe how to deploy this web service in sharepoint site.

Create a Visual Studio Project for the web service

1.Create Project: Create a new web service project from visual studio. A default web service will automatically be added in the project. Remove that one and add a new web service.


2. Use SPContext if Required: Add required methods in the web service. To use SharePoint classes add references to SharePoint Assembly. You can access the current SharePoint Context by accessing Microsoft.SharePoint.SPContext.


3. Place DLL in GAC: Once you are done with coding and the project is compiling ok then you need to place the dll of the project to GAC. Sign your assembly with strong name before deploying in GAC.


4. Modify web config by adding the the assembly in safecontrol: Add the assembly in the safe control section of the web config.


5. Change the web Service Markup: Now your web services's class in GAC so you need to link the asmx file to the dll in GAC. Open the ServiceName.asmx file (in markup mode by right clicking on the asmx file in VS and click View Markup). You will find the markup file as shown below:

<%@ WebService Language="C#" CodeBehind="RepositoryService.asmx.cs" Class="RepositoryServiceProject.RepositoryService" %>

Here the codebehind attribute refers to the cs file (in this case webservice.asmx.cs) associated with this service and class attribute refers to the class in that code behind file (RepositoryServiceProject.WebService1)will be used for this web service.


As our web service's code behind file will be in GAC so we need to link the web service to use the assembly in the GAC. You need to remove the codebehind attribute from the asmx markup and need to provide the full assembly/class name in the class attribute. For me the change was as shown below:

<%@ WebService Language="C#" Class="RepositoryServiceProject.RepositoryService, RepositoryServiceProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2c2b5c92b3495f9" %>

 

Generate and Modify Discovery and WSDL file

To use the web service we have just developed we need to create discovery (.disco) and WSDL (.wsdl) files. To generate these two files.


1. Deploy the asmx file to a temporary site: Create a demo web site from IIS and deploy the asmx file in the web site. Say the url is http://myserver/myservice.asmx. We need this temporary deployment to generate disco and wsdl file.


2. Generate Disco and wsdl file: To generate the disco and wsdl you need to open the visual studio command prompt.
disco http://myserver/myservice.asmx /out:c:\webservicefiles
Here the out parameter defines where the output disco and wsdl file will be placed. Change the url http://myserver/myservice.asmx to one where you deployed your service temporarily.


3. Customize disco file: After successfully running the disco command you'll find two files in the output directory. Open the disco file

  • replace the line

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

with

<%@ 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"; %>

  • replace the following lines in the disco file
  <contractRef ref="http://server1/RepositoryService.asmx?wsdl" docRef="http://server1/RepositoryService.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
  <soap address="http://server1/RepositoryService.asmx" xmlns:q1="http://server1.org/" binding="q1:RepositoryServiceSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
  <soap address="http://server1/RepositoryService.asmx" xmlns:q2="http://server1.org/" binding="q2:RepositoryServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />

with

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

4. Customize wsdl file: Open the wsdl file.
  • replace the following line:

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

with

<%@ 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"; %>

  • find the following two lines in the wsdl file
<wsdl:service name="RepositoryService">
    <wsdl:port name="RepositoryServiceSoap" binding="tns:RepositoryServiceSoap">
      <soap:address location="http://server1/RepositoryService.asmx" />
    </wsdl:port>
    <wsdl:port name="RepositoryServiceSoap12" binding="tns:RepositoryServiceSoap12">
      <soap12:address location="http://server1/RepositoryService.asmx" />
    </wsdl:port>
  </wsdl:service>

and in the above section replace the location with value

<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
So the finally the section will look like:

<wsdl:service name="RepositoryService">
    <wsdl:port name="RepositoryServiceSoap" binding="tns:RepositoryServiceSoap">
      <soap:address location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> />
    </wsdl:port>
    <wsdl:port name="RepositoryServiceSoap12" binding="tns:RepositoryServiceSoap12">
      <soap12:address location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> />
    </wsdl:port>
  </wsdl:service>

5.Rename the wsdl and disco file:
  • Rename the yourservice.disco file to yourservicedisco.aspx
  • Rename the yourservice.wsdl file to yourservicewsdl.aspx
6. Copy the web service file to its final location: Now copy three files yourservice.asmx, yourservicedisco.aspx and yourservicewsdl.aspx in the location like "Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI".

7. Make final changes to the spdisco.aspx: Open the file spdisco.aspx on location "Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI". Now add the following two lines inside <discovery></discovery> tag. Remember to replace the MyService.asmx with your service name in the following code snippet.

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

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

Check your web service

Now you can check if your web service is working or not. At first try to browse the web service from browser. If it works then try to write a simple client application and then try to call the web methods form that client application. The best way to check the web service is to access SPContext.Current inside web service code. If SPContext.Current is not null then definitely your web service is deployed properly.

6 comments:

  1. Thanks for the information on custom web design. This would help a lot.

    ReplyDelete
  2. <%@ WebService Language="C#" Class="RepositoryServiceProject.RepositoryService, RepositoryServiceProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2c2b5c92b3495f9" %>

    In the above, is it possible to get values dunamically? eg: Version=VERSION, where VERSION value is stored somewhere in teh list and dynamically get the value.. Is this possible?

    ReplyDelete
  3. @Pradeepa, I think you can - but you need to customize a lot. However I think you should not as there's a good number of ways you can achieve the same dynamic behaviour with Dependency Injection, Assembly Redirection

    ReplyDelete
    Replies
    1. Hi sohel.
      thanks for the reply. PLease could u provide me few links, it will be great helpful for me..:)

      thankew

      Delete

Note: Only a member of this blog may post a comment.