Usando el nuevo modelo de desarrollo para SharePoint con PowerShell

Muy buenas a todos,

Hace unos meses, escribí acerca del nuevo modelo de desarrollo para SharePoint OnLine y SharePoint OnPremises propuesto por Microsoft e incluso una de mis colaboraciones en CompartiMOSS giró en torno a este tema.

Nuevo modelo de desarrollo de Sharepoint. Adaptando nuestras soluciones de granja

Número #24 de CompartiMOSS y nueva colaboración con la revista

Como ya decía en aquella ocasión, trabajar con las API cliente se podría hacer tanto por medio de la API REST, con la API CSOM o JSOM o incluso PowerShell. Tenía muchas ganas de ver cómo se podría trabajar con éste último y para un proyecto en el que estoy trabajando recientemente decidí que ya era el momento.

La primera intención, fue desarrollar mis propios Cmdlets o mis propios Scripts con funciones para realizar las distintas operaciones que fuese necesitando. Finalmente decidí previamente indagar por la cuenta de GitHub de OfficeDev/Pnp, donde encontré un gran trabajo especifico sobre PowerShell, proporcionando una gran cantidad de Cmdlets desarrollados que permiten trabajar con las API Cliente, concretamente CSOM, y PowerShell. Por supuesto, trabajo que decidí utilizar, y que os recomiendo a todos.

https://github.com/OfficeDev/PnP-powershell

En el artículo de hoy, os quiero mostrar cómo instalar y configurar en nuestro servidor estos Cmdlets y cómo se pueden usar algunos de ellos a modo de ejemplo. No obstante, en la página de Pnp hay una documentación muy buena sobre todas las opciones de que disponemos.

Instalando los Cmdlets en el servidor

Para poder tener disponibles todos los Cmdlets de PowerShell tendremos que seguir los siguientes pasos:

1.- En primer lugar descargar el proyecto Visual Studio desde la cuenta de GitHub de OfficeDev/Pnp-PowerShell.

download

2.- Para poder instalar el proyecto, es necesario descargar e instalar las WiX Tools en nuestro equipo.

wix

3.- A continuación abrimos la solución que descargamos anteriormente y para poder crear la solución, necesitamos agregar dos paquetes desde Nugets. El primero de ellos es el OfficeDev Core para SharePoint Online o OnPremises, en función de para qué lo vayamos a usar.

coreoffice

4.- El siguiente paquete es la librería ADAL para la autenticación.

identity

5.- Tras esto ya se puede hacer el build del proyecto lo cual dejará instalados los Cmdlets en nuestro equipo

install

Si ahora abrimos por ejemplo el IDE de PowerShell, en la lista de comandos disponibles, si ponemos en el cajón de búsqueda SPO, filtrará todos los comandos que se han añadido.

Usando los nuevo Cmdlets

A continuación voy a mostrar un breve ejemplo de cómo podríamos usar los nuevos Cmdlets con PowerShell.

Connect-SPOnline -Url $url -Credentials (Get-Credential)

Add-SPOField -DisplayName "Example" -InternalName "Example" -Group "ExampleSPO" -Type Integer
Add-SPOField -DisplayName "Example1" -InternalName "Example1" -Group "ExampleSPO" -Type Text
Add-SPOField -DisplayName "Example2" -InternalName "Example2" -Group "ExampleSPO" -Type Choice -Choices "uno","dos","tres"

Add-SPOContentType -Name "ContentTypeExample" -Description "Description to Content Type" -Group "ExampleSPO"

Add-SPOFieldToContentType -Field "Example" -ContentType "ContentTypeExample"
Add-SPOFieldToContentType -Field "Example1" -ContentType "ContentTypeExample"
Add-SPOFieldToContentType -Field "Example2" -ContentType "ContentTypeExample"

New-SPOList -Title "List Title" -Template GenericList -EnableContentTypes
Add-SPOContentTypeToList -List "List Title" -ContentType "ContentTypeExample" -DefaultContentType

En el código de ejemplo se muestra cómo conectarse a un sitio de SharePoint OnLine, crear columnas de sitio, un tipo de contenido y asociarlo a una lista que se ha creado previamente.

Y esto es todo por hoy, por si aún no lo conocíais, espero que os sea de utilidad y que en la medida de lo posible, podáis usarlo en vuestros proyectos.

Hasta la próxima.

Timer jobs para SharePoint OnLine

Muy buenas a todos,

El modelo de desarrollo de SharePoint OnLine, como ya es conocido, no nos permite el uso de soluciones de granja en nuestros desarrollos, basado fundamentalmente en el modelo de objetos de servidor. Por contra, nos propone un modelo basado en los mejorados modelos de cliente.

A priori, puede parecer que le modelo de objetos de cliente tiene ciertas limitaciones por medio de las cuales no podremos cubrir requisitos que impliquen por ejemplo desarrollar TimerJobs. ¿Es esto cierto?, la realidad es que con el modelo de objetos de cliente, no vamos a poder crear TimerJobs tal y como estábamos acostumbrados con las soluciones de granja, ¿significa esto que no podremos crear tareas programadas en SharePoint OnLine?, aquí la respuesta es obviamente no.

Para poder hacerlo tendremos, eso si, que combinar alguno de los servicios que pone a nuestra disposición Microsoft, a través de Azure. Usaremos los WebJobs de Azure para, en combinación con el modelo de clientes, crear una tarea programada para SharePoint OnLine.

