Pregunta para los fanáticos de optimalización en programación: como leer todas las subWebs de un SPSite de SharePoint de la forma más rápida, efectiva y eficiente posible?
Primero que todo el problema: para un portal (bastante) grande de SharePoint, en donde al final habrá algunos miles de subSites, es necesario crear una especie de “árbol” con la estructura. Usar un cacheo del árbol después de que se ha leído de arriba abajo mejora el rendimiento, por supuesto, pero primero hay que haber leído todos los sitios y sus subsitios y sus subsitios ad infinitum… La estructura es bastante dinámica, cambiando en (en el peor de los casos) dentro de minutos, así que el cacheo no se puede mantener por más de algunos minutos sin correr el riesgo de que el usuario pierda información.
Lo primero es que hay que usar recursividad para poder entrar por todas partes, eso es seguro. Pero dentro del lazo de la recursión es necesario conseguir el SPWebCollection de alguna forma. En principio tenemos dos maneras: con “SPSite.AllWebs()” o con “SPSite.OpenWeb().GetSubwebsForCurrentUser()”. El primer método se descarta bastante rápido por problemas de seguridad: si el usuario que está creando el árbol no tiene derechos suficientes en una u otra SPWeb en el camino, recibirá simplemente un “Access Denied” sin más, y el asunto se detiene irremediablemente. Peor aún, el usuario tiene que tener derechos de “Full Control”, de otra forma SharePoint simplemente se niega a seguir adelante.
Así que queda el segundo método. Para mi gran sorpresa, tampoco funciona en la forma deseada. Por una u otra razón, el método tampoco devuelve todas las subWebs directamente bajo la Web actual. Después de renegar, sudar, llorar y rogar, al final resulta que hay que usar el asunto por medio del “SPSite.RootWeb.GetSubwebsForCurrentUser()” y no por medio del “OpenWeb()”. Porque? Ni idea… según la fantastica información proporcionada por el SDK, la propiedad RootWeb “Gets the root Web site of the site collection” y el método “OpenWeb” “Returns the site that is associated with the URL that is used in an SPSite constructor”… más claro no canta una gallina… y según mi humilde entender, los dos hacen lo mismo, pero de diferente manera… lo de diferente manera es seguro, en cualquier caso…
Pero el asunto va por otro lado. AllWebs y GetSubwebsForCurrentUser son simplemente asesinos del rendimiento, pues los dos no hacen más que un bucle de web en web para sacar la lista requerida. Cuando estamos hablando de unos cuantos de sitios, que hay que leer de vez en cuando, simplemente no importa como lo hacen. Cuando hay que leer miles de sitios con mucha frecuencia, los servidores de la granja simplemente se van a 100% de CPU, y el usuario se puede ir a tomar un café mientras la información aparece en pantalla.
Por eso de que a veces quedan marcas en la memoria de cosas leídas hace un montón de tiempo, me he acordado de un documento de Steve Peschka (Microsoft) de hace más de un año: “Working with large lists in Office SharePoint Server 2007” (http://go.microsoft.com/fwlink/?LinkId=95450&clcid=0x409) que describe cómo usar la clase “PortalSiteMapProvider”. Esta es una clase de SharePoint que probablemente solo conoce el desarrollador que la hizo, y que fue creada originalmente para ayudar a cachear la navegación (según las palabras de Steve Peschka). La clase contiene un “PortalWebSiteMapNode” que a su vez contiene la propiedad “GetChildNodes” que nos entrega una colección de los subWebs que estamos buscando… perfecto… casi perfecto… hmmm… inservible… “PortalSiteMapProvider” es una clase de MOSS y yo lo necesito para WSS…
Gustavo – http://www.gavd.net/servers/
Escriba un Comentario que me haga reir…
Que cosas!, cuando ya pensaste que estaba solucionado con esa clase, no jala para WSS, en fin! una monería mas de este mundo atolondrado, jaja saludos!
Luis.