Acabo de sufrir en “mis cannes”, este bonito error, justo cuando intentaba eliminar un tipo de contenido, que había creado una feature de una solución personalizada, que había desarrollado.
Lo primero a comprobar, que yo ya había hecho, es que ese tipo de contenido, no puede estar siendo usado en ninguna lista ni biblioteca. Además, debes comprobar que ese tipo de contenido, no sea tipo base, de algún otro contenido que sí se está usando. También puedes usar alguna herramienta del estilo SharePoint Manager, donde tienes un atributo Usage, que te dirá si se está usando en algún sitio.
Si ya has hecho esta comprobación, y aún así, te sigue dando el error, lo siguiente a comprobar (que ha sido mi salvación), es que NO tengas nada en la papelera de reciclaje. Y recuerda, que SharePoint tiene “2 papeleras”:
![clip_image002[4] clip_image002[4]](http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmanez/clip_5F00_image0024_5F00_thumb_5F00_18373C0D.jpg)

![clip_image002[7] clip_image002[7]](http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmanez/clip_5F00_image0027_5F00_thumb_5F00_6C56C250.jpg)
Tras esto, si desactivas la feature, el tipo de contenido debería de desaparecer.
Espero que os sirva, y si no, ya sabes:


Saludos!!
Hoy me preguntaba cuántas funciones del Excel 2010 (el cliente, el de toda la vida), son compatibles con Excel Web App (en el Explorador). Pues bien, están perfectamente documentadas por Microsoft, y la sorpresa es que prácticamente todas las de Excel 2010, están disponibles para Excel Web App.
El listado de todas las funciones, lo tenemos aquí:
http://office.microsoft.com/en-us/web-apps-help/excel-functions-alphabetical-HA010342655.aspx
Mientras que las diferencias que nos podemos encontrar, entre usarlas en Excel 2010, o en Excel Web App, se resumen en la siguiente tabla:

Y también tenemos el Intellisense desde el navegador!

Por otro lado, os cuento algo que me ha extrañado muchísimo, y que me ha hecho perder 10 minutos de búsqueda:
Desde Excel Web App, NO se pueden añadir (ni eliminar) hojas al libro.
Por si no os lo creéis (yo no me lo creía…), aquí os dejo un post del foro de Office 365, donde un ingeniero de MS lo confirma:
http://community.office365.com/en-us/f/175/t/8239.aspx
Para añadir y eliminar hojas del libro, hay que pasar por el Excel cliente.
Saludos!!
En este post vamos a ver como podemos añadir usuarios externos a la organización, en una lista de distribución.
Para ello, deberemos ser un usuario con permisos para administrar la organización. Una vez logado en OWA, nos vamos a “Opciones”:

Dentro de “Todas las opciones”, nos aseguramos de seleccionar “Administrar Mi organización”

Dentro de “Usuarios y grupos”, entramos en “Contactos externos”, y añadimos los emails externos que queremos añadir a la lista de distribución.


Una vez añadido el contacto externo, ya podemos añadirlo a nuestra lista de distribución.

Editamos nuestra lista de distribución, seleccionando la lista, y pulsando en “Detalles”
En la pantalla de edición de lista, pulsamos en la sección “Pertenencia”, y en el botón “Agregar”

En la ventana de selección de usuarios, buscamos los usuarios externos que añadimos anterioremente. Fijaros como los usuarios externos, tienen un icono diferente a los usuarios de la organización.

Añadimos el usuario, guardamos nuestra lista de distribución, y ya lo tenemos.
Espero que os sirva.
Saludos!!
Una de las características de OWA en Office 365, es la posibilidad de agrupar los correos, según el asunto del mismo. Es lo que se llama “Conversaciones”. Esto te agrupa aquellos emails reenviados, respuestas, etc, sobre un mail original. Me refiero a esto:

Sin embargo, yo no consigo acostumbrarme a esta vista, así que, si os pasa como a mi, podemos evitar esta agrupación por Conversaciones, si expandimos el menú “Ver”

Y desmarcamos la opción: “Usar conversaciones”
Saludos!!
Como ya sabréis, desde Sky Drive, podemos usar las Office Web Applications para crear documentos Office.
En este post, vamos a ver lo sencillo que es compartir un documento.

Disponemos de varias opciones a la hora de compartir el documento:
- Podemos enviarlo por correo electrónico:

De esta forma llega un mail al usuario, con un enlace al documento:

El usuario puede acceder al documento, y con una cuenta Live ID, puede editarlo y trabajar conjuntamente con su creador.
Una vez lo hemos enviado para compartir, si volvemos sobre la opción “Compartir”, podemos editar los permisos que queremos que tenga el usuario al que se lo hemos enviado:

También podemos volver a compartir con otras personas.
- Compartir en redes sociales: Podemos vincularnos a diferentes redes sociales, y compartir el archivo en ellas. Aquí tenemos el listado completo de todas las redes compatibles: https://profile.live.com/cid-bbe19230d69f94c5/Services/ Por ejemplo, si me vinculo con Facebook, tenemos:

Y aparece publicado en mi muro:

- Compartir mediante vínculo. Podemos crear un vínculo para compartir el archivo, con 3 niveles de permisos:

No sé a vosotros, pero a mi me encanta la facilidad de trabajo con las Office Web Apps, y podemos compartir archivos a través de un servicio como Sky Drive.
Saludos!!
Supongamos que tenemos nuestra web pública, creada con Office 365. Sería algo así:

Ahora imaginemos que queremos colocar varios documentos, para descarga de cualquier usuario que visite la web (casos de éxito, fichas de producto, portfolio, etc).
Para ello, podemos usar la biblioteca de documentos, que viene por defecto en nuestro sitio, o podemos crear nuestra propia biblioteca. Yo he creado una nueva biblioteca de documentos, llamada “Casos de exito”, y he subido un par de archivos, que quiero publicar para que pueda descargarlos cualquier usuario que visite mi web pública.

El siguiente paso, es hacer visibles esos documentos. Por desgracia, no existe un webpart de biblioteca, al estilo de los sitios de grupo, pero sí tenemos la posibilidad de crear hipervínculos a los documentos.
Por ejemplo, vamos a editar la página principal, y añadir una zona de Casos de éxito

Antes de añadir los enlaces, volvemos a la biblioteca de documentos, y copiamos el acceso directo a cada documento que queremos:

Volvemos a editar la página, y para cada documento creamos un Hipervínculo, desde la Ribbon.
Elegimos la opción de Sitio Web, y pegamos el enlace al documento (y editamos el texto a mostrar)

Nota: Como veis en la imagen, tenemos la opción de vincular un documento de la biblioteca “Mis Documentos”, que nos pone fácil la selección del documento, y no hay que ir copiando y pegando links. Sin embargo, si vamos a tener muchos documentos, y de varios “tipos”, probablemente sea más fácil de administrar, si creamos varias bibliotecas.
Aceptamos, guardamos la página, y ya tenemos preparado nuestra sección de casos de éxito.

Nota: Con este método, el link será un enlace a ver el documento en el navegador, si lo que queremos es que el usuario descargue el archivo directamente, tendremos que editar el enlace, para que apunte sólo al documento. Sería: sitio_web + nombre_biblioteca + nombre_documento. En este sentido, el enlazar documentos desde la biblioteca de Mis documentos, es más sencillo, ya que el hipervínculo que crea, es de esta forma.
Como vemos, los sitios públicos de Office 365, todavía necesitan alguna vuelta más, pero al menos, tenemos varios “workarrounds”, para poder hacer lo que necesitamos.
Saludos!!
Hace un tiempo me preguntaron si sería posible usar el AjaxControlToolkit dentro de SharePoint 2010.
Mi respuesta rápida fue que sí, que tan sólo bastaría con descargar el AjaxControlToolkit de la versión basada en el .NET Framework 3.5, que es la base de SharePoint 2010.
Sin embargo, cuando me puse a ello, no fue tan sencillo. Al parecer, las últimas versiones del AjaxControlToolkit, aún estando basadas en .NET 3.5, no son compatibles con SharePoint.
Finalmente, conseguí hacerlo funcionar, siguiendo las indicaciones de este post:
Ajax Control Toolkit with SharePoint 2010
Una vez conseguí hacerlo funcionar, me pregunté si sería viable en Office 365, y no, no lo es. Como no tenía muy claro el motivo de que no funcionase, rebusqué bastante por la web, hasta que me encontré un comentario del inmenso Wictor Willen en un post que trataba el tema.
Según comenta el propio Wictor aquí:
“Hi, this is not a bug. It’s a feature of the Sandbox. The SB creates its own copy of the Page object and “copies” some information from the real Page object to the SB page object – but not everything such as the ScriptMgr reference etc.”
Y para acabar, después de mis peripecias, mi recomendación se orienta más a no usar los controles del Toolkit, y tirar más hacia jQuery, y su extensión jQuery.UI
Saludos!
Lo que se pretende conseguir en este post, es que los “detectores” de fuentes RSS de los navegadores web, detecten la RSS de nuestro sitio público, que queremos establecer por defecto.
Me refiero a que, por ejemplo, si entramos en un sitio público de SharePoint, no tengamos desactivado, lo siguiente:

Antes de empezar con el cómo, os paso un link de cómo configurar las RSS en SharePoint 2010 (algo sencillísimo). Este link además, incluye cómo hacerlo por power-shell:
http://get-spscripts.com/2010/11/enabling-and-configuring-sharepoint-rss.html
A partir de aquí, tendremos la opción de RSS en la configuración de cualquier lista/biblioteca de SharePoint:


Volviendo a nuestro objetivo, conviene aclarar, que, para que un navegador detecte la fuente RSS, se utiliza el siguiente código HTML:
1: <link rel="alternate"
2: type="application/rss+xml"
3: title="Tasks"
4: href="/_layouts/listfeed.aspx?List=845f5cb5%2D09dd%2D4930%2D8534%2D61110a2df788" />
SharePoint ya se encarga de añadir ese HTML, siempre que estemos navegando por una lista/biblioteca que tenga las RSS activadas, tal y como vemos en esta imagen:

Sin embargo, no ocurre así cuando estamos en un sitio de publicación. En estos sitios, lo normal es activar las RSS de la biblioteca de páginas, ya que será lo que más interesa al usuario final.
En estos casos, cuando el usuario navega por páginas de la biblioteca de páginas, SharePoint no incluye el HTML de la RSS, y el usuario, se lleva la sensación de que no hay ninguna fuente RSS.
Podemos solucionarlo de forma muy sencilla, editando la MasterPage del sitio de publicación, e incluyendo ese HTML. Sin embargo, para este post, vamos a resolverlo de forma algo más “elegante”, a través de una Feature, que hará uso de los controles delegados de SharePoint.
Para saber qué es un Control delegado, podemos revisar los siguientes enlaces:
- Blog del CIIN: http://geeks.ms/blogs/ciin/archive/2011/10/22/sharepoint-2010-controles-delegados-i.aspx
- Blog Chris O’Brien http://www.sharepointnutsandbolts.com/2007/06/using-delegate-control.html
Nosotros vamos a “sobrescribir” el control delegado: “AdditionalPageHead”, que se sitúa dentro del HEAD de la página.
Primero de todo, vamos a crear un User Control, que sustituirá el Control delegado. Podéis ver aquí la estructura del proyecto SharePoint, y el código del control.

1: <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
2: <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
3: <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
4: <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
5: <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
6: <%@ Import Namespace="Microsoft.SharePoint" %>
7: <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
8: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SetDefaultRssLinkControl.ascx.cs" Inherits="Spartans.Sharepoint.DefaultRss.ControlTemplates.Spartans.Sharepoint.DefaultRss.SetDefaultRssLinkControl" %>
9: <link rel="alternate"
10: type="application/rss+xml"
11: title="Fuentes RSS"
12: href="http://team.heroes.lab/_layouts/listfeed.aspx?List=%7B845F5CB5%2D09DD%2D4930%2D8534%2D61110A2DF788%7D&Source=http%3A%2F%2Fteam%2Eheroes%2Elab%2FLists%2FTasks%2FAllItems%2Easpx" />
En el href del control, pondremos el link de la fuente RSS. Dicho link es muy sencillo de averiguar, basta con acceder a la biblioteca, y usar el botón RSS:

