SharePoint Lookup Field Throttling Causes Missing Fields in CSOM Query

A very annoying bug appeared few weeks ago in one of our production environments with SharePoint 2013.

SYMPTOMS

You have a custom list with some lookup columns that refer to other lists. In our case the main list contained news and the lookup columns contained the classification of the news.

You add a new lookup column to the list, due to customer feedback.

Suddenly, you can’t get the list results any more by code. When you do a CSOM query, the lookup fields are lost. Only the non-lookup fields are retrieved.

CAUSE

SharePoint throttling also includes list item maximum lookup references. It is set to eight (8) lookup fields per list, by default.

Resource Throttling

This particular configuration is set on the web application throttling page in Central Administration, under the heading “List View Lookup Threshold”.

SOLUTION

If you don’t need all of the lookups at the same time, you can still make the query by choosing the fields you want to retrieve. However, in our case we needed all of the classification columns.

In this case you have two choices:

  • Increase the list lookup threshold limit to more than 8 (that’s what we did)
  • Establish a large query window, an interval during the day during which you can perform the queries

Las apps de SharePoint 2013 (V): Una app provider-hosted en Azure

En la serie de posts sobre el desarrollo de apps de SharePoint 2013, hemos visto hasta ahora un ejemplo de app de SharePoint 2013 para niños alojada en SharePoint mismo y otro ejemplo de app alojada “automágicamente” en Azure. Ahora falta una vuelta de tuerca más para ver el modelo que nos queda: las llamadas aplicaciones provider-hosted.

Si recordamos los tres modelos de alojamiento de apps que hay en SharePoint 2013, las aplicaciones provider-hosted requieren intervención manual para que SharePoint y la parte servidora se hablen entre ellos. En el caso de Azure esto se reduce bastante porque las herramientas de SharePoint y de Azure nos lo facilitan, pero si hacemos una subida a la nube de Amazon o a nuestro propio datacenter, la cosa se nos hace un poquito más engorrosa, sin llegar a ser difícil en ningún caso.

El punto de partida

Vamos a empezar con la aplicación desarrollada para el modelo autohosted en Azure, para ir más ágiles y para seguir usando ASP.NET MVC (que es lo que mola ahora).

image

La vamos a subir “manualmente” a Azure Web Sites y le vamos a decir a SharePoint que se conecte a ella cuando el usuario clica la app.

Nota: A los que ya conocéis Azure y pensáis que estoy mostrando solo la parte “express”, os comento que estoy dejano para una próxima entrega de la serie de posts una app totalmente “Azure” que use servicios más avanzados como Storage, SQL Azure etc.

Configuración de Azure

El primer paso es ir a nuestro panel de control de Azure (o darnos de alta en la prueba gratis de Azure de 90 días y luego ir al panel de control). Allí crearemos un sitio web de Azure, sencillo, y usaremos los detalles del sitio para configurar el proyecto MVC en Visual Studio.

Iremos a la opción Sitios Web y crearemos uno nuevo con el nombre EdinSpMvc-Provider.

image

Esperamos unos momentos y el sitio se habrá creado correctamente

image

Ahora vamos a clicar la flecha al lado del nombre del sitio web para ver el panel de control del sitio y descargaremos el perfil de publicación (en Vista Rápida) para usarlo en Visual Studio más adelante.

image

Creación de la app en SharePoint

