Git gotcha

A little Git gotcha that I’ve seen crop up from time to time is an obtuse error encountered when trying to pull a branch or carry out a Git fetch command:

  • error: cannot lock ref ‘refs/remotes/origin/feature/xyz’: is at aff0047acaf8f324f70b9d7f71279f9ed5efb66d but expected 4b3db3223c87a8b0a06ed0f731aa15b5d8f6dfc8
  • ! 4b3db3223..e7a86e61afeature/xyz -> origin/feature/xyz (unable to update local ref)

This can affect developers during their day to day workflow using Git but where its most commonly noticed is on the build server when all the CI builds start failing, emails get sent, alarms go off and people get shouty. 😉

It’s not particularly obvious, but this can occur if there are two branches on origin with the same name but different capitalisation e.g.

  • feature/xyz
  • feature/Xyz

This only occurs on Operating Systems with case insensitive file systems such as Windows.

To resolve the issue rename or delete one of the branches and you’re good to go again.

Sitecore Virtual Developer Day 2019

Sitecore hosted their second Virtual Developer Day on 7th March. This was a free online event offering a series of webcasts on Sitecore related topics by a variety of speakers from the community. After filling in a simple registration form the, presentation link is sent to your Inbox and you can log in.

As a freelancer I personally find it worthwhile every so often to down tools and take a day out to watch and read up on some of the interesting content produced by the Sitecore community. Virtual Developer Day makes this easy by bringing together a bunch of presentations which were recorded as part of Sitecore Symposium in Florida last year.

Each video was scheduled to start at a preset time in one of four timezones. Once a video had started it immediately switched into a “on demand mode” which meant it could be streamed at your leisure thereafter.

If you value your time, (and you should!) it’s important to make the videos work for you. I recommend picking the topics/speakers you’re interested in and having something to do in between the videos, or potentially end up procrastinating and wasting large parts of the day. I had other client work to do alongside/in between the videos so it ended up being a productive “day off”. 

It didn’t take me long to figure out that rather than wait for the videos I was interested in to start I could switch the selected time zone to Australia time and watch any of the videos on demand rather than wait for them to be broadcast at a preset time.

The On24 webinar interface made for a nice experience – the video and accompanying slides were presented in resizable windows together with a built in twitter window for social interaction, the format worked well.

Picks of the days for me were:

  • Martina Welander‘s guide to privacy and GDPR in Sitecore was delivered enthusiastically on what might otherwise be a dry topic
  • Raul Jimenez presenting a great video on harnessing the power of Docker for Sitecore development
  • Sheetal Jain‘s engaging presentation on Salesforce integration with Sitecore.
  • Kelly Rusk‘s dulcit tones on his SIF Deep dive
  • Martin Davies‘ Helix Smells – detailing solutions to issues that often crop up when implementing Helix patterns in development

At the time of writing you can still register to view the videos and therefore stream them at your leisure.

Gems from the Marketplace – Sitecore Security Rights Reporting

In this series I’ll be mentioning some of those slightly lesser known modules that exist in the Sitecore Marketplace, which I’ve found particularly useful. There really is a plethora of useful modules on there, some quite old, some bang up to date, but hopefully you might find one or two as useful as I have.

The first one up is called the Sitecore Security Rights Reporting module by Jan Bluemink.

I found this module very helpful when trying to observe the current state of the Roles and Users in a particular Sitecore instance, with a view to rationalising the list of people with admin access and reorganising the role membership.

Accessible from the Security Tools menu, it allows you to easily view user role membership in a matrix format that you can drill down into, and saves a lot of time spent clicking into and out of the standard Sitecore dialog boxes.

Overview can be particularly useful when reorganising
or pruning a large number of roles and users

As a footnote Jan advises that the tool makes use of database queries that may put load on the server, so bear that in mind when running it anywhere other than locally. 

Jan has also recently updated the module for Sitecore 9.1.

Beware of View Compilation with Helix Features!

Totally sensationalist headline for a small issue but now I’ve got your attention… 😛

View precompilation is cool, it lets us catch errors at compile time, helping us to fail faster and we can avoid the performance hit of compilation at runtime since the views are already compiled. We no longer need to ship the cshtml files resulting in smaller deployments and it can also help solve issues with large numbers of physical view files. 

However I’ve noticed an interesting issue when creating Helix features, in that, in some situations the wrong view will be rendered for a component.

What?

Imagine we have two Helix Features, which output as assemblies FeatureA.dll and FeatureB.dll. They both have components (View or Controller rendering it doesn’t matter) that reference the same view name in their respective projects e.g. ~/Views/Test.aspx.
Despite the fact they are in two different assemblies, with view precompilation enabled, Feature B’s view will always be rendered out to screen when asking for FeatureA:

Controller Action method asks for View A and gets View B

This is obviously less than ideal as when adding Feature B, a developer would not envisage Feature A being affected by their change. The issue would not be caught unless we explicitly test Feature A is still working correctly when deploying Feature B (full regression test perhaps).

This occurs with the latest versions (at the time of writing) of two popular precompilation libraries available on Nuget:

Why?

Diving deep into the StackExchange.Precompilation library… 

When called upon to render a view the view engine code in the StackExchange code loops through all types in each loaded assembly and checks whether any of the types inherit or implement WebPageRenderingBase (which your compiled views will do)

It retrieves the [CompiledFromFileAttribute] from the compiled view class:

namespace ASP {
[CompiledFromFile("E:\\dev\\Sandbox\\Sitecore\\Components\\Test\\TestLayout\\Test.cshtml")] 
public class _Page_Components_Test_TestLayout_Test_cshtml : WebViewPage<TestGlassModel> 
{   
protected HttpApplication ApplicationInstance

This absolute path retrieved from the attribute is clearly unique between assemblies, but unfortunately it is converted into a virtual path, and the uniqueness is lost.

This virtual path is added as the key to a _views dictionary together with the compiled view type as per below:

private readonly Dictionary<string, Type> _views;           
foreach (var view in viewTypes)                
{                   
var attr = view.GetCustomAttribute<CompiledFromFileAttribute>();                   
  if (attr != null)                   
  {
      _views[MakeVirtualPath(attr.SourceFile, sourceDirectory)] = view; // Dictionary value can get overwritten here when MakeVirtualPath generates a string which is already present in the dictionary.                   
}               
}

The loop then continues through the list of assemblies.

The problem becomes apparent when two assemblies have the same generated virtual view path, the assembly that comes alphabetically last wins out and overwrites the value corresponding to the virtual path key string in the _views dictionary.

The Razor Generator code works in a similar way and uses a _mappings dictionary for the views also keyed on the virtual view path and hence exhibits the same problem.

By Decompiling the views we can immediately see the issue with the Razor Generator approach. They have identical virtual views stored in the [PageVirtualPath] attribute so are indistinguishable:

Now having two Helix Features with the same virtual view paths is likely to be a rare occurrence but it’s an interesting observation nonetheless. Its slightly more likely to crop up in those solutions where View compilation has existed in the project for a long period of time. The copying of physical views is not necessary, so the developers will never experience physical view copy clashes in local builds when adding new Features. Its also worth being observant when attempting to moduralise vertically sliced Sitecore solutions where views form part of a Component/Feature folder together with concerns such as the Controller and Viewmodel. Controllers returning a local view may end up with the same virtual path though still highly unlikely as hopefully the folder structure will be distinct enough.

The workaround is to ensure you have different folder paths and or view names for each Feature when using View compilation .

Sample demo

In order to demonstrate the issue with a code sample I’ve pushed a demo to Github which you can download and run with IIS Express.  I’ve removed the dependency on Sitecore for demo purposes since it is not a requirement in order to convey the problem.

How to verify what’s inside your Sitecore Rendering Cache

I recently found myself doing some performance optimisations around renderings in Sitecore, one of which involved caching. Having spent time cache tuning some renderings I wanted to prove the cache contained the HTML markup I expected . Unfortunately Sitecore doesn’t let you view the contents of the HTML cache without writing some custom code. 

Sitecore Rocks to the rescue! To view the keys in Sitecore rocks select the caches tab from the Sitecore Explorer and scroll down to “yoursitename[html]” and double click. The “Explore cache” window will appear and you should then be able to see the cache keys currently in the cache. Sitecore Rocks will display the cache keys but unfortunately not the cached HTML that is stored against them.

Sitecore Rocks allows you to see the cache keys in use but not the corresponding markup

So i decided to knock up a (very) quick and dirty admin page in the same vein as the standard Sitecore admin pages. This can simply be dropped in the Sitecore admin folder and when browsed to, will display a list of cache keys and respective cached HTML for a given site. I’ve submitted this page as a module in the Sitecore Marketplace that is easy to download and use. It’s also on Github.

Custom cache viewer allows you to view the markup stored against each cache key
Custom Cache Viewer allows you to view the markup stored against each cache key

To use:

  • Download the module from the Marketplace when approved or from Github
  • Copy the aspx file to the /sitecore/admin folder in your installation
  • Browse to /sitecore/admin/htmlcacheviewer.aspx
  • Select a cache from the list of site caches in the drop down listThe page will automatically update to show the current cache keys and values in the selected HTML cache 
  • To order the cache keys alphabetically ascending or descending click the cache key column header
  • For those cache keys that include a Sitecore GUID such as when Varying by Datasource a clickable link is generated that will dump you into the content editor and select the item in question.
  • To copy the HTML markup to the clipboard for further analysis click the copy button for the row you wish to copy.
  • The list of cache keys is retrieved when first selected, so to refresh to show the current state click the Refresh link under the drop down list of caches.

Let me know if you find it useful (or not!)

Using View Renderings with Glass Mapper and compiled views

Our old friend View Renderings cropped up recently when we moved our ORM related code into it’s own Helix style foundation module. First up a short history of View Renderings in Sitecore…

Traditionally when using View renderings in Sitecore, if we didn’t want to use the built in Sitecore.Mvc.Presentation.RenderingModel model for our views we’d build a custom model and ensure Sitecore itself was aware of it by creating a Model item in /sitecore/layout/Models and fill in the Model field of the View rendering.

Without this Sitecore cannot resolve the model correctly:

So far, so old.

Being forced to add a model to Sitecore felt a bit limiting, and back in 2014 John West wrote a nice article demonstrating how to remove the need for specifying the model in Sitecore (since it is already present on the top of your view) https://community.sitecore.net/technical_blogs/b/sitecorejohn_blog/posts/determine-models-from-views-with-the-sitecore-asp-net-cms

Later on, Nat Mann ran with the idea and optimised the solution for performance: https://cardinalcore.co.uk/2015/03/24/getting-a-sitecore-model-from-the-cshtml-view/

Now we can use a custom model without the need to define the model in Sitecore. Sweet!

But what if you’re using Glass Mapper…

No problem, Glass has incorporated the GetModelFromView code into the library as of release 4.0.0.4 adding the ability to determine the model required for a View Rendering from the Cshtml file itself.

This means you can happily use your Glass models with View Renderings and again, with no Sitecore Model admin.

All straight forward, but what if your views are precompiled (as Kamsar blogs about here) and don’t actually exist on disk?

Mike Edwards has happily provided the solution; Incorporating this code into your GlassMapperScCustom class will allows Glass to probe compiled view assemblies and locate the view:

public class CompiledViewTypeFinder : IViewTypeResolver
{
        public Type GetType(string path)
        {
            ViewContext current = ContextService.Get().GetCurrent<ViewContext>();
            var partial = ViewEngines.Engines.FindPartialView(current, path);

            var type = partial.View.GetType().GetField("_viewType", BindingFlags.Instance | BindingFlags.NonPublic)
                    .GetValue(partial.View)
                as Type;

            Type baseType = type.BaseType;

            if (baseType == null || !baseType.IsGenericType)
            {
                Sitecore.Diagnostics.Log.Warn(string.Format(
                    "View {0} compiled type {1} base type {2} does not have a single generic argument.",
                    path,
                    type,
                    baseType), this);

                return typeof(NullModel);
            }

            Type proposedType = baseType.GetGenericArguments()[0];
            return proposedType == typeof(object)
                ? typeof(NullModel)
                : proposedType;
        }
}

public static partial class GlassMapperScCustom
{
        ...
        ...
        public static void PostLoad() 
        {
            GetModelFromView.ViewTypeResolver = new ChainedViewTypeResolver(
                    new IViewTypeResolver[] {
                    new CompiledViewTypeFinder(),
                    new RegexViewTypeResolver() });
        }
        ...
        ...
}

This blog uses images designed by Freepik