Mostrando entradas con la etiqueta SharePoint 2007. Mostrar todas las entradas
Mostrando entradas con la etiqueta SharePoint 2007. Mostrar todas las entradas

Habilitar/deshabilitar los ficheros Javascript de debug de SharePoint

5.10.11 / Comments (0) / by Unknown

SharePoint viene con versiones de debug de los ficheros estándar .JS. : core.debug.js, init.debug.js… Estas versiones contienen el mismo código que los originales pero con las líneas formateadas y las funciones y variables con nomenclatura inteligible. Los JS originales tienen el código reducido al máximo para pesar el tamaño mínimo.

Alguna vez te preguntarás por qué las páginas de tu portal están cargando las versiones debug en lugar de las versiones reducidas. Por ejemplo, puedes constatar este hecho con las Internet Explorer Development Tools:

image

La explicación es muy simple y proviene de la configuración del atributo debug del nodo <compilation> dentro de <system.web> del web.config de tu portal.

<compilation batch="false" debug="false">   –> Ficheros JS originales

<compilation batch="false" debug="true">   –> Ficheros JS debug

Otro motivo muy importante para no olvidarse de poner debug=”false” en los entornos de producción.

Detectar inicio de sesión de usuario en SharePoint

23.9.11 / Comments (2) / by Unknown

Dado que el uso del evento Session_Start en las aplicaciones web de SharePoint es un mecanismo de más que dudoso éxito:

http://stackoverflow.com/questions/2948471/handling-session-start-and-session-end-events-global-asax-sharepoint

http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/79f69293-a91c-4426-acac-ff23030db1ee/

propongo un método para detectar cuando un usuario ha empezado sesión en una aplicación web SharePoint. Aprovechando que disponemos de master pages, podemos incrustar en ellas un control de servidor que se ejecutará en todas las páginas y añadirle la siguiente lógica:

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (HttpContext.Current.Request.Cookies["Mi_Cookie_Sesion"] == null)
{
// Realizar nuestras acciones de inicio de sesión
// ...

HttpContext.Current.Response.Cookies.Add(new HttpCookie("Mi_Cookie_Sesion"));
}
}





Resumiendo, crear una cookie de sesión ASP.NET (objeto HttpCookie sin tiempo de expiración) y comprobar su existencia al iniciar. Las cookies de sesión persisten mientras el usuario está autenticado y caducan cuando hace logout o cuando cierra el navegador.

“Attempted to use an object that has ceased to exist” al eliminar web parts

19.9.11 / Comments (0) / by Unknown

Otra batallita más para cuando sea abuelo. En una página hay dos instancias de mi web part personalizado (es decir, con código mío). Todo va bien hasta que, una vez configuradas las propiedades del primero, me pongo a configurar las del segundo. Guardo la página y –puf- las propiedades no se han guardado. Qué raro. Intento el eliminar el web part y aparece esta alarmante excepción:

Attempted to use an object that has ceased to exist. (Exception from HRESULT: 0x80030102 (STG_E_REVERTED))

Afortunadamente, googleando (yo también lo uso, Chan), llegamos a la conclusión que mi código está usando tácticas de guerrilla para cargarse el contexto de SharePoint:

SPSite site;

try
{

// site = new SPSite
site = SPContext.Current.Site; // miedo y pavor

// ... decenas de líneas de código más tarde

}
finally
{
if (site != null) site.Dispose(); // ouch!
}






Evidentemente si liberas un SPSite obtenido del contexto, el siguiente web part que intente usarlo va a acabar con la cara negra de pólvora. Así pues, prescindo del Dispose y mi página ya funciona con total normalidad. Circulen, no hay nada que ver.

Content query web part: The query cannot be completed because the number of lists in the query exceeded the allowable limit

1.6.11 / Comments (1) / by Unknown

Bueno, una perla más de conocimiento adquirida gracias a la experiencia empírica de comprobar cómo un sitio de producción que funciona perfectamente, después de crear un nuevo subsitio, empieza a mostrar en web parts de consulta de contenido el siguiente mensaje:

There is a problem with the query that the web part is using. Check the configuration of the web part and try again.

Mirando el log de SharePoint aparece la siguiente excepción:

The query cannot be completed because the number of lists in the query exceeded the allowable limit.

Después de agotar la sarta de improperios producto del momento de tensión, la solución encontrada es localizada rápidamente y puesta en funcionamiento con éxito.

  • El límite de listas soportadas en un CQWP cross-site (o SPSiteDataQuery) por defecto es 1000.
  • Ese límite se puede ampliar al valor deseado o poner a 0 (infinito) pero mucho ojo con los efectos colaterales de rendimiento.
  • En un SPSiteDataQuery podemos usar directamente la propiedad MaxListsLimit para establecer ese valor.
  • En un CQWP debemos establecer la propiedad ListsOverride del web part a:
  • <property name="ListsOverride" type="string">
    <![CDATA[<Lists ServerTemplate="#ID_TEMPLATE_LISTA#" MaxListLimit="#LÍMITE#">]]>
    </property>

ID de templates de lista. Los más comunes:

100 Generic list

101 Document library

102 Survey

103 Links list

104 Announcements list

105 Contacts list

106 Events list

107 Tasks list

108 Discussion board

109 Picture library

119 Wiki Page library

301 Blog Posts list

302 Blog Comments list

303 Blog Categories list

850 Page Library

Más en http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splisttemplatetype.aspx

 

Info extraída de http://technet.microsoft.com/en-us/library/cc263061(office.12).aspx#Content_query

Herramientas para rastreo de logs de SharePoint (2)

14.4.11 / Comments (2) / by Unknown

Mandíbula desencajada se me ha quedado al conocer gracias a Javier Hidalgo la existencia desde 2009 de ULS Viewer, aplicación de explotación de logs ULS que, por comparación, deja a las dos anteriores herramientas comentadas en la categoría de semi-chusta.

image

ULS Viewer es también un simple ejecutable, descargable desde MSDN (pero al parecer sin soporte de la propia MS), y ofrece todo lo siguiente:

  • Leer eventos de log de ficheros especificados por usuario, de portapapeles o en tiempo real desde los ficheros de log ULS del servidor. Podemos agregar (append) eventos de distintas fuentes.

image

  • Filtrado, por supuesto, por todos los atributos del evento y por distintas operaciones de filtrado. Los criterios de filtro pueden acumularse con ANDs y ORs.

image

  • Notificaciones: es decir, la posibilidad de ser informado en el área de notificaciones de Windows de los eventos críticos o de aquellos eventos filtrados por nuestros criterios. Esta funcionalidad tiene muchas similitudes con el SPTraceView de Hristo Pavlov, herramienta que también circula por el mundillo desde hace tiempo, pero que a mi juicio queda desfasada ante la potencia de ésta.

image

image

  • Posibilidad de definir formato condicional de color para ciertos eventos que cumplan ciertos filtros. Nuestros ojos agradecerán sin duda evitar tanta monocromía.

image

  • Podemos organizar y filtrar los eventos por los Correlation ID.

image

  • Smart Highlight: ésta me encanta. Cuando se activa, al hacer hover encima de un valor determinado de una columna, resalta automáticamente el resto de valores iguales.

image 

  • Podemos añadir bookmarks en los eventos de log.
  • Podemos buscar textualmente en toda la información de log abierta en la sesión.
  • Podemos ocultar/reordenar las columnas de los eventos.
  • Podemos guardar la sesión en ficheros de log o en workspaces (conjunto de fuentes, filtros, formatos y notificaciones configuradas en una sesión).

 

Simplemente apabullante. SharePoint 2010 debería haber contado con algunas si no todas estas funcionalidades de serie. Mis servidores ya no usan otra cosa.

Reemplazar la página de Access Denied en SharePoint

7.4.11 / Comments (0) / by Unknown

"Have you ever...?" La página de acceso denegado en SharePoint es feucha, y puede ser blanco de las iras de aquellos que han mimado y cuidado hasta el extremo el branding de su portal. De pronto, un usuario accede al sitio, a alguien se le olvida asignar un permiso y... ugh. Qué desagradable.

 

image

image

Y lo bueno (y lo malo) es que por ahora hay dos maneras de evitar esto: controlando las excepciones de acceso denegado por código (SPSecurity.CatchAccessDeniedException) o bien implementando un HttpModule como el siguiente:

using System;
using System.Web;

namespace MyNamespace
{
public class CustomAccessDenied : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += ContextAcessDenied;
}

public void Dispose()
{

}

static void ContextAcessDenied(object sender, EventArgs e)
{
try
{
var httpApp = sender as HttpApplication;
if (httpApp != null)
{
var context = httpApp.Context;

var httpUrl = context.Request.Url.ToString();

if (httpUrl.ToLower().Contains("/_layouts/accessdenied.aspx"))
{
HttpContext.Current.Server.ClearError();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Redirect(
"/Anonymous/Pages/CustomAccessDenied.aspx", false);
}
}
}
catch (Exception ex)
{
//...
}
}

}
}

Este HttpModule redirigiría las peticiones que han devuelto con URL '_layouts/accessdenied.aspx' a una página personalizada que debería estar en un subsitio anónimo de nuestra colección de sitios. Ello implica, sí, habilitar la disponibilidad de acceso anónimo en toda la colección.

Este HttpModule sería, de las dos soluciones, la menos intrusiva en el código de nuestro portal. Y que conste que no soy para nada partidario de hinchar los web apps de handlers y módulos, pero reconozco que en esta ocasión el requerimiento lo merece...

 

Edit: cuidado con la opción "Sign as a different user" del menú Welcome. Redirige a /_layouts/accessdenied.aspx?loginasanotheruser=true&Source=... Tenemos que modificar el HttpModule para que deje pasar estas peticiones.

Localized resource for token 'groupExpColl' could not be found

1.4.11 / Comments (0) / by Unknown

Una de dejar el log de ULS como una patena. Si estamos desplegando features con definiciones de lista, podemos advertir en los ficheros de log las siguientes entradas:

Localized resource for token 'groupExpColl' could not be found 
for file with path: "C:\Program Files\Common Files\Microsoft 
Shared\Web Server Extensions\12\Template\Features\
<nuestra_feature>\<nuestra_lista>\schema.xml
Localized resource for token 'filterIframeTitle' could not be found 
for file with path: "C:\Program Files\Common Files\Microsoft 
Shared\Web Server Extensions\12\Template\Features\
<nuestra_feature>\<nuestra_lista>\schema.xml

Esto se debe a que en el schema.xml que estamos desplegando aparecen dos literales de recursos:

  • $Resources:groupExpColl;
  • $Resources:filterIFrameTitle;

que no hacen referencia explícita a ningún fichero de recursos, pero que están localizados en el “core.resx”. Tenemos dos opciones: o reemplazamos estas ocurrencias por $Resources:core,groupExpColl; y $Resources:core,filterIFrameTitle; o, mucho mejor, si especificamos en nuestro feature.xml:

DefaultResourceFile="core"

Este post es una adaptación libre de http://blogs.msdn.com/b/carloshm/archive/2008/03/13/did-you-find-groupexpcoll-error-in-your-logs.aspx

Herramientas para rastreo de logs de SharePoint

9.2.11 / Comments (0) / by Unknown

Rastrear los ficheros de log de SharePoint es una actividad que realizamos demasiado a menudo como para dejarnos la vista en una ventana de Bloc de notas. La inercia del día a día nos lleva muchas veces a “mirar y buscar rápido”, pero deberíamos tomar como medida no pasar más de 1 minuto de reloj examinando el log en texto plano para 1) optimizar nuestra capacidad de producción y 2) cuidar nuestra salud física y mental.

