Pages

Top 5 posts

Monday, March 29, 2010

Dreamcore is coming. Hope to see you in Boston!


If you read this, you may have already registered for Dreamcore or at least thought about it. For those who have not heard about it, this is the first Sitecore partner conference that offers huge opportunity to learn about cutting edge stuff we do with the products, do some networking, share experience and of course have fun!

I am proud to be presenting at developer tracks with the following topics. Here is the brief abstract of those:
- Data Retrieval Techniques with Sitecore
Everyone knows that Sitecore CMS gives you tons of options in every aspect of development. Knowing how to access Sitecore data is very important. Knowing what approach is more efficient for certain requirements is absolutely critical. In this session, I outline different use cases and covers multiple ways to address each of them using such methods as traditional data access API, Sitecore Query, Fast Query, Search Index, Database Crawler, Link Database, etc. After the session the attendee will be able to easily match a use case with the most appropriate and performing way to address it.
- Using Lucene.NET with Sitecore
This topic is related to “Data Retrieval Techniques with Sitecore” and goes deeper in exploration of Lucene.NET implementation in Sitecore. During this session the I will demonstrate the real world use case of this technology for the CMS reporting.

Our search analytics proved that Lucene is the most demanding topic on SDN, so hope it is appropriate.

Any feedback about the specifics of what you would like to see is appreciated!

Monday, March 15, 2010

Sitecore Friendly URLs and plus sign


One of the customers recently asked about using the plus sign in URLs, for example: http://localhost/news+events.aspx

There are at least two ways to accomplish this:
1. Allow “+” in item name via a configuration change
For this you will need to adjust the regular expression in the “ItemNameValidation” setting in web.config and make sure + sign is not  present in the “InvalidItemNameChars” setting.

2. Rely on the display name instead.
I personally like this approach better where you don’t need to adjust item naming rules and at the same time leverage the flexibility provided in Sitecore CMS 6.x by the dynamic link management component called “Link Manager”:

<linkManager defaultProvider="sitecore">
      <providers>
        <clear />
        <add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="true" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="asNeeded" languageLocation="filePath" shortenUrls="true" useDisplayName="true" />
      </providers>
</linkManager>

In addition to the tricks describe here and here, you can instruct Sitecore to leverage item display names instead of item names for URLs by just flipping the “useDisplayName” parameter to “true”. This parameter is also extremely useful for multilingual sites.

Now you can change the display name of the NewsEvents item to “News+Events” and have a plus in your URL.
While everything looks great, it turned out that the request for http://localhost/news+events.aspx was failing with the error below:

Server Error in '/' Application.


Object reference not set to an instance of an object.

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.NullReferenceException: Object reference not set to an instance of an object.

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:

 
[NullReferenceException: Object reference not set to an instance of an object.]
   Sitecore.Nexus.Web.HttpModule.(Object sender, EventArgs e) +340
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +79
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +170


Version Information: Microsoft .NET Framework Version:2.0.50727.4927; ASP.NET Version:2.0.50727.4927

The error stack trace hinted that this is somewhere at the high level, when Sitecore’s processing is not triggered yet.

After some research on the web, I’ve found that the problem is actually related to IIS, specifically IIS7’s security filtering module which does not allow double-escaped URLs. The following configuration change addresses the problem:

<system.webServer>
  <security>
     <requestFiltering allowDoubleEscaping="true" />
   </security>
</system.webServer>

That's it, folks!

Thursday, March 11, 2010

Publish to pre-production web database


Update 3/11/2010: Correction » the last parameter of the ExtendedPublishOptions constructor should be “false”.  Please see below for details.

In my experience with enterprise level implementations, there is often a need for a separate “stage environment” for final content preview or a pre-production phase of workflow.

It is also often the case that the environmental limitations or restrictions make the content delivery part of the authoring environment suitable for such purpose. For example, your e-commerce infrastructure could not be available from the authoring instance. One of the possible ways to approach such a requirement is to configure a stand-alone staging instance of Sitecore which will be used for content delivery instance and is commonly configured exactly like one of the servers in the web farm. There is one exception though – the database that is used for content delivery is generally different from the one that is used in production content delivery.

With this approach, now the question is how to plug in workflow in a way that content could go via this “stage” environment and then only upon final approval will be able to get to “production”.

Now there is a problem that you cannot get get items published until they are in final workflow state. You could have two workflow states “Staged” and “Published”, both marked as final and with auto publish actions connected.
I don’t like this approach since it goes against the workflow nature – only one state should be marked as final.

Alternatively, you can plug in a “copy item” workflow action to the “Staged” workflow state where you can programmatically copy an item from master database to stage web.

While this approach does seem legitimate, it works around the need of publishing thus any additional processing you may be having in publish(item) pipeline would not work.

I looked into the option of having publishing process ignore workflow when publishing to stage. While this seemed like a dangerous path to go, I have soon discovered that the PublishHelper’s GetVersionToPublish method already accepts this notion of passing a “requireapproval” flag to the underlying publishing mechanism. Since it is always passes “true”, I started looking into ways to make this flag dynamic and figured that setting it on the level of PublishOptions could be a good idea. For example, from the code of my workflow action I would be able to define whether I want to have workflow respected or not.

Here is what you will need to do to make it work.

First, override the default PipelinePublishProvider and plug it into the web.config:

<publishManager defaultProvider="default" enabled="true">
    <providers>
        <clear />
         <!--<add name="default" type="Sitecore.Publishing.PipelinePublishProvider, Sitecore.Kernel" />-->
         <add name="default" type="SCUSAINC.Publishing.ExtendedPublishProvider, SCUSAINC.Publishing" />
     </providers>
</publishManager>

Secondly, you will need to override the CreatePublishHelper class:

public class ExtendedPublishProvider : PipelinePublishProvider
    {
        public override PublishHelper CreatePublishHelper(PublishOptions options)
        {
            Assert.ArgumentNotNull(options, "options");
            if (options is ExtendedPublishOptions)
                return new ExtendedPublishHelper(options as ExtendedPublishOptions);

            return new PublishHelper(options);
        }
    }

After that, introduce two more classes – ExtendedPublishHelper and ExtendedPublishOptions:

public class ExtendedPublishHelper : PublishHelper
    {
        private readonly ExtendedPublishOptions _options;

        public ExtendedPublishHelper(ExtendedPublishOptions options)
            : base(options)
        {
            _options = options;
        }

        public override Item GetVersionToPublish(Item sourceItem)
        {
            Assert.ArgumentNotNull(sourceItem, "sourceItem");
            if (Options is ExtendedPublishOptions)
            {
                return sourceItem.Publishing.GetValidVersion(Options.PublishDate, _options.RequireApproval);
            }

            return sourceItem.Publishing.GetValidVersion(Options.PublishDate, true);
        }
    }

public class ExtendedPublishOptions : PublishOptions
    {
        public ExtendedPublishOptions(Database sourceDatabase, Database targetDatabase, PublishMode mode, Language language, DateTime publishDate, bool requireApproval)
            : base(sourceDatabase, targetDatabase, mode, language, publishDate)
        {
            RequireApproval = requireApproval;
        }

        public bool RequireApproval { get; set; }
    }

Now you are ready to launch publishing with workflow settings completely ignored. For example, this is how you can do it from the workflow action:

var database = Factory.GetDatabase(databaseName);

var options = new ExtendedPublishOptions(dataItem.Database, database, PublishMode.SingleItem, dataItem.Language, DateTime.Now, false)
{
         RootItem = dataItem,
         Deep = true;
};

new Publisher(options).PublishAsync();

3/11/2010: Correction » the last parameter of the ExtendedPublishOptions constructor should be “false”.
Instead of hardcoding it, I’d suggest having a parameter on the level of a workflow action which you can read and pass on.

private static bool RequireApproval(string parameters)
{
         return WebUtil.ParseUrlParameters(parameters)["RequireApproval"] == "true";
 }
public void Process(WorkflowPipelineArgs args)
{
                ...
               var requireApproval = RequireApproval(innerItem["parameters"]);
               var options = new ExtendedPublishOptions(dataItem.Database, database, PublishMode.SingleItem, dataItem.Language, DateTime.Now, requireApproval)
              
                ...
           
 }

That’s it!

Tested on Sitecore 6.1. Expected to work with 6.2.

Sitecore startup time - something that could improve it


One of the things any Sitecore developer had to deal with is startup time. There are tons of reasons why an application pool may restart (file change notification, config change, etc.) so this generally happens pretty often, especially on a development machine.

So I decided to spend some time on the problem and engaged our brilliant technical support into this little project.

For some reason my local results were drastically different from what tech support reported. Most likely configuration-related. I was getting about 45 seconds for the application startup after IISRESET. I noticed that more than half of this time was spent something non-Sitecore related since the log was showing up only after about 25 seconds. Weird.

There are some interesting findings and the numbers I got on my side may not be 100% accurate, but that was not the goal of this exercise. I wanted to find quick and safe ways to remove/disable something that would not affect the development environment.

While monitoring the activity of the w3wp process using Process Monitor, I’ve noticed a lot of checks going against VeriSign service for assembly signature verification. The calls as you can imagine can slow down the startup quite a bit.
It turned out that introducing the following setting in machine.config disables this process.

<runtime>
      <generatePublisherEvidence enabled="false"/>
</runtime>

This single change helped me see the log file created much faster and the total time was decreased to 6-7 seconds total, only 4-5 of them seemed to be Sitecore-related!

It is important to remember that the location of the machine.config file depends on your platform. For 32-bit it can be found here: C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG
For 64-bit here: C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG

Another thing to try is to disable Performance Counters in web.config as I’ve seen a lot of activity around registry and performance counters.
<setting name="Counters.Enabled" value="false" />

Now this helped me gain another .5 second for the initial startup (before Sitecore log got created).
Sweet!

