Monday, October 31, 2011

Send a SharePoint 2010 document to an external web service using Records Center (II)

In the previous entry I explained the solution adopted to send documents from a SharePoint library to an external web service using Records Center, and the first of the 2 steps to do that:

  • Add a a new connection in the configuration in Central Admin –> General Application Settings –> Configure send to connections.
  • Create a new webservice in a different Web Application (normal ASP.NET service).

In this new post I will explain how to override the standard service OfficialFile.asmx to copy documents to the Records Center, with new functionality to send to our own external service. Following one of the steps that Wictor Wilén described in this post, I managed to implement this same MOSS web service.

First of all, create a new VS2010 project of type ASP.NET Web Service application.

image

Then, using the tool wsdl.exe from the .NET Framework SDK we can get an interface based on the WSDL definition of the OfficialFile.asmx service. So to ensure that we have the latest web service interface, let’s execute the following command to get the interface we will add to our code.

wsdl /out:IRecordsRepositorySoap.cs /n:TestRecordsCenter_WebRole /serverinterface 
http://<serverUrl>/<recordsCenterUrl>/_vti_bin/OfficialFile.asmx?WSDL

That command will create the file IRecordsRepositorySoap.cs containing the definition of the web service. Someting with the following structure:


/// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
    [System.Web.Services.WebServiceBindingAttribute(Name="RecordsRepositorySoap", Namespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/")]
    public interface IRecordsRepositorySoap {
       
        /// <remarks/>
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/recordsrepository/SubmitFile", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        string SubmitFile([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] byte[] fileToSubmit, [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] RecordsRepositoryProperty[] properties, string recordRouting, string sourceUrl, string userName);
       
        /// <remarks/>
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/recordsrepository/GetFinalRoutingDes" +
            "tinationFolderUrl", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        DocumentRoutingResult GetFinalRoutingDestinationFolderUrl([System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] RecordsRepositoryProperty[] properties, string contentTypeName, string originalSaveLocation);
       
        /// <remarks/>
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/recordsrepository/GetServerInfo", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        string GetServerInfo();
       
        /// <remarks/>
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/recordsrepository/GetRecordRoutingCo" +
            "llection", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        string GetRecordRoutingCollection();
       
        /// <remarks/>
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sharepoint/soap/recordsrepository/GetRecordRouting", RequestNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", ResponseNamespace="http://schemas.microsoft.com/sharepoint/soap/recordsrepository/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        string GetRecordRouting(string recordRouting);
    }

Now we can use this interface as a Service Reference, so add this file directly to the solution to implement at least these five methods. Then create a new service .asmx (it is not necessary to call it OfficialFile.asmx) and the final solution will look to something like this:


image


Keep in mind that it is necessary to implement and override the five methods of the Service reference. One important point is that these methods can return anything (“hello World”, i.e., but obviously the connection will not work properly.´), except the method GetServerInfo(), which MUST return a string containing an XML string with the following format:


<ServerInfo><ServerType>Test Server</ServerType><ServerVersion>1.0</ServerVersion></ServerInfo>

Where ServerType and ServerInfo can be anything. No official documentation was found with this info, and I could only find something about that in Wictor’s blog.


The OfficialFile.asmx file will finally look like this (there are a lot of discussions in different forums about the correct way to declare this service, but this should work 100%). Keep in mind that you may need to deploy the built DLL to the GAC.


<%@ WebService Language="C#" Class="OfficialFile, SharePointToHYDMediaService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f16d3448d010e7e6" %>

And the code-behind (except using sentences):


[WebService(Namespace = "http://schemas.microsoft.com/sharepoint/soap/recordsrepository/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class OfficialFile : System.Web.Services.WebService, CustomRecordsCenter_WebRole.IRecordsRepositorySoap
{
   
    public string SubmitFile(byte[] fileToSubmit, RecordsRepositoryProperty[] properties, string recordRouting, string sourceUrl, string userName)
    {
        return "<ResultCode>Hello World</ResultCode>";
    }
    public string GetServerInfo()
    {
        return "<ServerInfo><ServerType>Test Server</ServerType><ServerVersion>1.0</ServerVersion></ServerInfo>";
    }
    public string GetRecordRoutingCollection()
    {
        return "Hello World";
    }
    public string GetRecordRouting(string recordRouting)
    {
        return "Hello World";
    }
    public DocumentRoutingResult GetFinalRoutingDestinationFolderUrl(RecordsRepositoryProperty[] properties, string contentTypeName, string originalSaveLocation)
    {
        return null;
    }
}

The next step consists on deploy the webservice to a different web application that you can create directly in the IIS Manager. This application needs to run under the SharePoint application pool to work properly, so configure this when you create the WebSite clicking the button Select application pool.


image 


Publish your service to the web application, and cross fingers.


image


If everything went fine, you should be able to browse your custom web service.


image


Finally, add the new service (that remember is based on the original OfficialFile.asmx) as a Service Connection as described in the part I of this post. Clicking in the link to test the service, should show a confirmation popup.


image


The custom Service Connection to send documents to an external web service is up and running, and although making a real test will throw an exception (basically because all the “return ‘Hello World’”) a debugger can be attached to the w3wp.exe process to check that it is working with the custom web service.

1 comment: