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.

ambiguous reference error

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.

blank view model value in Sitecore View Rendering

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.

Sitecore View Rendering with valid model value

Conclusion

Upgrading to Glass Mapper v4.3 was fairly straightforward and well worth the effort.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s