En este artículo trataré de dar una introducción a Glass.Mapper,  las ventajas que ofrece al usarlo en Sitecore y un ejemplo practico que ilustre el funcionamiento de esta herramienta.

Introducción

Glass Mapper es un ORM, un framework para mapping de objetos,  que mapea los items que generamos en Sitecore a nuestro modelo manteniendo las relaciones entre objetos. De este modo, tenemos facilmente mapeado los campos en propiedades de nuestros modelos proporcionándonos acceso a su contenido (content field). Es decir, los campos (fields) de nuestros templates se exponen como propiedades de lectura/escritura y permiten su testeabilidad.

Ventajas de Glass.Mapper

Así como ASP.NET MVC tiene soporte para TDD (Test Driven Development o Desarrollo Dirigido por Tests), Sitecore MVC no da soporte a ello ya que el acceso a su contexto (Sitecore Context) es estático, y este es necesario para acceder a la API de Sitecore. Esto lo resuelve Glass.Mapper gracias a:

  1. Glass Mapper proporciona dos interfaces ISitecoreContext y ISitecoreService. La primera, ISitecoreContext, es la implementación de Glass del Sitecore Context, que podemos usar para acceder al mismo y realizar tests unitarios.
  1. Y la otra ventaja fundamental de Glass Mapper es evitar lo que se conoce como ‘boiler plate code’ o lo que es lo mismo código no reutilizable que tenemos que escribir en multiples sitios de un proyecto web.

Trabajando con Glass.Mapper

El mejor modo de ver como funciona una herramienta de este tipo es a través de un ejemplo, por lo que vamos  a crear un modelo con clases que  la informacion de un Menu de Navegación tipico de cualquier web. Crearemos  los modelos para recoger los elementos de un menú de navegación y una interfaz que herederá de una interfaz base, que recogerá dichos elementos en una colección.

A la hora de crear nuestro modelo, debemos utilizar los atributos que nos proporciona para aplicarlos a nuestras clases y campos de forma que con los mismos le indicamos la configuración de mapeo entre los items de Sitecore  y nuestras clases. Como practica recomendada, debemos crear una interfaz IBaseItem de la que heredan el resto de clases/interfaces con los campos Id, Version y Children (que es una colección de IBaseItems).

Nuestro modelo y nuestro proyecto ASP.NET MVC deberán incluir las librerias de Glass, que bien podemos incluirlas manualmente o descargarnoslas utilizando el gestor de paquetes  NuGet.

Nuestro proyecto con el mo
Glass DLLs

Nuestro proyecto MVC, además debería incluir una referecia a Castle.Core

Glass Libraries

Para el siguiente ejemplo crearemos una interfaz IBaseItem de la que heredan el resto de clases/interfaces con los campos Id, Version y Children (que es una colección de IBaseItems). Aqui está el codigo de la interfaz IBaseItem

using System;
using System.Collections.Generic;
using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.Configuration.Attributes;

namespace GlassMapper.Models.Common
{
 public interface IBaseItem
 {
 [SitecoreId]
 Guid Id { get; }

 [SitecoreInfo(SitecoreInfoType.Language)]
 Sitecore.Globalization.Language Language { get; }

 [SitecoreInfo(SitecoreInfoType.Version)]
 int Version { get; }

 IEnumerable<IBaseItem> Children { get; set; }
 }
}

Después por cada tipo de item que maneja en los renderings, o lo que vendría a ser lo mismo, por cada template crea una interfaz con los mismas propiedades que fields tiene ésta. Esto le permite a Glass.Mapper hacer el mapeado automático de los ítems de dicho template, su contenido, con los nuestros objetos

La interfaz INavigationMenu

using System.Collections.Generic;
using Glass.Mapper.Sc.Configuration.Attributes;
using GlassMapper.Models.Common;

namespace GlassMapper.Models.Navigation
{
 [SitecoreType(TemplateId = "{F5E2916D-F072-4F93-82E2-E7E32A7BF212}", AutoMap = true)]
 public interface INavigationMenu : IBaseItem
 {
 [SitecoreChildren(InferType = true)]
 IEnumerable<INavigationItem> NavigationItems { get; set; }

 [SitecoreChildren(InferType = true)]
 IEnumerable<INavigationMenu> NavigationMenus { get; set; }
 }
}

 

La interfaz INavigationItem con el campo de tipo Link que utilizaremos para renderizar

using GlassMapper.Models.Common;
using Glass.Mapper.Sc.Configuration.Attributes;

namespace GlassMapper.Models.Navigation
{

 [SitecoreType(TemplateId = "{83D8A37A-598C-413C-B0FF-2544F47CD91D}", AutoMap = true)]
 public interface INavigationItem : IBaseItem
 {
 Glass.Mapper.Sc.Fields.Link Link { get; set; }
 }
}

Como ya habrás deducido, el TempalteId indicado en el atributo SitecoreType corresponde a los templates de la instancia Sitecore que contienen dichos campos (field types).

 

Ahora creamos un Controllador que herede de GlassController  y que utilice el contexto actual a través de SitecoreContext para obtener la informarción de los items para el menu de Navegación con el metodo Top() y lo mismo para el pie de pagina con el método Footer()

using System;
using System.Web.Mvc;
using GlassMapper.Models.Navigation;
using Glass.Mapper.Sc.Web.Mvc;

namespace GlassMapper.Controllers
{
 public class NavigationController : GlassController
 {
  public ActionResult Top()
  {
   INavigationMenu topMenu = SitecoreContext.GetItem<INavigationMenu>("/sitecore/content/example/data/navigation/top");
   return View(topMenu);
  }
  public ActionResult Footer()
  {
   INavigationMenu footerMenu = SitecoreContext.GetItem<INavigationMenu>("/sitecore/content/example/navigation/footer");
   return View(footerMenu);
  }
 }
}

Y a continuación el codigo de la vista Top.cshtml que se encargará de renderizar el menú de Navegació.

using System;
using System.Web.Mvc;
using GlassDemo.Models.Navigation;
using Glass.Mapper.Sc.Web.Mvc;

namespace GlassDemo.Controllers
{
 public class NavigationController : GlassController
 {
  public ActionResult Top()
  {
   INavigationMenu topMenu = SitecoreContext.GetItem<INavigationMenu>("/sitecore/content/glassdemo/data/navigation/top");
   return View(topMenu);
  }
  public ActionResult Footer()
  {
   INavigationMenu footerMenu = SitecoreContext.GetItem<INavigationMenu>("/sitecore/content/glassdemo/example/navigation/footer");
   return View(footerMenu);
  }
 }
}