Lo siguiente que debemos decirle a SharePoint, es que utilice nuestro control, en lugar del control delegado. Para ello, creamos un nuevo item de tipo “Empty element”, y editamos el fichero Elements.xml:
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <Control Id = "AdditionalPageHead"
4: Sequence="50"
5: ControlSrc="~/_ControlTemplates/Spartans.Sharepoint.DefaultRss/SetDefaultRssLinkControl.ascx" />
6: </Elements>
Si desplegamos nuestra feature, y volvemos a nuestro sitio de publicación, tenemos:

y esto es así, porque nuestro código HTML, se ha ampliado en el HEAD, con el código HTML

Espero que os sirva.
Un saludo!!
Si tu solución de SharePoint posee varios webparts, quizá quieras considerar lo que os cuento en breve, de cara a tener una organización de los items del proyecto algo más limpia, y evitar entradas SafeControl innecesarias en el web.config.
Imaginemos que nuestra solución tiene 3 webparts visuales, añadidos a través de la plantilla de Visual Studio. Quedaría algo así:

Para empezar, fijaros en los NameSpaces que tenemos, para cada webpart:
1: namespace Spartans.Sharepoint.OrganizedWebparts.VisualWebPart3
2: //...
3: namespace Spartans.Sharepoint.OrganizedWebparts.VisualWebPart2
4: //...
5: namespace Spartans.Sharepoint.OrganizedWebparts.VisualWebPart1
Un poco “feo” bajo mi punto de vista. Además, si nos vamos a las propiedades de cada webpart, y nos fijamos en la colección de Safe Control Entries:


Vemos que tenemos una entrada SafeControl, y lo mismo para el resto de webparts. Esto hará, que al desplegarlo, tengamos 3 entradas en nuestro Web.Config:
1: <SafeControl Assembly="Spartans.Sharepoint.OrganizedWebparts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=76693daf4f35b7d3" Namespace="Spartans.Sharepoint.OrganizedWebparts.VisualWebPart1" TypeName="*" Safe="True" SafeAgainstScript="False" />
2: <SafeControl Assembly="Spartans.Sharepoint.OrganizedWebparts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=76693daf4f35b7d3" Namespace="Spartans.Sharepoint.OrganizedWebparts.VisualWebPart2" TypeName="*" Safe="True" SafeAgainstScript="False" />
3: <SafeControl Assembly="Spartans.Sharepoint.OrganizedWebparts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=76693daf4f35b7d3" Namespace="Spartans.Sharepoint.OrganizedWebparts.VisualWebPart3" TypeName="*" Safe="True" SafeAgainstScript="False" />
¿No sería más limpio organizar los Namespaces de forma algo más lógica, y sólo tener una entrada a nivel de web.config, que incluya todos los webparts de nuestra solución?
Vamos a ello !!
Primero de todo, ya que los webparts visuales se basan en controles de usuario, y es posible que nuestra solución tenga otros controles de usuario, vamos a añadir la carpeta mapeada de SharePoint “ControlTemplates”, y creamos una carpeta para todos nuestros controles:

Ahora vamos a mover los controles de usuario que usan los webparts visuales, a esa carpeta. Y ya que estamos, vamos a cambiar el Namespace de los 3 controles, para que todos pertenezcan al mismo Namespace.
1: namespace Spartans.Sharepoint.OrganizedWebparts.Web.UI
Recordar que al cambiar el Namespace, también lo tenemos que hacer en el fichero .ascx, en el atributo “Inherits” de la directiva “Control”:
1: <%@ Control
2: Language="C#"
3: AutoEventWireup="true"
4: CodeBehind="VisualWebPart3UserControl.ascx.cs"
5: Inherits="Spartans.Sharepoint.OrganizedWebparts.Web.UI.VisualWebPart3UserControl" %>
Ahora tenemos que cambiar algunas cosas de los webparts.
Primero de todo, ya que no queremos varias entradas SafeControl en el web.config, las eliminamos de las propiedades.

Lo siguiente es re-apuntar a la nueva ubicación de los controles:
1: [ToolboxItemAttribute(false)]
2: public class VisualWebPart3 : WebPart
3: {
4: // Visual Studio might automatically update this path when you change the Visual Web Part project item.
5: private const string _ascxPath = @"~/_CONTROLTEMPLATES/OrganizedControls/VisualWebPart3UserControl.ascx";
6:
7: protected override void CreateChildControls()
8: {
9: Control control = Page.LoadControl(_ascxPath);
10: Controls.Add(control);
11: }
12: }
Y ya que nos ponemos, vamos a cambiar el Namespace de los webparts, y agruparlos en el mismo:
1: namespace Spartans.Sharepoint.OrganizedWebparts.Web.UI.Webparts
Al cambiar el Namespace, tenemos que actualizar también el fichero .webpart
1: <?xml version="1.0" encoding="utf-8"?>
2: <webParts>
3: <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
4: <metaData>
5: <type name="Spartans.Sharepoint.OrganizedWebparts.Web.UI.Webparts.VisualWebPart1, $SharePoint.Project.AssemblyFullName$" />
6: <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
7: </metaData>
8: <data>
9: <properties>
10: <property name="Title" type="string">Oraganized webparts VisualWebPart1</property>
11: <property name="Description" type="string">This is webpart 1, from Organized webparts sample</property>
12: </properties>
13: </data>
14: </webPart>
15: </webParts>
Para acabar, nos falta configurar la solución para que genere una única entrada de SafeControl en el web.config. Para ello, vamos a utilizar el editor del Manifest del paquete de nuestra solución. Este editor, permite combinar el XML que ha autogenerado Visual Studio, con nuestros propios valores insertados en el cuadro de texto.