Se que muchos ya las conocemos, pero desde aquí hago recordatorio de la existencia de dos utilidades en Codeplex cuya complejidad de ejecución es simplemente copiar un .EXE, ejecutarlo y especificar el/los fichero/s a rastrear.

SharePoint Log Reader: de interfaz simple, provee de tabulación, búsqueda y filtrado de los registros (por múltiples valores); incluye botón de copia a portapapeles y lee múltiples ficheros. Es WPF. No permite ordenación.

http://sharepointlogreader.codeplex.com/

SPLogReader0

SPLogReader1

 

ULS Log Viewer: de interfaz igualmente simple, provee de tabulación, búsqueda, ordenación y filtrado de los registros (por un solo valor a la vez); lee múltiples ficheros. Es WPF.

http://ulsviewer.codeplex.com/

image

¿Con cuál me quedo? Quizá el filtrado por múltiples valores le da una ventaja definitiva al SharePoint Log Reader, pero ambas son opciones perfectamente válidas para su cometido.

SPException: Unable to complete this operation. Please contact your administrator.

18.1.11 / Comments (0) / by Unknown

El síntoma: en un entorno estable de MOSS 2007 en el cual no se han hecho modificaciones recientemente empezamos a notar esta excepción en las operaciones de escritura desde modelo de objetos, por ejemplo en una operación tan sencilla como un SPListItem.Update(), que funcionaba perfectamente y ahora no.

La comprobación: sin dudarlo hay que consultar el espacio de disco disponible, por este orden, en:
  • servidor de base de datos
  • web front-ends de SharePoint
El diagnóstico más que probable: el servidor de base de datos está al límite de su capacidad. Los motivos pueden ser diversos pero la comprobación immediata a realizar a continuación es el tamaño de los distintos ficheros de datos y de log de las bases de datos SQL alojadas en el servidor. Quizá alguna de las bases de datos puede tener disparado el tamaño el fichero log de transacciones; en tal caso habría que estudiar cual es el motivo de ello y si es conveniente truncarla. Si la decisión es que sí, hay múltiples entradas en la red describiendo cómo hacerlo:
http://www.google.es/search?q=sharepoint+content+database+log+sql+shrink&rls=com.microsoft:es&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1

La conclusión: el espacio en disco de los servidores es una variable lo suficiente crítica en el funcionamiento de nuestros servidores como para que esté adecuadamente monitorizada.

Microsoft.SharePoint.Utilities: el namespace que vale su peso en oro (1)

15.12.10 / Comments (0) / by Unknown

Resulta que un día te das cuenta que vas por tu duodécima implementación de codificación HTML (XML) de un string y decides preguntarte si existe una inteligencia suprema que ya la ha programado para todo el universo. Y obtienes la respuesta y otras muchas revelaciones que nunca habrías soñado conocer. Esas revelaciones están debidamente paquetizadas y ready-to-use en el namespace Microsoft.SharePoint.Utilities.

Quien más quien menos conoce el cajón de sastre llamado SPUtility y sus métodos miscelánicos. Ahora os propondré un viaje en distintos capítulos por algunas otras clases de indiscutible utilidad. Hoy para empezar:

SPHttpUtility o cómo olvidarse para siempre de string.Replace

La intención de esta clase estática es proveer de métodos también estáticos para la codificación y decodificación de strings durante el procesamiento de peticiones web. Lo más interesante es:

string ConvertSimpleHtmlToText(string html, int maxLength)
Convierte una cadena html (por ejemplo, de un campo de rich text o un PublishingContent) a texto plano, eliminado los tags HTML. ¿A que te estás dando de cabezazos?