En la entrada de hoy vamos a ver un ejemplo de un WebJob de Azure que realiza un tarea en background sobre SharePoint OnLine, crearemos un TimerJob para SharePoint OnLine. Para llevarlo a cabo he seguido estos dos tutoriales que os recomiendo por si quereis echar un vistazo.

https://msdn.microsoft.com/en-us/library/office/dn986826.aspx

https://azure.microsoft.com/es-es/documentation/articles/websites-dotnet-deploy-webjobs/

Creando el proyecto en Visual Studio 2013

Voy a desarrollar un WebJob que escribe en una lista de SharePoint OnLine un registro cada cierto tiempo. Para ello vamos a crear en Visual Studio una aplicación de consola.

Una vez que hemos creado la aplicación de consola, vamos a añadir por medio de Nuget los siguientes paquetes:

  • App for SharePoint ToolKit (for SharePoint OnLine)
  • Microsoft.SharePoint.2013.Client.16

Esto nos añadirá todos los elementos necesarios para autenticarnos y acceder a SharePoint OnLine desde nuestra Aplicación de consola.

A continuación os comparto el código del WebJob que he desarrollado.

namespace AzureWebJobExample
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ClientContext context = new ClientContext("https://<sharepointsiteurl>"))
            {
                // Use default authentication mode.
                context.AuthenticationMode = ClientAuthenticationMode.Default;
                context.Credentials = new SharePointOnlineCredentials(GetSPOAccountName(), GetSPOSecureStringPassword());

                try
                {
                    var list = context.Web.Lists.GetByTitle("Noticias");
                    context.Load(list);
                    context.ExecuteQuery();

                    var itemCreateInfo = new ListItemCreationInformation();
                    var listItem = list.AddItem(itemCreateInfo);
                    listItem["Title"] = "News Web Job Example Added " + DateTime.Now;
                    listItem["nwhz"] = "This is an example of a item added from a time job";
                    listItem.Update();
                    context.ExecuteQuery();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR: " + ex.Message);
                    Console.WriteLine("ERROR: " + ex.Source);
                    Console.WriteLine("ERROR: " + ex.StackTrace);
                    Console.WriteLine("ERROR: " + ex.InnerException);
                }
            }
        }
        private static SecureString GetSPOSecureStringPassword()
        {
            try
            {
                Console.WriteLine("Entered GetSPOSecureStringPassword.");
                var secureString = new SecureString();
                foreach (char c in ConfigurationManager.AppSettings["SPOPassword"])
                {
                    secureString.AppendChar(c);
                }
                Console.WriteLine("Constructed the secure password.");

                return secureString;
            }
            catch
            {
                throw;
            }
        }

        private static string GetSPOAccountName()
        {
            try
            {
                Console.WriteLine("Entered GetSPOAccountName.");
                return ConfigurationManager.AppSettings["SPOAccount"];
            }
            catch
            {
                throw;
            }
        }

    }
}

Como podéis ver el código es muy sencillo, tan solo hay que añadir dos funciones, tal y como nos cuentan en uno de los enlaces que os he indicado, para obtener del app.config el usuario y la contraseña para conectarnos a SharePoint OnLine. Tras esto, usando el modelo de objetos de cliente para C# se hacen las operaciones deseadas sobre SharePoint OnLine.

Lo que nos queda ahora, es publicar el WebJob en Azure para que funcione correctamente, que será lo que veremos en la próxima sección

Publicando el WebJob en Azure

Vamos a ver ahora los pasos para publicar nuestro WebJob en Azure y ver como funciona.

1.- Seleccionamos la opción de publicar la aplicación de consola como Azure WebJob

webjob1

2.- El siguiente es configurar el WebJob

webjob2

Es importante tener en cuenta una cosa. Este WebJob se crea en el modo gratuito (o yo no he encontrado la forma de crearlo desde visual studio en otro modo), y este modo tiene una limitación a la hora de la frecuencia permitida de como máximo una hora, por lo que si seleccionamos una frecuencia mayor, nos dará un error. Luego podremos modificar la frecuencia desde el portal de Azure si queremos hacerlo más frecuente, pero para empezar, debemos de tener en cuenta esa restricción.

3.- A continuación configuramos el website al que estará asociado el webjob

webjob3

webjob4

webjob5

webjob6

4.- Cambiando la configuración del WebJob en el portal de Azure

webjob7

En nuestro portal de Azure, en el Área de «Programador», accedemos a la colección de trabajos que se ha creado por defecto y en «Escalar», cambiamos del modo gratis a estándar y cambiamos el límite de frecuencia de ejecución. Tras esto entramos a trabajos y configuramos el que tenemos creado para que se ejecute a cada minuto (para poder ver como funciona el WebJob que hemos creado más rápidamente). No debemos olvidar guardar los cambios para que surtan efecto.

5.- Viendo los resultados del webjob.

webjob9

webjob10

Tanto en el sitio de SharePoint, como dentro de nuestro website de Azure se pueden ver los resultados de la ejecución del WebJob. Aquí se puede ver el resultado del TimerJob para SharePoint OnLine que hemos creado ;).

Y nada más por hoy, espero que como siempre os sea útil, evidentemente el ejemplo es muy sencillo, y podemos ir mucho más allá con esta técnica, pero simplemente os quería mostrar cómo hacerlo.

Un saludo a todos

Métodos de extensión en C#. Usándolos en desarrollo para SharePoint

