Pues simplemente eso, compartir la liga de MSDN en donde se enumeran los métodos y tipos que son/serán marcados como "Deprecated" para la version 2010 de SharePoint y que de entrada deberiamos estar evitando en nuestro código, en aras de hacer menos dolorosa la experiencia de migración (por lo menos en cuanto a desarrollo se refiere).
Es importante mencionar que los tipos y métodos marcados con el atributo "Obsolete", continuarán funcionando en nuestro código, y solo generarán warnings al momento de compilar, aunque es muy recomendable que sean sustituidos por las nuevas implementaciones.
lunes, 14 de diciembre de 2009
domingo, 13 de diciembre de 2009
Exportar listas de Sharepoint como Features
Hoy quiero compartir uno de los tips que utilizo muy a menudo cuando desarrollo, el de cómo exportar la definición de una lista cualquiera de SharePoint y construir una Feature para poder provisionarla en otros sitios.
Muchos podrán pensar que podemos hacer lo mismo solo guardando la lista como plantilla y después agregándola al sitio que deseemos, sin embargo, para nosotros los desarrolladores, siempre es mejor tener todo por código, y que al crear nuestro paquete de instalación (WSP), este contenga una Feature que provisione la definición e instancia de la lista, es decir, todo lo necesario para que nuestro desarrollo funcione.
Básicamente esta solución lo que hace es utilizar la API que se encuentra en las dll’s:
VSeWSS.Server.Services.dll
VSeWSS.Server.SPProxies.dll
Pasos a seguir para provisionar la definición e instancia de nuestra lista a través de una feature.
1.- El código que nos permite extraer la definición de una lista
El código principalmente utiliza la funcionalidad que ya existe en la clase SPService del ensamblado VSeWSS.Server.Services, que es instalado junto con las extensiones de Visual Studio 2008 para Windows SharePoint Services 3.0, si tu instalación fue hecha en la ruta por default, estos ensamblados se encuentran en C:\Program Files\Microsoft SharePoint Developer Tools 9.0\svc\bin.
El método ExportListDefinition, que es el que se encarga de extraer la definición de la lista en cuestión, hace uso del método GetListTemplateFileExport de la clase SPService, el cual regresa un objeto del tipo ExportFilesResponse, el cual posteriormente es utilizado como parametro en el llamado al metodo SaveAsFile de la clase SPDefinitionExporter, pero que mejor que ver el código para aclarar cualquier duda.
La clase SPDefinitionExporter
Para fines didacticos he creado una lista llamada Empleados, la cual servira para demostrar como extraer su definición y despues crear la feature que provisionara la definición obtenida, así como una instancia de la lista. La lista tiene la siguiente estructura:
Corriendo este programita con los siguientes argumentos
ExportListDefinition.exe -url http://siber:81 -path "c:\temp" -listname Empleados
2.- Creando la feature
Una vez que ya tenemos los archivos obtenidos de la utilería que exporta la definición de la lista, es tiempo de crear la feature que provisionara estos archivos en un sitio de SharePoint, para esto recomiendo utilizar algún asistente como VSeWSS 1.3, WSPBuilder, etc.
Yo utilizo WSPBuilder simplemente porque estoy más familiarizado con él, y su uso me parece mas intuitivo.
Entonces creamos la solución, agregamos una nueva feature, y creamos una jerarquía de archivos como la siguiente:
3.- Archivos complementarios
Por default al crear la feature, el asistente nos creara un archivo elements.xml, el cual renombraremos como Instance.xml, y cuya estructura es la siguiente:
También, debemos colocar el archivo ListDefinition.xml, que la utilería creó, al mismo nivel que el archivo Feature.xml y el archivo Instance.xml, a continuación como se ve el archivo Instance.xml de mi ejemplo:
Noten que he resaltado el Id de estos dos elementos, y esto es porque este Id debe ser el mismo, y debe corresponder también con el que se encuentra en el archivo schema.xml, como se aprecia a continuación:
Y ya por último, en el archivo Feature.xml debemos hacer referencia a estos 3 archivos que acabo de mencionar, en la sección ElementManifest, como se muestra a continuación:
Una vez que hagamos todo esto y despleguemos nuestra solución (WSP), en la granja de SharePoint, activamos la Feature que hemos creado.
Y ahora en el sitio en que activamos la feature tenemos una instancia de la lista de empleados:
Pero además podemos crear una lista con el mismo template, ya que también provisionamos la lista como plantilla:
Además dejo el código, para que lo revisen.
Espero que este tip, sea de utilidad
Happy Coding!
Muchos podrán pensar que podemos hacer lo mismo solo guardando la lista como plantilla y después agregándola al sitio que deseemos, sin embargo, para nosotros los desarrolladores, siempre es mejor tener todo por código, y que al crear nuestro paquete de instalación (WSP), este contenga una Feature que provisione la definición e instancia de la lista, es decir, todo lo necesario para que nuestro desarrollo funcione.
Básicamente esta solución lo que hace es utilizar la API que se encuentra en las dll’s:
VSeWSS.Server.Services.dll
VSeWSS.Server.SPProxies.dll
Pasos a seguir para provisionar la definición e instancia de nuestra lista a través de una feature.
1.- El código que nos permite extraer la definición de una lista
El código principalmente utiliza la funcionalidad que ya existe en la clase SPService del ensamblado VSeWSS.Server.Services, que es instalado junto con las extensiones de Visual Studio 2008 para Windows SharePoint Services 3.0, si tu instalación fue hecha en la ruta por default, estos ensamblados se encuentran en C:\Program Files\Microsoft SharePoint Developer Tools 9.0\svc\bin.
El método ExportListDefinition, que es el que se encarga de extraer la definición de la lista en cuestión, hace uso del método GetListTemplateFileExport de la clase SPService, el cual regresa un objeto del tipo ExportFilesResponse, el cual posteriormente es utilizado como parametro en el llamado al metodo SaveAsFile de la clase SPDefinitionExporter, pero que mejor que ver el código para aclarar cualquier duda.
/// <summary> /// Exporta la lista indicada hacia el directorio de salida /// </summary> /// <param name="outputdir" /> /// <param name="url" /> /// <param name="listname" /> private static void ExportListDefinition(string outputdir, string url, string listname) { SPSite site = null; SPWeb web = null; try { using (site = new SPSite(url)) { using (web = site.OpenWeb()) { Guid g = web.Lists[listname].ID; SPService service = new SPService(); ExportFilesResponse response = service.GetListTemplateFileExport(url, g); if (response.IfSuccess) { if (response.Entity != null) { SPDefinitionExporter exporter = new SPDefinitionExporter(outputdir, url); exporter.SaveAsFile(response.Entity); } } } } } catch (Exception ex) { if (web != null) web.Dispose(); if (site != null) site.Dispose(); throw ex; } }
La clase SPDefinitionExporter
internal class SPDefinitionExporter { public string ExportLocation { get; set; } public virtual string TargetSiteUrl { get; set; } // Methods public SPDefinitionExporter(string exportLocation, string targetSiteUrl) { this.ExportLocation = exportLocation; this.TargetSiteUrl = targetSiteUrl; } public void SaveAsFile(ExportFileEntity file) { if (file != null) { string path = string.Format("{0}{1}", this.ExportLocation, file.RelativePath); Directory.CreateDirectory(GetParentDirectoryPath(path)); if (file.IsText) { SaveAsFile(file.ContentStr, path); } else { SaveAsFile(file.ContentBin, path); } } } public void SaveAsFile(IEnumerable<ExportFileEntity> files) { if (files != null) { foreach (ExportFileEntity entity in files) { this.SaveAsFile(entity); } } } private static void SaveAsFile(string contents, string path) { FileStream stream = File.Create(path); StreamWriter writer = new StreamWriter(stream, Encoding.UTF8); writer.Write(contents); writer.Flush(); writer.Close(); stream.Close(); } private static string GetParentDirectoryPath(string path) { if (string.IsNullOrEmpty(path)) { return string.Empty; } int length = path.LastIndexOf(@"\"); return path.Substring(0, length); } private static void SaveAsFile(byte[] contents, string path) { FileStream output = File.Create(path); BinaryWriter writer = new BinaryWriter(output); writer.Write(contents); writer.Flush(); writer.Close(); output.Close(); } }
Corriendo este programita con los siguientes argumentos
ExportListDefinition.exe -url http://siber:81 -path "c:\temp" -listname Empleados
2.- Creando la feature
Una vez que ya tenemos los archivos obtenidos de la utilería que exporta la definición de la lista, es tiempo de crear la feature que provisionara estos archivos en un sitio de SharePoint, para esto recomiendo utilizar algún asistente como VSeWSS 1.3, WSPBuilder, etc.
Yo utilizo WSPBuilder simplemente porque estoy más familiarizado con él, y su uso me parece mas intuitivo.
Entonces creamos la solución, agregamos una nueva feature, y creamos una jerarquía de archivos como la siguiente:
3.- Archivos complementarios
Por default al crear la feature, el asistente nos creara un archivo elements.xml, el cual renombraremos como Instance.xml, y cuya estructura es la siguiente:
También, debemos colocar el archivo ListDefinition.xml, que la utilería creó, al mismo nivel que el archivo Feature.xml y el archivo Instance.xml, a continuación como se ve el archivo Instance.xml de mi ejemplo:
Noten que he resaltado el Id de estos dos elementos, y esto es porque este Id debe ser el mismo, y debe corresponder también con el que se encuentra en el archivo schema.xml, como se aprecia a continuación:
Y ya por último, en el archivo Feature.xml debemos hacer referencia a estos 3 archivos que acabo de mencionar, en la sección ElementManifest, como se muestra a continuación:
Una vez que hagamos todo esto y despleguemos nuestra solución (WSP), en la granja de SharePoint, activamos la Feature que hemos creado.
Y ahora en el sitio en que activamos la feature tenemos una instancia de la lista de empleados:
Pero además podemos crear una lista con el mismo template, ya que también provisionamos la lista como plantilla:
Espero que este tip, sea de utilidad
Happy Coding!
Etiquetas:
Desarrollo SharePoint,
Features,
Gerardo Reyes Ortiz,
SharePoint,
Xml
lunes, 7 de diciembre de 2009
[SharePoint] - Obtener la url de un recurso desde la zona correcta
Alguien había oído hablar del método SPUtility.AlternateServerUrlFromHttpRequestUrl?
Pues básicamente este método nos permite hacer un mapeo de un recurso entre distintas zonas, y nos devuelve la url del recurso en la zona correcta.
A continuación un ejemplo de donde podría ser útil este método, cabe mencionar que estoy acomodando el escenario de tal manera de que se puede notar la funcionalidad de este método.
Por poner un escenario básico, el siguiente:
Tenemos una web application con la url http://intranet.corp.com, que ha sido extendida a la zona de extranet en la url http://extranet.corp.com, para tener un método de autentificación distinto.
Y tenemos una lista con un campo de tipo Imagen, estos campos almacenan rutas absolutas, por lo que cuando se guarde en este campo con una imagen desde la intranet, la ruta que almacenara será más o menos así:
http://intranet.corp.com/PublishingImages/Image1.jpg
Cuando nosotros leamos la lista y construyamos nuestro HTML para que muestre la imagen en una webpart,
Si el usuario esta accediendo desde la zona de intranet todo irá bien, sin embargo, si el usuario ha accedido desde la zona de Extranet, se pintara el mismo HTML, porque la url se está leyendo directamente de la lista. Y cuando esto suceda, al usuario se le solicitaran las credenciales pertinentes para obtener acceso al recurso, porque este se encuentra en una zona diferente.
A fin de solucionar este escenario hipotético podemos utilizar el método SPUtility.AlternateServerUrlFromHttpRequestUrl, el cual nos permite transformar esta url por la url correcta dependiendo de la zona en que nos encontremos. Como se aprecia en el fragmento de código siguiente:
Happy Coding!
Pues básicamente este método nos permite hacer un mapeo de un recurso entre distintas zonas, y nos devuelve la url del recurso en la zona correcta.
A continuación un ejemplo de donde podría ser útil este método, cabe mencionar que estoy acomodando el escenario de tal manera de que se puede notar la funcionalidad de este método.
Por poner un escenario básico, el siguiente:
Tenemos una web application con la url http://intranet.corp.com, que ha sido extendida a la zona de extranet en la url http://extranet.corp.com, para tener un método de autentificación distinto.
Y tenemos una lista con un campo de tipo Imagen, estos campos almacenan rutas absolutas, por lo que cuando se guarde en este campo con una imagen desde la intranet, la ruta que almacenara será más o menos así:
http://intranet.corp.com/PublishingImages/Image1.jpg
Cuando nosotros leamos la lista y construyamos nuestro HTML para que muestre la imagen en una webpart,
Existen dos escenarios posibles:
Si el usuario esta accediendo desde la zona de intranet todo irá bien, sin embargo, si el usuario ha accedido desde la zona de Extranet, se pintara el mismo HTML, porque la url se está leyendo directamente de la lista. Y cuando esto suceda, al usuario se le solicitaran las credenciales pertinentes para obtener acceso al recurso, porque este se encuentra en una zona diferente.
A fin de solucionar este escenario hipotético podemos utilizar el método SPUtility.AlternateServerUrlFromHttpRequestUrl, el cual nos permite transformar esta url por la url correcta dependiendo de la zona en que nos encontremos. Como se aprecia en el fragmento de código siguiente:
///Y con esto al crear el HTML correspondiente a la imagen, el resultado variará dependiendo de la zona en la cual nos encontramos./// Recuperacion de la lista /// ///private SPList GetList() { SPList listImages = null; using (SPSite site = new SPSite ("http://intranet.corp.com")) { using (SPWeb web = site.OpenWeb()) { listImages = web.Lists["PublishingImages"]; for (int index = 0; index < listImages.Items.Count; index++) { //url de la imagen, extraida directamente desde la lista string urlImage = listImages.Items[index]["Thumbnail"].ToString(); string correctUrl = string.Empty; //obtenemos solo la url, sin el nombre de la imagen if (urlImage.Contains(",")) { urlImage = urlImage.Split(",".ToCharArray())[0]; } if (Uri.IsWellFormedUriString(urlImage, UriKind.RelativeOrAbsolute) == true) { Uri uriImage = new Uri(urlImage); correctUrl = SPUtility.AlternateServerUrlFromHttpRequestUrl(uriImage).ToString(); } listImages.Items[index]["Thumbnail"] = correctUrl; } } } return listImages; }
Otros posibles escenarios de uso podrían ser al customizar las búsquedas, al obtener los resultados de estas, las urls de los resultados vendrán con la url de la zona default, pero con el método mencionado podemos solucionar este problema SPUtility.AlternateServerUrlFromHttpRequestUrl Method
Happy Coding!
Etiquetas:
Desarrollo SharePoint,
Gerardo Reyes Ortiz,
México,
SharePoint,
Web parts,
WebParts
Suscribirse a:
Entradas (Atom)