string HtmlEncode(string valueToEncode)
Codifica una cadena de texto para ser incluída en markup HTML, es decir, reemplaza " / ' / < / > / & por &quot; / &apos; / &lt; / &gt; / &amp; . Opcionalmente tenemos también el HttpUtility.HtmlEncode . A ver, que el Regex que implementaste está muy bien pero...

string HtmlDecode(string valueToDecode, bool decodeNbsp)
El correspondiente método de decodificación. "decodeNbsp" a true para si deseamos decodificar también los &nbsp; a espacios.

string HtmlEncodeAllowSimpleTextFormatting(string valueToEncode)
Codifica una cadena para aparecer entre merkup HTML pero además sustituye los espacios y saltos de línea por &nbsp; y <br/> (eso sí, codificados a &amp;nbsp; y &lt;br&gt;).

string UrlKeyValueEncode(string keyOrValueToEncode)
Codifica una clave o valor de una querystring para construir una URL, es decir, escapa los caracteres no admitidos por un querystring. El HttpUtility.UrlEncode de toda la vida.

string UrlKeyValueDecode(string keyOrValueToDecode)
Decodifica una clave o valor de querystring.

string EcmaScriptStringLiteralEncode(string scriptLiteralToEncode)
Veamos, ésta no es de utilidad inmediata pero en algunas funcionalidades de SP, hay que transferir strings a traves de JavaScript (ECMAScript), para lo cual algunos caracteres necesitan ser codificados a formato Unicode (\u00XX). Este método proporciona dicha codificación.

SharePoint 2007: Reemplazar master page en páginas de aplicación

10.12.10 / Comments (0) / by Unknown

La application.master que viene de serie en las páginas del directorio  _layouts es una cruz que nos tortura constantemente a los desarrolladores de SharePoint. Es única por servidor, no está soportado el modificarla y, para colmo, las páginas de aplicación que la usan son múltiples y habituales (newsbweb.aspx, createpage.aspx, mysubs.aspx,...). Con lo cual, es frecuente el requerimiento de que estas páginas dispongan de un look&feel como mínimo parecido al del resto de páginas del sitio (ya sean páginas de publicación o páginas de formulario -DispForm.aspx, EditForm.aspx,...-, a las que no hay problema para asignarles una master page). Y con toda la razón del mundo, porque el aspecto de esas páginas canta como una almeja.

A riesgo de meter la pata en el hoyo de lo "not supported", voy a proponer un mecanismo, a mi juicio bastante limpio, para reemplazar la master page en tiempo de ejecución para esas páginas. Está comprobado con muchas de las páginas de aplicación, aunque no garantiza su efectividad en el 100% de ellas. Y no, no hay ningún HttpModule de por medio.

Si implementamos un page adapter para estas páginas de layout, podemos tener control de sus propiedades en runtime. Ahora sólo quedaría modificar la propiedad MasterPage, el pequeño inconveniente es que sólo puede modificarse antes o durante del método OnPreInit() y que ese método no existe en un control adapter. Bueno, un vistazo al ciclo de vida de los controles ASP.NET, y veremos que existe un evento DeterminePostBackMode() invocado justo antes de OnPreInit. Este evento procesa los datos enviados por postback a la petición actual, estableciendo el valor IsPostBack y devolviendo la colección de valores recibidos. Sí, sí, muy bien. Pero de lo mío, ¿qué? Bien, pues si el page adapter sobreescribe este evento, llama al base (importante no olvidarlo) y luego modifica la propiedad MasterPageFile, bingo! Tenemos una página de aplicación con la master page deseada.

/// <summary>
/// Adapter for SharePoint layout pages to replace their masterpage
/// </summary>
public class CustomLayoutPageAdapter : PageAdapter
{
public override System.Collections.Specialized.NameValueCollection
DeterminePostBackMode()
{
NameValueCollection result = base.DeterminePostBackMode();

try
{
Page page = this.Control as Page;
page.MasterPageFile = "/_catalogs/masterpage/XXXXXX.master";
}
catch { }

return result;
}
}

