Glass.Mapper is an ORM (Object-relational mapping) tool in Sitecore. Without it, developers are tasked with manually mapping and querying Sitecore data to populate objects in the code.
Glass.Mapper makes mapping Sitecore data to strongly typed C# models in our solution exceptionally easy. It also has support for the Experience Editor to make any field editable.
Let's Get Started
The first thing you must do is create a Template for your Sitecore object. In this Demo, we are creating a basic Template in Sitecore with three fields:
- Heading - Single-Line Text Field
- Body - Single-Line Text Field
- Link - General Link Field
We will want to save the associated GUIDs for this newly created Template (and future Templates) in a file called Templates.cs. This way, all our GUIDs are stored and referenced from one location.
public class Templates
{
public struct HeroBanner
{
public const string ID = "{950709F6-01BC-4252-B7A3-4A24D39D3F9B}";
public struct Fields
{
public const string Heading = "{7DE51C08-3EA0-47A8-9E67-6C601831547A}";
public const string Body = "{B297F254-B3E7-482E-9E8E-6474ED4CE1D8}";
public const string Link = "{ECB530C8-62D6-46F9-973C-24379320FB34}";
}
}
}
It is recommended that you create a BaseModel that all Glass.Mapper Models inherit from. Within this Model, we will define standard fields like the Id, Url, and TemplateId, as seen below.
If you are using the Helix pattern in Sitecore, this file should live in one of the Foundation projects where other Features can inherit it.
public class BaseModel {
[SitecoreId]
public virtual Guid Id { get; set; }
[<span class="hljs-meta">SitecoreInfo(SitecoreInfoType.Url)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">string</span> Url { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
[<span class="hljs-meta">SitecoreInfo(SitecoreInfoType.TemplateId)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> Guid TemplateId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
Here we will create our object that our Sitecore data in our Controller will eventually populate.
It is best practice to reference the fields in our ViewModel by the GUIDs we have added to our Templates.cs file. There is a way to auto-map the Sitecore fields to the C# property name if they match. However, when we use the Field GUID, if the name of a Field is changed in Sitecore, it will not break our code.
[SitecoreType(TemplateId = Templates.HeroBanner.ID)]
public class CardOverlayBannerViewModel : BaseModel
{
[SitecoreField(FieldId = Templates.HeroBanner.Fields.Heading)]
public virtual string Heading { get; set; }
[<span class="hljs-meta">SitecoreField(FieldId = Templates.HeroBanner.Fields.Body)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">string</span> Body { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
[<span class="hljs-meta">SitecoreField(FieldId = Templates.HeroBanner.Fields.Link)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> Link Link { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
IMvcContext is a Service that exists (as of Glass.Mapper 5), allowing us to get our data source item and map it to our strongly typed C# object.
We use Dependency Injection to instantiate the object in our Controller's constructor.
Then we can use _mvcContext.GetDataSourceItem<Type>(); in our Controller function called by the Controller Rendering item within Sitecore. This will get the data source item tied to the current rendering and map it to the passed Type we have inserted between the brackets.
<span class="hljs-keyword">private</span> IMvcContext _mvcContext; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BasicContentController</span>(<span class="hljs-params">IMvcContext mvcContext</span>)</span> { _mvcContext = mvcContext; } <span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">HeroBanner</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">var</span> model = _mvcContext.GetDataSourceItem<HeroBannerViewModel>(); <span class="hljs-keyword">return</span> View(model); }
Now we will create our Razor .cshtml file. Note: This file must have the same name as the controller function (i.e. HeroBanner.cshtml) otherwise, you will need to pass in the filename as a parameter in the View method.
When we use @Html.Glass().Editable, we allow the fields to be editable within Experience Editor in Sitecore. These fields will then render out just the field's contents in Preview or Normal mode. Nothing will be rendered out if there is no data in the field.
There are some other functions, such as @Html.Glass().RenderLink, which we use when we want to render out link fields. In my example below, I have shown you how to add a class to the anchor tag rendered by this code.
@using Glass.Mapper.Sc.Web.Mvc
@model MyProject.Feature.ViewModels.HeroBannerViewModel
<div class="hero-banner">
<h1>@Html.Glass().Editable(x => x.Heading)</h1>
<div class="body">@Html.Glass().Editable(x => x.Body)</div>
@Html.Glass().RenderLink(x => x.Link, new { @class = "button" }, isEditable: true)
</div>
For learning's sake, I have also included another example of how a link could be rendered in the view file. Let's say we wanted to wrap our component's contents in an anchor tag, making the whole component clickable.
In this case, we would want to use the BeginRenderLink function. Make sure this is captured in a using tag, as seen below. The parameters for this method are the same as above.
@using Glass.Mapper.Sc.Web.Mvc
@model MyProject.Feature.ViewModels.HeroBannerViewModel
<div class="hero-banner">
@using (BeginRenderLink(x => x.Link, new { @class = "link-wrapper" }, isEditable: true))
{
<h1>@Html.Glass().Editable(x => x.Heading)</h1>
<div class="body">@Html.Glass().Editable(x => x.Body)</div>
}
</div>