Friday, November 22, 2013

Tricks and Optimizations for you Sitecore website

When working with Sitecore there are some optimizations/configurations I usually repeat in order to make my app production ready.
Following is a small list I have compiled from experience, Sitecore documentation, communicating with Sitecore Engineers etc.
This is not supposed to be technically complete and might not be fit for all environments.

Simple configurations that can make a difference:
1) Configure Sitecore Caches. This is the most straight forward and sure way of increasing the performance of your website.
Data and item cache sizes (/databases/database/ [id=web] ) should be configured as needed. You may start with a smaller number and tune them as needed.
<cacheSizes hint="setting">
          <data>300MB</data>
          <items>300MB</items>
          <paths>5MB</paths>
          <standardValues>5MB</standardValues>
  </cacheSizes>

Tune the html, registry etc cache sizes for your website.


<cacheSizes>
      <sites>
        <website>
          <html>300MB</html>
          <registry>1MB</registry>
          <viewState>10MB</viewState>
          <xsl>5MB</xsl>
        </website>
      </sites>
    </cacheSizes>

Tune the prefetch cache settings under the App_Config/Prefetch/ folder.

Sample /App_Config/Prefetch/Web.Config:
<configuration>
  <cacheSize>300MB</cacheSize>
  <!--preload items that use this template-->
  <template desc="mytemplate">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}</template>

  <!--preload this item-->
  <item desc="myitem">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX }</item>

  <!--preload children of this item-->
  <children desc="childitems">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}</children>
</configuration>

Break your page into sublayouts so you may cache most of them.

Read the caching configuration reference: http://sdn.sitecore.net/upload/sitecore6/sc62keywords/cache_configuration_reference_a4.pdf



2) Disable Analytics for the Shell Site
<site name="shell" virtualFolder="/sitecore/shell" physicalFolder="/sitecore/shell" 
rootPath="/sitecore/content" startItem="/home" language="en" database="core" domain="sitecore" 
loginPage="/sitecore/login" content="master" contentStartItem="/Home" enableWorkflow="true" 
enableAnalytics="false" xmlControlPage="/sitecore/shell/default.aspx" browserTitle="Sitecore" 
htmlCacheSize="2MB" registryCacheSize="3MB" viewStateCacheSize="200KB" xslCacheSize="5MB" />
 

3) Increase the Check Interval for the MemoryMonitorHook so it doesn’t run every 5 seconds (default).


<hook type="Sitecore.Diagnostics.MemoryMonitorHook, Sitecore.Kernel">
        <param desc="Threshold">800MB</param>
        <param desc="Check interval">00:05:00</param>
        <param desc="Minimum time between log entries">00:01:00</param>
        <ClearCaches>false</ClearCaches>
        <GarbageCollect>false</GarbageCollect>
        <AdjustLoadFactor>false</AdjustLoadFactor>
      </hook>
 

4) Set Analytics.PeformLookup (Sitecore.Analytics.config) to false if your environment doesn’t have access to the internet or you don’t intend to use reverse DNS lookup.
<setting name="Analytics.PerformLookup" value="false" />
 

5) Set the value of the “Media.MediaLinkPrefix” setting to “-/media”:

<setting name="Media.MediaLinkPrefix" value="-/media" />

Add the following line to the customHandlers section:
<customHandlers>
  <handler trigger="-/media/" handler="sitecore_media.ashx" />
  <handler trigger="~/media/" handler="sitecore_media.ashx" />
  <handler trigger="~/api/" handler="sitecore_api.ashx" />
  <handler trigger="~/xaml/" handler="sitecore_xaml.ashx" />
  <handler trigger="~/icon/" handler="sitecore_icon.ashx" />
  <handler trigger="~/feed/" handler="sitecore_feed.ashx" />
</customHandlers>

Link: http://squad.jpkeisala.com/2011/10/sitecore-media-library-performance-optimization-checklist/



6) Performance counters should be disabled in production if not being monitored
<setting name="Counters.Enabled" value="false" /> 



7) Disable Item/Memory/Timing threshold warnings. Due to the nature of this component, it brings no value in production.
<!--<processor type="Sitecore.Pipelines.HttpRequest.StartMeasurements, Sitecore.Kernel" />--> 

<!--<processor type="Sitecore.Pipelines.HttpRequest.StopMeasurements, Sitecore.Kernel">
  <TimingThreshold desc="Milliseconds">1000</TimingThreshold> 
  <ItemThreshold desc="Item count">1000</ItemThreshold> 
  <MemoryThreshold desc="KB">10000</MemoryThreshold> 
</processor>—>
 



8) The ContentEditor.RenderCollapsedSections setting is a hidden setting in the web.config file, which by default is true. Setting it to false will improve client performance for authoring environments.
<setting name="ContentEditor.RenderCollapsedSections" value="false" /> 