Ahora sólo queda utilizar este page adapter, creando un fichero my.compat.browser en App_Browsers con una definición <adapter> para cada página de aplicación que queramos reemplazar. ¿Engorroso? Depende, esto nos asegura que estaremos reemplazando la master page sólo en las páginas que queremos y no a lo loco, en todo el back-office de SharePoint. Ejemplo:



<adapter controlType="Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePagePage,
Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"
adapterType="MyNamespace.CustomLayoutPageAdapter,
MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXXXX"
/>


¿Cómo obtengo el tipo correspondiente a una página de aplicación? Normalmente se ve fácil consultando el código fuente de la página y identificando su clase codebehind. Aquí van una cuantas páginas típicas y sus tipos:



createpage.aspx

Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePagePage, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



mysubs.aspx

Microsoft.SharePoint.ApplicationPages.MySubsPage, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



sitesubs.aspx

Microsoft.SharePoint.ApplicationPages.SiteSubsPage, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



newsbweb.aspx

Microsoft.SharePoint.ApplicationPages.SubNewPage, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



checkin.aspx

Microsoft.SharePoint.ApplicationPages.CheckIn, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



userdisp.aspx

Microsoft.SharePoint.ApplicationPages.UserDisplayPage, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



regionalsetng.aspx

Microsoft.SharePoint.ApplicationPages.RegionalSettingsPage, Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



subchoos.aspx

Microsoft.SharePoint.ApplicationPages.SubChoosPage, Microsoft.SharePoint.ApplicationPages,  Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c



Pero esto no es todo. Es muy importante notar que, si reemplazamos una application.master por una master page nuestra, es probable que las páginas de aplicación a las que hemos lobotomizado empiecen a echar en falta placeholders y controles, con la consecuente eclosión de fuegos artificiales diversos. Solución: localizar cuáles son esos placeholders y añadirlos a nuestra masterpage. Esto no es ciencia exacta: debemos testear cada página a la cual estamos aplicando este fix y asegurarnos que funciona correctamente. Dejadme solo  apuntar que para la mayoría de páginas de aplicación, el PlaceHolderFormDigest es necesario.



<asp:ContentPlaceHolder id="PlaceHolderFormDigest" runat="server">  
<SharePoint:FormDigest ID="FormDigest1" runat=server/>
</asp:ContentPlaceHolder>



Y nada más, si alguien aplica este método y quiere dar feedback sobre él, soy todo oídos.

Could not load file or assembly 'Microsoft.SharePoint.ApplicationPages PublicKeyToken=71e9bce111e9429c' o el arte de la colleja bien dada

26.11.10 / Comments (0) / by Unknown

En uno de estos iisreset con los que tan habitualmente masacramos a nuestro servidor web, podemos encontrarnos con que, de pronto, las páginas de /_layouts de SharePoint 2007 dejen de funcionar, mostrando:
Could not load file or assembly 'Microsoft.SharePoint.ApplicationPages PublicKeyToken=71e9bce111e9429c'

Este error no solo trae de cabeza a mucha gente:

http://social.technet.microsoft.com/Forums/en/sharepointgeneral/thread/e7463fba-1d31-4198-87b8-29cf107906dd

http://blog.dennus.net/2009/06/

http://www.tech-archive.net/Archive/SharePoint/microsoft.public.sharepoint.windowsservices/2008-06/msg00048.html

http://www.solomon-strutz.com/wordpress/?p=83sino

sino que además no dispone de un fix consensuado. Parece que al aparecer este mensaje, SharePoint entra en un estado de encallamiento que le impide resolver correctamente el ensamblado: reciclar el app pool igual ayuda, un iisreset o dos más pueden funcionar, quizá un reboot de la máquina... veis por donde voy, no? SharePoint necesita una colleja, un capón, un meneo; en definitiva, una acción humana que le haga ser capaz de nuevo de encontrar la DLL. Sirva esta entrada para sugerir una más a las anteriores citadas; como mínimo, ha funcionado en un caso donde no habían funcionado recycles e iisresets en solitario.