Muy buenas a todos,

Hoy lo que os traigo es más una recopilación de información que una entrada de mi cosecha propiamente, aunque creo que es muy interesante. No pasan días sin que aprendas cosas nuevas. Todo viene de una entrada en el blog de desarrollo de Encamina, el cual os recomiendo que sigáis porque se suelen hacer entradas muy interesantes. En esta semana se ha estado haciendo un recorrido por buenas prácticas a la hora de desarrollar sobre SharePoint y entonces es cuando me topé con los «Métodos de extensión en C#». Os dejo la entrada en cuestión.

http://blogs.encamina.com/desarrollandosobresharepoint/2015/05/05/como-aprovechar-la-potencia-de-c-en-nuestros-desarrollos/

Me ha llamado la atención el uso de los métodos de extensión de C#. Yo venía desde hace un tiempo usando algunas clases para facilitar determinadas acciones cuando desarrollo sobre SharePoint. Pero me ha resultado muy interesante ver que podemos, por medio de los métodos de extensión, asociarlos al objeto que afectan, de manera que el intellisense de VS lo detecta y además los puedes llamar como si fueran métodos del objeto propiamente dicho, sin tener que crear una clase derivada, ni heredar ni hacer nada con el objeto original. Os pongo un ejemplo de código con algo sencillo:

public static class Helper
{
   public static string MetodoExtensionEjemplo(this string s, string ejemplo)
   {
      //To do something
   }
}

Este método lo podríamos usar ahora de la siguiente forma

string s = "Hello Extension Methods";
s = s.MetodoExtensionEjemplo("hola");

La verdad es que resulta muy cómodo usarlo de esta forma. Como véis la sintaxis para definir este tipo de métodos es muy sencilla y lo vemos en el primer código.

  • La clase a la que pertenezca el método tiene que ser estática, así como el método propiamente dicho
  • El primer parámetro del método es del tipo al que queremos asociarle el método y lleva delante la palabra reservada this.

En mi caso usar esta opción que nos brinda C#, me da como resultado un código más limpio e intuitivo, así que por mi parte, merece la pena tenerlo en cuenta.

Y bueno, como me gusta compartir con la comunidad todo lo que puedo o creo que puede ser interesante, he subido a GitHub las dos clases que estoy usando como Helpers y en las que estoy usando los métodos de extensión. Por si os interesa, veréis que he creado dos clases, una que tiene las acciones «atómicas» (la clase Helpers) y otra que tiene acciones necesarias pero que son un poco «más complejas» (la clase Utility).

https://github.com/jcroav/SPHelpers

Sentíos libres de cogerlas, modificarlas, mejorarlas, proponer cambios, todo lo que suponga mejorar bienvenido sea. Por otro lado, si conocéis otros trabajos similares que se puedan utilizar y estén en fases más avanzadas, estaré encantado de saberlo. Yo de momento he creado los métodos que necesito para mi último proyecto y a medida que vaya necesitando modificar los mismos para añadir funcionalidad o mejoras o añadir nuevos los iré publicando en el repositorio.

Os dejo también el enlace de la MSDN sobre el tema de los métodos de extensión:

https://msdn.microsoft.com/es-es/library/bb383977.aspx

Webinar sobre «Ciclo de vida de una solución SharePoint»

Muy buenas tardes a todos,

Quería compartir con vosotros un enlace a un webinar que pude presenciar la pasada semana y que me parece de un interés capital para todas las personas que profesionalmente nos dedicamos a desarrollar sobre SharePoint. Dicho webinar estuvo dirigido por los MVPs de Encamina Alberto Díaz, Santiago Porras y Adrián Díaz, y nos estuvieron desvelando algunos de los aspectos más importantes a tener en cuenta durante el ciclo de vida de un proyecto de SharePoint y nos contaron los retos que se presentan y buenas prácticas en las distintas etapas de los mismos. Como os decía, algo capital para todos los que nos dedicamos al desarrollo de proyectos sobre SharePoint.

En el webinar hablaron de distintas etapas: Gestión de requisitos, Arquitectura de la solución, Desarrollo, Diseño, Construir y empaquetar, Calidad, Testing, Despliegue y Operaciones.

Simplemente os dejaré algunos consejos y «buenas prácticas» que he sacado del webinar.

  • El primer aspecto cuando estamos en la fase de requisitos es que hay que tener claro que estamos desarrollando sobre SharePoint, puede parecer algo muy obvio, pero todo el mundo implicado en el proyecto tiene que conocer el producto y lo que nos ofrece.
  • No se puede cambiar el producto y es importante, siempre que sea posible usar lo estándar y solo extenderlo en el caso de que nuestros requerimientos lo necesiten.
  • Usar patrones y buenas prácticas de desarrollo como haríamos para cualquier otro proyecto, porque en ese aspecto SharePoint no es diferente, se puede hacer sin ningún problema.
  • Usar una herramienta de control de código fuente.
  • Estandarizar los entornos de desarrollo por medio de herramientas tipo SPInstaller y conocer los requisitos de desarrollo y tenerlos en cuenta para todo el equipo de desarrollo.
  • Con respecto al diseño, hay que procurar homogeneizar el look & feel de páginas, los elementos y el comportamiento de los mismos dentro de nuestro proyecto. Tener una comunicación fluida y proactiva entre los equipos de desarrollo y diseñadores y algo muy importante, tratar los fallos de UX como defectos y no como mejoras en nuestros proyectos para evitar que caigan en el olvido.
  • Es importante hacer CodeReviews periódicas en las que se analice el código y se intente mejorar el mismo.
  • Sobre los desarrollos en SharePoint, se pueden y deben hacer Test unitarios. Evidentemente, habrá aspectos que no se pueden probar, como los elementos de la API, pero debemos testear la lógica de negocio de nuestra aplicación.
  • Establecer un proceso de despliegue de nuestras soluciones, que sea conocido y que por medio de PowerShell incluya también parametrizaciones, configuración y que todo quede registrado para poder hacer seguimiento. No usar SharePoint Designer para hacer modificaciones, o si se hace, convertirlo lo antes posible en un artefacto o elemento que pueda ser desplegable.

