SharePoint 2010: Nuevo Video Center for SharePoint 2010 Development!

La verdad, y ya lo he dicho en muchas ocasiones, es que con SharePoint 2010 no nos podemos quejar por falta de recursos para hacer extensible la plataforma mediante desarrollo. En este sentido, estos días ha visto la luz un nuevo centro de recursos que recopila una serie de videos sobre desarrollo tanto para SharePoint 2010 On-Premise como para SharePoint Online en Office 365. Se trata del Video Center | SharePoint Development al que podéis acceder desde este enlace: http://msdn.microsoft.com/en-us/sharepoint/hh298298.aspx

image

SharePoint 2010: Cambios a nivel de API con el SP1!

Siguiendo con la serie de artículos sobre novedades que incorpora el reciente service pack 1 (SP 1) de SharePoint 2010, en esta ocasión toca hablar sobre cambios (no muchos en este caso) a nivel de API. En este sentido, una buena referencia a partir de la cuál conocer la novedades es este post de Gary Lapointe: SharePoint 2010 SP1 Public API Changes.

SharePoint2010_thumb

SharePoint 2010: Personalización de la navegación (I)!

Uno de los elementos de un sitio de SharePoint que se puede personalizar de acuerdo a distintas técnicas es el menú de navegación vertical. En este primer artículo vamos a ver como se puede personalizar la navegación de un sitio mediante el modelo de objetos, vamos a utilizar un Feature Event Reciver:

  • En Visual Studio 2010 creamos un proyecto de tipo “Empty SharePoint Project” y elegimos como tipo de despliegue “Deploy as farm solution”.
  • Añadimos al proyecto una Feature que configuramos de forma que el ámbito de la misma sea “Web”.
  • Añadimos un Feature Event Receiver y añadimos una directiva using a Microsoft.SharePoint.Navigation.
  • Codificamos el método FeatureActivated() de la siguiente forma:
   1: public override void FeatureActivated(SPFeatureReceiverProperties properties)

   2: {

   3:     SPWeb spwWeb = (SPWeb)properties.Feature.Parent;

   4:     if (spwWeb != null)

   5:     {

   6:         SPNavigationNode spnNodo = null;

   7:         foreach (SPNavigationNode n in spwWeb.Navigation.QuickLaunch)

   8:         {

   9:             if (n.Title == "Aplicaciones")

  10:             {

  11:                 spnNodo = n; 

  12:                 break;

  13:             }

  14:         }

  15:         //Si no existe la sección...

  16:         if (spnNodo == null)

  17:         {

  18:             spnNodo = new SPNavigationNode("Aplicaciones","", false);

  19:             spwWeb.Navigation.QuickLaunch.AddAsFirst(spnNodo);

  20:         }

  21:         spnNodo.Children.AddAsFirst(

  22:             new SPNavigationNode(

  23:                 "Nóminas", 

  24:                 "Documentos%20compartidos/Aplicaciones.aspx", 

  25:                 false));

  26:     }

  27: }

  • Codificamos el método FeatureDeactivating() de la siguiente forma:
   1: public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

   2: {

   3:     SPWeb spwWeb = (SPWeb)properties.Feature.Parent;

   4:     if (spwWeb != null)

   5:     {

   6:         SPNavigationNode spnNodo = null;

   7:         foreach (SPNavigationNode n in spwWeb.Navigation.QuickLaunch)

   8:         {

   9:             if (n.Title == "Aplicaciones")

  10:             {

  11:                 spnNodo = n; 

  12:                 break;

  13:             }

  14:         }

  15:         if (spnNodo != null)

  16:         {

  17:             SPNavigationNode spnNodoHijo = null;

  18:             foreach (SPNavigationNode n in spnNodo.Children)

  19:             {

  20:                 if (n.Title == "Nóminas")

  21:                 {

  22:                     spnNodoHijo = n; 

  23:                     break;

  24:                 }

  25:             }

  26:             if (spnNodoHijo != null)

  27:             {

  28:                 spnNodoHijo .Delete();

  29:  

  30:                 if (spnNodo.Children.Count == 1)

  31:                 {

  32:                     spnNodo.Delete();

  33:                 }

  34:             }

  35:         }

  36:     }

  37: }

  • Comprobamos que el menú de navegación se ha personalizad de acuerdo al código anterior:
image image

 

Y hasta aquí llega este primer artículo sobre como personalizar la navegación de un sitio de SharePoint.

