Glass Mapper is hands down the best ORM available for Sitecore Development. I have been using it for five years and love it. It helps you map Sitecore templates and fields to .NET classes, objects and properties.
I recently decided to upgrade to v4.3 from v4.0.1.8. Upgrading from v3 to v4 was a little bit hairy, but upgrading to v4.3 was pretty easy.
Update from Nuget
First, I loaded the new version of Glass Mapper from Nuget. I opened the Package Manager Console and ran:
Install-Package Glass.Mapper.Sc -Version 4.3.4.197
Installing the Nuget package wipes out App_Start/GlassMapperScCustom.cs class, so I needed to re-add my custom data mappers. My GlassMapperScCustom class looked like this after I was done.
#region GlassMapperScCustom generated code using Glass.Mapper.Configuration; using Glass.Mapper.IoC; using Glass.Mapper.Maps; using Glass.Mapper.Sc.IoC; using IDependencyResolver = Glass.Mapper.Sc.IoC.IDependencyResolver; using Glass.Mapper.Configuration.Attributes; using SomeProject.CustomDataHandler; namespace SomeProject.App_Start { public static class GlassMapperScCustom { public static IDependencyResolver CreateResolver() { var config = new Glass.Mapper.Sc.Config(); var dependencyResolver = new DependencyResolver(config); // add any changes to the standard resolver here dependencyResolver.DataMapperFactory.Insert(0, () => new LinkListDataHandler()); dependencyResolver.DataMapperFactory.Insert(0, () => new CustomInternalLinkDataHandler()); return dependencyResolver; } public static IConfigurationLoader[] GlassLoaders() { var attributes = new AttributeConfigurationLoader("SomeProject"); return new IConfigurationLoader[] { attributes }; } public static void PostLoad() { var dbs = Sitecore.Configuration.Factory.GetDatabases(); foreach (var db in dbs) { var provider = db.GetDataProviders().FirstOrDefault(x => x is GlassDataProvider) as GlassDataProvider; if (provider != null) { using (new SecurityDisabler()) { provider.Initialise(db); } } } } public static void AddMaps(IConfigFactory< IGlassMap > mapsConfigFactory) { } } } #endregion
Ambiguous Reference
I re-built my solution and ran into some compiler errors.
Easy problem to resolve: a simple conflict between a Glass abstraction of the Sitecore Diagnostics log and the Sitecore Diagnostics log. I considered removing the references to Sitecore.Diagnostics and using the Glass method, but the Glass.Mapper.Sc.Log class requires an instance to be used. So, I simply globally changed my Log references in code to Sitecore.Diagnostics.Log.
Model Depth Check
The solution now compiled successfully. When I tested the application, I encountered:
Server Error in ‘/’ Application.
Model too deep. Potential lazy loading loop. Type requested: SomeProject.Models.IGlassBase SomeProject.Models.IGlassBase
SomeProject.Models.IGlassBase
SomeProject.Models.IGlassBase
SomeProject.Models.IGlassBase
SomeProject.Models.IGlassBase
SomeProject.Models.IGlassBase
SomeProject.Models.Pages.HomePage
SomeProject.Models.Parts.DesktopMenu
After a quick Google search, I re-read the Glass Mapper 4.3 Release Notes. The depth check mechanism added for the Cachable Changes was breaking the code. This was another easy fix. I refactored the CreateResolver method as per the release notes:
public static IDependencyResolver CreateResolver() { var config = new Glass.Mapper.Sc.Config(); // Needed to avoid Model too deep exception config.EnableLazyLoadingForCachableModels = true; var dependencyResolver = new DependencyResolver(config); // add any changes to the standard resolver here dependencyResolver.DataMapperFactory.Insert(0, () => new LinkListDataHandler()); dependencyResolver.DataMapperFactory.Insert(0, () => new CustomInternalLinkDataHandler()); var factory = dependencyResolver.ObjectConstructionFactory as AbstractConfigFactory < AbstractObjectConstructionTask >; factory.Remove< ModelDepthCheck >(); return dependencyResolver; }
Naughty GlassCast
The next issue I worked through was the depreciation of the GlassCast method. Mike Edwards, the “Godfather of Glass Mapper”, did an incredible job explaining why GlassCast can lead to performance problems. I had an embarrassing amount of GlassCast method calls sprinkled throughout the code base.
model = MiscContentFactory.GetRelatedContent (Sitecore.Context.Item.Parent.GlassCast< CustomModelClass >().Id.ToString(), parameters.NumberOfItems);
This was straight forward. I removed all references to GlassCast. I chose to replace GlassCast with use of the Cast method from the SitecoreService object.
ISitecoreService service = new SitecoreService(Sitecore.Context.Database); model = MiscContentFactory.GetRelatedContent (service.Cast< CustomModelClass >(Sitecore.Context.Item.Parent).Id.ToString(), parameters.NumberOfItems);
Embedded Markup in RenderLink Contents Parameter
The next implementation issue was instances of RenderLink being used with embedded markup in the contents attribute.
@RenderLink(x => home.SomeLinkProperty, new System.Collections.Specialized.NameValueCollection() { { "class", "print-logo" } }, contents: "< span class=\"icon-openenvelop\" >< / span > < span class=\"print-logo\">" + home. SomeLinkProperty.Text + " < / span >")
I could not find a way to make this work. I ended up converting every use of the method RenderLink to BeginRenderLink.
@using (BeginRenderLink(x => home.SomeLinkProperty, new System.Collections.Specialized.NameValueCollection() { { "class", "print-logo" } }, isEditable: true)) { < span class="icon-openenvelop" > < /span >< span class="print-logo" > @home. SomeLinkProperty.Text < / span > }
I suppose I could have created a helper class to work around this to avoid all the rework, but I felt this was clearer long term solution.
Empty Model Values for View Renderings
The last issue that I encountered was View Renderings with blank Model class values.
This caused the following error to appear on various pages:
The model item passed into the dictionary is of type ‘Sitecore.Mvc.Presentation.RenderingModel’, but this dictionary requires a model item of type ‘X’
Sloppy development practices left the Model values blank for some View Renderings, even though the View Renderings get bound to specific Model classes in the View. I reviewed all of the View Renderings and set the Model values that were blank to the appropriate custom model class.
Conclusion
Upgrading to Glass Mapper v4.3 was fairly straightforward and well worth the effort.