Codepoint

by Trentia Consulting

Reporting Services y SET FMTONLY

La instrucción SET FMTONLY en SQL Server se utiliza para definir si queremos recibir solamente metadatos cómo resultado de las solicitudes.

SET FMTONLY { ON | OFF }

La opción por defecto es SET FMTONLY OFF, por lo que si queremos ejecutar una consulta SQL y recibir solamente información sobre las columnas deberemos de cambiar previamente el valor a SET FMTONLY ON.

USE [Usuarios]
GO
SET FMTONLY ON
SELECT *
  FROM Usuarios
SET FMTONLY OFF
GO

SQL Reporting Services trabaja con FMTONLY activado (FMTONLY ON) al ejecutar la función Refresh Fields para leer las columnas de un procedimiento almacenado.

image_2

Sin embargo, es posible que si estamos tratando con un procedimiento almacenado complejo, SQL Server no pueda resolver los nombres de las columnas a no ser que previamente construya el conjunto de datos (lo que no ocurrirá ya que FMTONLY está en ON). Si nos encontramos en éste caso, nuestro conjunto de columnas de la respuesta del procedimiento almacenado estará vacío.

image_4

Para solucionarlo, podemos cambiar el estado de FMTONLY a OFF en nuestro procedimiento almacenado:

USE [Usuarios]
ALTER PROCEDURE [dbo].[sp_Consulta]
AS
BEGIN
    SET FMTONLY OFF;
 
    declare @sql varchar(5000)        

    SET @sql =
            'SELECT *                              
             FROM Usuario
             WHERE (1=1)'
    
    exec (@sql)
END

Cadena de conexión Sharepoint - Reporting Services

Para poder conectar un informe de Reporting Services con SharePoint no se puede realizar de la forma habitual mediante una consulta contra SQL, se ha de trabajar atacando el webservice facilitado por SharePoint.

Recordar que los webservices trabajan estructurados en formato XML, así pues de esta manera la consulta que se tendrá que usar en el informe también tendrá que ser en este formato para que se pueda comunicar de forma correcta.

Aquí dejo un ejemplo de cómo sería la consulta definida para poder acceder a un registro concreto de una lista definida en SharePoint:


   http://schemas.microsoft.com/sharepoint/soap/GetListItems
    
       
          
             [NombreDeLaLista]
          
          
           
          
          
 
 
 
   GetListItemsResponse/GetListItemsResult/listitems/data/row
 
 

Como se puede ver el único parámetro que tiene un valor definido es el que hace referencia al nombre de la lista, esto es así por que los otros parámetros también tienen que estar definidos en el formato XML, esto se hace de la siguiente forma:

  • Ir a la pestaña datos del informe.Acceder a las propiedades del conjunto de datos.
  • Ahora seleccionar la pestaña parámetros.
  • Definir los parámetros query y viewFields.
  • Poner los valores correspondientes a cada parámetro.

Aquí dejo un ejemplo de cada uno de ellos:

  • query:
    ="
       
        
         
         " & Parameters!ID.Value & "
        
       
      "
    
  • viewFields:
="
   
   
   
   
  "

Realizando esta serie de pasos ya podréis comunicar Reporting Services con SharePoint.

Títulos de página en páginas de publicación de SharePoint

Implementando una web en SharePoint 2010 quería añadir el nombre de la empresa al lado del título de cada página. Para ello, modifiqué la master para que el cambio se aplicara fácilmente a toda la web de la siguiente forma:

<title runat="server"><asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">SiteName</asp:ContentPlaceHolder> | Nombre de la empresa</title>

Una vez implementado, veía que dicho código no funcionaba. Finalmente encontré que lo que se quería añadir tenía que ponerse dentro de otro ContentPlaceHolder, de la siguiente forma:

<title runat="server"><asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">SiteName</asp:ContentPlaceHolder><asp:ContentPlaceHolder id="PlaceHolderPageTitle2" runat="server"> | Nombre de la empresa</asp:ContentPlaceHolder></title>

Permitir el acceso anónimo a páginas de SharePoint en el directorio _layouts

En algunas ocasiones os encontraréis con la posible necesidad de incorporar páginas de SharePoint en el mismo directorio _layouts. Algunos ejemplos: Páginas de login, mantenimientos, etc… En mi caso fueron páginas que implementaban un TPV para una web en SharePoint 2010.

En el proyecto en Visual Studio 2010, las páginas se encuentran debajo el directorio Layouts. Para hacerlo, se debe hacer clic con el botón derecho sobre el proyecto 'SharePointProject1' > 'Agregar' > 'Carpeta asignada "Layouts" de SharePoint'.

5

Automáticamente, SharePoint añade una carpeta con el nombre del proyecto dentro de 'Layouts'. Agregamos en ella la página de aplicación.

6