Añadimos nuestra entrada de SafeControl:
1: <?xml version="1.0" encoding="utf-8"?>
2: <Solution xmlns="http://schemas.microsoft.com/sharepoint/">
3: <Assemblies>
4: <Assembly Location="Spartans.Sharepoint.OrganizedWebparts.dll" DeploymentTarget="GlobalAssemblyCache">
5: <SafeControls>
6: <SafeControl Assembly="Spartans.Sharepoint.OrganizedWebparts" Namespace="Spartans.Sharepoint.OrganizedWebparts.Web.UI.Webparts" TypeName="*" />
7: </SafeControls>
8: </Assembly>
9: </Assemblies>
10: </Solution>
Si hacemos el Deploy de la solución, ya vemos que tenemos una única entrada SafeControl en el web.config:
1: <SafeControl Assembly="Spartans.Sharepoint.OrganizedWebparts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=76693daf4f35b7d3"
2: Namespace="Spartans.Sharepoint.OrganizedWebparts.Web.UI.Webparts"
3: TypeName="*"
4: Safe="True"
5: SafeAgainstScript="False" />
Al indicar el TypeName como “*”, estamos incluyendo todos los controles de ese Namespace (todos nuestros webparts de la solución).
Si además, vemos nuestra DLL con algún “Decompiler” (Reflector, ILSpy, JustDecompile…), vamos que nuestro namespaces, webparts y controls, están ordenaditos:

Si tenemos una solución con mucho desarrollo personalizado, seguro que agradecemos este orden.
Espero que os sirva.
Saludos!!
30
Sinceramente, desconozco el motivo, pero mi SharePoint Online no viene por defecto con los tipos de contenido de Office (excepto Word, que es el tipo por defecto para las bibliotecas de documentos).
En este post he encontrado la solución, aunque no la explicación:
http://office.microsoft.com/en-us/sharepoint-online-enterprise-help/add-multiple-office-templates-to-a-document-library-HA102409514.aspx
Tras seguir los pasos, que básicamente consiste en crear un nuevo tipo de contenido personalizado, que hereda de documento, y configurar sus propiedades avanzadas, donde en la plantilla a utilizar, la damos un fichero en blanco de tipo Office que queramos.
En ese mismo post, pone la siguiente nota:
“if your organization is using SharePoint Online/Microsoft Office 365, and you use the Microsoft Office Web Applications instead of Microsoft Office client programs, you must follow the steps in this article to enable users to create multiple Microsoft Office document types in a document library from within the browser.”
Esto pretende ser la explicación de por qué no aparecen esos tipos de contenido por defecto. Pero como os digo, pues no lo tengo muy claro, ya que en mi caso, usamos los clientes de Office. Al menos hasta donde yo lo entiendo.
Sea como sea, por lo menos tenemos una solución. Yo lo he hecho con OneNote, y funciona bien:

Si alguien sabe el motivo, que lo deje como comentario y actualizaré el post. Yo voy a seguir indagando.
Saludos!!
¿Te va lento tu sitio de SharePoint? … menuda preguntita
Si la respuesta es que sí, o al menos, crees que sí, es posible que este post te pueda ayudar. Ojo, no voy a preguntar, cómo has llegado hasta esa “lentitud”, y ya te aseguro, que habrá muchas más soluciones, pero aquí vamos a ver una posible solución, bastante rápida de probar, y de deshacer en caso de que no te sirva.
Otra condición para que te pueda ser útil tu post, es que tu desarrollo haga uso de UsersControls de asp.net (si tienes webparts visuales, tienes UserControls
)
Y la última condición, es la de siempre, cuando se trata de Cache, y es que la información que muestras en ese caso, no necesitas que sea “tiempo real”
Un caso concreto, bastante típico, es cuando has desarrollado algún control para una navegación personalizada. Es muy posible que tengas algoritmos recursivos complejos, que penalizan el rendimiento, y también es muy posible, que ese menú, cambie muy de vez en cuando.
Al lío. Partimos de un visual webpart. Si queremos cachear el contenido que genera ese user control, es tan sencillo como usar la directiva OutputCache sobre el .ascx:
1: <%@ OutputCache Duration="10" VaryByParam="None" %>
El atributo Duration indica el tiempo que se cacheará el contenido, y se expresa en segundos. El atributo VaryByParam, ahora luego lo explicaremos. De momento lo dejamos a “None”, que indica que no se tenga en cuenta (es obligado indicar algún valor).
Para probar que se cachea, vamos a añadir una etiqueta a nuestro control, que muestre la hora actual:
1: public partial class CachedWebPartUserControl : UserControl
2: {
3: protected void Page_Load(object sender, EventArgs e)
4: {
5: String message = String.Format("Time: {0}", DateTime.Now);
6: lblInfo.Text = message;
7: }
8: }
Hacemos el deploy y lo añadimos a una página.