- Mover el Microsoft.SharePoint.ApplicationPages.dll de _app_bin (del directorio de la aplicación web que está fallando) a otro sitio cualquiera.

- iisreset

- Cargar una página de /_layouts . Aparecerá de un error distinto.

- Volver a poner Microsoft.SharePoint.ApplicationPages.dll en _app_bin

- iisreset

- Cargar de nuevo la página de /_layouts .

Si todo ha funcionado como debería, habréis descolocado a SharePoint con un buen capón de padre y la página debería verse correctamente de nuevo.

Emergencia: no se propagan los perfiles de usuario a la User Information List

24.11.10 / Comments (0) / by Unknown

Panic situation: necesitamos obtener inmediatamente (se requiere el uso del adverbio "inmediatamente" para
provocar cierto grado de pánico) un campo de un usuario (el e-mail, por ejemplo) en el contexto de un sitio,
es decir a través de un objeto SPUser, que obtiene la información desde la lista interna de WSS / SharePoint
Foundation "User Information List". El problema es que el origen de ese campo no está en esa lista sino en el
repositorio de perfiles de usuario (User Profiles de MOSS 2007 / SharePoint Server), ya sea importado de un origen de datos, como Directorio Activo, o bien gestionado manualmente desde los perfiles de SSP / User Profile Service Application. Y la sincronización entre perfiles de usuario y "User Information List" es, como ya todos sabemos, muy suya.

Sobre la teoría de cómo funciona la sincronización entre ambos repositorios y cómo forzar la propagación de los campos, existen unos cuantos artículos bastante clarificadores, entre ellos éste de Mirjam van Olst:

http://www.sharepointchick.com/archive/2009/06/17/user-profiles-and-the-user-information-list-or-userinfo-table.aspx

También merecen una ojeada:

http://blogs.technet.com/paulpaa/archive/2009/10/01/user-profile-information-not-updated-on-site-collection-s-people-and-group.aspx

http://www.21apps.com/sharepoint/user-profiles-why-do-my-changes-not-show-in-other-sites/

Pero vamos a ponernos en el caso de que nada de los descrito en ellos funcione. No conseguimos propagar de ninguna manera el valor de los campos a la "User Information List" y los nervios aumentan. Necesitamos una solución de emergencia; encendemos el reflector con la Power-señal, PowerShell lo ve y acude a nuestro rescate.

Primero: abrir consola de PowerShell y cargar las librerías de SharePoint. Reminder para hacerlo:
SharePoint 2007
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
Sharepoint 2010
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
Segundo: manipular manualmente el elemento de la lista "User Information List" mediante object model, usando operaciones que recomiendo os acostumbréis a usar asiduamente por su sencillez e inmediatez.
$site = new-object Microsoft.SharePoint.SPSite("http:/{el_sitio}")
$web = $site.OpenWeb()
$list = $web.Lists["User Information List"]
$item = $list.GetItemByID(xx)
Donde xx será el ID del elemento (usuario), que podemos consultar en cualquiera de las URL
http://el_sitio/_layouts/people.aspx o http://el_sitio/_catalogs/users/detail.aspx . Si pasamos por encima
del enlace de cada elemento veremos una URL del estilo http://el_sitio/_layouts/userdisp.aspx?ID=xx
$item["EMail"] = "elcorreo@eldominio.com"
$item["JobTitle"] = "cargo"
$item[...] = ...
$item.Update()
Con esto, el SPUser dispondrá del campo actualizado inmediatamente. Solucionado; gracias PowerShell. Respecto a la propagación del campo desde perfiles de usuario, tranquilos, en un periodo de 24 horas, tarde o temprano se acabará produciendo automáticamente.