Os dejo el enlace del webinar que desde Encamina han dejado en su canal de Youtube y os recomiendo a todos que lo veáis porque os va a dar información de mucha utilidad.

Enlace al webinar de Ciclo de vida de una solución

Un saludo a todos. Nos vemos en breve con mas temas de interés sobre todo lo relacionado con Azure, SharePoint y Office 365 por el blog.

Usando Bower y Grunt en Visual Studio 2013

Muy buenas a todos,

Hoy os quiero contar los pasos que he dado para usar en mis proyectos de Visual Studio 2013 bower, usándolo como gestor de paquetes en el lado del cliente, y grunt, como task runner. Ambos están siendo muy comúnmente usados en el mundo del desarrollo de aplicaciones web y si bien, la versión de Visual Studio 2015 los incluye de forma nativa, podemos configurar nuestros proyectos web de Visual Studio 2013 para usar estas dos herramientas tan útiles.

Para todo aquel que le pueda interesar, dejo la entrada del blog en la que me he basado para hacer toda la configuración, aunque si accedéis veréis que en el post, se usa otro gestor de tareas llamado gulp en lugar de grunt.

http://blogs.msdn.com/b/cdndevs/archive/2015/02/17/using-bower-with-visual-studio-2013.aspx

Pero antes de entrar en detalle, vamos a ver qué son exactamente cada una de estas herramientas.

¿Qué es Bower?

Bower works by fetching and installing packages from all over, taking care of hunting, finding, downloading, and saving the stuff you’re looking for.

La primera pregunta que se nos plantea viendo lo que hace Bower es ¿Y Nugget?. La respuesta a esta pregunta es muy sencilla. Desde su aparición Nugget se ha descubierto como una herramienta muy eficaz para la gestión de paquetes de servidor, pero no así para paquetes de cliente. Bower se ha convertido en el estándar de facto en el desarrollo web. Es poco probable, que un desarrollador que crea una nueva librería en Javascript la ponga disponible como paquete Nugget, sin embargo es frecuente que esté disponible en Bower en todas sus versiones. Esto provoca desactualización o imposibilidad de usar determinadas librerías a través de Nugget, lo que desaconseja su uso como herramientas de gestión de paquetes del lado del cliente.

¿Qué es Grunt?

In one word: automation. The less work you have to do when performing repetitive tasks like minification, compilation, unit testing, linting, etc, the easier your job becomes.

En resumen, con Grunt vamos a poder automatizar determinadas tareas que van a ayudar a tener nuestra aplicación lista para poner en producción con acciones como: minimizar y agrupar los estilos, minimizar y agrupar los javascript, etc. En la entrada veremos una tarea que he creado que puede ser necesaria y recomendable cuando usamos Bower.

Configurando y usando Bower

Para la configuración de Bower, podéis fácilmente seguir la entrada del blog de la msdn sin ningún problema, es muy sencilla de seguir y está muy detallada, de hecho yo la he seguido y es lo que de forma simplificada explicaré por aquí, solo hay una cosa que cambia, porque a mi al menos, o no me quedaba claro en la entrada inicial o no estaba debidamente reflejado. Vamos a ello.

    1. El primer paso es instalar node.js, ya que tanto Bower como Grunt lo utilizan. Enlace de descarga de node.js
    2. A continuación, abrimos la línea de comandos e instalamos bower
npm install bower -g
    1. Tras esto, necesitaremos tener instalado Git, Bower utiliza Git para descargar los paquetes. Concretamente instalaremos msysgit. Durante la instalación, tendremos que seleccionar la opción que vemos en la imagen a continuación para que se realice toda la configuración correctamente

gitinstall

    1. Ya tenemos listo Bower para ser utilizado. Si lo vamos a usar dentro de un proyecto de MVC, antes tendremos que tener en cuenta que por defecto, la plantilla de este tipo de proyectos en Visual Studio incluye una serie de paquetes, entre ellos: bootstrap, jquery, modernizr, etc. Por lo que antes de comenzar a usar bower en nuestro proyecto, tenemos que desinstalarlos. Para ello accedemos a la consola de Nuget y ejecutamos el siguiente comando para cada uno de los paquetes
Uninstall-Package <package>

Ahora que ya tenemos listo Bower vamos a usarlo dentro de nuestro proyecto. Esto lo haremos a través de la línea de comandos. En mi caso, no he usado la interfaz de línea de comandos propia de Windows (cmd), ya que me daba errores al usarla con Bower y Git, y buscando por internet vi que recomendaban usar una interfaz de línea de comandos que se instala con msysgit. Esta es Git Bash.

