[SharePoint] Desarrollar y desplegar un servicio WCF en SharePoint 2010 con las CKSDev

Sí trabajas con SharePoint seguro que alguna vez has necesitado o puedes necesitar crear un servicio WCF custom que devuelva información de algun sistema y mostrarla en tu intranet.

Por ejemplo, imagina que necesitas hacer un API para comunicarte con un ERP, y que esta API necesita ser consumida desde diferentes sitios de tu intranet. Podríamos hacerlo con el BCS, pero imagina que quieres montarte WebParts con un aspecto visual chulo y que consuman esta información de manera asíncrona usando un framework javascript como jQuery, Mootols… entonces aquí el BCS se queda a un lado.

Manos a la obra

Lo primero que vamos a necesitar para hacer menos dolorosa la tarea de desplegar el WCF en SharePoint es descargar las CKSDev, que basicamente es unas extensiones para Visual Studio 2010 que mejoraran nuestra productividad cuando trabajamos desarrollando sobre SharePoint.

CKS – Development Tools Edition (Foundation)

CKS – Development Tools Edition (Server)

en mi caso he descargado e instalado las del servidor.

Una vez instaladas, abrimos Visual Studio 2010 y creamos un proyecto de vacío de SharePoint 2010:

image

Una vez creado, vamos a añadir nuestro servicio WCF, para ello pulsamos el botón derecho del ratón sobre nuestro proyecto Add –> New Item…

image
En la ventana de añadir nuevo elemento, seleccionamos WCF Service (CKSDev) y en mi caso lo he llamado ERPService

image

Una vez añadido, nuestra solución se muestra de la siguiente manera:

image

Tenemos el servicio ERPService y su contrato IERPService

Ahora nos toca analizar un poco el código generado para entender un poco como funciona y como se deplegará. Este es el contenido de nuestro servicio ERPService:

[BasicHttpBindingServiceMetadataExchangeEndpoint]

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

public class ERPService : IERPService

{

    // To test this service, use the Visual Studio WCF Test client

    // set the endpoint to http://<Your server name>/_vti_bin/CKSDev.DemoWCF/ERPService.svc/mex

    public string HelloWorld()

    {

        return "Hello World from WCF and SharePoint 2010";

    }

}

Por partes:

  1. BasicHttpBindingServiceMetadataExchangeEndpointAttribute, este atributo le dice a la factoría de SharePoint que cree automaticamente un metadata exchange endpoint para nuestro servicio, algo como esto http://<Your server name>/_vti_bin/CKSDev.DemoWCF/ERPService.svc/mex
  2. MEX es un standard que se usa para exponer los metadatos del servicio, y así nuestro clientes puedan consumirlo. En este ejemplo lo voy a quitar, porque yo no quiero usar MEX, voy a crear un servicio REST que devuelva JSON para que sea más sencillo de consumir vía JavaScript.
  3. También tenemos que cambiar el Factory de nuestro servicio, de este:
      <%@ ServiceHost Language="C#" Debug="true"

          Service="CKSDev.DemoWCF.ERPService, $SharePoint.Project.AssemblyFullName$" 

          Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory, 

          Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

       
      a este:
       
      <%@ ServiceHost Language="C#" Debug="true"

          Service="CKSDev.DemoWCF.ERPService, $SharePoint.Project.AssemblyFullName$" 

          Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, 

          Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

      El cambiar el factory del servicio es porque el anterior es para MEX y el nuevo que hemos puesto sirve para REST. aquí os dejo una tabla con los posibles service factory que podéis usar en SharePoint 2010:

      image
  4. El segundo atributo [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] lo dejamos para tener compatibilidad con ASP.NET, porque sino SharePoint nos mostrará un error al intentar acceder al servicio.
  5. Como podemos observar, nuestro servicio tiene un contrato IERPService que tiene solo un método HelloWorld. A continuación verememos como modificar el contratod e nuestro servicio.

A desarrollar!

Vamos a montar un sencillo ejemplo de un ERP con un módulo de Recursos Humanos para devolver la nómina del usuario conectado. AVISO: El código que se muestra dista muchísimo de la realidad, es un ejemplo y debe tratarse como tal, porque lo que se trata este ejemplo es de ver como crear el servicio, desplegarlo y consumirlo.

Lo primero es crear la entidad nómina que devolverá el módulo de Recursos Jumanos:

public class PayRoll

{

    public string Name { get; set; }

    public int EmployeeNumber { get; set; }

    public double Hours { get; set; }

    public double Gross { get; set; }

    public double Tax { get; set; }

    public double Insurance { get; set; }

    public double Deduction { get; set; }

}

A continuación, vamos a modificar nuestro contrato IERPService y le vamos a añadir un método que devuelva un objeto nómina –> PayRoll:

[ServiceContract]

public interface IERPService

{

    [OperationContract,

     WebGet(UriTemplate = "/HR/PayRoll",

         ResponseFormat = WebMessageFormat.Json)]

    PayRoll GetMyPayRoll();

}

Como podéis observar, le añadido algún atributo más:

  1. WebGet: Será la Url para acceder a este recurso vía HTTP.
  2. ResponseFormat: El formato de respuesta será JSON, así será más fácil de consumir desde JavaScript.

Podríamos hacer que el servicio REST retornase xml o json en función del Content-Type de la petición pero eso lo dejo para vosotros a modo de práctica.

Por último, vamos a nuestro servicio a implementar el método GetMyPayRoll:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

public class ERPService : IERPService

{

    public PayRoll GetMyPayRoll()