Office 365: Materiales sobre seguridad y privacidad!

Uno de los compromisos que Microsoft tiene con respecto a su plataforma de productividad en la nube, u Office 365, es la de garantizar la seguridad y privacidad de la información de los clientes que la utilicen. En este sentido, y de cara a tener claro como Microsoft garantiza el cumplimiento de seguridad y privacidad que se puede esperar, tenemos disponibles una serie de materiales en torno a estas cuestiones nada triviales:

  • Office 365 – Standard Response to Request for Information – Security and Privacy This white paper is aligned to the Cloud Security Alliance publication of a Cloud Control Matrix, to support customers in the evaluation of cloud services. The document provides our customers and internal Microsoft employees with detailed responses to the suggested principles put forth by the CSA then mapped to our ISO 27001 certification.
  • Microsoft Online Services Trust Center The trust center is an external site that provides our Office 365 customers with detailed information in simple terms about our commitments relating to privacy, security, and data handling.
  • Security in Office 365 White Paper The purpose of this paper is to provide an overview of the security practices and technology that support enterprise-level security in Microsoft Office 365 for businesses of all sizes.
  • Office 365 – Security Service DescriptionThis document provides information about security to customers in the standard form of a service description.
  • Office 365 Cloud Security Consideration Paper (To be posted here shortly) – This final paper is an expansion upon the Cloud Computing Security Considerations paper released almost a year ago by the Chief Security Advisor Team. It address cloud security considerations in an Office 365 environment and how to strike a balance between customers and Microsoft responsibilities.

Fuente: http://blogs.msdn.com/b/mvplead/archive/2011/07/07/security-and-privacy-support-reference-materials-for-office-365.aspx

SharePoint 2010: Trabajo programático con listas de tipo encuesta (I)!

Una de las listas que se crea por defecto en un sitio de tipo “Sitio de grupo” de SharePoint 2010 es la de tipo encuesta que permite modelar de forma sencilla cuestionarios en los que se pueden definir preguntas de distintos tipos y se permite responder a la misma de forma secuencial. Como habréis deducido, este tipo de lista es un tanto especial lo que es un factor a tener en cuenta cuando queremos atacarla programáticamente (para explotar las respuestas a una encuesta por ejemplo). Sin embargo, como os demostraré el trabajo vía API con este tipo de listas es similar al que realizamos con otros tipos:

  • Creamos en nuestro sitio de trabajo una lista de tipo encuesta.
  • Añadimos un par de preguntas de tipo “Una línea de texto”.
  • Respondemos al menos una vez a la encuesta.
image image image
  • Nos vamos a Visual Studio 2010 y creamos un proyecto de tipo Aplicación de Consola. Añadimos una referencia a Microsoft.SharePoint.
  • Añadimos una directiva using a Microsoft.SharePoint.
  • Añadimos un método estático a Program.cs que nos permita recorrer las respuestas de la encuesta y mostrar la información por pantalla como sigue:
   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5:  

   6: //Espacios de nombres necesarios

   7: using Microsoft.SharePoint;

   8: namespace SPEncuestasProc

   9: {

  10:     class Program

  11:     {

  12:         static void Main(string[] args)

  13:         {

  14:             ProcessSurvey();

  15:             Console.ReadLine();

  16:         }

  17:  

  18:         static void ProcessSurvey()

  19:         {

  20:             using (SPSite spsSitio = new SPSite("http://demo2010a:100/sites/PortalIntranet/"))

  21:             {

  22:                 using (SPWeb spwWeb = spsSitio.OpenWeb())

  23:                 {

  24:                     SPList splSurvey = spwWeb.Lists["Encuesta"];

  25:                     SPListItemCollection splicItemCollection = splSurvey.Items;

  26:                     int iInitialCount, iFieldsNumber, iAnswerNumber=0;                    

  27:                     foreach (SPListItem splItem in splicItemCollection)

  28:                     {

  29:                         Console.WriteLine("----Respuesta # {0} ----", iAnswerNumber);

  30:                        iFieldsNumber = splItem.Fields.Count;

  31:                        for (iInitialCount  = 0; iInitialCount < iFieldsNumber; iInitialCount++)

  32:                        {

  33:                            

  34:                            if (splItem[splItem.Fields[iInitialCount].InternalName]!=null)

  35:                            {

  36:                                Console.WriteLine(

  37:                                     splItem.Fields[iInitialCount].InternalName + " - " +

  38:                                     splItem[splItem.Fields[iInitialCount].InternalName]);    

  39:                            }                        

  40:                        }

  41:                        iAnswerNumber++;

  42:                     }

  43:                 }

  44:             }

  45:         }        

  46:     }

  47: }

  • Cómo veis, lo más interesante del método es la forma en la que se recorren todos los campos disponibles para un registro de la encuesta lo que nos permite acceder a las preguntas y a su respuesta. Esto lo conseguimos accediendo a la colección Fields disponible en cada objeto de tipo SPListItem de la lista.
  • Para cada campo, mostramos su nombre interno y su valor. La salida correspondiente por pantalla es la que se muestra a continuación:

image

Y hasta aquí llega este post sobre trabajo programático con listas de tipo encuesta.

SharePoint 2010: CSS Reference Chart!

Sin duda, a la hora de personalizar un sitio de SharePoint uno de los puntos claves a trabajar es el relativo a los estilos (CSSs) que tenemos que aplicar y sobre todo los estilos de SharePoint que queremos sobrescribir por lo que es muy importante tenerlos perfectamente localizados ya sea utilizando las herramientas de desarrollo del explorador web habitual de trabajo o bien consultando una excelente referencia creada por Heather Solomon: el CSS Reference Chart para SharePoint Foundation y SharePoint Server 2010 que recoge la mayoría de los estilos utilizados en ambos productos. Podéis acceder al CSS Reference Chart desde este enlace. Como podéis ver:

  • Los estilos se encuentran agrupados por categorías generales.
  • Para cada estilo se indica además de su identificador, el propósito del mismo y en que CSS se encuentra localizado (normalmente en el COREV4.css).

Sin duda un recurso imprescindible.

SharePoint2010_thumb

Office 365: ¿En cuántos equipos puedo instalar Office 2010 por cada suscripción?

Cómo sabéis, la suite de productividad de Microsoft en la nube Office 365 no sólo está formada por una serie de servicios que ofrecen capacidades de colaboración, comunicación, correo electrónico, mensajería instantánea, etc, sino que también incluye la posibilidad de usar la suite ofimática de Microsoft a través de la disponibilidad de Office 2010 Professional Plus. La novedad de disponer de esta suite es que no se necesita una clave de producto, sino que su uso se basa en el concepto de suscripción de Office 365. Ahora bien, una pregunta que nos puede venir a la cabeza es la de cuantas instalaciones de Office 2010 puedo realizar por suscripción. La respuesta es que 5 tal y como podéis encontrar en la siguiente referencia de TechNEt:  http://technet.microsoft.com/en-us/library/gg702619.aspx

image

Office 365: Disponible el Productivity Hub para SharePoint Online!

Tal y como podéis leer en este post del blog de Ian Morrish, tenemos disponible una versión del Productivity Hub para SharePoint Online en Office 365. Esta versión complementa las ya existentes para SharePoint 2007 y SharePoint 2010 On-Premise y trata de proporcionar un entorno centralizado en el que definir actividades de formación en torno a productos de Microsoft usando las capacidades de social computing de SharePoint 2010 como blogs, grupos de discusiones, etc. En general, se trata de facilitar el acceso a estas tecnologías por parte del usuario final. Podéis descargaros el Productivity Hub desde este enlace.

082511_2135_SharePointP1[1]

SharePoint 2010 & Azure: Integración de servicios mediante BCS (I)!

Una de las posibilidades que tenemos de integrar servicios WCF On-Premises o publicados en Azure es a través de los Business Connectivity Services (BCS) que facilitan el consumo de los mismos a través del correspondiente tipo de contenido externo (ECT) publicado en el catálogo de datos profesionales. A la hora de modelar estos ECTs tenemos dos posibilidades:

  • Utilizando SharePoint Desinger 2010 (SPD 2010).
  • Utilizando Visual STudio 2010.

