Muchos de los servicios ofrecidos por Azure se pueden utilizar para ampliar y mejorar el funcionamiento de SharePoint, tanto on-premises como en la nube. Uno de los servicios que ofrece Azure es "Cloud Services", que es una solución de Plataforma como Servicio (PaaS) que proporciona toda la infraestructura física más el software de base para ejecutar aplicaciones Web personalizadas. Utilizando Azure Cloud Services solamente es necesario construir (desarrollar) la aplicación, compilarla, empaquetarla y desplegarla al servicio; de todo el resto, crear máquinas virtuales, configurarlas, darles mantenimiento y respaldo, se encarga Azure.
Azure Cloud Services ofrece una máquina virtual para cada servicio que se crea, en la que el usuario es administrador y puede controlar todo su funcionamiento. En contraposición, Azure Web Apps permite crear aplicaciones Web de la misma forma que Cloud Services, pero toda la infraestructura es compartida y el usuario no tiene ni derechos de administrador del servicio ni en la máquina virtual que hospeda el servicio.
Cuando se crea un Azure Cloud Service, el motor de servicios de Azure (llamado el "Fabric Controller") despliega y configura todos los aspectos necesarios para que el servicio funcione inspeccionando el paquete de despliegue. De esta forma, si por alguna razón el servicio deja de funcionar, el Fabric Controller puede en cualquier momento crear un nuevo servicio, instalar el paquete y seguir funcionando con una caída del sistema de solamente algunos minutos. Lo mismo ocurre cuando se necesita incrementar el poder de procesamiento del servicio: si el usuario indica que necesita más CPU o memoria, el Controller se encarga de crear la (o las) máquina virtual necesaria, configurarla, instalar el paquete y configurar el balanceador de carga para que todo funcione apropiadamente, sin que el usuario tenga que intervenir de ninguna manera. Una consecuencia importante de esta arquitectura es que no se debe mantener ningún tipo de dato localmente en un servidor del Cloud Service, es decir, el software creado tiene que ser "stateless". Tampoco se deben realizar configuraciones manualmente en los servidores, todo debe ser hecho por medio de scripts.
Azure Cloud Service permite crear dos tipos de roles: "Web Role" y "Worker Role". La principal diferencia es que el primero dispone de IIS instalado por defecto y el segundo no. El Web Role es un servicio ideal para crear servicios WCF (Windows Communication Foundation) que se pueden utilizar de diferentes maneras con SharePoint. Por medio de un servicio WCF se pueden conectar sistemas externos con SharePoint de tal forma que los datos que contienen se pueden procesar dentro de SharePoint mismo y se pueden hacer interactuar con el Business Connectivity Service de SharePoint, haciéndolos, al mismo tiempo, indexables con el motor de búsqueda.
Creación de un servicio de Azure Cloud Service
Para comenzar a utilizar el servicio es necesario crear primero un Recurso de Trabajo de Cloud Service:
- En el nuevo panel defina un nombre para el servicio ("ZooCS" en el ejemplo), la suscripción de Azure a utilizar, el grupo de recursos de Azure (o crear uno nuevo) y la localización del centro de datos de Azure. Utilice el botón de "Create". Después de algunos segundos, el nuevo servicio aparece en la lista de "Cloud Services" del portal.
Creación de un servicio Web WCF (SOAP)
WCF permite crear servicios Web que pueden ser utilizados por múltiples tipos de sistemas. Por defecto, las plantillas de Visual Studio para WCF crean servicios SOAP (Simple Object Access Protocol) que utiliza XML para el intercambio de información estructurada entre los sistemas conectados. WCF SOAP es, también, el protocolo indicado para conectar sistemas externos con el Business Connectivity Service de SharePoint. El siguiente ejemplo crea un servicio Web WCF con Visual Studio 2015 (aunque el procedimiento es igual a con Visual Studio 2013) que no utiliza datos de ningún otro sistema, sino que maneja datos creados y mantenidos en memoria. El objetivo del ejemplo es mostrar cómo crear el servicio; después de creado, el servicio se puede conectar de forma sencilla con cualquier tipo de fuente de datos (Base de Datos, sistema externo, etc.). Note, además, que el código fuente del ejemplo solamente contiene rutinas básicas para atrapar excepciones, por lo que no está listo para ser utilizado en sistemas de producción.
Instale el Azure SDK para Visual Studio 2015 si no lo tiene instalado en VS. Desde el sitio de Microsoft (https://azure.microsoft.com/en-us/downloads/archive-net-downloads/) se puede descargar e instalar.
Inicie Visual Studio 2015 y cree un nuevo proyecto del tipo "Cloud" - "Azure Cloud Service" y asígnele un nombre ("ZooWCF" en el ejemplo).
Visual Studio inicia el proyecto y abre el archivo "Service1.svc.cs". Usando el "Solution Explorer" de Visual Studio, renombre los archivos "IService1.cs" en "IZoo.cs" y "Service1.svc en "Zoo.svc".
En el archivo "Service1.svc.cs", renombre la clase "Service1" a "Zoo". Elimine todos los comentarios agregados por defecto por la plantilla.
Si está utilizando Visual Studio 2015, el proyecto "ZooWebRole" es creado utilizando .NET Framework 4.5.2. En el momento (cambió en enero del 2016 a 4.5.2, pero servicios creados anteriormente siguen funcionando con 4.5.0), Azure utiliza la versión 4.5.0, por lo que es indispensable cambiar el framework en el proyecto de Visual Studio desde su pantalla de propiedades. Otra posibilidad es que después de desplegar el proyecto en Azure, utilizando su máquina virtual se instale el framework 4.5.2 (vea el punto 29 que trata sobre la máquina virtual del servicio).
Abra el archivo "IZoo.cs" y reemplace el código dentro de la función "public class CompositeType" con el siguiente fragmento. Esta es la entidad que se va a utilizar para definir los objetos de tipo "Animal" del Zoológico. Note que las tres variables iniciales utilizadas para las propiedades tienes que tener alcance "public", de otra forma el servicio de SharePoint BDC no podrá utilizar el servicio WCF:
1 [DataContract]2
1 public class Animal2
1 {2
1 Int32 animalID;2
1 string animalName;2
1 string animalDanger;2
12
1 [DataMember]2
1 public Int32 AnimalID2
1 {2
1 get { return animalID; }2
1 set { animalID = value; }2
1 }2
12
1 [DataMember]2
1 public string AnimalName2
1 {2
1 get { return animalName; }2
1 set { animalName = value; }2
1 }2
12
1 [DataMember]2
1 public string AnimalDanger2
1 {2
1 get { return animalDanger; }2
1 set { animalDanger = value; }2
1 }2
1 }2
1 [ServiceContract]2
1 public interface IZoo2
1 {2
1 [OperationContract]2
1 IEnumerable<Animal> ReadList();2
12
1 [OperationContract]2
1 Animal ReadItem(int animalID);2
12
1 [OperationContract]2
1 Animal Create(Animal newAnimal);2
12
1 [OperationContract]2
1 void Update(Animal animal);2
12
1 [OperationContract]2
1 void Delete(int animalID);2
1 }2
1 static List<Animal> myZoo = new List<Animal>2
1 {2
1 new Animal(){ AnimalID = 1, AnimalName = "Cucaracha", AnimalDanger = "Poco" },2
1 new Animal(){ AnimalID = 2, AnimalName = "Pulga", AnimalDanger = "Mucho" }2
1 };2
1 public IEnumerable<Animal> ReadList()2
1 {2
1 try2
1 {2
1 IEnumerable<Animal> animalList = // Using LINQ2
1 from oneAnimal in myZoo2
1 orderby oneAnimal.AnimalID2
1 select new Animal2
1 {2
1 AnimalID = oneAnimal.AnimalID,2
1 AnimalName = oneAnimal.AnimalName,2
1 AnimalDanger = oneAnimal.AnimalDanger2
1 };2
12
1 return animalList;2
1 }2
1 catch (Exception ex)2
1 {2
1 throw new Exception("There was a problem reading animal data - ", ex);2
1 }2
1 }2
1 public Animal ReadItem(int animalID)2
1 {2
1 try2
1 {2
1 IEnumerable<Animal> animalList =2
1 from oneAnimal in myZoo2
1 where oneAnimal.AnimalID == animalID2
1 select new Animal2
1 {2
1 AnimalID = oneAnimal.AnimalID,2
1 AnimalName = oneAnimal.AnimalName,2
1 AnimalDanger = oneAnimal.AnimalDanger2
1 };2
12
1 return animalList.First();2
1 }2
1 catch (Exception ex)2
1 {2
1 throw new Exception("There was a problem reading animal data - ", ex);2
1 }2
1 }2
1 public Animal Create(Animal newAnimal)2
1 {2
1 try2
1 {2
1 myZoo.Add(newAnimal);2
12
1 return newAnimal;2
1 }2
1 catch (Exception ex)2
1 {2
1 throw new Exception("There was a problem creating a new animal - ", ex);2
1 }2
1 }2
1 public void Update(Animal animal)2
1 {2
1 try2
1 {2
1 int animalIndex = myZoo.FindIndex(a => a.AnimalID == animal.AnimalID); // Using Lambda Expressions2
1 if (animalIndex >= 0)2
1 myZoo[animalIndex] = animal;2
1 }2
1 catch (Exception ex)2
1 {2
1 throw new Exception("Problem updating animal with ID = " + animal.AnimalID.ToString() + " - ", ex);2
1 }2
1 }2
1 public void Delete(int animalID)2
1 {2
1 try2
1 {2
1 IEnumerable<Animal> animalList =2
1 from oneAnimal in myZoo2
1 where oneAnimal.AnimalID == animalID2
1 select oneAnimal;2
12
1 myZoo.Remove(animalList.First());2
12
1 //myZoo.Remove(myZoo.Find(a => a.AnimalID == animalID)); // Using Lambda Expressions2
1 }2
1 catch (Exception ex)2
1 {2
1 throw new Exception("Problem deleting animal with ID = " + animalID.ToString() + " - ", ex);2
1 }2
1 }2
En principio, el servicio WCF contiene todo el código para definir la entidad, la interface y los métodos CRUD y está listo para funcionar. Ejecute el proyecto en forma de debuggeo. Esto inicia el Emulador de Azure y también IIS Express. Verifique que el proyecto compila y ejecuta correctamente (una instancia de IE debe iniciarse automáticamente con algunos mensajes indicando que el servicio está ejecutando sin problemas). Visual Studio incluye un Emulador de Azure Service Cloud que permite hacer funcionar el servicio WCF localmente sin necesidad de subirlo a Azure. De igual manera, se inicia IIS Express de forma automática para hostear el servicio. Es importante hacer notar que, si el computador en donde se está desarrollando el código es también un servidor de SharePoint, la combinación de Emulador e IIS Express destruye totalmente algunos de los servicios de SharePoint (BCS, Apps entre otros) y no hay forma de volverlos a hacer funcionar fuera de reinstalar totalmente a SharePoint.
Detenga la ejecución del proyecto. Agréguele a la Solución de Visual Studio un nuevo proyecto del tipo "Console Application" llamado "ZooWCFTest"
Después de que el proyecto ha sido creado, seleccione su directorio de "References" y utilizando el menú contextual, seleccione "Add Service Reference". En la ventana de "Add Service Reference" utilice el botón de "Discover". En el panel de "Services" debe aparecer el servicio acabado de crear. Selecciónelo y utilice el botón de "OK" para crear la referencia
1 static void Main(string[] args)2
1 {2
1 ZooWCFTest.ServiceReference1.ZooClient myclient = new ZooWCFTest.ServiceReference1.ZooClient();2
1 Console.Clear();2
12
1 Console.WriteLine("** ReadList test");2
1 Console.WriteLine("Numero inicial de animales = " + myclient.ReadList().Count().ToString());2
12
1 Console.WriteLine("** ReadItem test");2
1 ZooWCFTest.ServiceReference1.Animal myResponse = myclient.ReadItem(1);2
1 Console.WriteLine("Animal con ID 1 = " + myResponse.AnimalName + " " + myResponse.AnimalDanger);2
12
1 Console.WriteLine("** Delete test");2
1 myclient.Delete(2);2
1 Console.WriteLine("Animal con ID 2 eliminado");2
1 Console.WriteLine("Numero de animales = " + myclient.ReadList().Count().ToString());2
12
1 Console.WriteLine("** Create test");2
1 ZooWCFTest.ServiceReference1.Animal newAnimal = new ServiceReference1.Animal();2
1 newAnimal.AnimalID = 10;2
1 newAnimal.AnimalName = "Elefante";2
1 newAnimal.AnimalDanger = "Ninguno";2
1 ZooWCFTest.ServiceReference1.Animal myAnimal = myclient.Create(newAnimal);2
1 Console.WriteLine("Nuevo animal = " + myAnimal.AnimalName + " " + myAnimal.AnimalDanger);2
1 Console.WriteLine("Numero de animales = " + myclient.ReadList().Count().ToString());2
12
1 Console.WriteLine("** Update test");2
1 ZooWCFTest.ServiceReference1.Animal updateAnimal = new ServiceReference1.Animal();2
1 updateAnimal.AnimalID = 1;2
1 updateAnimal.AnimalName = "Cucaracha";2
1 updateAnimal.AnimalDanger = "Peligrosisima";2
1 myclient.Update(updateAnimal);2
1 myResponse = myclient.ReadItem(1);2
1 Console.WriteLine("Animal con ID 1 = " + myResponse.AnimalName + " " + myResponse.AnimalDanger);2
1 }2
Detenga el servicio WCF. Una vez comprobado que el servicio funciona correctamente en el Emulador local, es necesario subirlo a Azure. En el Solution Explorer de Visual Studio seleccione el proyecto "ZooWCF" y utilizando el menú de contexto seleccione "Publish". En la ventana de "Publish Azure Application" que aparece, introduzca la cuenta y clave de Azure en donde se ha creado el Cloud Service del punto 1
Una vez las credenciales han sido aceptadas, la casilla de "Choose your subscription" permite seleccionar la suscripción utilizada para crear el servicio del punto 1. "Next":
En la primera pestaña ("Common Settings") se puede seleccionar también "Enable Remote Desktop for all roles". Un Servicio Cloud en Azure crea una máquina virtual a la que es posible acceder por medio de Remote Desktop. Cuando se selecciona esta opción, es necesario definir las credenciales del usuario de Remote Desktop en la ventana que aparece automáticamente.
Una vez desplegado en Azure, el servicio se puede testear con la Aplicación de Consola creada en el punto 20 cambiando el URL de la referencia de servicio, o utilizando alguna otra herramienta como "WcfTestClient". Note que WcfTestClient ya no viene incluida con Visual Studio 2015, pero se puede descargar desde varios sitios en Internet. El URL del servicio es el configurado en el punto 4 cuando se creó el Cloud Service en Azure, seguido por ".cloudapp.net/[NombreClase].svc" (en el ejemplo seria "http://zoocs.cloudapp.net/zoo.svc"). Desde la consola de manejo de Azure se puede encontrar también el URL, junto con todas sus opciones de configuración.
Si se seleccionó la opción de "Enable Remote Desktop for all roles" en el punto 26 de despliegue, se puede interactuar directamente con la máquina virtual del Cloud Service. En Visual Studio abra el "Server Explorer" y expanda la sección de "Azure" - "Cloud Services". Utilizando el menú contextual sobre la entrada de la instancia aparece una opción para iniciar el Remote Desktop de Windows y conectarse con la máquina virtual. Utilice la clave configurada en el punto 26.
Utilización del servicio SOAP en el servicio de BCS de SharePoint
Una vez el servicio WCF está instalado y configurado en Azure Cloud Services, puede ser consumido por el Business Connectivity Service de SharePoint. Esto permite no solo integrar los datos e interactuar con ellos directamente desde SharePoint, sino que también se pueden indexar para poderlos consultar por medio del motor de búsqueda, y utilizarlos como metadatos por medio de la columna de datos externos.
Desde la Administración Central de SharePoint, vaya a "Administración de aplicaciones" - "Administrar aplicaciones de servicio" - "Servicio de almacenamiento seguro". Si el servicio no ha sido configurado, comience por generar una clave para activarlo.
Utilice el botón de "Nueva" (en la cinta). En la nueva página, defina el ID (una cadena cualquiera), nombre para mostrar y correo electrónico; seleccione "Grupo restringido" en la sección "Tipo de aplicación de destino" - "Siguiente".
Para los nombres de campo utilice "Nombre de usuario" y "Contraseña" y en las casillas de "Tipo de campo" seleccione "Nombre de usuario" y "Contraseña". Conserve las otras opciones por defecto. "Siguiente".
En la siguiente página seleccione el (o los) usuario que va a ser administrador y los usuarios que serán miembros del grupo de seguridad. "Aceptar".
Una vez la aplicación de destino ha sido creada aparece en la lista de SharePoint. Selecciónela y utilice el botón de "Establecer". En la ventana que abre introduzca el nombre de usuario de Azure que tiene acceso al servicio WCF y su contraseña (dos veces). De esta forma se está dando acceso a un determinado número de usuarios de SharePoint al servicio de WCF en Azure. Note que desde el portal de Azure, en la secci ón del Cloud Service creado en el punto 1, es posible definir tanto los usuarios (dentro de Azure) que tienen acceso al servicio, como los roles que se le pueden asignar
Abra el sitio de SharePoint en donde se quiera utilizar el servicio WCF, utilice la pestaña de "Pagina" e inicie SharePoint Designer desde "Editar" - "Editar en SharePoint Designer".
En SharePoint Designer haga clic sobre "Tipos de contenido externo" en el menú vertical al lado izquierdo. Utilice el botón de "Tipo de contenido externo" en la sección de "Nueva" de la cinta.
Asígnele un nombre al Tipo de Contenido ("Zoo") y utilice el vínculo de "Haga clic aquí para detectar orígenes de datos externos…".
En la nueva página utilice el botón de "Agregar conexión". Seleccione "Servicio WCF" como "Tipo de origen de datos" y "Aceptar".
En la casilla de "Dirección URL de metadatos de servicio" introduzca el URL del servicio WCF en Azure (punto 28) seguido por "?wsdl", así que en el ejemplo quedaría "http://zoocs.cloudapp.net/zoo.svc?wsdl". En "Dirección URL de extremo de servicio" utilice el mismo URL pero sin "?wsdl" esta vez ("http://zoocs.cloudapp.net/zoo.svc"). Seleccione la opción "Conectar con identidad personalizada suplantada" en la sección de "Configuración de autenticación del servicio WCF", y en la casilla de "Id. de aplicación de almacenamiento seguro" utilice el valor creado en el punto 32. No modifique las opciones restantes. "Aceptar". SharePoint Designer hace contacto con el servicio en Azure y muestra los métodos del servicio WCF:
La conexión con el servicio WCF está asegurada, pero los métodos no están mapeados a los que utiliza el BDC. Seleccione "ReadList" en el panel del BDC y utilizando el menú contextual seleccione "Nueva operación Leer lista". Utilice el botón de "Siguiente" - "Siguiente" en la ventana que aparece y en la ventana de "Parámetro de devolución" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Finalizar".
Seleccione "ReadItem" en el panel del BDC y utilizando el menú contextual seleccione "Nueva operación Leer elemento". Utilice el botón de "Siguiente" en la ventana que aparece y en la ventana de "Parámetro de entrada" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Siguiente". En la ventana de "Parámetro de devolución" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Finalizar".
Seleccione "Create" en el panel del BDC y utilizando el menú contextual seleccione "Nueva operación Crear". Utilice el botón de "Siguiente" en la ventana que aparece y en la ventana de "Parámetro de entrada" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Siguiente" - "Finalizar".
Seleccione "Delete" en el panel del BDC y utilizando el menú contextual seleccione "Nueva operación Eliminar". Utilice el botón de "Siguiente" en la ventana que aparece y en la ventana de "Parámetro de entrada" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Finalizar".
Seleccione "Update" en el panel del BDC y utilizando el menú contextual seleccione "Nueva operación Actualizar". Utilice el botón de "Siguiente" en la ventana que aparece y en la ventana de "Parámetro de entrada" seleccione "AnimalID" en el panel central y "Asignar a identificador" en el panel de "Propiedades" - "Finalizar".
Guarde la configuración del BDC (icono con un disco en la esquina superior izquierda).
Utilice el botón de "Crear lista y formulario" en la cinta. En la nueva ventana que aparece asígnele un nombre a la Lista (campo "Nombre de lista") y "Aceptar".
Regrese al sitio de SharePoint (punto 36), vaya a "Contenidos del sitio" y haga clic sobre la nueva Lista creada. SharePoint muestra la Lista con los datos del servicio WCF en Azure. Todas las operaciones CRUD están disponibles desde SharePoint.
Convertir el servicio WCF a REST
Aunque un servicio SOAP se puede utilizar con una multitud de tecnologías, es mucho más fácil de programar y mucho más compatible con otros sistemas si dispone de una interface REST (Representational State Transfer). El servicio SOAP se puede extender para que soporte las dos interfaces, permitiendo que un programador lo utilice en la forma que sea más apropiada.
Para hacer el servicio WCF compatible con REST es necesario crear dos modificaciones en el código fuente: decorar el contrato de la entidad, y modificar el web.config para que el servicio tenga doble punto de entrada.
1 public interface IZoo2
1 {2
1 [WebGet(UriTemplate = "/ReadList", ResponseFormat = WebMessageFormat.Json)]2
1 [OperationContract]2
1 IEnumerable<Animal> ReadList();2
12
1 [WebGet(UriTemplate = "/ReadItem?AnimalID={animalID}", ResponseFormat = WebMessageFormat.Json)]2
1 [OperationContract]2
1 Animal ReadItem(int animalID);2
12
1 [WebInvoke(Method = "POST", UriTemplate = "/Create", ResponseFormat = WebMessageFormat.Json)]2
1 [OperationContract]2
1 Animal Create(Animal newAnimal);2
12
1 [WebInvoke(Method = "PUT", UriTemplate = "/Update", ResponseFormat = WebMessageFormat.Json)]2
1 [OperationContract]2
1 void Update(Animal animal);2
12
1 [WebInvoke(Method = "DELETE", UriTemplate = "/Delete?AnimalID={AnimalID}", ResponseFormat = WebMessageFormat.Json)]2
1 [OperationContract]2
1 void Delete(int animalID);2
1 }2
1 <system.serviceModel>2
1 <behaviors>2
1 <serviceBehaviors>2
1 <behavior name ="servicebehavior">2
1 <serviceMetadata httpGetEnabled="true"/>2
1 <serviceDebug includeExceptionDetailInFaults="true"/>2
1 </behavior>2
1 </serviceBehaviors>2
1 <endpointBehaviors>2
1 <behavior name="restbehavior">2
1 <webHttp />2
1 </behavior>2
1 </endpointBehaviors>2
1 </behaviors>2
1 <services>2
1 <service name="ZooWebRole.Zoo" behaviorConfiguration="servicebehavior" >2
1 <endpoint name="RESTEndPoint" contract="ZooWebRole.IZoo" binding="webHttpBinding" address="restservice" behaviorConfiguration="restbehavior"/>2
1 <endpoint name="SOAPEndPoint" contract="ZooWebRole.IZoo" binding="basicHttpBinding" address="" />2
1 </service>2
1 </services>2
1 <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />2
1 </system.serviceModel>2
1 <httpProtocol>2
1 <customHeaders>2
1 <add name="Access-Control-Allow-Origin" value="*" />2
1 <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />2
1 <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />2
1 </customHeaders>2
1 </httpProtocol>2
Despliegue la solución de nuevo tal como se indicó en el punto 24. Si la ventana de publicación muestra un icono de error en la suscripción de Azure, utilice el botón de "Previous" dos veces y "Reenter your credentials"; luego de logeado en Azure puede publicar de nuevo. Después de un par de segundo, aparece una ventana preguntando si desea reemplazar el despliegue que ya existe ("Replace").
Para testear el servicio REST se puede utilizar un navegador yendo al URL "http://[NombreCloudService].cloudapp.net/[NombreServicio].svc/[DireccionEndPoint]/[Metodo]" , para el ejemplo seria "http://zoocs.cloudapp.net/zoo.svc/restservice/ReadList" para utilizar el método ReadList. Los resultados aparecen en formato JSON, tal como se indicó en el contrato:
Un navegador solamente da acceso a métodos GET básicos (de hecho, solamente al método ReadList). Para testear todos los métodos se pueden utilizar otro tipo de herramientas que interceptan el tráfico y pueden inyectar parámetros, como por ejemplo Fiddler.
Utilización del servicio REST en una aplicación SharePoint Hosted
Cuando se desea conectar una aplicación SharePoint Hosted con un servicio WCF es indispensable que el servicio tenga una interface REST para poder utilizarlo por medio de JavaScript. El siguiente ejemplo crea una aplicación SharePoint Hosted y la conecta con el servicio WCF REST desarrollado en la sección anterior.
Inicie Visual Studio y cree una nueva solución del tipo "Office/SharePoint" - "Aplicaciones" - "Aplicación para SharePoint". Asígnele un nombre.
En la ventana de "Nueva aplicación para SharePoint" configure el URL del sitio de desarrollador de SharePoint y seleccione "Hospedado por SharePoint".
En la siguiente ventana del asistente de creación seleccione "SharePoint2013" (aunque la aplicación puede funcionar, y se programa, de forma exactamente igual que para "SharePoint Online").
Cuando el proyecto termina de cargar, en el archivo "Default.aspx" reemplace todo el código en la sección bajo el placeholder "PlaceHolderMain" con el código siguiente, que simplemente crea cinco botones que llaman funciones respectivas:
1 <div>2
1 <p>2
1 <input id="btnReadList" type="button" value="Read List" onclick="btnReadList_Click()" />2
1 <input id="btnReadItem" type="button" value="Read Item" onclick="btnReadItem_Click()" />2
1 <input id="btnCreate" type="button" value="Create" onclick="btnCreate_Click()" />2
1 <input id="btnUpdate" type="button" value="Update" onclick="btnUpdate_Click()" />2
1 <input id="btnDelete" type="button" value="Delete" onclick="btnDelete_Click()" />2
1 </p>2
1 </div>2
1'use strict';2
12
1var baseUrl = "http://[NombreCloudService].cloudapp.net/zoo.svc/Service1.svc/restservice/";2
12
1function btnReadList_Click() {2
1 CallService("GET", baseUrl + "ReadList", "application/xml", "");2
1}2
12
1function btnReadItem_Click() {2
1 CallService("GET", baseUrl + "ReadItem?AnimalID=1", "application/xml", "");2
1}2
12
1function btnCreate_Click() {2
1 CallService("POST", baseUrl + "Create", "application/json; charset=utf-8", '{"AnimalID": 4, "AnimalName": "Elefante", "AnimalDanger": "Muy Poco"}');2
1}2
12
1function btnUpdate_Click() {2
1 CallService("PUT", baseUrl + "Update", "application/json; charset=utf-8", '{"AnimalID": 4, "AnimalName": "Elefantico", "AnimalDanger": "Excesivamente"}');2
1}2
12
1function btnDelete_Click() {2
1 CallService("DELETE", baseUrl + "Delete?AnimalID=4", "application/xml", "");2
1}2
12
1function CallService(csType, csUrl, csContentType, csData) {2
1 $.ajax(2
1 {2
1 type: csType,2
1 url: csUrl,2
1 contentType: csContentType,2
1 data: csData,2
1 success: CallbackSuccess,2
1 error: CallbackError2
1 });2
12
1 function CallbackSuccess(response) { alert("Bingo! --> " + response.text); }2
1 function CallbackError(err) { alert("Nopes! --> " + err.statusText); }2
1}2
Para hacer que IE acepte CORS, abra sus "Opciones de Internet" y la pestaña de "Seguridad". Utilice el botón de "Nivel personalizado" y seleccione la opción "Habilitar" de "Tener acceso a origen de datos entre dominios". Desde este momento la aplicación funciona sin problemas. Todos los navegadores modernos tienen la posibilidad de configurar CORS (menos Microsoft Edge hasta el momento de escribir este artículo).
Cuando se utiliza una aplicación de SharePoint Provider Hosted las posibilidades de programación son mucho más amplias. Por ejemplo, utilizando ASP.NET en una aplicación SharePoint Provider Hosted, el código de la interface en una página aspx podría ser de la forma siguiente para producir exactamente el mismo efecto que el del ejemplo con JavaScript (y sin problemas de CORS):
1<body>2
1 <form id="form1" runat="server">2
1 <div>2
1 <asp:Button ID="btnReadList" runat="server" Text="Read List" OnClick="btnReadList_Click" /> 2
1 <asp:Label ID="lblReadList" runat="server" Text="Result"></asp:Label>2
1 </div><br />2
1 <div>2
1 <asp:Button ID="btnReadItem" runat="server" Text="Read Item" OnClick="btnReadItem_Click" /> 2
1 <asp:Label ID="lblReadItem" runat="server" Text="Result"></asp:Label>2
1 </div><br />2
1 <div>2
1 <asp:Button ID="btnCreate" runat="server" Text="Create" OnClick="btnCreate_Click" /> 2
1 <asp:Label ID="lblCreate" runat="server" Text="Result"></asp:Label>2
1 </div><br />2
1 <div>2
1 <asp:Button ID="btnUpdate" runat="server" Text="Update" OnClick="btnUpdate_Click" /> 2
1 <asp:Label ID="lblUpdate" runat="server" Text="Result"></asp:Label>2
1 </div><br />2
1 <div>2
1 <asp:Button ID="btnDelete" runat="server" Text="Delete" OnClick="btnDelete_Click" /> 2
1 <asp:Label ID="lblDelete" runat="server" Text="Result"></asp:Label>2
1 </div>2
1 </form>2
1</body>2
Y el código behind de la página tal como el del siguiente fragmento:
1namespace ZooWebApp2
1{2
1 public partial class myZooASPNET : System.Web.UI.Page2
1 {2
1 string baseUrl = "http://[NombreCloudService].cloudapp.net/zoo.svc/restservice/";2
12
1 protected void btnReadList_Click(object sender, EventArgs e)2
1 {2
1 string url = baseUrl + "ReadList";2
12
1 var syncClient = new WebClient();2
1 var content = syncClient.DownloadString(url);2
12
1 List<Animal> readAnimals = (List<Animal>)JsonConvert.DeserializeObject(content, typeof(List<Animal>));2
12
1 lblReadList.Text = "Done";2
1 }2
12
1 protected void btnReadItem_Click(object sender, EventArgs e)2
1 {2
1 string url = baseUrl + "ReadItem?AnimalID=1";2
12
1 var syncClient = new WebClient();2
1 var content = syncClient.DownloadString(url);2
12
1 Animal readAnimal = (Animal)JsonConvert.DeserializeObject(content, typeof(Animal));2
12
1 lblReadItem.Text = "Done";2
1 }2
12
1 protected void btnCreate_Click(object sender, EventArgs e)2
1 {2
1 string url = baseUrl + "Create";2
12
1 Animal myAnimal = new Animal { AnimalID = 3, AnimalName = "Elefante", AnimalDanger = "Muy poco" };2
1 string jsonAnimal = JsonConvert.SerializeObject(myAnimal);2
12
1 var syncClient = new WebClient();2
1 syncClient.Headers[HttpRequestHeader.ContentType] = "application/json";2
1 syncClient.Encoding = Encoding.UTF8;2
1 var content = syncClient.UploadString(url, "POST", jsonAnimal);2
12
1 lblCreate.Text = "Done";2
1 }2
12
1 protected void btnUpdate_Click(object sender, EventArgs e)2
1 {2
1 string url = baseUrl + "Update";2
12
1 Animal myAnimal = new Animal { AnimalID = 3, AnimalName = "Elefantico", AnimalDanger = "Muy peligroso" };2
1 string jsonAnimal = JsonConvert.SerializeObject(myAnimal);2
12
1 var syncClient = new WebClient();2
1 syncClient.Headers[HttpRequestHeader.ContentType] = "application/json";2
1 syncClient.Encoding = Encoding.UTF8;2
1 var content = syncClient.UploadString(url, "PUT", jsonAnimal);2
12
1 lblUpdate.Text = "Done";2
1 }2
12
1 protected void btnDelete_Click(object sender, EventArgs e)2
1 {2
1 string url = baseUrl + "Delete?AnimalID=3";2
1 var syncClient = new WebClient();2
1 var content = syncClient.UploadString(url, "DELETE", "");2
12
1 lblDelete.Text = "Done";2
1 }2
1 }2
12
1 public class Animal2
1 {2
1 public Int32 AnimalID { get; set; }2
1 public string AnimalName { get; set; }2
1 public string AnimalDanger { get; set; }2
1 }2
1}2
En el código se define una clase con la entidad de la misma forma que está definida en el servicio WCF. Luego, para los dos métodos GET, cada uno de los eventos de los botones llama el servicio utilizando el método "DownloadString" de la clase "WebClient" de System.Net y deserializa la respuesta JSON utilizando el método "DeserializeObject" de JsonConvert. Los métodos PUT, POST y DELETE crean primero un objeto del tipo Animal con los valores apropiados, lo serializa a JSON utilizando el método "SerializeObject" de JsonConvert y lo envía al servicio WCF utilizando el método "UploadString" de la clase "WebClient".
Conclusiones
Dentro de las múltiples maneras de utilizar los servicios de Azure para complementar el funcionamiento de SharePoint, Cloud Services permite crear servicios Web WCF que sirven como la puerta de entrada a cualquier tipo de sistema externo.
Con Azure Cloud Services se pueden crear servicios WCF con interfaces SOAP y/o REST que pueden ser consumidos directamente por el BCS de SharePoint (y su motor de búsqueda), o por Aplicaciones de SharePoint, Provider o SharePoint Hosted. Por medio de la interface REST se pueden crear aplicaciones SharePoint Hosted o Provider Hosted que consuman los datos ofrecidos por el servicio WCF.
CORS puede constituirse en un problema cuando se utiliza JavaScript con la interface REST del servicio, pero este es un problema general de JavaScript y los navegadores modernos, no un problema de SharePoint o Azure Cloud Services.
Gustavo Velez Office Severs and Services MVP gustavo@gavd.net http://www.gavd.net