Solr startup issue as window service on Windows 10

If you are configuring Sitecore 9 then you have to setup Solr as window service for supporting xConnect. While starting Solr as window service you may have following issue

Program “Solr Path” exited with return code 3221225794.

To fix this issue , kindly make sure that you are using windows 10 supported version of NSSM. Here are the comments available on https://nssm.cc/download for windows 10

Windows 10 Creators Update

2017-04-26: Users of Windows 10 Creators Update should use prelease build 2.2.4-101 to avoid an issue with services failing to start. If for some reason you cannot use that build you can also set AppNoConsole=1 in the registry (\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<servicename>\Parameters)

, noting that applications which expect a console window may behave unexpectedly.

 

Retrieve the control parameters while item context is not available

If you would like to retrieve the control parameters while item context is not available.you can use following code


Sitecore.Data.Database db = Sitecore.Data.Database.GetDatabase("database name");
DeviceItem di = DeviceItem.ResolveDevice(db);

Item item = db.GetItem("Pass the Item ID to retrieve it from database");
Sitecore.Layouts.RenderingReference[] rendering = item.Visualization.GetRenderings(di, true);
Sitecore.Layouts.RenderingReference rendItem = rendering.FirstOrDefault(rend => rend.RenderingItem.InnerItem.Paths.FullPath == "compare with control name for which you would like to retrieve parameters");
System.Collections.Specialized.NameValueCollection parameterCollection = Sitecore.Web.WebUtil.ParseUrlParameters(rendItem.Settings.Parameters);

Sitecore – IMS (If-Modified-Since) request header for Media Items

We recently had an issue related to media item response status. While a CDN service was making a request to access Sitecore Media item and current date is passed in if-modified-since request header, response status code was always 200. However requested media items were not modified since a long time and response status code should be 304. To troubleshoot this issue when I explore the Sitecore code (MediaRequestHeader) , found that Sitecore has exact match logic to compare the “If-Modified-Since” with media item modified date. It means if a media item is modified lets say on “01/01/2018 01:00:00 PM” and request header has value “If-Modified-Since:Mon, 01 Jan 2018 01:00:00” it will give 304 status code. Any request which has any other date or time will always respond with 200 status code.

To fix this issue there are multiple approaches and choice can be based on your project condition.

  1. While CDN is making a call to Sitecore server for media item , it should pass the last modified date of file which CDN received as response on first request. .
  2. Override the Sitecore implementation to compare the dates in MediaRequestHeader
  3. Open a ticket with Sitecore to check if they have any patch for it

Sitecore – Failed to find the root item

Recently content managers were getting following issue while accessing the file upload option to import the translations. After analysis we found that its  

<securityEnabled>true</securityEnabled>

configuration under the filesystem database node (

<database id="filesystem" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">

). To fix this issue you may disable the security for file system.

Error : An instance of Sitecore.Data.Items.Item was null. Additional information: Failed to find the root item “/”.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: An instance of Sitecore.Data.Items.Item was null. Additional information: Failed to find the root item “/”.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: An instance of Sitecore.Data.Items.Item was null. Additional information: Failed to find the root item “/”.]
Sitecore.Web.UI.HtmlControls.DataContext.GetState(Item& root, Item& folder, Item[]& selected) +1904
Sitecore.Web.UI.HtmlControls.DataContext.get_AtRoot() +60
Sitecore.Web.UI.HtmlControls.UpAction.OnDataContextChanged(DataContext dataContext) +24
Sitecore.Web.UI.HtmlControls.Control.HandleMessage(Message message) +391
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +67
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.DispatchMessage(Control control) +157
Sitecore.Shell.Framework.Commands.MessageCommand.Execute(CommandContext context) +636
Sitecore.Web.UI.Sheer.ClientPage.SendMessage(Message message) +90
Sitecore.Web.UI.HtmlControls.DataContext.OnChanged() +104
Sitecore.Web.UI.HtmlControls.DataContext.set_DataViewName(String value) +186
Sitecore.Shell.Applications.Files.FileExplorer.FileExplorerForm.OnLoad(EventArgs e) +97

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) +0
System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) +128
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +146
Sitecore.Reflection.ReflectionUtil.CallMethod(Type type, Object obj, String methodName, Boolean includeNonPublic, Boolean includeInherited, Boolean includeStatic, Object[] parameters) +223
Sitecore.Web.UI.Sheer.ClientPage.OnLoad(EventArgs e) +592
System.Web.UI.Control.LoadRecursive() +68
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4498

How to get Sitecore Agent details

If you have scenario to get the details of Sitecore Agents, its last run time and interval to run, below code will help

	Sitecore.Tasks.Scheduler scheduler = new Sitecore.Tasks.Scheduler();
            var agentData  = scheduler.GetType().GetField("m_agents", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(scheduler);

            Type schedulerType = typeof(Sitecore.Tasks.Scheduler);
            Type agentType = schedulerType.GetNestedType("Agent", BindingFlags.NonPublic);
            FieldInfo lastrunpro = agentType.GetField("m_lastRun", BindingFlags.NonPublic | BindingFlags.Instance);
            FieldInfo Name = agentType.GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance);
            FieldInfo interval = agentType.GetField("m_interval", BindingFlags.NonPublic | BindingFlags.Instance);

            if (agentData != null)
            {
                var agentCollection = agentData as IEnumerable;

                foreach (object agent in agentCollection)
                {
                    AgentsList.Add(new AgentsInfo() {
                        Name = Convert.ToString(Name.GetValue((agent))).Replace("Sitecore.Tasks.", ""),
                        LastRunTime = Convert.ToString(lastrunpro.GetValue((agent))),
                        Interval = Convert.ToString(interval.GetValue((agent)))
                    });
                }
            }
        }

 

 

