Sitecore Workflow commands not being shown in the ribbon or gutter.

Requirement

The customer required that when an item is in a a specific workflow state, the item cannot be edited.

Sitecore has a special security permission to achieve this Workflow State Write, if you set this to deny on the relevant workflow item, the item will become readonly whilst in that state. Perfect I thought, of course you have to ensured that the user has the Workflow Command Execute permission.

Problem

Unfortunately in Sitecore 8.1.0.151207, if you do not have write access to the item, the workflow commands are not shown in the ribbon and the workflow gutter icon is not visible either.

Therefore, the user cannot approve or reject the item, unless they are an administrator!

note: Both the ribbon & gutter icons issues are registered as a bugs and therefore Sitecore will fix it.

Solution

However, if you want to display workflow commands in the ribbon even if workflow write access is denied you can follow the following steps:

  • Use dotpeak, resharper, etc and decompile Sitecore.Shell.Applications.ContentManager.Panels.WorkflowPanel class.
  • Change the namespace and or the class name.
  • Modify the CanShowCommands method, in my case I checked to see if the current user has the workflow execute permissions.
 public static bool CanShowCommands(Item item, WorkflowCommand[] commands)
 {
   Assert.ArgumentNotNull(item, "item");
   if ((item.Appearance.ReadOnly || (commands == null)) || (commands.Length <= 0))
   {
     return false;
   }
   if (Context.IsAdministrator ||(item.Access.CanWriteLanguage() && (item.Locking.CanLock() || item.Locking.HasLock())))
     return true;

   // get command item from 'master' database
   Item curItem = item.Database.GetItem(ID.Parse(commands[0].CommandID));
   // check if user can execute workflow commands
   if (AuthorizationManager.IsAllowed(curItem, AccessRight.WorkflowCommandExecute, Context.User))
     return true;
   return false;
 }
  • Build the assembly and deploy it to the website.
  • Modify the following item in the Core database /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Workflow/WorkflowPanel change the Type field, so it matches your WorkflowPanel class.

I hope this helps, and yes I know it is not nice, but until this bug is fixed it was the best that I could do.

How to kill Sitecore – whilst installing an update package

Problem

Whilst installing an update package on the client’s/customer’s development environment the ASP.NET worker process would be killed suddenly. This issue was found on Sitecore 8.1 Update 4.

error

There was nothing shown in the Sitecore log or in the windows Event log. Therefore I took a Memory dump and investigated the dump using Debug Diagnostic 2 . I found at the bottom of the report 100000’s of lines with the same 4 lines of text, so I assumed there was an infinite loop, which was responsible for using all the memory, and crashing the ASP.NET worker process.

loop

I could not reproduce the error in a clean installation of Sitecore, so I assumed it was due to configuration and or some solution specific code. So I started making a comparison between the customers solution and the clean sitecore and I identified that the following settings where defined twice:

  • ServerTimeZone
  • ContentSearch.SearchMaxResults
  • ContentSearch.DefaultIndexConfigurationPath

showconfig.aspx confirmed this as you can see below.

1

2

The first was caused by an error in the solution specific configuration, the remaining were caused by 2 Sitecore includes having the same setting.

Solution

Ensure no settings and or other configuration is duplicate. Typically after I found out what the error was I discovered that Sitecore writes a warning in the log file! Maybe I should pay more attention to warnings.

warn

Anyway I hope this helps 🙂

 

 

 

 

Helix and Modular Architecture

Helix is Sitecore’ s code name for Modular Architecture, Helix is composed of 2 main areas:

  • Principles
  • Practical Applications (i.e. how we support/implement/conform to the principles/guidelines)

Unfortunately, many on slack & twitter are focusing on the Practical Applications and not the principles. The architectural principles are more important, than how we support/implement the website; So in this blog I will make a brief introduction to the principles.

Helix/Modular Architecture is primarily based on Packaging Principles. In addition, several concepts have been introduced to help support Packaging Principles:

  1. Layers
  2. Module (referred to a package in Packaging Principles)

Now whilst not strictly part of Modular Architecture – I believe all software development should adhere to SOLID principles.

Packaging principles

Is a way of grouping classes to make them more organized, manageable and maintainable! It helps us understand which classes can be packaged together which is called package (module) cohesion and how these packages should relate with one another called package (module) coupling.

“Building software without packaging, is like trying to build a sand castle one grain at a time” – Uncle Bob

The result of packaging in Helix terminology it is called a Module (not a package); therefore, for the remained of this blog I will use module i.e. Module Coupling/Cohesion etc.

Module Coupling

Module Coupling is the corner stone principle in Modular Architecture and determines how modules relate/depend on each other.