My local tests on a dual core laptop indicated that Sitecore desktop (http://localhost/sitecore/shell/default.aspx) starts up in about 6 seconds after IISRESET while the front-end (http://localhost/) in approximately 3-4 seconds!

Caveats:
- My tests appear to be specific to my environment, and did not have same results on another machine where I saw anything around 10-13 seconds which appear to be quite normal for a large ASP.NET applicaiton.
- My test installation had default content and configuration. You may get different results due to the whole array of factors, especially there is a lot of data pre-fetching going on. Check our caching reference for more details. 

Let me know if this works for you, please do share your experience.

Here is the official Sitecore support article.

Wednesday, March 10, 2010

Things to consider when using Sitecore Packager


It is going to be a quick one. There is a simple checklist of things that you can use to help Packager be your friend.

1. Don’t include stuff you don’t need to. I see people including the whole folder with system templates instead of adding only custom templates or just changed fields on the system templates if there are any.

2. Use PChex component to verify package integrity.

3. Prefer dynamic sources over static sources. Kerry describes why here.

4. Disable search index to improve performance of package installation.

5. Get yourself familiar with the Installation Options. Use “Overwrite” very, very carefully as it may overwrite the branches.

6. Predefine those installation options. If somebody else is going to install your package, you don’t want them to choose for you.

7. Though readme gets ignored in most cases, do your best to supply the installation information or post-install directions with the package metadata.

8. Make sure to save the package project (xml file).

I realize that this may not be a complete list, so please feel free to share your experience and do comment.

Thanks!

Tuesday, March 09, 2010

Read only view of Rich Text field for Sitecore editor


Today I want to share an idea of a lightweight customization for Sitecore CMS that meant to increase usability of the rich text field for your editors. The idea is inspired by great feedback I received recently while being in the field.

The basic problem reported by one of the editors who uses Sitecore on the daily basis, is that when a content item is approved in workflow there is no way to see what’s inside of a rich text field easily. All field buttons are grayed out thus disabled:
disabled rich text field
…so the only way is to click “Lock and Edit” which creates a new version:
lock-and-edit

As you can imagine, this is not generally acceptable. If your non-admin editor user simply wants to see what’s in there, you don’t want a new version to be created.

Now it is worth mentioning that the item which is approved, unlocked is disabled for editing only if “RequireLockBeforeEditing” setting is set to true which is often the case, since you would want to have “Lock and Edit” in place so new version of the approved content is created.

Same goes along with the items that are locked. If there is a locked item, I would still want to see the content of the rich text field in read-only mode.

So one of the easiest ways I could think of to address this was enable “preview” of the rich text field in a modal dialog on double click.

Tech support provided the following solution which enabled the double click on disabled rich text field and showed the “preview” version of the field in a modal dialog:image

To make it work, follow these steps:
1. Open Preview.aspx under /sitecore/shell/Controls/Rich Text Editor.
2. Locate the scEdit() function and comment out the first IF statement:

function scEdit() {
        //if (scDisabled == "1") {
         // return;
       // }
        
var form = scGetForm();
...

3. Compile the following code:

namespace Company.Web.Fields
{
   using Sitecore.Diagnostics;
   using Sitecore.Shell.Applications.ContentEditor.RichTextEditor;
   using Sitecore.Web.UI.Sheer;

   public class RichText : Sitecore.Shell.Applications.ContentEditor.RichText
   {
      protected new void EditText(ClientPipelineArgs args)
      {
         Assert.ArgumentNotNull(args, "args");
         if (Disabled && !args.IsPostBack)
         {
            var url = new RichTextEditorUrl
                         {
                            Conversion = RichTextEditorUrl.HtmlConversion.Runtime,
                            Disabled = Disabled,
                            FieldID = FieldID,
                            ID = ID,
                            ItemID = ItemID,
                            Language = ItemLanguage,
                            Mode = string.Empty,
                            Source = Source,
                            Url = "/sitecore/shell/Controls/Rich Text Editor/Preview.aspx",
                            Value = Value,
                            Version = ItemVersion
                         };

            var str = url.GetUrl();
            SheerResponse.ShowModalDialog(str.ToString(), "800px", "500px", string.Empty, true);
            args.WaitForPostBack();
         }

         base.EditText(args);
      }
   }
}

4. In web.config, add your own controlSource reference to the namespace above:

<controlSources>
      <source mode="on" namespace="Sitecore.Web.UI.XmlControls" folder="/sitecore/shell/override" deep="true" />
...
       <source mode="on" namespace="Company.Web.Fields" assembly=" Company.Web" prefix="custom" />
</controlSources>

5. In the core database, locate the Rich Text field item (/sitecore/system/Field types/Simple Types/Rich Text) and adjust the value of the “control” field:
custom:RichText
Note that the prefix is used from the controlSource reference above.

Simple and lightweight customization that should bring some value. Sitecore rocks!

Tested on 6.1, expected to work on 6.0.x and 6.2.