February 28, 2017

Sitecore Server Switch

February 28, 2017

Sitecore Server Switch

One of the most time-consuming aspects of installing and configuring Sitecore is configuring the servers for their specific roles.  Per Sitecore documentation, specific configuration files should be enabled or disabled for a Content Management (CM) server and likewise, specific files should be enabled or disabled for Content Delivery (CD) server.  Failing to configure the servers for their roles can cause Sitecore to not perform as expected.

Note: There are additional roles for server configurations such as Processing, Reporting and Publishing.

Sitecore's ARM templates look to solve this problem in that they can quickly spin up and configure a Sitecore server, but this only works when using Azure PAAS.  For those not using Azure PAAS, manually adjusting the configuration files can be time consuming.

Sitecore Server Switch looks to solve this issue by using PowerShell.  After installing Sitecore on a server, you can run the "Sitecore_Switch_CM_CD_Lucene_Solr.ps1" script to configure a server as a CM server, as a CD server and additionally configure it to utilize either Lucene or Solr indexing.

Sitecore Server Switch currently supports Sitecore 8.0 (all versions) and Sitecore 8.2 Update 2.  More versions are coming soon.

Sources

Sitecore Server Switch GitHub Source
Sitecore Server Switch on the Sitecore Marketplace (coming soon!)

Acknowledgments

Big shout-out to Sarkis Einarsson for his PowerShell scripts that were the base of this project. (http://sitecoreunleashed.blogspot.com/2015/09/sitecore-8-toggle-cd-configuration.html)

Additional Reading

You can also take this to the next level and automate everything.  Check out Patrick Perrone's work into this space with his automation scripts.

Update (03/01/2017)

And of course, how it usually happens, after writing this module and post, I came across this site that has some automation scripts for 8.2 and even includes the ability to configure additional roles: https://bitbucket.org/sitecoreautomationteam/sitecore-automation/wiki/sitecore-environment
Note: I have not tested this.

And I've also been made aware of Michael West's PowerShell scripts as well: https://gist.github.com/michaellwest/d1124a459cb1fb47486f87d488ecfab8

February 17, 2017

Implement TDS Code Generation for a Helix Generic Repository Foundation Layer

February 17, 2017

Implement TDS Code Generation for a Helix Generic Repository Foundation Layer
I recently sat down to implement some of the suggestions from Phil and Jason's amazing book on Sitecore development, Professional Sitecore 8 Development.  I already had a few Helix architecture implementations under my belt, but felt like I could improve on what I had done.  I think it's probably the case after each implementation that you always find things to improve on for the next implementation. In particular, I was trying to get my Helix architecture to be more consistent, efficient and repeatable.

In chapter 5 of the Professional Sitecore 8 Development book, Phil and Jason speak of improving the architectural design by using design patterns.  Specifically, they recommend creating a generic repository foundation layer.  One of the tools that can help accomplish this goal is Glass Mapper.  Using Glass, we are able to let the repository remain generic and we can tell it the type of object to return at runtime.  In order to constrain the generic repository, their examples set the interface of the generic repository to require that the type being passed in implements "ICmsEntity" (a separate foundation layer that is used to represent a Sitecore item)

So, the "ICmsEntity" interface (code lifted directly from Professional Sitecore 8 Development) looks like this:
And the generic repository (code lifted directly from Professional Sitecore 8 Development)  looks like this:
As you can see, the ICmsEntity interface is empty.  It's really just a way to differentiate Sitecore items from other classes/items.  What we want to do is make sure that any interfaces that we create via Glass that represent Sitecore items implement this ICmsEntity interface.

The example in the book goes on to explain how you can utilize an ORM foundation layer to map to all your Sitecore objects.  In my case, I'm using Team Development For Sitecore (TDS) and have have TDS projects generating my code within my feature layers.

To utilize this generic repository and to have it incorporate the ICmsEntity interface constraint, we need to modify the code generation templates that TDS uses.  This is where it gets super-easy to implement. (wait, it's supposed to be difficult, right?)

First, edit the "glassv3header.tt" T4 template to import the namespace of the foundation layer that contains the ICmsEntity interface.  I'll continue to use the namespaces specified in the example from the book for consistency.  See line #11 below:

Now, edit the "glassv3item.tt" T4 template to have the interfaces that are created implement the ICmsEntity interface.  See line #8 below:

Re-generate your code and you're done!  You now automatically have all your Sitecore objects implementing the ICmsEntity interface and your generic repository will be able to retrieve the proper objects.

Additional Reading/Resources

Professional Sitecore 8 Development - You *do* have the book already, right??
Helix - Helix documentation


January 23, 2017

Setting Sitecore SQL Server Database Permissions

January 23, 2017

Setting Sitecore SQL Server Database Permissions

I recently started on a Sitecore 8.2 project and was setting the SQL Server permissions for the SQL user that I had created for Sitecore to use.  The idea here is to provide least-permissions to the user so that it has enough access to work, but not so much access that it is able to do things that it should not be able to. I feel like I spent way too much time looking for the permissions that should be set.  I eventually found what I was looking for in the installation guide for Sitecore! (#rtfm)

In an effort to make sure this information is accessible (read: so that I find it when I forget next time), I've duplicated the content here.

For the "Master", "Web", "Sessions" and "Analytics" databases, select the following permissions:

  • db_datareader
  • db_datawriter
  • public 

For the Core database, select the following permissions:

  • db_datareader
  • db_datawriter
  • public
  • aspnet_Membership_BasicAccess
  • aspnet_Membership_FullAccess
  • aspnet_Membership_ReportingAccess
  • aspnet_Profile_BasicAccess
  • aspnet_Profile_FullAccess
  • aspnet_Profile_ReportingAccess
  • aspnet_Roles_BasicAccess
  • aspnet_Roles_FullAccess
  • aspnet_Roles_ReportingAccess

For all databases:

In addition to assigning the proper roles to your user for the Sitecore databases, you also want to allow the user to execute stored procedures.  For each database, open the "Properties" window, select "Permissions", select your user and select the "Grant" checkbox for the "Execute" permission.

This is all from the 8.2 Update 2 installation guide, which I can't seem to link to due to authentication requirements on http://dev.sitecore.net, but I think the permissions are the same for previous versions of Sitecore as well.

August 11, 2016

Sitecore Config Transforms - Use Replace instead of Remove

August 11, 2016

Sitecore Config Transforms - Use Replace instead of Remove

I love config transforms.  I love being able to have a single file that can be transformed for any number of my build destinations.  It's much, much better than trying to maintain separate config files for each destination.  Many times, I have config files that should *only* exist on either a CM or CD server.  Originally, I used the "Remove" method to remove the entire contents of a config file like so:


While it doesn't technically break anything, it leads to errors in the logs on Sitecore startup that complain about "Reader is in incorrect state":


The fix is actually really easy.  Instead of removing the entire "sitecore" node in the file, just replace it:

Now Sitecore be all happy.


June 28, 2016

Using Config Transforms to Manage Sitecore Indexes

June 28, 2016

Using Config Transforms to Manage Sitecore Indexes

In my previous post, I talked about setting up your Solr indexes to use the "SwitchOnRebuildSolrSearchIndex" index type to avoid index downtime.  In that post, I mentioned that I was using Config Transforms in order to manage the configuration settings across my different environments.  Here's a quick example of how to set up an index for the different environments:

The 'Default' or 'Standard' Index configuration that I have in my solution:

What's going on?:

  • I have separate configurations for "Web" vs "Master" databases. This configuration is for the "Web index. 
  •  I'm using the 'onPublishEndAsync' indexing strategy since this is my "Web" database.  This tells Solt to update the index when a publish is complete.

I then "Add Transform" in Visual Studio to create the specific versions for the other environments.

Note: In order to add the tranformations, you have to have separate solution configurations configured for each environment.

I'll skip all my local/dev/qa/stage environments and just show what I've got for production, but note that each environment can and usually *should* have its own transformation.

Production CM server configuration:

What's going on?:

  • I tell the transform to look for all indexes in the parent config file and change the index type to "SwitchOnRebuildSolrSearchIndex."  I like to keep only one index per configuration file, but if you had multiple indexes defined, this will change all of them.
  • I'm inserting the "rebuildcore" parameter into the index configuration.  This is required so that Sitecore knows which Solr core to swap to after the rebuild is complete.  It's also very important that it goes in in the third position as Sitecore expects it there.

When the transformation is applied, it looks like this:

For the Production CD server, I have the following transform:

What's going on?:

  • As with the CM server, I'm changing the index type to "SwitchOnRebuildSolrSearchIndex", but as you will see with the next point, it doesn't really matter.
  • We are setting the index strategy to "manual."  Our Solr indexes are centrally located on another server and we want the indexing to only happen once.  The rebuilding of the indexes are controlled by the actions of the CM server.
Setting up different configurations based on environment is easily accomplished using config transforms.  It keeps your configuration files clean and easy to manage.


March 26, 2016

Solr in Production for Sitecore - SwitchOnRebuildSolrSearchIndex

March 26, 2016

Solr in Production for Sitecore - SwitchOnRebuildSolrSearchIndex

The configuration for running Solr in your local dev environment is likely going to be different than running it in the production environment.  Oftentimes, your local indexes will be configured as a type of "Sitecore.ContentSearch.SolrProvider.SolrSearchIndex" while using the "syncMaster" indexing strategy.  This strategy rebuilds the index after data changes are saved in the master database.  It works well locally if you want to avoid having to publish to the Web database to see your indexes update, but this doesn't work in a production environment where your Content Delivery (CD) servers don't have access to the master database.  Not to mention, you don't want to be indexing content that hasn't been published yet.

In a production environment, it is much more common to use the "SwitchOnRebuildSolrSearchIndex" index type while using the "onPublishEndAsync" indexing strategy.  This type keeps your indexes up and running even when they are rebuilding.  This is accomplished by building to a secondary index and when the rebuild is complete, Sitecore uses that index as the primary index.  The rebuild is triggered when items are published to the 'Web' database.

Note: I should also note here that the CD servers should actually have their indexing strategies set to "manual" due to the Content Management (CM) server controlling when the central Solr indexes are being rebuilt .  More on this below.

Since I have different strategies defined for the different environments and have different build configurations in my Visual Studio solution, I utilized config transforms to allow the correct type and strategy to be used in the different environments.  I'll detail these transforms in a future blog post.

For this example, my local development instance has a custom index used for indexing products defined as follows:

          <index id="product_search_index" type="Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider">
            <param desc="name">$(id)</param>
            <param desc="core">$(id)</param>
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/productSearchIndexConfiguration" />
            <strategies hint="list:AddStrategy">
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/syncMaster" />
            </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>web</Database>
                <Root>/sitecore/Content/Products</Root>
              </crawler>
            </locations>
          </index>

My local dev instance is a CM/CD combined instance and as you can see in my config, it uses the "Sitecore.ContentSearch.SolrProvider.SolrSearchIndex" type, with the "syncMaster" strategy on the "master" database.  I can now update items and have them immediately available in my index without having to go through the trouble of publishing.

When deploying to a dev, stage or prod CM server, I want to ensure that my products index is always available and only contains data that has been published.  We can accomplish this with the "SwitchOnRebuildSolrSearchIndex" index type and the "onPublishEndAsync" indexing strategy.  I have the following defined for a dedicated CM server:

          <index id="product_search_index" type="Sitecore.ContentSearch.SolrProvider.SwitchOnRebuildSorlSearchIndex, Sitecore.ContentSearch">
            <param desc="name">$(id)</param>
            <param desc="core">$(id)</param>
            <param desc="rebuildcore">$(id)_sec</param>
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/productSearchIndexConfiguration" />
            <strategies hint="list:AddStrategy">
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
            </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>web</Database>
                <Root>/sitecore/Content/Products</Root>
              </crawler>
            </locations>
          </index>

Note: These two index configurations are shown to illustrate the process for both switching and utilizing the onPublishEndAsync strategy.  In an actual production environment, you should separate your indexes so that you have one for the master database and one for the web database.

The changes of note here are:
  1. The index type was changed to "Sitecore.ContentSearch.SolrProvider.SwitchOnRebuildSorlSearchIndex"
  2. We added a new parameter named "rebuildcore".  This tells Sitecore the name of the secondary core to utilize while building.  Note that you need to have an additional core created to facilitate this.
  3. The strategy has been changed to "onPublishEndAsync"
  4. The "Database" we are indexing is the "Web" database.
This is a configuration for a CM server.  In order to keep the CD servers from kicking off a rebuild of the indexes, you should set their index strategy type to "contentSearch/indexConfigurations/indexUpdateStrategies/manual".

Now, each time you publish an item, the index will be automatically updated and you don't have to worry about the rebuild time taking it offline as Sitecore will be using the secondary core you defined.

Additional Reading

December 23, 2015

Could not create instance of type: Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex. No matching constructor was found.

December 23, 2015

Could not create instance of type: Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex. No matching constructor was found.

Okay, that's a long post title.

While configuring a new Sitecore 8.1-Update 1 site that is using Lucene for indexing, I ran into an issue while changing all the indexes to utilize SwitchOnRebuildLuceneIndex.  We do this to allow the system to switch indexes while the new index is rebuilding so that we don't temporarily lose access to an index while it is being rebuilt.  Configuration-wise, we do this by utilizing config transforms.

After building and deploying the solution locally, I was seeing the following nested exception:

Exception: Sitecore.Exceptions.ConfigurationException
Message: Could not create instance of type: Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex. No matching constructor was found.
Source: Sitecore.Kernel
   at Sitecore.Configuration.Factory.CreateFromTypeName(XmlNode configNode, String[] parameters, Boolean assert)
   at Sitecore.Configuration.Factory.CreateObject(XmlNode configNode, String[] parameters, Boolean assert, IFactoryHelper helper)
   at Sitecore.Configuration.Factory.GetInnerObject(XmlNode paramNode, String[] parameters, Boolean assert)
   at Sitecore.Configuration.Factory.AssignProperties(XmlNode configNode, String[] parameters, Object obj, Boolean assert, Boolean deferred, IFactoryHelper helper)
   at Sitecore.Configuration.Factory.CreateObject(XmlNode configNode, String[] parameters, Boolean assert, IFactoryHelper helper)
   at Sitecore.Configuration.Factory.CreateObject(String configPath, String[] parameters, Boolean assert)
   at Sitecore.ContentSearch.ContentSearchManager.get_SearchConfiguration()
   at Sitecore.ContentSearch.ContentSearchManager.GetIndex(String name)
   at Sitecore.Marketing.Search.CampaignDefinitionSearchProvider..ctor(String indexName)

So I had actually recently seen a very similar error while configuring some Solr indexes for a different client.  From that troubleshooting experience, I knew I could crack open the Sitecore.ContentSearch.LuceneProvider assembly to look for the constructor that was having issues.

I could see that the SwitchOnRebuildLuceneIndex constructor accepts three parameters: name, folder and propertyStore.

Upon inspecting my transforms, I came across the Sitecore.ContentSearch.Lucene.Index.Analytics.config file.  This config file specifies the sitecore_analytics_index index, and has four parameters: name, folder, propertyStore and group.  This is more than the SwitchOnRebuildLuceneIndex constructor is expecting.

Workaround/Fix

Don't use SwitchOnRebuildLuceneIndex on the sitecore_analytics_index!  Just leave it as the 'standard' type of Sitecore.ContentSearch.LuceneProvider.LuceneIndex.

As to why this index is different, Patrick notes that the crawlers indexing the analytics data are observers and there is no need to have a secondary index.  Read more in his blog post.