Stable-dependencies principle (SDP)

Depend in the direction of stability – a module should only rely on modules that are more stable than itself.

A stable piece of code is one where its interface does not change over time.

Features are expected to change over time and are less stable, as requirements change and or new requirements occur. Unstable code is not bad but a reality!

stable

Stable-abstractions principle (SAP)

Abstractness should increase with stability. Modules that are maximally stable should be therefore maximally abstract. Unstable modules should be concrete. The abstraction of a module should be in proportion to its stability

Acyclic dependencies principle (ADP)

The dependencies between modules must not form cycles, i.e. no circular references are enforced by Visual Studio for C# but not JavaScript, Sitecore Templates, Query strings, web services etc.

Module Cohesion

The following principles help identify what should be packaged together as a module.

Common-closure principle (CCP)

The classes in a module should be closed together against the same kinds of change. A change that affects a module affects all the classes in that module and no other module.
What changes together, should live together.

Common-reuse principle (CRP)

When you depend on one class in a module you depend on all the classes in that module, not just the one you are using.

Reuse-release equivalence principle (REP)

Essentially means that the module must be created with reusable classes — “Either all the classes inside the module are reusable, or none of them are”. The classes must also be of the same family.

Layers

layers

Layers help by visualizing and enforcing the stable dependency and stable abstraction principles of module coupling. Each layer defines the stability of the modules and the direction of dependency.

Modules in the feature layer should not reference each other. A layer is physically described in your solution by folders in the file system, solution folders in Visual Studio, folders in Sitecore along with namespaces in code.

A layer is physically described in your solution by folders in the file-system, solution folders in Visual Studio, folders in Sitecore along with namespaces in Foundation Layer (previously call framework).

Foundation Layer

This layer is the most stable and contains only modules which are not subject to change, and if they do change it will have implications for all modules, typical foundation modules:

  • Taxonomy
  • Dictionary
  • Indexing

Feature Layer

Modules in this layer resembles the customer domain and need to be flexible, and therefore are more likely to change, typical feature modules:

  • Navigation
  • Search
  • Metadata

Project Layer

The project is the least stable layer and can reference all modules as it is used to aggregate the functionality provided by the feature and foundation layers, typical project modules:

  • Page Types
  • Design
  • Context (Responsible for dependency injection (IoC), of course a feature can internally use DI/IoC)

Module

The result of packaging a number of classes together is called a MODULE. Each module is represented by a single Visual Studio project.

A module divides domain functionality into loosely coupled modules with clear boundaries, where each Module can contain Presentation, Business logic, Sitecore Content (Templates, layouts, setting items, etc.) and Data (Sitecore, SQL, etc.).

module

I hope this blog post was helpful and I plan to do a series on common pitfalls which are usually related to the following 2 issues:

  1. One or more modules needs to reference another module in the same layer (which they should NOT do).
  2. how to identify a module and what should be in it.

Sitecore SheerResponse.Download Error with XML

I had  a solution where we need to generate an XML file and download it from the Sitecore client. But when using SheerResponse.Download to download an XML file, it would add 2 elements to the end of the XML document (see the image below). The issue was found in sitecore 8.1 rev. 151207 (Update-1).

extra-elements

Sitecore have registered this a bug and provided a solution where I had to modify the main layout for the Sitecore client and use several support DLL’s, I decided not to do this.

Solution

I therefore did what I consider to be a nasty hack, but better than the alternative of modifying the Sitecore client, so please do not judge me for this!

SheerUI has a Eval function, which allows you to execute JavaScript within the Sitecore client. So I added an A tag, with a link to the file and then called click on the link.

internal void DownloadFile([NotNull] FileInfo file)
  {
    Assert.ArgumentNotNull(file, "file");
    var virtualPath = file.FullName;
    var rootPath = HostingEnvironment.MapPath("/");
    if (rootPath == null)
       return;

    virtualPath = virtualPath.Replace(rootPath, string.Empty);
    virtualPath = $"/{virtualPath.Replace("\\", "/")}";
    string js = $"var link=document.createElement('a');document.body.appendChild(link);link.href = '{virtualPath}';link.download='{file.Name}';link.click();";
    SheerResponse.Eval(js);
  }

Finding Sitecore fields in the inheritance hierarchy website from HELL!

We have all been there we take over a solution we didn’t develop and the complexity, hierarchy and structure of the templates is completely crazy!!!

You have a field, but trying to find the definition and or what template it belongs to is a nightmare.

The Solution How to find any field with 1 click!

Open up DbBrowser (sitecore/admin/dbbrowser.aspx) navigate to the item and click on the field and it takes you directly to the fields definition.

dbbrowser 2

