Friday, February 05, 2010

Sitecore 6 quick tip. Email as user name for authentication


It is pretty common to have email served as username for authentication in web systems for both visitors and internal users. Sitecore Content Management System is no exception.

With 5.3 it was pretty easy since users were just items – adjust the regex of the “ItemNameValidation” setting, make sure you don’t have @ and dots in the “InvalidItemNameChars” setting and you are pretty much set.

Now as you know, Sitecore 6 has different rules for security so you will need to do the following to make it work:
1. Make sure the membership provider treats email as a unique attribute for users so you don’t end up with more than one user attached to the same email:
<add name="sql" type="System.Web.Security.SqlMembershipProvider" connectionStringName="core" applicationName="sitecore" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" maxInvalidPasswordAttempts="256" />

2. Put email into both username and email properties (fields) of a user during the registration (can be handled via code).

3. Introduce the following entry into the web.config’s <settings> section. The “value” attribute parameter contains the regular expression used in the Create User dialog within User Manager. This regex should allow emails, otherwise Sitecore will fallback on a default regex that does not allow it.
<setting name="AccountNameValidation" value=".+" />

4. If you want to handle the case when email needs to be changed, either provide an extranet form for the profile section on your website or you can even take it one step forward – modify the EditUser dialog within User Manager to have this ability.

Happy coding!

Friday, January 29, 2010

Better Know Sitecore: Preventing multiple messages of the same type in the log


I would like to start a series of blog posts titled “Better Know Sitecore” where I will cover those areas of the product that are on on the surface, for example, useful utility methods that can save you time, efficient development techniques, etc.

Today we are covering the “Sitecore.Diagnostics” namespace, specifically, the “Log” class which most of you used for logging.
Recently discovered method of this class “SingleError” can be used when you would like to log only one instance of a specific error, not more than that. For example, we used it when trying to get a template for an item. If a template is not found or invalid, we don’t want to output it more than once. Under the hood, there is a caching mechanism in place that checks if the same error message is already in the collection – skip it, otherwise call the “Error” method.

Thanks goes to Sergey for clarifying it.

Happy logging!

Wednesday, January 27, 2010

No such host is known


Real quick tip. Such error may appear when you DNS is down or unreachable. To fix this, add your hostname that is in the bindings for IIS website to the hosts file under C:\Windows\System32\drivers\etc, point it to the local IP and that that should help till the issue with DNS is resolved:
127.0.0.1      yoursite.com

Tuesday, December 22, 2009

Publish to pre-production web database


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, true)
{
         RootItem = dataItem,
         Deep = true;
};

new Publisher(options).PublishAsync();

That’s it!

Tested on Sitecore 6.1. Expected to work with 6.2.

Monday, December 14, 2009

Get all published items in Sitecore 6.1/6.2


You may need to get all items that were processes by a publishing operation for different reasons, for example, pull certain information for each item and notify CDN of a change so cache could be purged. AKAMAI can be configured to behave that way.
Currently we have two articles on the subject. This one describes how to use the PublishEngine, second article suggests approach with custom PublishLog. Both are not compatible with 6.x. So I’ve looked into the options for the latest Sitecore with tech support. Our findings included introduction of a new PublishProcessor which examines the Queue property of PublishContext, but this did not work properly for smart publishing and I wanted a bulletproof yet simple approach applicable to all possible publishing modes.
Then I remembered that we are already doing similar things for indexing. The update index job processes only changed items and gets that information from the History storage.