Sitecore Customize Media Provider

There are scenarios when you have to customize/override Sitecore default media provider. Like in my case we enabled Akamai (CDN) for media items and  requirement was to generate the media items url using Akamai domain rather than site domain.  There are other scenarios also where you may have to customize media provider.

So to customize media provider

  • Create a new public class and inherit it from resource.Media.MediaProvider class and Sitecore.Events.Hooks.IHook Interface, like
public class CustomMediaProvider : MediaProvider, Sitecore.Events.Hooks.IHook
  • Create initialize method
public void Initialize()
        {
            MediaManager.Provider = this;
        }

  • Create constructor of class and create mediacreator object
public CustomMediaProvider ()
        {
            OverrideMediaCreator();
        }

        protected void OverrideMediaCreator()
        {
            Sitecore.Resources.Media.MediaCreator mediaCreator = GetMediaCreator();
            if (mediaCreator == null)
            {
                return;
            }

            Creator = mediaCreator;
        }

        protected virtual Sitecore.Resources.Media.MediaCreator GetMediaCreator()
        {
            return Factory.CreateObject("mediaLibrary/mediaCreator", false) as MediaCreator;
}
  • Override the GetMediaUrl and customize the code as per your need
public override string GetMediaUrl(MediaItem item)
        {
            return GetCDNURL(base.GetMediaUrl(item));
        }

        public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
        {
            return GetCDNUrl(base.GetMediaUrl(item, options));
        }

  • Do a entry in custom patch file
<sitecore>
<hooks>
      <hook  type="Assembly.Namespace.CustomMediaProvider, Assembly Details">
      </hook>
    </hooks>
</sitecore>
  •  Complete code is as follows
public class CustomMediaProvider : MediaProvider,IHook
    {
        public void Initialize()
        {
            MediaManager.Provider = this;
        }

        public override string GetMediaUrl(MediaItem item)
        {
            return GetCDNUrl(base.GetMediaUrl(item));
        }

        public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
        {
            return GetCDNUrl(base.GetMediaUrl(item, options));
        }

        string GetCDNUrl (string url)
        {
            ….
        }

        public CustomMediaProvider ()
        {
            OverrideMediaCreator();
        }

        protected void OverrideMediaCreator()
        {
            Sitecore.Resources.Media.MediaCreator mediaCreator = GetMediaCreator();
            if (mediaCreator == null)
            {
                return;
            }

            Creator = mediaCreator;
        }

        protected virtual Sitecore.Resources.Media.MediaCreator GetMediaCreator()
        {
            return Factory.CreateObject("mediaLibrary/mediaCreator", false) as MediaCreator;
        }
    }

Sitecore Best Practices

This is my first blog and i would like to start with Best Practices. Here are few Sitecore best practices which are common for any Sitecore implementation.

  • Content Tree
    • Data Template
      • Standard values should be defined for data template created for application.
      • Use inheritance as much as possible. It will help to reduce the repetition of fields or data templates
      • Do not cyclical template inheritance
      • Assign icon to template so it can easily be separated from other templates and usage can be recognized.
      • Organize Templates into folders so that it can easily be identified for their function.
      • Define insert options to manage the options available for CA.
      • Use Token to reduces the amount of text that a content author is required to enter when creating a new item
      • Avoid change in /Sitecore/Templates/System
    • Branch Template
      • Define branches so that a common structure can be created for sites
    • Site Structure
      • Limit the number of items under a single node. Sitecore recommend for 100 items per node
      • Limit the number of versions.
  • Code
    • Optimize Sitecore queries. Make sure that query should not traverse at n level of nodes. It should be restricted at one level.
    • Do not use Fast Queries. Fast query does not use sitecore cache and directly hit SQL server and you may have performance issues on SQL Server.
    • Avoid direct SQL call from code.
    • Use override folder to override sitecore functionality
    • Avoid direct database reference in code
    • Limit use of GetAncestors and/or GetDescendants API calls
    • Minimize the use of the SecurityDisabler
    • Minimize usage of “heavy” queries for Treelist and Multilist fields.
  • Config
    • Use patching to separate custom config vs Sitecore config
    • Use number as prefix to define patch filename. It will help to define the execution order.
    • Enable SwitchMasterToWeb .config on content delivery server
  • IIS
    • Enable dynamic content compression on IIS
  • Analytics
    • Disable analytics if not in use
  • Media
    • Store media in database.
    • Enable drag and drop functionality for media lib
  • Security
    • Apply security to roles rather than users
    • Break inheritance rather than explicitly deny access rights
    • Limit access to the parts of the content tree
    • Limit access to the ribbon items relevant to the user
    • IIS should prevent anonymous users from accessing the following folders:
      •  /App_Config
      • /sitecore/admin
      • /sitecore/debug
      • /sitecore/shell/WebService
    • Restrict upload by
      • Configure IIS to denied “Script” and “Execute” permissions on “upload” folder.
      • Deny permission to users to upload files to the “Temp” folder.
      • Disable upload Watcher
      • Depending on your circumstances, “Upload Filter Tool” should be installed
  • Workflow
    • Configure workflow for content items and authoring process for content
    • Make sure that workflow has final state
    • Publishing restricted to specific roles
  • Publishing
    • Disable full site publishing for authors
    • If you have very large number of items in tree, restrict publishing of complete tree . It may impact performance
  • Cache
    • Prefetch cache : Find the items which should be available on Sitecore startup and configure template IDs of them in prefetch cache
    • Cache size : Evaluate the size defined against the prefetch, data, item and html cache on content authoring and delivery server.
    • Use HTML Cache for better performance at presentation level.
  • Agents : Make sure that only required agents should be enabled on content delivery servers