    {

        return new PayRoll

                   {

                       Deduction = 19.0,

                       EmployeeNumber = 100010001,

                       Gross = 0,

                       Hours = 8.5,

                       Insurance = 5,

                       Name = SPContext.Current.Web.CurrentUser.Name,

                       Tax = 16

                   };

    }

}

¿Donde se despliega mi servicio y como accedo a él?

El servicio se despliega por defecto en el directorio C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14ISAPINombre_De_Tu_Proyecto. Si quieres como en mi caso que se depliegue en el ISAPI hay que hacer el siguiente cambio.

Sobre nuestro proyecto de SharePoint deleccionado, le damos al Ver todos los archivos:

image

Doble click sobre el archivo SharePointProjectItem.spdata

image

Y cambiamos el directorio donde se despliega de este:

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

<ProjectItem Type="CKS.Dev.SharePoint.WcfService" 

             SupportedTrustLevels="All" 

             SupportedDeploymentScopes="Web, Site, WebApplication, Farm, Package" 

             xmlns="http://schemas.microsoft.com/VisualStudio/2010/SharePointTools/SharePointProjectItemModel">

  <Files>

    <ProjectItemFile Source="ERPService.svc" Target="ISAPICKSDev.DemoWCF" Type="RootFile" />

  </Files>

</ProjectItem>

a este otro:
 
<?xml version="1.0" encoding="utf-8"?>

<ProjectItem Type="CKS.Dev.SharePoint.WcfService" 

             SupportedTrustLevels="All" 

             SupportedDeploymentScopes="Web, Site, WebApplication, Farm, Package" 

             xmlns="http://schemas.microsoft.com/VisualStudio/2010/SharePointTools/SharePointProjectItemModel">

  <Files>

    <ProjectItemFile Source="ERPService.svc" Target="ISAPI" Type="RootFile" />

  </Files>

</ProjectItem>

Una vez hecho esto, desplegamos la solución desde Visual Studio 2010 y accedemos con el navegador a nuestro servicio. El servicio está disponible en todos los sites de nuestro site collection, así pues podemos acceder desde las siguientes urls:

SiteCollection –> http://site/_vti_bin/CKSDev.DemoWCF/ERPService.svc

SubSite –> http://site/subsite/_vti_bin/CKSDev.DemoWCF/ERPService.svc

image

Al ser un servicio REST nos dice que no hay endpoint, pero como hemos escrito una url de fácil de recordar y entender (Eso es lo bueno de REST frente  a SOAP), basta con ponerla en el navegador y vemos el resultado en JSON:

http://site/_vti_bin/CKSDev.DemoWCF/ERPService.svc/HR/PayRoll

Url del servicio + Nombre del módulo del ERP + Acción

image

Estoy usando para ver el JSON de la respuesta la extensión JSON Viewer:

image

Llamar al servicio desde jQuery

A continuación vamos a añadir un WebPart Visual a nuestro proyecto al que llamaremos WebPartjQuery y que será el que registre los JavaScripts necesarios para llamar a nuestro servicio:

image

Vamos a añadir el código JavaScript necesario para la llamada al servicio y para ello editamos el ascx:

image

Para no descargar jQuery y añadirlo al proyecto vamos a hacerlo mediante CDN:

http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js

Para registrar el script vamos a hacer uso del método RegisterClientScriptInclude

Page.ClientScript.RegisterClientScriptInclude("jQuery",

                    "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js");

Que genera el siguiente tag:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>

Y luego registramos el script que hará la llamada a nuestro servicio de ERP:

const string jQueryScript = @"$(document).ready(function () {

                                                $.ajax({

                                                    dataType: 'json',

                                                    cache: false,

                                                    url:'http://sitio/_vti_bin/ERPService.svc/HR/PayRoll',

                                                    success: function (data) {

                                                        alert('EmployeeNumber: ' + data.EmployeeNumber);

                                                    },

                                                    error: function (a, b, c) {

                                                        alert('Error');

                                                    }

                                                });

                                            });";

 

Page.ClientScript.RegisterClientScriptBlock(GetType(), "ajax", jQueryScript, true);

Que genera el siguiente código:

<script type="text/javascript">

//<![CDATA[

$(document).ready(function () {

                    $.ajax({

                        dataType: 'json',

                        cache: false,

                        url:'http://sitio/_vti_bin/ERPService.svc/HR/PayRoll',

                        success: function (data) {

                            alert('EmployeeNumber: ' + data.EmployeeNumber);

                        },

                        error: function (a, b, c) {

                            alert('Error');

                        }

                    });

                });//]]>

</script>

El código básicamente lo que hace, es hacer una llamada ajax al servicio de ERP y mostrar en un alert el número de empleado.

Volvemos a desplegar la solución desde Visual Studio 2010 y vamos a añadir el WebPart para ver el resultado. Para ello editamos la página:

image

Nos situamos con el puntero del ratón donde queramos añadir el WebPart y pulsamos en el botón Insertar WebPart de la Ribbon:

image

Pulsamos en la categoría Custom, seleccionamos el WebPartjQuery y pulsamos el botón Añadir:

image

Si todo lo hemos hecho bien, el resultado es un alert con el número de empleado:

image

Ahora es tarea del lector profundizar un poco en jQuery, plantillas JavaScript como PURE, jsViews para mejorar el aspecto visual y en general familiarizarse un poco con el uso de JavaScript.

Un saludo y espero que os haya gustado!

Bibliografía: WCF Services in SharePoint Foundation 2010

Código de ejemplo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *