Before we can actually create the real store functionalities, we will have to add the models and data.
Because we added the Glass.Mapper extension to this solution we can create code first models which will automatically be created in Sitecore as templates.
Creating the models
Normal MVC conventions suggest to add your models in the “Models” folder of your solution, so we will do the same, though it isn’t required.
Let’s first add the Genre model. Add the following “Genre.cs” to the “Models” folder:
using System.Collections.Generic; using Glass.Mapper.Sc.Configuration; using Glass.Mapper.Sc.Configuration.Attributes; namespace MusicStore.Web.Models { [SitecoreType(true, "{A326A413-C7E0-4B59-968D-CC7076EEB983}", TemplateName = "Genre")] public class Genre : IBaseEntity { [SitecoreField("{9789128F-A10B-440E-AADE-B1F34132386D}", SitecoreFieldType.SingleLineText, "Data", FieldName = "Name", FieldSortOrder = 100)] public virtual string Name { get; set; } [SitecoreField("{F8BF9715-7693-485E-AE88-AB4F04096EFA}", SitecoreFieldType.RichText, "Data", FieldName = "Description", FieldSortOrder = 200)] public virtual string Description { get; set; } public List<Album> Albums { get; set; } } }
As you can see the class and its attributes have data annotations which Glass.Mapper uses to create the template and its fields. Next to that the class extends the BaseCommon class from the eFocus.Sitecore.Glass module. This class contains some default Sitecore attributes, like the Sitecore path and Sitecore item ID.
Each class and attribute has to have its own unique GUID. You can also give the templates and fields custom names instead of the code name. And there are multiple field types you can choose from.
For more information and tutorials, see the Glass.Mapper website(http://glass.lu/Mapper/Sc/Tutorials)
As you can also see, we already added a List with albums. This attribute will later be used for the albums overview. But we haven’t created the Album model yet, so let’s add the following class:
using Glass.Mapper.Sc.Configuration; using Glass.Mapper.Sc.Configuration.Attributes; using Glass.Mapper.Sc.Fields; namespace MusicStore.Web.Models { [SitecoreType(true, "{1483783D-CF92-499B-B45F-47D90E9A17A9}", TemplateName = "Album")] public class Album : IBaseEntity { [SitecoreField("{03C3753B-F325-4D56-BFC9-AA00EF110445}", SitecoreFieldType.SingleLineText, "Data", FieldName = "ExternalId", FieldSortOrder = 50)] public virtual string ExternalId { get; set; } [SitecoreField("{A4B5B52B-FC82-413F-B5D0-D3DFF2CBE5BE}", SitecoreFieldType.SingleLineText, "Data", FieldName = "Title", FieldSortOrder = 100)] public virtual string Title { get; set; } [SitecoreField("{0A721A79-C81A-4019-833A-B4B3C58185BD}", SitecoreFieldType.Droplink, "Data", FieldName = "Genre", FieldSource = "DataSource=/sitecore/content/MusicStore/Content/Genres&IncludeTemplatesForSelection=Genre", FieldSortOrder = 200)] public virtual Genre Genre { get; set; } [SitecoreField("{F53A93B9-C6DF-4F87-8984-96E10633617E}", SitecoreFieldType.Droplink, "Data", FieldName = "Artist", FieldSource = "DataSource=/sitecore/content/MusicStore/Content/Artists&IncludeTemplatesForSelection=Artist", FieldSortOrder = 300)] public virtual Artist Artist { get; set; } [SitecoreField("{EAEA340A-EA56-47F7-A1B5-807F7F7A02FC}", SitecoreFieldType.Number, "Data", FieldName = "Price", FieldSortOrder = 400)] public virtual decimal Price { get; set; } [SitecoreField("{E7FCE177-5AA7-4CF6-A982-0270435FCBE7}", SitecoreFieldType.Image, "Data", FieldName = "Album Art", FieldSortOrder = 500)] public virtual Image AlbumArt { get; set; } } }
A new thing we see in this class is the virtual reference to the Genre, Artist and Image models. This attribute is automatically filled with the correct data of the Sitecore item selected in the Album item.
We can also see there is a “FieldSource” added to the Genre and the Artist field. This means the user can only select a droplink value from below that Sitecore path.
Last but not least we will have to add the Artist model before we can build. So add the following model to the project:
using Glass.Mapper.Sc.Configuration; using Glass.Mapper.Sc.Configuration.Attributes; namespace MusicStore.Web.Models { [SitecoreType(true, "{4A80F39F-7A31-43FE-BC3E-0F83E5C482D5}", TemplateName = "Artist")] public class Artist : IBaseEntity { [SitecoreField("{1D66D9D8-2711-4C70-95C2-9DDE6F7C1E4F}", SitecoreFieldType.SingleLineText, "Data", FieldName = "Name", FieldSortOrder = 100)] public virtual string Name { get; set; } } }
Creating functionalities
Next up is creating the StoreController. In our StoreController we will want to have a Details method which shows a View with album details. This method will know which album to show the details from by using the wildcard principal. This means we will create a wildcard page on which the last part of the page URL will be the album id.
But before we create the Controller itself we want to have a service which can provide us with the album data. The BoC package provides some basic repository functionalities which we can use to provide data from Sitecore. But because these functionalities are very basic, we need to create a shell around them. So let’s create an AlbumService which derives from the BoC.Service.BaseModelService<TModel> class(where TModel should obviously be implemented as Album). This BaseModelService uses Content Search to provide some basic repository functionalities, like getting but also inserting and updating data.
Then create a method GetAlbum with a string parameter id. This method will use the BaseModelService It’s Get method to get the specific album model from Sitecore.
using System; using System.Linq; using BoC.EventAggregator; using BoC.Persistence; using BoC.Services; using BoC.DataContext; using BoC.Validation; using MusicStore.Web.Models; using Sitecore.Data; namespace MusicStore.Web.Services { public class AlbumService : BaseModelService<Album>, IAlbumService { public AlbumService(IModelValidator validator, IEventAggregator eventAggregator, IRepository<Album> repository) : base(validator, eventAggregator, repository) { } public Album GetAlbum(object id) { using (DataContext.BeginDataContext()) { int externalId; Album album = null; if (id is Guid) album = Get(id.ToString()); else if (ID.IsID(string.Concat(id))) album = repository.Get(string.Concat(id)); else if (int.TryParse(string.Concat(id), out externalId)) album = Find(a => a.ExternalId.Equals(string.Concat(id), StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); else album = Find(a => a.Name.Equals(string.Concat(id), StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); return album; } } } }
Now we can create the StoreController with the Details method. The method receives a string parameter with the id(which will be provided through the WildcardValueProvider from the BoC)
Create the content
Now build the solution, deploy it, and open the Sitecore Content Editor.
The generated templates created by Glass.Mapper are placed in the /sitecore/templates/GlassTemplates folder. Move the templates we just created to a more specific project location like /sitecore/templates/User Defined/MVC MusicStore.
Now you can start adding the content for the Artists, Genres and Albums.
Make sure the FieldSource value of the Album fields is still correct. Either create the same structure, or change the value of the FieldSource.