I can’t believe I have used so much time trying to unravel the base Template field to find where a field is defined in sitecore, when there is such a simple solution.

I hope this helps others 🙂

Sitecore client and logon is very slow (properties table AGAIN)

The problem

I was at a customer to help identify why their Sitecore 7.2 client and logon was so slow!

Investigation

There are a number of things I look at when the Sitecore client starts to run slowly:

  1. Slow Event handlers (save, rename, create, etc)
  2. Slow pipeline processors (usually don’t check that it is a sitecore specific requests)
  3. History, Publish queue or Event queue have to many entries, see my blog on how to fix this.
  4. Property change events flooding the Event Queue in the Core database, see my blog on how to fix this

But after ensuring all the previous issues were not the problem, I found a new issue with the properties table.

Properties Table flooded with SC_Ticket entries

The properties table in the core database had over 500000 entries, it was filled with SC_TICKET_xxx entries.

tickets

Unfortunately the properties table does not have a created date column, so I could not write an SQL script to purge all the entries that where more than X days old.

I noticed that in the value column there was a time-stamp embedded in the Value field. My initial solution was to could create an sitecore agent to do the following:

  1. iterate over all the entries in the properties table
  2. Parse the value for SC_Ticket entries
  3. Remove all the entries that were older than X days.

I knew Sitecore must have a class, which had created all these entries. So using DotPeek I started my search and found the TicketManager class. The TicketManager even had a IsTicketExpired function.

is expired function

Solution

I found that there is already a Sitecore agent that checks for any tickets that are expired and removes them. It is called the CleanupAuthenticationTicketsAgent for some reason this was not in the web.config, but it is easy enough to add see below.

agent

But the important step is to reduce the number of days to keep the tickets as the default is 180. The Authentication.ClientPersistentLoginDuration setting is responsible for determining how long before the ticket should expire (see the IsTicketExpired function in the image above).

I set Authentication.ClientPersistentLoginDuration to 5 and it reduced the number of entries in the properties table to around 500, and then sitecore client and logon was much faster.

Prior to writing this post I wasn’t aware but the is a blog about how sitecore sessions can expire.

Un-tangling Sitecore configuration includes

I recently worked on a project that used SlowCheetah (XML Transforms) and Octopus variable substitution to modify the custom Sitecore include files.

It proved difficult to determine what the Sitecore configuration was in each environment, especially for the content delivery servers, as it was not possible to call showconfig.aspx.

Solution

Each time the application starts, it writes out the contents of the merged Sitecore configuration to a file in the logs folder. The file name contains the instance name, date and time created. So in addition to seeing the current configuration, you can also see how it changes over time (very useful after a deploy where nothing works).

Get the merged Sitecore configuration

It turned out to be very simple to implement, as it only takes one line of code to get the merged Sitecore configuration:

XmlDocument xmlDocument = Sitecore.Configuration.Factory.GetConfiguration();

Create a custom pipeline processor class

Create a processor for the initialize pipeline, so each time Sitecore is started the processor will be called to ensure that the configuration is saved. Create a public class with a public member called Process, which accepts a parameter of type PipelineArgs. The code below is all that is needed.

namespace Exmaple
{
  public class SaveSitecoreConfiguration
    {
        public void Process(PipelineArgs args)
        {
            string fullPath=string.Empty;
            try
            {
                XmlDocument configuration = Factory.GetConfiguration();
                string filename = string.Format("SitecoreConfiguration.{0}.{1}.xml", DateTime.Now.ToString("yyyyMMdd-hhmm"), Sitecore.Configuration.Settings.InstanceName);
                string logFolder = Sitecore.Configuration.Settings.LogFolder;

                // Is it a relative or virtual folder ?? could be a configured to point at an physical directory
                if (!Directory.Exists(logFolder))
                {
                    logFolder = HttpContext.Current.Server.MapPath(logFolder);
                }
                

                fullPath = Path.Combine(logFolder, filename);
                configuration.Save(fullPath);

            }
            catch (System.NotSupportedException supportedException)
            {
                Sitecore.Diagnostics.Log.Error(string.Format("Error saving sitecore configuration, path:{0}", fullPath), supportedException, this);
            }
            catch (Exception exception)
            {
                Sitecore.Diagnostics.Log.Error("Error saving sitecore configuration", exception, this);
            }
        }

    }
}

Configuration Changes

The processor has to be added to the initialize pipeline, I would recommend you create an include file to achieve this, but for the sake of clarity I have added it directly to the web.config, see below.

example

Now every-time Sitecore is started it writes out the configuration, so it is easy to get the configuration and monitor how it changes for all environments over time.

I hope this helps you untangle the Sitecore includes which at times can be a nightmare.