No se puede ver, pero cuando refresco el navegador, el valor sigue siendo el mismo, hasta dentro de 10 segundos, que se refresca a la hora actual. Funciona!! 
¿Y que ocurre si mi webpart, muestra datos en función de algún parámetro que llega por QueryString? Pues para eso, podemos utilizar el VaryByParam, indicando el nombre del parámetro que viaja en la querystring:
1: <%@ OutputCache Duration="10" VaryByParam="option" %>
Si modificamos ligeramente el código del usercontrol con:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: string option = Request.QueryString["option"];
4:
5: if (String.IsNullOrEmpty(option))
6: {
7: option = "A";
8: }
9:
10: String message = String.Format("QuestyString option: {1}. Time: {0}", DateTime.Now, option);
11: lblInfo.Text = message;
12: }
Y volvemos a probar, veremos que en este caso, el contenido se cachea según el valor de la querystring “option”. Por ejemplo, cargamos la página por primera vez, y obtenemos:
QuestyString option: A. Time: 3/23/2012 6:29:54 PM
Si acto seguido (antes de que pasen los 10 segundos), cargamos la página de nuevo, pero pasando por querystring: “?option=B”, tenemos:
QuestyString option: B. Time: 3/23/2012 6:29:58 PM
Fijaros que todavía no se han cumplido los 10 segundos, y vemos un valor actualizado con la “option=B”.
Te recomiendo que le eches un vistazo a todas las posibilidades de la directiva OutputCache, ya que tiene más opciones que quizá te interesen (por ejemplo, cachear, no en función de un parámetro, sino del valor que tome otro control: listbox, textbox, etc).
Para acabar, otra recomendación importante, es que antes de hacer nada, midas que es lo que está causando ese mal rendimiento. Porque: ¿seguro que va lento? ¿seguro que es un problema de tu código? (igual es la red, o que el servidor está mal dimensionado, o la instalación, o la alineación de Júpiter con Saturno…)
Para medir esto, podemos utilizar 2 objetos:
Lecturas recomendadas:
Articulos panel del desarrollador (Por Gustavo Velez):
http://www.gavd.net/servers/sharepointv4/spsv4_item.aspx?top=4&itm=972
http://www.gavd.net/servers/sharepointv4/spsv4_item.aspx?top=art&itm=1417
http://www.gavd.net/servers/sharepointv4/spsv4_item.aspx?top=1&itm=1433
Serie “Developing for Perfomance” (por Tobias Zimmergren)
http://www.zimmergren.net/technical/sp-2010-developing-for-performance-part-1-developer-dashboard
Ya hace un tiempo que tenemos disponible Lync para iPad, pero todavía no lo había probado, y la verdad, es que me ha sorprendido gratamente.
Podéis descargarlo desde iTunes (http://itunes.apple.com/us/app/microsoft-lync-2010-for-ipad/id484222449?mt=8), y es muy sencillo de configurar. Lo único que os puede marear, es en el caso de que estéis utilizando más de un dominio de Office 365: por ejemplo, el típico de “nnn.onmicrosoft.com”, y el corporativo de la empresa: “fabrikam.com”.
En este caso, tenemos que introducir 2 nombres de usuario diferentes. El primero es el del dominio “nnn.onmicrosoft.com”, mientras que el segundo, es el usuario de tu dominio corporativo: “fabrikam.com”

Y una vez configurado, ya podemos usar lync desde el iPad:

Espero que os sirva.
Saludos!!
Seguramente, si habéis desarrollado alguna solución para SharePoint, más allá de los típicos webparts, habréis necesitado almacenar “parámetros” de configuración, por ejemplo, la URL de un servicio web en Azure, tu AppId para usar Bing Maps, etc.
Existen varias opciones para hacer esto, yo hoy os voy a hablar de usar las PropertyBags. En SharePoint, la mayoría de los objetos, tienen una propiedad “Properties” que suele ser un HashTable o un SPPropertyBag para poder almacenar propiedades en modo key-value.
Algunas clases que contienen esa propiedad son:
Si queremos provisionar valores a ese campo de forma declarativa, lo podemos hacer usando un elemento Module, de Visual Studio.
En su Elements,xml, usaremos el nodo PropertyBag. En el MSDN está perfectamente explicado el significado de cada propiedad. Yo os dejo un ejemplo de uso de todas las combinaciones posibles:
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <!--Propiedad creada a nivel de 'site collection'-->
4: <PropertyBag HyperlinkBaseUrl="http://team.heroes.lab" Url="" ParentType="Web" RootWebOnly="TRUE">
5: <Property Name="ProductsListGuid" Value="2b2b944d-8cc8-4448-bcb2-9478d0787175" Type="string" />
6: </PropertyBag>
7: <!--Propiedad creada a nivel de sub-site-->
8: <PropertyBag HyperlinkBaseUrl="http://team.heroes.lab/sites/site1" Url="" ParentType="Web" RootWebOnly="FALSE">
9: <Property Name="ProductsListGuid" Value="2b2b944d-8cc8-4448-bcb2-9478d0787175" Type="string" />
10: </PropertyBag>
11: <!-- Propiedad creada a nivel de File, en este caso para una Master Page-->
12: <PropertyBag HyperlinkBaseUrl="http://team.heroes.lab/" Url="_catalogs/masterpage/default.master" ParentType="File" RootWebOnly="FALSE" />
13: <!-- Propiedad creada a nivel de SPListItem, item ID 23 de la lista Products -->
14: <PropertyBag HyperlinkBaseUrl="http://team.heroes.lab/sites/site1" Url="Lists/Products" ParentType="ListItem" ItemIndex="23">
15: <Property Name="DiscountPercentage" Value="10" Type="int" />
16: </PropertyBag>
17: </Elements>
Con esto, al desplegar nuestra solución, provisionaremos esas Properties a nuestros elementos (webs, ficheros o items de listas).
Para acabar, un simple ejemplo de como iterar por esa bolsa de propiedades. En este caso, recorremos las Properties del SPWeb raíz:
1: SPWeb rootWeb = SPContext.Current.Site.RootWeb;
2:
3: foreach (DictionaryEntry entry in rootWeb.AllProperties)
4: {
5: string property = String.Format("{0}, {1}{2}", entry.Key, entry.Value, Environment.NewLine);
6: txtPropertyBag.Text += property;
7: }
Espero que os sirva.
Un saludo!!
Recientemente, he tenido que cambiar GUIDs, nombres y demás, a un proyecto SharePoint de Visual Studio.
Pues bien, si se cambia el GUID de una clase que es manejadora de los eventos de una Feature:
1: /// <summary>
2: /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
3: /// </summary>
4: /// <remarks>
5: /// The GUID attached to this class may be used during packaging and should not be modified.
6: /// </remarks>
7: [Guid("bbd1a0cd-e938-4483-8328-e63209dc2f1c")]
8: public class MyProjectEventReceiver : SPFeatureReceiver
Tendremos que cambiar también el ID que aparece en las propiedades de la Feature, desde Visual Studio.

Sin embargo, si usamos la herramienta para generar GUIDs de Visual Studio:

Nos generará un GUID en mayúsculas, que si tal cual colocamos, tanto en el fichero de la clase, como en las propiedades de la feature, al desplegarlo en SharePoint, no encontraremos el pantallazo de error.
No sé si, porque me sonaba de haber leído algo parecido, o porque lo soñé, o porque ya llevo mis añitos viendo cosas “raras”, se me ocurrió que podía ser que el GUID debiera estar en minúsculas, así que, a ello fui. Y, sin cambiar nada más, la cosa funcionó!!, así que me temo que esa era la causa.
Espero que os sirva.
Saludos!!
Previously on Fringe…
Digo, anteriormente vimos cómo referenciar hojas de estilos con rutas relativas a una colección de sitios de SharePoint Online, o a un sitio concreto. Sin embargo, esa misma técnica, no es aplicable si lo que queremos son añadir referencias a archivos .js.
Si intentamos hacer algo como lo siguiente:
1: <script type="text/javascript" src="<%$SPUrl:~SiteCollection/Style Library/JQUERY/mainFunctions.js%>"></script>
Obtendremos una pantalla de error, con su correspondiente CorrelationID. En ese mismo error, ya veremos una pista de cómo resolverlo. Ya que nos dirá que debemos sustituirlo por un asp:literal.
Si le hacemos caso, y lo colocamos en el lugar adecuado, obtendremos el resultado esperado. Quedando como:
<script type="text/javascript" src='<asp:Literal runat="server" Text="<%$SPUrl:~SiteCollection/Style Library/JQUERY/mainFunctions.js%>" />'></script>
Otra opción que también parece funcionar, consiste en utilizar el control de SharePoint ScriptLink
1: <SharePoint:ScriptLink ID="MyScriptLink1" Name="~sitecollection/Style Library/Home/JS/myscript.js" runat="server" />
Saludos!!
Hoy me he encontrado que algo tan “sencillo”, como añadir “options” a un campo de tipo SPFieldChoice, no es tan sencillo cuando lo hacemos en SharePoint online.
Si queremos añadir una opción más a un campo dado, el código sería tan sencillo como:
1: try
2: {
3: SPList list = SPContext.Current.Web.Lists.TryGetList("Products");
4:
5: if (list == null)
6: {
7: throw new SPException("List not found");
8: }
9:
10: SPFieldChoice fieldChoice = list.Fields.GetField("ChoiceColumn") as SPFieldChoice;
11: fieldChoice.Choices.Add("New option");
12:
13: fieldChoice.Update();
14: }
15: catch (Exception ex)
16: {
17: TextBox1.Text = ex.ToString();
18: }
Si eso mismo, lo desplegamos en una solución de granja, funciona perfectamente.
Sin embargo, si lo hacemos en una solución sandbox, no obtendremos ningún error, pero la opción nunca se añadirá al SPFieldChoice.
En principio, la clase SPFieldChoice es perfectamente válida en Sandboxed solutions, su propiedad Choices también lo es.
El motivo lo desconozco por completo, y además, me parece rarísimo, ya que he revisado con Reflector el código del método UpdateInternal, y me parece de lo más sencillo, así que no me explico que puede haber diferente en la dll de la Sandbox, para que no funcione.
Por suerte, sí tenemos solución, y es tan “sencilla”, como editar la propiedad SchemaXml, y añadirle el XML necesario para la nueva Opción. Aquí podemos ver un ejemplo:
1: <Field Type="Choice" DisplayName="ChoiceColumn" Required="FALSE" EnforceUniqueValues="FALSE" Indexed="FALSE" Format="Dropdown" FillInChoice="FALSE" ID="{5a7765f4-07c7-4dd9-8237-1f73174bede0}" SourceID="{e71844c7-9724-47c7-92d1-6c279e3ad8a0}" StaticName="ChoiceColumn" Name="ChoiceColumn" ColName="nvarchar3" RowOrdinal="0" Version="3">
2: <Default>Option 1</Default>
3: <CHOICES>
4: <CHOICE>Option 1</CHOICE>
5: <CHOICE>Option 2</CHOICE>
6: <CHOICE>Option 3</CHOICE>
7: <CHOICE>New option</CHOICE>
8: </CHOICES>
9: </Field>
Esto lo podemos hacer bien sencillo con LINQ to XML:
1: //Get SPFieldChoice from desired List
2: SPFieldChoice fieldChoice = GetChoiceColumn();
3:
4: //Parse SchemaXml property as XElement
5: XElement fieldXml = XElement.Parse(fieldChoice.SchemaXml);
6:
7: //Create XElement node: <CHOICE>now</CHOICE>
8: XElement choice = new XElement("CHOICE");
9: choice.SetValue("Added_" + DateTime.Now.ToString());
10: //Get CHOICES node and Add new CHOICE node
11: fieldXml.Element("CHOICES").Add(choice);
12: //Update SchemaXml and Field
13: fieldChoice.SchemaXml = fieldXml.ToString();
14: fieldChoice.Update();
Y así, podemos añadir una nueva opción a nuestro campo SPFieldChoice en soluciones Sandbox.
Saludos!!
Si habéis guardado algún sitio de Office 365 como plantilla, y desplegáis la solución en otro site o colección de sitios, es posible que os encontréis un error al intentar desactivar la solución.
Seguramente os ocurrirá si habéis estado creando y eliminando sitios basados en esa plantilla.
Para poder desactivar la solución sin que os falle, primero, obviamente, tendremos que asegurarnos de que no hay ningún site existente basado en esa plantilla.
Además, y esto ya no es tan evidente, es que te asegures que no tienes nada relacionado con esa plantilla, en la papelera de reciclaje:

Y lo último, y nada evidente, es que compruebes esto mismo, en la “otra” papelera de reciclaje (sí, es la misma papelera, pero tiene 2 vistas diferentes, y desde el link anterior, sólo vemos una de ellas):

Y dentro de esta, revisa las 2 vistas disponibles:

Que por cierto, las 2 vistas tienen el mismo nombre, pero creo que es por una mala traducción del Inglés, ya que en inglés se llaman:
- End user recicle bin items
- Deleted from end user recicle bin items
Después de eliminar todo lo relacionado con esa plantilla (sitios eliminados que estaban basados en esa plantilla), ya deberías poder desactivar la solución sin problemas.
Nada más, agradecer a mi compañero Juan Moreno, que se dio unos cuantos cabezazos hasta encontrar esa “papelera escondida” 
Saludos!!
Hace un tiempo os hablé de la SharePoint Software Factory. Pues bien, hace unos días que se ha liberado una nueva versión, la 3.2
Os copio la lista de novedades, y os pongo algún pantallazo de mis favoritas 
- Menu "List And Doc": Linq to SharePoint (imports the schema of several lists to LINQ classes)
- Menu "BCS": Simple BCS Model
- Menu "BCS": Import BCS Model from Database
- Menu "BCS": Model BCS Model with classes
- Menu "BCS": Quick Deploy BCS Model (undeploys/deploys BCS model via powershell)
- Menu "Security": Minimal CAS, Medium CAS, recipes for single CAS Policy Items etc.
- Menu "ASP.NET": WCF Webservice
- code snippets added, partly from http://spcodesnippets.codeplex.com Thx to Ayman El-Hattab (http://aymanelhattab.com)
- Added custom FxCopDictionary to allow project specific exclusions for abbreviations, keyword, acronyns etc. Dictionary will be automatically used in Realase build configuration.
Fijaros que maravilla para generar un data context de LINQ to SharePoint:

Tras el asistente, nos genera, por un lado, un fichero XML de configuración del SPMetal, por si queremos repetir la generación, y por otro lado, 2 ficheros con una clase parcial para el contexto.
1: <?xml version="1.0" encoding="utf-8"?>
2: <!--
3: Use this file to re-import the lists for LINQ to SharePoint
4: Imported from URL: http://team.heroes.lab/
5: Call to SPMetal: "C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\BIN\spmetal.exe" /web:"http://team.heroes.lab/" /parameters:"E:\ORIGEN\Alejandria\Lab\SPSF.v32.ApplicationSample\Components\LinqToSharePoint1\LinqToSharePoint1Context.xml" /language:csharp /namespace:SPSF.v32.ApplicationSample.Components /code:"E:\ORIGEN\Alejandria\Lab\SPSF.v32.ApplicationSample\Components\LINQToSharePointDefinitions\LinqToSharePoint1\LinqToSharePoint1Context.designer.cs"
6: -->
7: <!-- Code initially generated with SharePoint Software Factory 2010, Version 3.2 , spsf.codeplex.com -->
8: <Web
9: AccessModifier="Public"
10: Class="LinqToSharePoint1Context" xmlns="http://schemas.microsoft.com/SharePoint/2009/spmetal">
11: <List
12: Name="Announcements">
13: <ContentType
14: Name="Anuncio">
15: <Column
16: Name="ContentType" />
17: <Column
18: Name="Title" />
19: <Column
20: Name="Body" />
21: <Column
22: Name="Expires" />
23: <ExcludeOtherColumns />
24: </ContentType>
25: <ContentType
26: Name="Carpeta">
27: <Column
28: Name="ContentType" />
29: <Column
30: Name="Title" />
31: <Column
32: Name="FileLeafRef" />
33: <Column
34: Name="ItemChildCount" />
35: <Column
36: Name="FolderChildCount" />
37: <ExcludeOtherColumns />
38: </ContentType>
39: </List>
40: <ExcludeOtherLists />
41: <ExcludeOtherContentTypes />
42: </Web>
También podemos añadir servicios de WCF, donde la plantilla ya prepara el package para su despliegue en el servidor de SharePoint:


Otra novedad es que se han añadido numerosos code-snippets. Aquí tenemos las categorías:

Destacar también que dispone de un asistente para migrar a esta última versión, proyectos realizados en la versión anterior.
Un saludo!!
Cuando se realiza una búsqueda en SharePoint, se aplica un filtrado de los resultados, según el usuario que lanza la query. Es decir, si un usuario no tiene permisos sobre una lista concreta, obviamente, los resultados que hagan referencia a esa lista, no le aparecerán al usuario.
Ahora bien, hoy me he encontrado con un caso que no cumplía esta premisa, y que puede ser bastante frecuente durante la fase de desarrollo del proyecto. Resulta que estaba lanzando una búsqueda con un usuario que era Colaborador del site, por lo que tiene permisos para ver y editar todas las listas, y sin embargo, en las búsquedas, no me devolvía ningún resultado. Sin embargo, me iba a una lista cualquiera, y podía ver y editar un item que cumplía con la query de búsqueda.
De hecho, si hacía la misma búsqueda con otro usuario colaborador, sí me salían resultados válidos. ¿¿??
Pues bien, aquí van los motivos:
- No tenía programado ningún crawling, ni completo ni incremental. Al ser un entorno de desarrollo, lo que hago es forzar el crawl según necesito.
- El usuario que no devolvía resultados de la búsqueda, lo había añadido al sitio, después de haber hecho el último crawl.
- Al forzar un nuevo crawling, y probar de nuevo con el usuario que no devolvía nada, ahora, sí me devolvía los resultados de búsqueda esperados.
La conclusión es que el índice de búsquedas que monta SharePoint, copia mucha información del contenido, incluyendo, los permisos de los usuarios.
Para comprobarlo, he repetido el proceso:
- He quitado del site a otro usuario que era colaborador
- He forzado un nuevo crawling
- He vuelto a añadir al usuario como colaborador
- He realizado una búsqueda con dicho usuario, y efectivamente, no he obtenido ningún resultado de búsqueda.
- He forzado un segundo crawling
- Al volver a buscar con el mismo usuario, ya aparecían los resultados de la búsqueda esperados.
Moraleja:
Lleva esto en mente, y programa el crawling incremental y completo, según las necesidades de que dichos resultados estén “actualizados”. Ten en cuenta que a parte de esos permisos, también copia gran parte del contenido, por lo que es muy sencillo que elementos que hayan sido eliminados, o actualizado algún metadato, sigan apareciendo en los resultados de búsquedas con una versión incorrecta.
Saludos!!
Cuando creamos un nuevo sitio de SharePoint, debemos elegir una plantilla de sitio, en la que queremos basar nuestro nuevo sitio. Si lo hacemos desde la interfaz web, lo tenemos muy fácil, y tan sólo tenemos que elegirla, tal y como vemos en la imagen:

Si queremos hacerlo desde power-shell, podemos usar el comando New-SPSite donde con el parámetro Template, le daremos la plantilla a utilizar. Ese parámetro, nos pide un código de plantilla. Podemos ver los códigos instalados, con otro comando de power shell:
Que nos dará un listado como el siguiente (repetido para cada idioma instalado):
1:
2: Name Title LocaleId Custom
3: ---- ----- -------- ------
4: GLOBAL#0 Global template 1033 False
5: STS#0 Team Site 1033 False
6: STS#1 Blank Site 1033 False
7: STS#2 Document Workspace 1033 False
8: MPS#0 Basic Meeting Workspace 1033 False
9: MPS#1 Blank Meeting Workspace 1033 False
10: MPS#2 Decision Meeting Workspace 1033 False
11: MPS#3 Social Meeting Workspace 1033 False
12: MPS#4 Multipage Meeting Workspace 1033 False
13: CENTRALADMIN#0 Central Admin Site 1033 False
14: WIKI#0 Wiki Site 1033 False
15: BLOG#0 Blog 1033 False
16: SGS#0 Group Work Site 1033 False
17: TENANTADMIN#0 Tenant Admin Site 1033 False
18: ACCSRV#0 Access Services Site 1033 False
19: ACCSRV#1 Assets Web Database 1033 False
20: ACCSRV#3 Charitable Contributions Web Database 1033 False
21: ACCSRV#4 Contacts Web Database 1033 False
22: ACCSRV#6 Issues Web Database 1033 False
23: ACCSRV#5 Projects Web Database 1033 False
24: BDR#0 Document Center 1033 False
25: OFFILE#0 (obsolete) Records Center 1033 False
26: OFFILE#1 Records Center 1033 False
27: OSRV#0 Shared Services Administration Site 1033 False
28: PowerPointBroadca... PowerPoint Broadcast Site 1033 False
29: PPSMASite#0 PerformancePoint 1033 False
30: BICenterSite#0 Business Intelligence Center 1033 False
31: SPS#0 SharePoint Portal Server Site 1033 False
32: SPSPERS#0 SharePoint Portal Server Personal Space 1033 False
33: SPSMSITE#0 Personalization Site 1033 False
34: SPSTOC#0 Contents area Template 1033 False
35: SPSTOPIC#0 Topic area template 1033 False
36: SPSNEWS#0 News Site 1033 False
37: CMSPUBLISHING#0 Publishing Site 1033 False
38: BLANKINTERNET#0 Publishing Site 1033 False
39: BLANKINTERNET#1 Press Releases Site 1033 False
40: BLANKINTERNET#2 Publishing Site with Workflow 1033 False
41: SPSNHOME#0 News Site 1033 False
42: SPSSITES#0 Site Directory 1033 False
43: SPSCOMMU#0 Community area template 1033 False
44: SPSREPORTCENTER#0 Report Center 1033 False
45: SPSPORTAL#0 Collaboration Portal 1033 False
46: SRCHCEN#0 Enterprise Search Center 1033 False
47: PROFILES#0 Profiles 1033 False
48: BLANKINTERNETCONT... Publishing Portal 1033 False
49: SPSMSITEHOST#0 My Site Host 1033 False
50: ENTERWIKI#0 Enterprise Wiki 1033 False
51: SRCHCENTERLITE#0 Basic Search Center 1033 False
52: SRCHCENTERLITE#1 Basic Search Center 1033 False
53: SRCHCENTERFAST#0 FAST Search Center 1033 False
54: visprus#0 Visio Process Repository 1033 False
Es el Name de ese listado, el que debemos utilizar para el parámetro Template. Ejm:
1: New-SPSite http://www.contoso.com
2: -OwnerAlias "DOMAIN\jdoe"
3: -HostHeaderWebApplication $w
4: -Name "Contoso"
5: -Template "STS#0"
Pero ¿qué significan esos códigos?
Pues bien, los Site Definition de SharePoint, se componen, entre otras cosas, de 2 ficheros .XML:
- webTemp.xml: Existe uno por cada lenguaje instalado, y contiene las entradas de las plantillas de sitio, que luego se listan en las primeras imágenes del post.
- ONET.xml: Contiene las configuraciones de cada plantilla, como pueden ser las listas, módulos, features a nivel site y web, etc.
Si abrimos el fichero webTemp.xml, que se almacena en \14\Template\Locale\XML\ veremos varias entradas de este tipo:
1: <Template Name="STS" ID="1">
2: <Configuration ID="0" Title="Team Site" Hidden="FALSE" ImageUrl="/_layouts/images/stts.png" Description="A site for teams to quickly organize, author, and share information. It provides a document library, and lists for managing announcements, calendar items, tasks, and discussions." DisplayCategory="Collaboration" > </Configuration>
3: <Configuration ID="1" Title="Blank Site" Hidden="FALSE" ImageUrl="/_layouts/images/stbs.png" Description="A blank site for you to customize based on your requirements." DisplayCategory="Collaboration" AllowGlobalFeatureAssociations="False" > </Configuration>
4: <Configuration ID="2" Title="Document Workspace" Hidden="FALSE" ImageUrl="/_layouts/images/stdw.png" Description="A site for colleagues to work together on a document. It provides a document library for storing the primary document and supporting files, a tasks list for assigning to-do items, and a links list for resources related to the document." DisplayCategory="Collaboration" > </Configuration>
5: </Template>
Pues bien, si volvéis a fijaros en los códigos de las Template, veréis que se forman como:
1: Name + # + ID configuración
¿Y cómo se relaciona con el fichero ONET.xml (que es el que contiene la chicha de la definición del Site)?
Pues bien, lo primero es que dentro del directorio \14\Tempate\SiteTemplates, tendremos una carpeta con el nombre del atributo Name del nodo Template. Es en esa carpeta, dentro de la subcarpeta \XML, donde encontraremos el ONET.xml. Si vemos ese fichero, veremos que hay una parte de Configurations, donde coinciden los IDs de cada nodo Configuration del webTeml.xml
1: <Configurations>
2: <Configuration ID="-1" Name="NewWeb" MasterUrl="_catalogs/masterpage/v4.master" />
3: <Configuration ID="0" Name="Default" MasterUrl="_catalogs/masterpage/v4.master">
4: <Lists>
5: <List FeatureId="00BFEA71-E717-4E80-AA17-D0C71B360101" Type="101" Title="$Resources:core,shareddocuments_Title;" Url="$Resources:core,shareddocuments_Folder;" QuickLaunchUrl="$Resources:core,shareddocuments_Folder;/Forms/AllItems.aspx" />
6: ...
7: </Lists>
8: <Modules>
9: <Module Name="Default" />
10: </Modules>
11: <SiteFeatures>
12: <!-- BasicWebParts Feature -->
13: <Feature ID="00BFEA71-1C5E-4A24-B310-BA51C3EB7A57" />
14: </SiteFeatures>
15: <WebFeatures>
16: <!-- TeamCollab Feature -->
17: </WebFeatures>
18: </Configuration>
19: <Configuration ID="1" Name="Blank" MasterUrl="_catalogs/masterpage/v4.master">
20: ...
Saludos!!
Más artículos
Página siguiente >