Ahora iremos a nuestro sitio en SharePoint 365 Developer Site (en mi caso es https://edinkapic.sharepoint.com/sites/dev). Tenemos que hacer un “truquillo” para registrar una app manualmente: añadiremos a la URL del sitio el sufijo /_layouts/15/appregnew.aspx.

Se nos abre la ventana de registro de una nueva app.

image

Esta es “la madre del cordero” que enlaza SharePoint con nuestra app. Explicaré los conceptos que tenemos que introducir (para más detalles está la MSDN):

  • App Id: esto es un Guid que identifica la app de manera única. Generaremos uno al azar dándole al botón Generar.
  • App Secret: esto la parte pública de una clave asimétrica que usa SharePoint para validar que nuestra app tiene permisos para conectarse. Nuestra app en MVC se conectará a SharePoint pasándole la este secreto junto con más parámetros y SharePoint comprobará que es efectivamente la app que él autorizó. Generaremos una al azar dándole al botón Generar.
  • Title: El título de la app. Pondremos App Provider-Hosted en Azure y MVC
  • App Domain: aquí irá el dominio de nuestro hosting (Azure Web Sites). Pondremos edinspmvc-provider.azurewebsites.net
  • Redirect URL: aquí pondremos la página de inicio de nuestra aplicación MVC, en nuestro caso https://edinspmvc-provider.azurewebsites.net/Home. Es imprescindible poner HTTPS (en Azure no tenemos que preocuparnos porque automáticamente tenemos HTTPS en Web Sites, pero si lo subimos a otro hosting tenemos que asegurarnos de que disponga de HTTPS habilitado).

image

Le damos a Create y nos aparecerán los detalles una app que lamentablemente no será funcional porque todavía no hemos subido nada a Azure. Apuntamos estos detalles para más adelante.

image

Intercambio de cromos

Ahora nos toca retocar un poco nuestra solución en Visual Studio para pasar estos datos de la app manualmente a nuestros proyectos.

En el proyecto de SharePoint App (EdinSpMvc)

Primero vamos a cambiar el tipo del proyecto de app de SharePoint 2013 de Autohosted a Provider-hosted. No hay ninguna UI para hacerlo, pero afortunadamente editando el AppManifest.xml lo podemos conseguir. Sólo hay que:

  • Eliminar la sección AppPrerequisites
  • Reemplazar el elemento AutoDeployedWebApplication dentro de AppPrincipal por <RemoteWebApplication ClientId="508e1afa-40d8-4e2b-99dc-7604460cf864" />. Si habéis prestado atención, es el AppId que nos ha generado SharePoint para la app.
  • Sustituir la URL en el elemento StartPage por la URL completa del sitio, quedando así: https://edinspmvc-provider.azurewebsites.net/Home?{StandardTokens}

image

En el proyecto web MVC (EdinSpMvc4Web)

Aquí tenemos que añadir los valores reales de AppId y AppSecret dentro del fichero web.config (en los elementos ClientId y ClientSecret):

image

Ahora procederemos a subir el proyecto web a Azure. Para ello haremos botón derecho en el proyecto web, clicar Publish y en la pantalla que se nos abre elegir el fichero que previamente descargamos de Azure.

imageimage

Le damos a Publish y veremos que Visual Studio sube nuestra app a Azure y la abre. No os preocupéis que esté dando errores al abrirse, es normal porque le falta el contexto de app de SharePoint.

image

Aún nos queda un pequeño paso: meter el AppId y AppSecret otra vez en Azure ya que al subir la web se “pierde” el valor de los appSettings. Para ello hay que ir a la pantalla de gestión de Sitios Web de Azure y en el enlace Configuración de nuestro sitio añadir las dos entradas idénticas a las del web.config. ¡No os olvidéis de darle a Guardar en la botonera inferior!

image 

Pasos finales y el resultado

Ahora podemos hacer un Deploy de la solución desde Visual Studio 2012 y ocurrirá la magia, esta vez con un poco más de preparativos que la última vez.

imageimage

Como es habitual, os dejo el código de esta aplicación en mi cuenta de SkyDrive.

¡Hasta la próxima entrega!

Las apps de SharePoint 2013 (IV): Una app en MVC y en Azure

En la serie de posts sobre el desarrollo de apps de SharePoint 2013, hasta ahora hemos visto como se desarrolla una app sencilla y alojada en SharePoint (es decir, las “SharePoint-hosted” apps). Ahora vamos a subir un poco la dificultad (no mucho, os lo prometo) y vamos a hacer una app que se ejecuta fuera de SharePoint.

Para que el ejemplo sea más interesante, vamos a hacerlo en un “sabor” de ASP.NET al que no estamos tan acostumbrados los SharePointeros: ASP.NET MVC 4. Como la app fuera de SharePoint puede estar escrita en cualquier lenguaje que se nos antoje, usaremos MVC 4 para aprovecharnos de la librería de modelo de objetos de cliente de SharePoint 2013 (CSOM) y ahorrarnos trabajo.

SharePoint 2013 y Azure

En estos momentos Microsoft ofrece una cuenta de desarrollador de Office (incluyendo SharePoint) gratis si nos apuntamos en este enlace. Con ello se nos dará un sitio en Office 365 Preview (es decir la versión 2013) ya preparado para alojar apps de SharePoint 2013. Además, se nos dará una cuenta “invisible” en Azure para nuestras apps. Digo que es invisible porque no hay manera (de momento) de gestionar la suscripción para estas apps.

image

Para las apps que se consideran “Autohosted”, Visual Studio 2012 con las herramientas de SharePoint va a hacer una doble función:

  • Si estamos desarrollando y le damos a F5, VS2012 va a subir el descriptor de nuestra app a la cuenta de Office 365 de desarrollador (esto lo configuramos nosotros en el proyecto de app) pero la apuntará a nuestro localhost donde se ejecutará el proyecto web de ASP.NET que contiene la lógica de la app.
  • Si hacemos un Deploy de la solución, VS2012 subirá el descriptor de la app a Office 365 (como antes) pero además subirá el proyecto web a un subdominio de o365apps.net, que es una suscripción especial de Azure Web Sites disponible a nosotros como desarrolladores de la app. El subdominio será un GUID creado de manera automática al deployar la app. Además, va a cambiar el descriptor de la app para que apunte a Azure y no a nuestro localhost.

Vale la pena recalcar que la suscripción “invisible” de Azure para apps de Office/SharePoint sólo incluye Web Sites (un hosting de IIS, vamos) y SQL Azure (mediante scripts), sin incluir nada de Media Services, Mobile Services, Storage, Compute y otras maravillas de Azure.

La app en Azure y MVC, paso a paso

Para que todo esto resulte más fácil de digerir, vamos a hacer un pequeño ejemplo que muestre las listas y bibliotecas que hay en el SharePoint donde está alojada la app. Lo codificaremos en MVC 4 y lo “subiremos automágicamente” a Azure. El prerrequisito es, como siempre, tener instaladas las herramientas de desarrollo de SharePoint 2013 con Visual Studio 2012 y tener la suscripción de desarrollador de Office 365.

Abrimos Visual Studio 2012 como Administrador y creamos un proyecto nuevo de Aplicación de SharePoint 2013. Le decimos a VS2012 que la app es de tipo Autohosted y le pasamos la URL de nuestro Developer Site de Office 365.

imageimage

Visual Studio creará dos proyectos: el de la app (EdinSpMvc, poco más que un manifest) y el proyecto ASP.NET WebForms (EdinSpMvcWeb) con la parte de la app que se ejecuta fuera de SharePoint. Como podéis ver, contiene una página Default.aspx de toda la vida.

image

Como esta basura tecnología no nos interesa, vamos a agregar otro proyecto web, esta vez una aplicación web de MVC 4. Es importante seleccionar NET Framework 4 en vez de 4.5 que nos sale por defecto, ya que el Azure que nos da Office Developer no tiene todavía soporte para NET 4.5. A continuación, elegimos Basic como plantilla por defecto de la aplicación MVC.

imageimage

Ya tenemos 3 proyectos: el de la app, el de web ASP.NET y el de web MVC 4.

image

Vamos a configurar el proyecto web MVC con algunos detallitos para que funcione bien con SharePoint 2013. Tenemos la suerte de que las herramientas de VS2012 ya lo hacen automáticamente por nosotros.

Primero, vamos a las propiedades del proyecto de app de SharePoint para asociar el proyecto web MVC en la propiedad Web Project. En este momento VS2012 nos preguntará si queremos que nos adjunte las referencias de SharePoint y que quite la página por defecto, a lo de que vamos a contestar que sí.

imageimage

Fijaos que el proyecto MVC ahora tiene las referencias de SharePoint 2013 y de Identity Framework, así como el fichero auxiliar TokenHelper.cs que nos ayudará a hacer la autenticación contra SharePoint. Además, la propiedad SSL Enabled del proyecto MVC está puesta a True porque es necesario HTTPS para que funcione el paso de credenciales.

Por último, hay que corregir la Start URL de la app (que apunta ahora a EdinSpMvc4Web/Pages/Default.aspx) editando el fichero AppManifest.xml del proyecto de app de SharePoint. Ponemos EdinSpMvc4Web/Home para apuntar al controller Home.

image

Podemos eliminar el proyecto de ASP.NET WebForms, porque ya no lo necesitamos.

Ahora vamos a agregar la “chicha”, la lógica de negocio en nuestra aplicación MVC. Para ello crearemos un controller nuevo llamado HomeController y una vista asociada llamada Index en su carpeta ViewsHome.

imageimageimageimage

En la acción Index del HomeController, vamos a ponerle el siguiente código, sin olvidarnos de poner la clausula using Microsoft.SharePoint.Client:

var contextToken = TokenHelper.GetContextTokenFromRequest(System.Web.HttpContext.Current.Request);
var hostWeb = System.Web.HttpContext.Current.Request["SPHostUrl"];

using (var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority))
{
    var web = clientContext.Web;

    clientContext.Load(web, w => w.Lists.Include(l => l.Title).Where(l => !l.Hidden));
    clientContext.ExecuteQuery();
    clientContext.Dispose();

    return View(web.Lists);
}

En este ejemplo lo que hacemos es obtener el token de contexto (proporcionado por SharePoint 2013 al redireccionar a la app en Azure) y con este token de contexto abrimos un contexto de cliente (lo que necesitamos para usar el modelo de objetos de cliente de SharePoint 2013). Fijaos que no estamos proporcionando ninguna credencial de cliente, sino que la propia app se autentica contra SharePoint.

Ahora nos falta hacer que la vista muestre las listas que le hemos pasado en la acción. Abrimos la vista y le añadimos:

@{
    ViewBag.Title = "App de SharePoint con MVC";
}

<div>
    <ul>
        @foreach (var list in Model)
        {
            <li>@list.Title</li>
        }
    </ul>
</div>

Con este código conseguimos que la vista muestra las listas que le pasa el controlador. Le damos a F5 y nuestra app se ejecuta en SharePoint 2013 pero apuntando a nuestro localhost:

image

Confirmamos que nuestra app es de confianza…y vemos la app ejecutándose en MVC (en nuestra máquina):

image

Para los curiosos: el VS2012 ha agregado un ClientId y ClientSecret a nuestro web.config automáticamente (y también los ha registrado en el servidor de SharePoint). De esta manera la llamada de nuestra aplicación MVC a SharePoint está autorizada porque se basa en un ID y secreto conocidos por SharePoint.