9) Add a machineKey section to your Web.Config file when using a web farm. Link: http://msdn.microsoft.com/en-us/library/ff649308.aspx



10) If you get errors in the log files similar to:


WARN Could not create an instance of the counter 'XXX.XXX'

(category: 'Sitecore.System')

Exception: System.UnauthorizedAccessException

Message: Access to the registry key 'Global' is denied.

Make sure the ApplicationPool user is a member of the system “Performance Monitor Users” group on the server.



11) Disable WebDAV configurations on the CD Server if not being used.

More: http://sitecoreblog.alexshyba.com/2011/04/disable-webdav-in-sitecore.html



12) Change Log4Net settings to only log Errors on content delivery environments to avoid unnecessary logging.
<root>
      <priority value="ERROR" />
      <appender-ref ref="LogFileAppender" />
    </root>
(From Sitecore: please note that this may result in Sitecore Support not being able to help you immediately due to log incompleteness. 
Logging reconfiguration might be necessary before further investigation could be performed.)
 

13) Disable Analytics for any content item that doesn’t add value. For example a page that redirects to another page.


image

image



14) When using Web User Controls avoid registering them on the page the asp.net way:

<%@ Register Src="~/layouts/UserControls/MyControl.ascx" TagName="MyControl" TagPrefix="uc2" %>

Use Sublayout web control instead – This way Sitecore caching could be leveraged

<sc:Sublayout ID="ID" Path="/layouts/UserControls/MyControl.ascx" Cacheable="true" runat="server" />



15) Avoid querying for all children recursively when all items are direct children.
Sitecore.Context.Database.SelectItems("/sitecore/content/Home//*");

//Use:

Sitecore.Context.Database.GetItem("/sitecore/content/Home");
 

16) On IIS — you enable static & dynamic content compression on CM and CD

More: http://technet.microsoft.com/en-us/library/cc754668%28WS.10%29.aspx


image


 

17) Enable HTTP Keep-alive and content expiration in IIS.


image


18) Use GUID’s when accessing items and fields instead of names or paths. Its faster and wont break your code when things get moved or renamed.
Context.Database.GetItem("{324DFD16-BD4F-4853-8FF1-D663F6422DFF}")
Context.Item.Fields["{89D38A8F-394E-45B0-826B-1A826CF4046D}"];

//is better than

Context.Database.GetItem("/Home/MyItem")
Context.Item.Fields["FieldName"]





Hope this helps.

Friday, November 1, 2013

Adding Facebook Open Graph Tags to an MVC Application

If you have any kind of share functionality within your application it’s a good practice to add
the basic Facebook open graph tags to the header of all pages.

For an MVC application this can be as simple as adding these tags to the Head section of the Layouts file.
<head>
    <title>@ViewBag.Title</title>
    <meta property="og:title" content="@ViewBag.FacebookTitle" />
    <meta property="og:type" content="website"/>
    <meta property="og:url" content="@ViewBag.FacebookUrl"/>
    <meta property="og:image" content="@ViewBag.FacebookImage"/>
    <meta property="og:site_name" content="Site Name"/>
    <meta property="og:description" content="@ViewBag.FacebookDescription"/>
</head> 
 
These ViewBag properties can then be populated from any action:
 
private ActionResult MyAction()
    {
        ViewBag.FacebookDescription = "My Actions Description";
        ViewBag.FacebookUrl = "My Full Url";
        ViewBag.FacebookTitle = "My Actions Title";
        ViewBag.FacebookImage = "My Actions Social Image";
        ....
    }
 
You might want to populate these ViewBag properties with default values when the actions don’t populate them. This can be done in 2 places.
 
1. In the Layout itself. (check the ViewBag properties and set them if they are empty)
 
@{
    ViewBag.FacebookTitle = ViewBag.FacebookTitle ?? "My Default Title";    
    ViewBag.FacebookUrl = ViewBag.FacebookUrl ?? HttpContext.Current.Request.RawUrl;
    ViewBag.FacebookImage = ViewBag.FacebookImage ?? "http://www.mysite.com/images/logo_main.png";
    ViewBag.FacebookDescription = ViewBag.FacebookDescription ?? "My Default Description";
}


 
2. Create an action filter and add it to all Controllers or your base controller.
 
public class FacebookActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var viewBag = filterContext.Controller.ViewBag;

            viewBag.FacebookDescription = "My Actions Description";
            viewBag.FacebookUrl = "My Full Url";
            viewBag.FacebookTitle = "My Actions Title";
            viewBag.FacebookImage = "My Actions Social Image";

            base.OnActionExecuting(filterContext);
        }
   }
 
Add attribute to your BaseController.
 
[FacebookActionFilter]
public class HomeController : Controller
 {
  ....
 }