Vamos ahora a entrar al directorio del proyecto, y comenzaremos con el uso de Bower. Lo primero que haremos será iniciar el fichero de configuración de Bower. Para ello ejecutamos:

bower init

Una vez creado el fichero bower.json, podemos comenzar a instalar paquetes, esto lo haremos de la siguiente forma.

bower install jquery --save
bower install polymer --save

Una Buena Práctica recomendada para el uso de los paquetes que se obtienen con Bower, es no agregar directamente todos los archivos descargados con Bower a nuestro proyecto, ya que los paquetes en muchas ocasiones contienen más archivos de los que realmente necesitaremos, por lo que se recomienda copiar al proyecto solo aquellos archivos que realmente sean necesarios. ¿Cómo hacemos esto, manualmente?. La respuesta evidentemente es no, para esto tenemos nuestro Task Runner, Grunt 😉

Configurando y usando Grunt

En primer lugar, para añadir el soporte a Grunt para nuestro proyecto vamos a crear dos ficheros que añadiremos a la raíz del mismo package.json y gruntfile.js. El fichero package.json inicialmente contendrá la siguiente información.

{
"name": "WebApplication1",
"version": "1.0.0",
"description": "WebApplication package project",
"main": "gruntfile.js",
"license": "ISC";
}

A continuación y como ejemplo, la tarea que vamos a crear va a copiar los ficheros necesarios de los paquetes que hemos obtenido mediante Bower a la carpeta Scripts, donde se encuentran los ficheros js de nuestro proyecto. El código del fichero gruntfile.js es el siguiente:

module.exports = function (grunt) {

    grunt.initConfig({
        copy: {
            main: {
                files: [
                  {
                      expand: true,
                      cwd: '../bower_components/webcomponentsjs/',
                      src: ['webcomponents.js'],
                      dest: 'Scripts'
                  },
                  {
                      expand: true,
                      cwd: '../bower_components/jquery/dist',
                      src: ['jquery.min.js'],
                      dest: 'Scripts'
                  }
                ]
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.registerTask('build', ['copy']);
};

Obviamente, aún podríamos hacer algunas tareas de minimización y agrupamiento de ficheros con grunt y que serían necesarias, aunque eso lo dejo para más adelante, es posible que en alguna entrada futura os cuente como hacerlo.

Para que funcione correctamente, necesitamos un plugin de Grunt, «grunt-contrib-copy». Cuando necesitemos añadir determinados plugins para nuestras tareas de Grunt, lo haremos desde la línea de comandos usando la utilidad npm de node.js. Nos vamos al directorio del proyecto y ejecutamos el siguiente comando.

npm install grunt-contrib-copy --save-dev

Una vez que ya tenemos instalado el plugin, desde la línea de comandos en el directorio en el que está nuestro archivo gruntfile.js (la raíz del proyecto), ejecutamos grunt. Esto llevará a cabo la tarea que hemos creado. La primera vez que ejecutamos grunt, tendremos que añadir manualmente los archivos que se han añadido a la tarea al proyecto, aunque esta acción no tendremos que volver a hacerla.

Como hemos visto, hasta ahora estamos usando la línea de comando para ejecutar Grunt. Pero, ¿Y si queremos que se ejecute automáticamente Grunt cuando hacemos el deploy del proyecto, esto es posible?, la respuesta es si. Para esto tenemos varias extensiones de Visual Studio que nos lo permiten. En mi caso he utilizado Task Runner Explorer.

La descargamos y la instalamos y ya podremos usarla en nuestro Visual Studio 2013. Vamos a View->Other Windows->Task Runner Explorer y cuando se abre la nueva ventana, lo primero que hacemos es pulsar sobre el botón actualizar para que capture todas las tareas creadas si aún no lo habia hecho.

taskrunnerexplorer

Aquí vemos que podemos configurar si queremos que una determinada tarea se ejecute antes del deploy de la solución, con lo que podremos automatizar correctamente la ejecucion de Grunt y no tendremos que hacerlo manualmente a través de la línea de comandos.

run

binding

Os dejo para terminar, algunos enlaces más de utilidad relacionado con lo que hemos visto en la entrada:

http://gruntjs.com/
http://bower.io/
https://visualstudiogallery.msdn.microsoft.com/8e1b4368-4afb-467a-bc13-9650572db708

Y esto es todo por hoy, yo a partir de ahora voy a utilizar estas dos herramientas en todos mis proyectos, por las ventajas que ofrecen, espero que todos podáis hacerlo.

Un saludo y hasta la próxima

Manejo de Excepciones en aplicaciones de varias capas

Cuando desarrollamos aplicaciones, es habitual dividir la lógica de nuestra aplicación en varias capas. Normalmente un mínimo de 3 capas (las conocidas como three-tier applications) que separan: Capa de presentación, capa de lógica de negocio y capa de acceso a datos.

Un tema importante en este tipo de implementaciones es, que approach utilizar para el manejo de excepciones, para ello hoy he tenido la oportunidad de leer un artículo muy interesante en c-sharpcorner que quiero compartir con vosotros en el que hablan de cómo tratar el manejo de excepciones en aplicaciones de este tipo y dan una serie «reglas» que hay que tener en cuenta. Este es el artículo en cuestión:

http://www.c-sharpcorner.com/Blogs/46991/standard-way-of-exception-handling-in-3-tier-or-n-tier-appli.aspx

En el artículo destacan los siguientes aspectos a tener en cuenta a la hora de implementar el manejo de excepciones en este tipo de aplicaciones:

  1. Encapsular la excepción que se ha lanzado en una excepción personalizada
  2. Almacenar en un log los detalles de la excepción (o hacerlo en la base de datos)
  3. Si la excepción proviene de una capa anterior, trasladar las excepción hasta la capa superior sin grabar la excepción, ya que esto se ha hecho en la capa de origen
  4. Si estamos en la capa visual mostrar un mensaje amigable al usuario

Además en el artículo comparten una imagen que ayuda a aclarar la implementación de excepciones que también quiero compartir.

Exception

Lo que quiero hacer a continuación es mostraros con un ejemplo de código cómo podríamos hacer la implementación que nos sugieren en el artículo anterior, o al menos tal y como yo lo he entendido. El ejemplo está hecho para .NET, aunque se puede aplicar en cualquier lenguaje de programación.

Ejemplo de implementación del manejo de errores en aplicaciones de varias capas

Para el ejemplo en cuestión, se tratará de una aplicación en tres capas, por lo que contaremos con una clase que representaría a cada una de las capas: Acceso a datos, Lógica de Negocio y Presentación, y otras tantas clases personalizadas de excepciones.

Vamos a empezar definiendo las Clases de Error Personalizadas

public class DataAccessException: Exception
{
    public DataAccessException(){}
    public DataAccessException(string message) : base(message){}
    public DataAccessException(string message, Exception inner) : base(message, inner){}
}

public class BusinessLogicException: Exception
{
    public BusinessLogicException(){}
    public BusinessLogicException(string message) : base(message){}
    public BusinessLogicException(string message, Exception inner) : base(message, inner){}
}

Podríamos tener en cada capa más clases de excepciones personalizadas en función del tipo de error, forma de almacenamiento del mismo y posibles acciones a llevar a cabo en cada caso, al pasar de una capa a otra encapsularíamos estas excepciones en la genérica de cada capa.

Vamos a ver ahora como se implementarían las distintas clases de cada capa.

public class ExampleDataAccess : DataAccess
{
    public function List&lt;Data&gt; GetSomeData()
    {
        try
        {
            //Do DataAccess Work
        }
        catch(Exception ex)
        {
            LogError(ex);
            throw new DataAccessException(&quot;Some friendly Message&quot;, ex);
        }
    }
}

public class ExampleBusinessLogic : BusinessLogic
{
    public function bool DoSomeBusinessProcess()
    {
        try
        {
            //Do Business Work
        }
        catch(DataAccessException dae)
        {
            throw dae;
        }
        catch(Exception ex)
        {
            LogError(ex);
            throw new BusinessLogicException(&quot;Some Friendly Message&quot;, ex);
        }
    }
}

public class ExampleView : View
{
    public function void InitializeView()
    {
        try
        {
            //Do View Work
        }
        catch(DataAccessException dae)
        {
            ShowFinalFriendlyMessageToUser();
        }
        catch(BusinessLogicException ble)
        {
            ShowFinalFriendlyMessageToUser();
        }
        catch(Exception ex)
        {
            LogError(ex);
            ShowFinalFriendlyMessageToUser();
        }
    }
}

Y esto es todo, aquí tenéis el ejemplo, yo lo estaba empezando a usar en cierta medida en mis últimos desarrollos, pero con esto creo que mi manejo de errores quedará mucho más completo y me permitirá tener una mejor traza y seguimiento de los mismos.

Espero que vosotros lo podáis utilizar igualmente.

Un saludo

Monitorizando desarrollos en SharePoint: SPMonitoredScope, ULS y Developer Dashboard

Hola a todos,

Un tema importante cuando se desarrolla para SharePoint es todo lo relacionado con la monitorización del código desarrollado, para poder hacer seguimiento y el control de las excepciones que se producen en el mismo.

SharePoint nos da muchas herramientas para realizar estas tareas, hoy vamos a ver las que estoy utilizando yo en mis proyectos actualmente. Hace tiempo que he estado leyendo sobre ellas, pero no quería escribir hasta que no las hubiera probado y utilizado por mi mismo.

Developer Dashboard

El Developer Dashboard es una herramienta que aparece a partir de la versión de SharePoint 2010 para permitir, tanto a los administradores como desarrolladores de SharePoint, hacer seguimiento y monitorizar diferentes aspectos de la herramienta como pueden ser WebParts, eventos y llamadas a base de datos entre otra información de utilidad. El Developer Dashboard inicialmente está deshabilitado, aunque se puede activar o bien vía Modelo de objetos, PowerShell o stsadm.exe.

Os dejo unos enlaces sobre cómo activar el Developer Dashboard, y reproduzco cómo hacerlo vía PowerShell, para mí la forma más cómoda de hacerlo.

http://zimmergren.net/technical/sp-2010-developing-for-performance-part-1-developer-dashboard

http://sharepointgroup.wordpress.com/2012/05/04/enbl-sharepoint-developer-dashboard-with-powershell/

Para activarlo vía PowerShell haremos los siguiente

$dashboard = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings;
$dashboard.DisplayLevel = “OnDemand”;
$dashboard.TraceEnabled = $true;
$dashboard.Update()

Hay otras dos posibilidades para la opción DisplayLevel: On, Off.

image_12

Esta es una captura de pantalla del Dashboard de SharePoint 2010, el de SharePoint 2013 incluye importantes mejoras, pero aún no he podido probarlo, porque no he tenido oportunidad, aunque hay un rediseño completo del dashboard y una mejora en la forma y cantidad de la información que se muestra.

SPMonitoredScope

La clase SPMonitoredScope nos va a permitir monitorizar partes del código desarrollado. Os dejo el enlace donde se describe esta clase.

http://msdn.microsoft.com/es-es/library/office/ff512758(v=office.14).aspx

El uso de SPMonitoredScope es muy sencillo, solo es necesario encapsular aquella parte del código propio desarrollado que queremos que sea monitorizado. Vamos a ver un ejemplo:

using(SPMonitoredScope scope = new SPMonitoredScope("Ejemplo1"))
{
      //Aquí el código a monitorizar
      SomethingToDo();
}

La información que se genera a partir de este código se puede consultar o bien en el Developer Dashboard o en el ULS (Unified Logging Service).

Unified Logging Service

Otro de los elementos que nos permite monitorizar lo que ocurre con nuestro código es a través del ULS (Unified Logging Service). Éste, proporciona un mecanismo eficaz para escribir información útil para identificar y ayudar en la solución de problemas durante el ciclo de vida de la aplicación. El ULS permite escribir eventos en el Log de SharePoint normalmente almacenado en la siguiente ruta «\14\LOGS\SERVER-YYYmmDD-ID.log».

Desde el modelo de objetos del servidor podemos escribir en ese Log de manera que posteriormente podamos acceder al mismo y analizar lo que ha ocurrido. Voy a mostrar a continuación como podemos usar el ULS en SharePoint.

try
{
  //OwnCode
} 
catch (Exception ex) 
{
  SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("EXAMPLE", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
}

Os dejo un enlace donde podréis ver el significado de cada uno de los parámetros del método WriteTrace, aunque básicamente lo que estamos haciendo es escribir una entrada en el Log, con la categoría «EXAMPLE» de tipo Unexpected y con la información del mensaje de la excepción y la traza de la misma.

http://msdn.microsoft.com/es-es/library/microsoft.sharepoint.administration.spdiagnosticsservicebase.writetrace.aspx

En el siguiente artículo de la MSDN se puede ver una forma de crear una clase para encapsular el logging de errores y poder hacerlo de una forma más sencilla y elegante.

http://msdn.microsoft.com/en-us/library/office/gg512103(v=office.14).aspx

Para poder realizar una mejor visualización y análisis del ULS disponemos de la herramienta ULS Log Viewer, que podremos descargar de forma gratuita y usarla para un análisis de los log más sencilla y clara.

Y hasta aquí lo que quería comentar sobre el tema de monitorización y seguimiento de código en SharePoint, espero que sea de utilidad. Quizá un poco tarde para haber empezado a usarlo, pero como dicen, si la dicha es buena, siempre estamos a tiempo.

Un saludo.

Recopilatorio de enlaces: configuración de granjas de servidores en SharePoint

Buenas a todos,

Hoy lo que os quiero dejar son una serie de enlaces a artículos que he estado leyendo sobre aspectos a tener en cuenta para la configuración de una granja de SharePoint. La verdad es que es un tema que últimamente me interesa mucho y le he estado dedicando un tiempo a informarme bien, o al menos algo mejor. Espero que sean de vuestro interés.

Topología de Granjas de SharePoint

http://blogs.technet.com/b/meamcs/archive/2012/05/30/prepare-sharepoint-farm-part-4-install-and-configure-sharepoint-farm-3-tier.aspx

http://nikpatel.net/2013/03/20/new-best-practices-for-sharepoint-2013-farm-design-streamlined-topology/

http://www.microsoft.com/en-us/download/confirmation.aspx?id=37000

Instalación y puesta en marcha de un granja de SharePoint

http://www.compartimoss.com/revistas/numero-19/buenas-practicas-en-infraestructura-en-sharepoint-2013-parte-1

http://www.compartimoss.com/revistas/numero-20/buenas-practicas-en-infraestructura-en-sharepoint-2013-parte-ii

http://www.sinsharepointnohayparaiso.com/Blog/Entrada/92/Cuentas-administrativas-para-instalar-configurar-SharePoint-2013

http://technet.microsoft.com/es-es/library/ee805948(v=office.15).aspx

http://technet.microsoft.com/es-es/library/cc261752(v=office.15).aspx

SharePoint en Azure

http://blogs.encamina.com/desarrollandosobresharepoint/2014/09/16/como-montar-un-entorno-de-desarrollo-sharepoint-en-azure/

http://blogs.encamina.com/desarrollandosobresharepoint/2014/09/23/como-montar-un-entorno-de-sharepoint-en-azure-ii/

http://blogs.encamina.com/desarrollandosobresharepoint/2014/09/30/como-montar-un-entorno-de-sharepoint-en-azure-sharepoint-server/

Warmup Script para SharePoint

¿No os ha pasado a menudo que los primeros accesos a las aplicaciones basadas en SharePoint son más lentos de lo normal? ¿Y a medida que entráis la aplicación web empieza a responde a un ritmo más adecuado? A mi si ;).

Por defecto IIS recicla los pool de aplicaciones cada noche para limpiar la memoria, aspecto considerado además una buena práctica. Esto provoca que los primeros accesos de la mañana sean más lentos, pudiendo incluso provocar TimeOut.

Para resolver esto existe lo que se conoce como Warm-up script. El concepto básico, para dummies, de este script es hacer de forma automática esos primeros accesos, para que la experiencia de usuario en las primeras ocasiones que se entra a la aplicación web del día, no sea la de que la aplicación funciona excesivamente lenta.

Os dejo un enlace que me han recomendado con un script de este tipo que se puede utilizar tanto en SharePoint 2010 como SharePoint 2013

https://spbestwarmup.codeplex.com/

Como trabajar con los objetos SPWeb y SPSite

Buenas a todos,

Hoy quiero hacer un resumen de un artículo de la MSDN, en donde se explica cómo trabajar adecuadamente con estos dos objetos de SharePoint. Últimamente, como a otros artículos de buenas prácticas, acudo muy a menudo a éste, con el objetivo de mejorar el desempeño del código y seguir las recomendaciones a la hora de desarrollar para SharePoint.

Desde que he retomado mi blog ya he escrito algunas entradas comentando acerca de algunas de las buenas prácticas que se deberían de seguir. Hoy resumo en una tabla todas las buenas prácticas del artículo para tener una guía de acceso rápido y poder fácilmente recordar como se deben usar estos dos objetos, sobre todo al principio algunos de los casos me sorprendieron. Como siempre, para recordarlo me resulta más sencillo escribirlo y compartirlo ;).

Accediendo a SPWeb y SPSite
Mal uso:

using(SPWeb web = (new SPSite(url)).OpenWeb){}
Buen uso:

using(SPSite site = new SPSite(url))
{
    using(SPWeb web = site.OpenWeb())
    {

    }
}
Uso del contexto
Mal uso:

using(SPWeb web = SPContext.Current.Web){}

using(SPSite site = SPContext.Current.Site){}
Buen uso:
Cuando se usa el contexto los objetos no tienen que ser liberados, ya que estos son manejados por el Framework de SharePoint que se encarga de gestionarlos.
Añadir una nueva colección de sitios
Mal uso:

SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollection = siteCollections.Add
("sites/example","DOMAIN\\exampleUser","example@example.com");
Buen uso:

SPSiteCollection siteCollections = webApp.Sites;
    using (SPSite siteCollection = siteCollections.Add
("sites/example","DOMAIN\\exampleUser","example@example.com"))
    {
    }
Accediendo a la colección de sitios usando el índice []
Mal uso:

SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = siteCollections[0];
Buen uso:

SPSite siteCollectionInner = null;
        try
        {
            SPSiteCollection siteCollections = webApp.Sites;

            siteCollectionInner = siteCollections[0];
        }
        finally
        {
            if (siteCollectionInner != null)
                siteCollectionInner.Dispose();
        }
Recorriendo todas las colecciones de sitios
Mal uso:

SPSiteCollection siteCollections = webApp.Sites;

foreach (SPSite siteCollectionInner in siteCollections){}
Buen uso:

SPSiteCollection siteCollections = webApp.Sites;

foreach (SPSite siteCollectionInner in siteCollections)
{
    try{
                // ...
    }
    finally
    {
        if(siteCollectionInner != null)
            siteCollectionInner.Dispose();
    }
}
Añadiendo nuevos sitios
Mal uso:

SPWeb web = siteCollection.AllWebs.Add("example");

SPWebCollection webCollection = siteCollection.AllWebs;
SPWeb innerWeb = webCollection.Add(strWebUrl);
Buen uso:

using (SPWeb web = siteCollection.AllWebs.Add
("site-relative URL"))
{}

SPWebCollection webCollection = siteCollection.AllWebs;
using (SPWeb innerWeb = webCollection.Add(strWebUrl))
{
     //...
}
Accediendo sitios usando el índice []
Mal uso:

SPWeb web = siteCollection.AllWebs[0]
Buen uso:

using (SPWeb web = siteCollection.AllWebs[0])
{
}
Recorriendo todos los sitios de una colección
Mal uso:

foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
      //To do something
}
Buen uso:

foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
     try
     {
         //To do something
     }
     finally
     {
         if(innerWeb != null)
              innerWeb.Dispose();
     }
}
Usando RootWeb
Mal uso:

Buen uso:
Al igual que cuando usamos el contexto, ese objeto no debe ser liberado

SPWeb rootWeb = siteCollection.RootWeb;

Dejo para el final la explicación del por qué de los «buen uso» de cada caso, ya que prácticamente en todos se trata del mismo motivo.

Los objetos SPSite y SPWeb usan código y memoria no manejada. Esto provoca principalmente que el «garbage collector» no libere automáticamente y de forma correcta los objetos de este tipo. Si no se resuelve adecuadamente haciendo uso de dispose o en su defecto, por medio de using, quedarán residuos de memoria que no son correctamente desalojados. Esto puede provocar problemas de rendimiento o problemas de memoria de la aplicación, entre otros.

Como siempre, os dejo el enlace de referencia (este ya enlazado alguna que otra vez):

http://msdn.microsoft.com/en-us/library/aa973248.aspx

Para comprobar que estamos usando correctamente los objetos SPSite y SPWeb, existe la herramienta SPDisposeCheck, que se puede usar tanto integrada con Visual Studio, como ejecutada desde línea de comandos para evaluar una dll completa. Con esta herramienta podemos comprobar de forma sencilla si se están siguiendo estas buenas prácticas.

Espero que os sirva esta entrada de referencia para recordar el uso adecuado de estos objetos.