image

El último paso que nos queda es darle un poco de aspecto de SharePoint a la app, cambiando la “master” (la vista _layout.cshtml) para incluir la barra de herramientas de SharePoint 2013.

En la sección BODY añadiremos un DIV a modo de “placeholder” donde insertaremos la barra de herramientas.

<div id="barraSharePoint"></div>

En la sección HEAD, debajo de la referencia a @Scripts.Render("~/bundles/modernizr"), agregaremos el código siguiente:

<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script>     
    
<script type="text/javascript">
  var hostweburl;
  $(document).ready(function () {
      hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
      var scriptbase = hostweburl + "/_layouts/15/";
      $.getScript(scriptbase + "SP.UI.Controls.js", renderChrome)
  });
  function renderChrome() {
      var options = {
          "appIconUrl": "/Content/Images/user-logo.png",
          "appTitle": "@ViewBag.Title",
          "settingsLinks": [
              {
                  "linkUrl": "http://spblogedin.blogspot.com",
                  "displayName": "Blog de Edin"
              }
          ]
      };
      var nav = new SP.UI.Controls.Navigation("barraSharePoint", options);
      nav.setVisible(true);
  }
  function getQueryStringParameter(paramToRetrieve) {
      var params =
          document.URL.split("?")[1].split("&");
      var strParams = "";
      for (var i = 0; i < params.length; i = i + 1) {
          var singleParam = params[i].split("=");
          if (singleParam[0] == paramToRetrieve)
              return singleParam[1];
      }
  }
</script>

Lo que hace este código es obtener la URL del SharePoint (el parámetro SPHostUrl)  y llamar a su script SP.UI.Controls.js que se encarga de dibujar la UI. Lo llamamos desde SharePoint mediante una llamada a $.getScript (para evitar el problema de JS cross-domain) y en la función de callback pintamos una barra (un control SP.UI.Controls.Navigation). Para construir este control le pasamos un objeto JS con las propiedades que van a controlar la manera en la que se va a dibujar. He aprovechado también para agregar un pequeño logo para la aplicación, creando una carpeta Images dentro de Content en el proyecto MVC y subiendo el logo por defecto de una aplicación de LightSwitch.

Ahora ya estamos preparados para hacer un Deploy Solution en vez de un F5. Se nos vuelve a abrir una instancia del navegador pidiendo autorización para la app. La sorpresa es que esta vez nuestra aplicación de MVC está en el sitio web de Azure para Office Developers (dominio o365apps.net), como podéis observar:

image

Además, la aplicación ahora tiene una pinta más “SharePointera” y con un menú de control que tiene el enlace a este blog Winking smile

image

Os dejo el código fuente en mi SkyDrive, por si no tenéis ganas de escribir código, jeje.

En la próxima entrega de esta serie veremos como hacer una aplicación Provider-hosted en Azure, con lo que podemos aprovechar todos los servicios que nos ofrece Azure para construir nuestra app.