En este primer artículo vamos a ver la primera de las posibilidades que nos permita consumir un servicio WCF On-Premise o publicado en Azure a través de un ECT creado con SPD 2010:

  • Lo primero que tenemos que hacer es disponer de un servicio ya publicado. En mi caso, el servicio a consumir tiene definida la siguiente lógica:
   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Runtime.Serialization;

   5: using System.ServiceModel;

   6: using System.ServiceModel.Web;

   7: using System.Text;

   8:  

   9: namespace CustomerService

  10: {

  11:     // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.

  12:     // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.

  13:     public class CustomerService : ICustomerService

  14:     {

  15:         List<Customer> lCustomersList = new List<Customer>();

  16:  

  17:         /// <summary>

  18:         /// Gets the selelected customer

  19:         /// </summary>

  20:         /// <param name="sCustomerID">ID of the selected customer</param>

  21:         /// <returns></returns>

  22:         public List<Customer> getACustomer(string sCustomerID)

  23:         {

  24:             //Generate Customer Data

  25:             generateCustomerData();

  26:  

  27:  

  28:             //Querying the customer

  29:             var qCustomer = (from c in lCustomersList

  30:                              where c.IDCustomer == sCustomerID

  31:                              select c).ToList();

  32:             //Filling the returned data           

  33:             List<Customer> lrCustomer = qCustomer;

  34:  

  35:             return lrCustomer;

  36:         }

  37:  

  38:         public List<Customer> getAllCustomers()

  39:         {

  40:             generateCustomerData();

  41:             List<Customer> lAllCustomers = new List<Customer>();

  42:  

  43:             //Querying the customers

  44:             var qCustomers = (from c in lCustomersList

  45:                               select c).ToArray();

  46:             foreach (var qc in qCustomers)

  47:             {

  48:                 Customer tCustomer = new Customer();

  49:                 tCustomer.IDCustomer = qc.IDCustomer;

  50:                 tCustomer.sCustomerName = qc.sCustomerName;

  51:                 tCustomer.sCustomerAddress = qc.sCustomerAddress;

  52:                 tCustomer.sCustomerEMail = qc.sCustomerEMail;

  53:                 tCustomer.sCustomerPhone = qc.sCustomerPhone;

  54:  

  55:                 lAllCustomers.Add(tCustomer);

  56:             }

  57:  

  58:             return lAllCustomers;

  59:         }

  60:         /// <summary>

  61:         /// This method generates customer data for the service

  62:         /// </summary>

  63:         private void generateCustomerData()

  64:         {

  65:             Customer cCustomer1 = new Customer();

  66:             cCustomer1.IDCustomer = "1";

  67:             cCustomer1.sCustomerName = "Juan Carlos González";

  68:             cCustomer1.sCustomerAddress = "C/ Camilo Alonso Vega 41 7 D 39007 Santander";

  69:             cCustomer1.sCustomerEMail = "jgonzalez@gruposodercan.es";

  70:             cCustomer1.sCustomerPhone = "647 391 399";

  71:  

  72:             lCustomersList.Add(cCustomer1);

  73:  

  74:             Customer cCustomer2 = new Customer();

  75:             cCustomer2.IDCustomer = "2";

  76:             cCustomer2.sCustomerName = "Ángel Acha";

  77:             cCustomer2.sCustomerAddress = "C/ Joaquín Costa s/n 39005 Santander";

  78:             cCustomer2.sCustomerEMail = "aacha@gruposodercan.es";

  79:             cCustomer2.sCustomerPhone = "942 760 620";

  80:  

  81:             lCustomersList.Add(cCustomer2);

  82:         }

  83:     }

  84: }

  • La clase Customer que sirve como base en los tipos devueltos por getACustomer() y getAllCustomers() tiene la siguiente implementación:
   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Web;

   5:  

   6: namespace CustomerService

   7: {

   8:     public class Customer

   9:     {

  10:         public string IDCustomer { get; set; }

  11:         public string sCustomerName{ get; set; }

  12:         public string sCustomerAddress { get; set; }

  13:         public string sCustomerEMail { get; set; }

  14:         public string sCustomerPhone { get; set; }

  15:     }

  16: }

  • Siendo ICustomerService la correspondiente interfaz en la que se definen tanto el contrato del servicio como las operaciones que implementa:
   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Runtime.Serialization;

   5: using System.ServiceModel;

   6: using System.ServiceModel.Web;

   7: using System.Text;

   8:  

   9: namespace CustomerService

  10: {

  11:     // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.

  12:     [ServiceContract]

  13:     public interface ICustomerService

  14:     {

  15:  

  16:         [OperationContract]

  17:         List<Customer> getAllCustomers();

  18:         [OperationContract]

  19:         List<Customer> getACustomer(string sCustomerID);

  20:  

  21:       

  22:     }

  23:  

  24:  

  25:  

  26: }

  • Finalmente, el archivo web.config vital para que el servicio pueda ser consumido tiene la siguiente forma:
   1: <?xml version="1.0"?>

   2: <configuration>

   3:   <system.web>

   4:     <compilation debug="true" targetFramework="4.0" />

   5:   </system.web>

   6:     <system.serviceModel>

   7:         <services>

   8:             <service behaviorConfiguration="CustomerService.CustomerWCFServiceBehavior" name="CustomerService.CustomerService">

   9:                 <endpoint address="" binding="basicHttpBinding" contract="CustomerService.ICustomerService" />

  10:                 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

  11:             </service>

  12:         </services>

  13:         <behaviors>

  14:             <serviceBehaviors>

  15:                 <behavior name="CustomerService.CustomerWCFServiceBehavior">

  16:                     <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->

  17:                     <serviceMetadata httpGetEnabled="true"/>

  18:                     <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->

  19:                     <serviceDebug includeExceptionDetailInFaults="false"/>

  20:                     <useRequestHeadersForMetadataAddress>

  21:                         <defaultPorts>

  22:                             <add scheme="http" port="81"/>

  23:                             <add scheme="https" port="444"/>

  24:                         </defaultPorts>

  25:                     </useRequestHeadersForMetadataAddress>

  26:                 </behavior>

  27:             </serviceBehaviors>

  28:         </behaviors>

  29:         <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

  30:     </system.serviceModel>

  31:     <system.webServer>

  32:         <modules runAllManagedModulesForAllRequests="true"/>

  33:     </system.webServer>  

  34: </configuration>