Por defecto la página hereda de LayoutsPageBase. Lo único que se tiene que hacer es cambiar esa herencia por UnsecuredLayoutsPageBase.

Public partial class ApplicationPage: UnsecuredLayoutsPageBase

Luego se tiene que sobrescribir la siguiente propiedad para permitir el acceso anónimo:

Protected override bool AllowAnonymousAccess { get { return true; } }

Una vez implementada la solución, se debería poder acceder a la página (http://miUrlDeSharePoint/_layouts/SharePointProject1/ApplicationPage.aspx) sin que te pida usuario y password.

Establecer una página maestra común en SharePoint Foundation 2010

Existen diversas manera de establecer una misma página maestra para los nuevos sitios que se crean en una solución web en SharePoint Foundation 2010. Existe una forma muy sencilla de lograr tal menester, sin necesidad de definiciones de plantillas de sitio ni cambiando definiciones de sistema. Con el desarrollo de un manejador de eventos de algunas lineas de código podemos lograr mantener un aspecto uniforme sea cual sea la plantilla de sitio que se utilice para crear nuevos sitios.

El objetivo de este manejador es que cada vez que se cree un nuevo sitio se le configure de forma automática sus propiedades referentes a páginas maestras con la misma configuración que la de la web principal o raíz de la colección. Para ello debemos capturar el momento en que se crea un nuevo sitio y actuar. Para ello heredaremos nuestra clase manejadora de la clase SPWebEventReceiver de SharePoint. El código que debemos generar para nuestra clase debe ser algo parecido a:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace Trentia.SharePoint.EventReceivers
{
    public class MasterPageEventReceiver : SPWebEventReceiver
    {
        public override void WebProvisioned(SPWebEventProperties properties)
        {
            Guid siteId = properties.SiteId;
            SPSecurity.RunWithElevatedPrivileges(() => {
                using (SPSite site = new SPSite(siteId))
                {
                    using (SPWeb web = site.OpenWeb(properties.WebId))
                    {
                        web.MasterUrl = site.RootWeb.MasterUrl;
                        web.CustomMasterUrl = site.RootWeb.CustomMasterUrl;
                        web.Update();
                    }
                }
            });
            base.WebProvisioned(properties);
        }       
    }
}

Este código debe ser encapsulado en un ensamblado y generarse una nueva característica para ser instalada y activada en las colecciones de sitio en que necesiteis uniformizar las páginas maestras.

Fichero Feature.xml



  
    
  
  

Fichero Elements.xml


  
    
      MasterPageEventReceiver
      WebProvisioned
      Trentia.SharePoint.EventReceivers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=169a06543af62ea6
      Trentia.SharePoint.EventReceivers.MasterPageEventReceiver
      10000
      Synchronous
    
  

Eliminar una plantilla de sitio de la galería de soluciones de SharePoint

Recientemente me he encontrado un problema al crear plantillas de sitio, o más bien al eliminarlas. Una vez se crea la plantilla de sitio con la opción Guardar como plantilla de la administración de un sitio ya existente, esa plantilla queda almacenada en la galería de soluciones de la colección de sitios. Para eliminarla se debe desactivar antes, pero es tarea imposible.

Después de muchas pruebas y intentos de encontrar formas alternativas para deshacerme de las plantillas de la galería de soluciones he encontrado la solución más efectiva. Se trata de ejecutar un comando de PowerShell.

Uninstall-SPUserSolution -Identity nombre_plantilla.wsp -Site http://misitio

Podéis encontrar más información sobre este comando en Technet.

Nueva versión de Umbraco en MVC 3

La versión 5 del conocido gestor de contenidos web Umbraco está disponible desde enero de 2012. La nueva versión, inicialmente denominada “Jupiter”, ha sido reconstruida para adaptarse a la arquitectura ASP.NET MVC 3, lo cual es una buena noticia para todos los desarrolladores que trabajan con Umbraco. Tambien es una buena noticia que a pesar de la actualización de arquitectura se consevan todas las funcionalidades de la versión anterior.

La nueva arquitectura ofrece un mayor rendimiento y mayores posibilidades de integración con sistemas externos a Umbraco.

Solucionar problema con la intercalación desde Linq

En caso de necesitar realitzar búsquedas contra el motor de base de datos sin tener en consideración mayúsculas/minusculas, acentos y otros símbolos de puntuación, desde SQL Server es necesario que la base de datos use una intercalación *_CI_AI

Pero aunque la base de datos esté bien configurada para que las consultas sean no sensitivas a este tipo de carácteres, si se realiza la consulta desde nuestra aplicación la consulta no será efectiva puesto que desde linq no se explota la facilidad que nos ofrece la base de datos.

Para solucionar esto hay un método que es el que muestro en el siguiente código:

string ntext = new string("TEXTO_A_BUSCAR".Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray());
Lista = Lista.Where(x => (UTF8Encoding.UTF8.GetString(UTF8Encoding.GetEncoding("ISO-8859-8").GetBytes(x.CAMPO_BD)).IndexOf(ntext, StringComparison.InvariantCultureIgnoreCase) > -1)).ToList();

En la primera instrucción normalizamos el texto a localizar en la base de datos, y en la segunda se realiza la búsqueda en sí misma sobre el campo de la base de datos con el cual deseamos hacer el filtro.

Espero que os sirva de ayuda.

Error al cargar y ejecutar el receptor de eventos. “0x8007047e”

Necesitaba que al crear cualquier site todas sus páginas tuviesen un diseño de página customizado.

Aunque en la configuración del site padre tenía configurado que tan sólo podían crearse páginas con el diseño de página en concreto, cuando se creaba el site, la página por defecto (Pages/default.aspx) seguía teniendo el diseño de página “WelcomeLinks”.

Para cambiarlo creé un EventReceiver sobreescribiendo el WebProvisioned (que se dispara una vez que el site se ha creado). Dentro del método, cambiaba el PageLayout y también su ContentType también customizado (añadiéndolo también a la biblioteca de Páginas, ya que no existía por defecto).

Éste es el código del event receiver:

SPWeb w = properties.Web;
PublishingWeb curPubWeb = PublishingWeb.GetPublishingWeb(properties.Web);
SPSite s = properties.Web.Site;
SPContentType contentType = s.RootWeb.ContentTypes["PaginaInvestigador"];
SPList spList = curPubWeb.PagesList;
PublishingPageCollection ppc = curPubWeb.GetPublishingPages();

foreach (PageLayout curLayout in curPubWeb.GetAvailablePageLayouts())
{
     if (ppc.Count > 0)
     {
          PublishingPage curPage = ppc[0];
          curPage.CheckOut();
          curPage.Layout = curLayout;
          curPage.ListItem["ContentTypeId"] = curLayout.AssociatedContentType.Id;
          curPage.ListItem.Update(); 
          curPage.Update();
          curPage.CheckIn(""); 
     }        
}

Para probarlo creaba un nuevo sitio. Cuando lo había creado intentaba editar la página default para comprobar que tanto el diseño de página como el tipo de contenido se habían cambiado correctamente y me daba el siguiente error:

Error al cargar y ejecutar el receptor de eventos Client.Web.SharePointApp.ResearcherSiteEventReceiver.ResearcherSiteEventReceiver en Client.Web.SharePointApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d3b00d8781e2eddd. A continuación se incluye información adicional.

: <nativehr>0x8007047e</nativehr><nativestack></nativestack>

Lo solucioné registrando el event receiver como síncrono de la siguiente forma:

En el fichero Elements.xml, añadir dentro de <Receiver>:

<Synchronization>Synchronous</Synchronization>

Solucionar problema con los diseños de página al actualizar o subir una backup de otra solución o granja

En determinadas ocasiones, cuando actualizamos nuestros desarrollos en máquinas o entornos de producción, nos damos cuenta que en algunas páginas de publicación, cuando las queremos editar, apuntan hacía un Page Layout o diseño de página que apunta hacía una URL del entorno de desarrollo.

No tiene fácil solución, ya que desde el entorno de SharePoint o desde el Designer no se pueden actualizar las referencias.

Por tanto, la única solución fácil y viable es actualizarla a través de código.

A continuación os adjunto una muestra del código que deberéis de aplicar en el caso que queráis aplicar o corregir el diseño de página de una página concreta.

string SiteUrl = "http://serverUrl";
string PageName = "MyPage.aspx";
string PageLayoutURL = "/_catalogs/masterpage/WelcomeLinks.aspx";

using (SPSite site = new SPSite(SiteUrl))
{ 
	using (SPWeb web = site.OpenWeb())  
	{
		WL(web.Title);
		
		PublishingWeb spPubWeb = PublishingWeb.GetPublishingWeb(web);    
		SPList pages = spPubWeb.PagesList;   
		
		foreach (SPListItem item in pages.Items)    
		{
			PublishingPage pubPage = PublishingPage.GetPublishingPage(item);       
			SPFieldUrlValue url = new SPFieldUrlValue(pubPage.ListItem[FieldId.PageLayout].ToString());
			
			if(pubPage.Name==PageName)
			{
				WL(pubPage.Name);
				WL(url.Url.ToString());
				
				SPFieldUrlValue newurl = new SPFieldUrlValue(PageLayoutURL);          
			
			Console.WriteLine(pubPage.Name);          
			
			pubPage.CheckOut();          
			
			pubPage.ListItem[FieldId.PageLayout] = newurl;          
			
			pubPage.ListItem.UpdateOverwriteVersion();           
			
			pubPage.ListItem.File.CheckIn("Fixed URL to page layout.", SPCheckinType.MajorCheckIn);   
			}
			
			
			
		}
	}
}