Anexo: entre los campos de un item de tipo usuario tenemos los siguientes:
Internal name - Display name

Title - Name
Name - Account
EMail - Work e-mail
Notes - About me
SipAddress - SIP Address
IsSiteAdmin - Is Site Admin
Deleted - Deleted
Picture - Picture
Department - Department
JobTitle - Title
IsActive - Is Active
FirstName - First name
LastName - Last name
WorkPhone - Work phone
Office - Office
UserName - User name
WebSite - Web site
SPSResponsibility - Responsibilities
ID - ID

SharePoint, InfoPath y "Network problems are preventing this file from being opened"

16.11.10 / Comments (0) / by Unknown

Es turno para una entrada de las de no arremangarse demasiado sobre un tema más que manido; no todo iba a ser profundidad e innovación. En un entorno con SharePoint 2007 e InfoPath con una biblioteca de formularios asociada a una plantilla de formulario XSN, intentamos crear un nuevo formulario y al arrancar InfoPath, ta-ta-chán:




El detalle del mensaje:

InfoPath cannot create a new, blank form.
InfoPath cannot open the form. to fix this problem, contact your system administrator.
Network problems are preventing this file from being opened. If this problem persists, contact your network administrator.

Bien; existe un elevado porcentaje de probabilidad de que algo de lo siguiente ocurra:

 Si chequeáis estos tres puntos y todos están funcionando, podéis seguir circulando, éste no es vuestro post.

Cómo modificar y recrear manualmente un WSP

8.11.10 / Comments (0) / by Unknown

Mi primera vampirización de lo ajeno en el blog será para un tema con el que he gastado suficiente tiempo investigando y, una vez encontrada una solución, me gustaría dejarlo bien localizado, procedimentado y traducido.

Contexto: debo modificar un WSP ya creado. Es una modificación muy sencilla, no requiere añadir ni eliminar ficheros, simplemente editar uno de ellos. No tengo DDF, no tengo proyecto de Visual Studio, no puedo dedicar mucho tiempo a ello. Todo ventajas.

Mark Rackley (http://www.sharepointhillbilly.com/archive/2010/02/16/rebuilding-a-.wsp-file-in-4-easy-steps.aspx) acude al rescate y nos ofrece la guía mínima de pasos para "tunear" un WSP con éxito (que complemento con mis humildes aportaciones):

- Renombrar el fichero WSP a CAB (Cabinet file).

- Extraer todo el contenido preservando la estructura de carpetas(utilizando 7Zip, WinRar o el mismo Windows, que permite consultar y extraer de ficheros CAB).

- Modificar los ficheros necesarios del contenido (con extrema precaución si se trata de XML de definición de features, manifests, etc.)

- Obtener el fichero DDF de forma automatizada (aquí la clave de todo este post) mediante la útil herramienta DDFGenerator . Simplemente ejecutar desde línea de comandos y especificar como único parámetro la ruta local donde está descomprimido el contenido de nuestro WSP. Esto generará un "solution.ddf" dentro de esa carpeta.

- Editar el fichero solution.ddf para corregir lo siguiente:

1) En las directivas iniciales .Set incluir: 
.Set CabinetNameTemplate=NombreDeNuestraSolucion.wsp
.Set MaxDiskSize=CDROM
La primera línea para hacer que el fichero se genere con el nombre deseado; la segunda para evitar que se genere partido en distintos ficheros.

2) Repasar las rutas relativas generadas en el DDF; si alguna de ellas contiene espacios en nombres de fichero o carpeta, debe ser puesta entre comillas (")

- Ejecutar la herramienta makecab.exe (Windows)
makecab.exe /F solution.ddf
Et voilà, dentro de una subcarpeta cuyo nombre es un numérico aparecerá el fichero WSP generado con nuestras modificaciones.

Los más aventurados que deseen añadir o eliminar ficheros pueden proceder a manipular el fichero solution.ddf a placer.