Publicado el servicio ya sea On-Premise o en Azure, lo que necesitaremos para consumirlo en un ECT creado con SPD 2010 son las Urls del servicio y del WSDL:

image image image
  • En la configuración de la conexión al servicio WCF tendremos que especificar tanto la URL del WSDL como la del propio servicio. Especificaremos además un nombre para la conexión.
  • Como veis, la configuración difiere ligeramente en el caso de que el servicio esté publicado en Azure con respecto a si está publicado On-Premise.
  • Una vez establecida la conexión, se muestran los dos métodos disponibles que nos permitirán definir las operaciones básicas del ECT que consume el servicio.
image image image
  • Comenzamos con la operación “Leer lista” a partir del método getAllCustomers().
  • En la primera pantalla del asistentes especificamos el nombre de la operación y pulsamos “Siguiente”.
  • Pulsamos de nuevo “Siguiente”.
image image image
  • En la siguiente pantalla configuramos los parámetros de retorno de la operación. Lo más importante aquí es definir el identificador de la operación y el campo a mostrar en el selector de datos externos. Además, podremos parametrizar el nombre para mostrar en cada campo. Pulsamos Finalizar para que la primera operación quede definida.
  • Lo siguiente que haremos es definir la operación “Leer elemento”.
  • Como antes, en la primera pantalla del asistente de configuración de la operación especificamos un nombre para la misma y pulsamos “Siguiente”.
image image image
  • De nuevo definimos el identificador de la operación que en este caso es aún más importante ya que nos permite devolver una única entidad.
  • Configuramos de nuevo los parámetros de retorno y pulsamos “Finalizar”.
  • Guardamos todos los cambios realizados para que el ECT se refleje en el catálogo de datos profesionales y pulsamos la opción “Crear listas y formularios” para proceder a crear la correspondiente lista externa.
image image image
  • En la ventana de definición de la lista especificamos el nombre de la misma y si vamos a usar formularios InfoPath. Pulsamos “Aceptar” para que se cree la lista externa.
  • Navegamos al sitio de trabajo y comprobamos que en la lista creada se muestran los datos expuestos por el servicio.
  • Editamos un registro y comprobamos que se visualiza sin problemas.
image image image

Y hasta aquí llega este primer post sobre la integración de servicios mediante BCS y SPD 2010.

SharePoint 2010: ¿Y cuánto me cuesta?

Una pregunta más que recurrente en torno a SharePoint 2010 es la relativa a los costes de licenciamiento en función del despliegue que se necesite de nuestro servidor favorito. Por suerte, y a pesar de lo complicado que es el modelo de licenciamiento de Microsoft, tenemos algunos recursos en los que apoyarnos para intentar atinar en lo que va a costar un cierto despliegue de SharePoint:

SharePoint2010_thumb