December 23, 2015

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

By: Craig Taylor
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.

October 22, 2015

EXM install fails when Admin user is disabled

By: Craig Taylor
October 22, 2015

EXM Install Fails when Admin user is disabled

Wow, been heads-down with client work for a while and haven't had a chance to write to the 'ol blog.  Glad to have some breathing room before the next project starts to get a few posts out.

While installing EXM 3.0 rev. 150429 on a Sitecore 8.0 Update 3 instance for a client, we ran into an interesting issue.  What is normally a pretty simple install was failing for us.

We were seeing the following error:

ERROR Installation failed: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Sitecore.Exceptions.AccessDeniedException: Only administrators can create new domains
   at Sitecore.SecurityModel.DomainManager.AddDomain(String domainName, Boolean locallyManaged)
   at Sitecore.Modules.EmailCampaign.Core.InstallationPostAction.AddCommonDomain()
   at Sitecore.Modules.EmailCampaign.Core.InstallationPostAction.RunPostStep()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Sitecore.Install.Installer.ExecutePostStep(String action, IProcessingContext context)
   at Sitecore.Shell.Applications.Install.Dialogs.InstallPackage.InstallPackageForm.AsyncHelper.CatchExceptions(ThreadStart start)
The "Sitecore.Exceptions.AccessDeniedException: Only administrators can create new domains" line really caught my eye and after poking around for a bit I discovered the issue: Sitecore was expecting the "sitecore/admin" user and we had disabled this account.  Now this was done intentionally for security reasons and we created a separate account with "admin" privileges.  So it appears as though the install requires that the "sitecore/admin" context is used when installing EXM.  (Good thing we only disabled the user and didn't delete it!)

Steps to Reproduce

  1. Use SIM (you *are* using SIM, right?) to spool up a fresh instance of 8.0 update 3.
  2. Create new account and give it administrator privileges.
  3. Log out of "sitecore\admin" and log in as the new admin user.
  4. Disable 'old' admin account.
  5. Upload and install EXM package on the CM server.
  6. Note failure message.

Workaround/Fix

Pretty straight-forward here, but install EXM under the context of the "sitecore/admin" user.

I reported my error and findings/workaround to Sitecore Support and they were able to confirm that this is a bug that will be resolved in a future version of EXM.

June 26, 2015

Run Multiple Solr Instances for Sitecore

By: Craig Taylor
June 26, 2015

Run Multiple Solr Instances for Sitecore

At Arke, we have recently made the switch to recommending Solr as the 'default' indexing solution for Sitecore rather than Lucene.  If you're wondering which to use on your project, please see Sitecore's document on when to use Solr over Lucene.

Switching to Solr

There was a little pain involved in switching from Lucene to Solr for an active project, but luckily, my co-worker, Patrick Perrone had already been down the path of getting Solr running on his Windows machine and provided an excellent step-by-step guide on how to make it work.  If you haven't already, see his 3-part series on Making Sitecore 8 and Solr Work Together.

Thanks to Patrick, getting Solr running was a breeze.  This worked great for my active project, but now I'm starting up new projects where Solr will be the indexing mechanism from day 1.  How will I separate client Solr cores from one another?

Installing Multiple Instances of Solr on your (Windows) Machine

Patrick's install guide works great when you're only going to be running a single instance of Solr, but in order to get a second instance of Solr running on my machine, I had to make some minor modifications.

Note: These steps assume you already have a solr instance up and running with the proper Sitecore-generated schemas.  If you haven't followed all the steps to get Solr running with Sitecore, please do those first to save a bit of configuration time on your cores later.

  1. Stop your Tomcat service.

  2. I installed my Solr directory at C:\Solr and all my standard Sitecore and custom cores were then in directories under there.  In order to clean things up, I created a new folder named ClientName1 that would now contain the cores for that client.  Go ahead and create a folder named ClientName2 while you're here for the project you are starting up.

  3. Once created, pull all the content from the root of C:\Solr into this new ClientName1 folder.

  4. Since the original cores were already configured to work with Sitecore, it's a simple matter of copy/pasting all the cores into a second client folder.  Copy all the files from the root of ClientName1 and paste them into ClientName2.  At this time, you should remove any custom cores that were defined specifically for client 1.  You can leave all the Sitecore cores as we're going to rebuild them as a final step anyways to get client 2 data into them.  Your Solr root should now just have client folders in it, nice and clean-like.

  5. Go into your 'Monitor Tomcat' tool and remove the Java Options you set as part of the initial configuration of Solr.  In my case, I removed Dsolr.solr.home=C:\Solr  This option tells Tomcat where the home Solr directory is, but it assumes there is only one instance running.  Our next steps will define the multiple home directories.

  6. Move the solr.war file out of the root of your ...\Tomcat 8.0\webapps\ directory.  In my case, I moved the solr.war file up one directory from C:\Program Files\Apache Software Foundation\Tomcat 8.0\webapps to C:\Program Files\Apache Software Foundation\Tomcat 8.0\  Having the war file in the webapps directory is another indicator to Tomcat that it's only running a single instance and it will ignore the configuration files we are going to set in the next step.

  7. Go to your \Tomcat 8.0\conf\Catalina\localhost directory and create new XML config files for each client.  I named mine solr-<clientNameX>.xml  Note that this filename will be how you access your Solr cores in the browser.  In this case, I'll access my two clients by http://tomcat:8081/solr-clientName1 and http://tomcat:8081/solr-clientName2.  You can name them whatever you like, but the contents should look like this:

    <Context docBase="C:\Program Files\Apache Software Foundation\Tomcat 8.0\solr.war" debug="0" crossContext="true" >
        <Environment name="solr/home" type="java.lang.String" value="C:\solr\ClientName1" override="true" />
    </Context>
    

    Here, you are referencing the path to the solr.war file that we moved and are setting the Solr home directory to where all your cores are for this client.

  8. Copy the XML file you just created and paste it to create the XML file for ClientName2. Edit the file and change the path to from the C:\solr\ClientName1 directory to the ClientName2 directory.

  9. Start your Tomcat service back up.

  10. Navigate to http://tomcat:8081/solr-clientname1 and http://tomcat:8081/solr-clientname2 and verify that both instances are running. (using the port number used when configuring Solr and the file names for the XML configs you defined)

  11. Edit your ContentSearch.Solr.ServiceBaseAddress setting in the Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config file to point to the correct new instance of Solr.

  12. Once running, go back to your Sitecore instances and rebuild your indexes!
You can now safely run Solr on multiple projects and have confidence that each client's cores will not be mixed up with one another.

June 18, 2015

Sitecore 8 Bug: Link Sets Anchor Target to Active Browser

By: Craig Taylor
June 18, 2015

Links be broke
We recently ran into an issue while trying to render links set in Sitecore 8 (Update 3, to be specific).  When using the "General Link" field to insert a link, we discovered that the "target" options for the link were incorrect.  The options provided out of the box were "Active Browser", "Custom" and "New Browser":

Original Link Target Options


One would assume that "Active Browser" would set the target of the anchor tag to "_self" or "_top" so that it opens in the same window.  Unfortunately, what happens is that Sitecore literally puts "Active Browser" in the target attribute, which is not valid and ends up actually opening a new window/tab.

Workaround/Fix

I opened a support ticket with Sitecore and they acknowledged this as a bug and it should be fixed in a future release.

In the meantime, you can adjust the settings of the "Link Details" box to display new target options as follows:

  1. In the "Core" database, navigate to the "/sitecore/client/Applications/Dialogs/InsertLinkViaTreeDialog/PageSettings/TargetsSearchPanelConfig" item.
  2. In the "Root" field of the "Filters" section, specify the "sitecore/client/Business Component Library/System/Texts/Targets" item. (default is "sitecore/client/Applications/Dialogs/InsertLinkViaTreeDialog/PageSettings/Targets")
Now, when you insert a link, you see target options that will work when rendered in the browser: "_blank", "_parent" and "_top":

Updated Link Target Options
Note: If you already had links set to "Active Browser", leaving the default of "SelectTarget" will still render the target as "Active Browser."  You need to open the "Insert Link" option, select "Insert" and then save the item for it to use the proper value.

May 22, 2015

Map a Drive to your Solution Folder to Avoid the File Name Length Error in TDS

By: Craig Taylor
May 22, 2015

Map a Drive to your Solution Folder to Avoid the File Name Length Error in TDS

I recently came across an article that was posted on Twitter about overcoming the dreaded 'File Name Length Error' in Team Development for Sitecore (TDS).

The article makes users aware of a built-in feature of TDS that allows you to use name aliases to overcome length issues.  In my experience, this generally works, but there are always times down the road where no amount of short aliases help due to the nested structure of your Sitecore solution combined with where you save your Visual Studio solution files on your dev machine.

What I like to do is map a drive to my solution files.  This takes my path from "C:\Users\ctaylor\Documents\Visual Studio 2013\Projects" to "Z:\".

I haven't seen the error in a while, but should I encounter it in the future, I can additionally utilize the alias feature of TDS.

March 28, 2015

Restore Access to an Administrator Account

By: Craig Taylor
March 28, 2015


For additional security, one of the first things I do when beginning work on a new Sitecore site is to remove the 'standard' "admin\b" account and instead create a new admin account with a different name (and password, of course!).  After doing this recently, we ran into a problem when the password for the new account was . . . lost.

Existing Functionality

There are some Sitecore tools designed to help manage accounts and access when the administrator user is unable to log in.  Unfortunately, the tools both assume that the user you are using is the 'standard' "admin" account and also that you haven't lost the password, but instead have been locked out of the account.  See John West's post regarding some common ways to get back in.

As John mentions, when the administrator password has been lost, you can simply log in with another account with administrator access in order to reset the password of the first account.  In our case, we only had one administrator account and had no way to get in otherwise.

The solution is to modify an existing tool.

Modify the "unlock_admin.aspx" Page

The "unlock_admin.aspx" page can be found at "/sitecore/admin/unlock_admin.aspx"  Unsurprisingly, the purpose of this page is to unlock the "sitecore\admin" account.  What we need to do is use this page to grab our admin user and reset the password.  The existing code only unlocks the locked admin account:

Membership.GetUser("sitecore\\admin").UnlockUser();
You can instead replace this with code that will set a password on any account in Sitecore:

MembershipUser mu = Membership.GetUser("sitecore\\[Your Administrator Account]");
mu.ChangePassword(mu.ResetPassword(), "[Your New Password]");

This code takes advantage of the .NET membership provider in order to change the password of the account specified.  Enable the button, view the page in the browser, click the button and you're done!  The password is changed and you can now log back in!

Just try not to lose the password this time.

Note: As John mentions in his post, always remember to go back and disable the 'unlock' button.  Also, while I have provided a solution that resets an administrator account password, please don't deploy this file.  It should only be used temporarily to get back into Sitecore.

February 23, 2015

Cascading Renderings in Sitecore 8

By: Craig Taylor
February 23, 2015

Cascading Renderings in Sitecore 8

I have a client that has a need to have managed content within their navigational menu.  We were able to dynamically insert placeholders and control the datasources for the renderings inserted.  When we went to another page in the site, we realized that the renderings we inserted were only associated with the original page instead of the entire site as we intended.  We needed to cascade the renderings down to all the subpages.

It's been done before

There are already some great starting points out there from Alex Shyba and Pavel Veller.  Alex originally wrote about it and Pavel updated the code to work with MVC.  Thanks guys!

One small change

With Sitecore 8 comes the idea of Versioned Layouts.  Since we can now have a shared and final layout, the code should be updated to check the "FinalLayoutField" so that we have access to any renderings added using the Experience Editor.

Field layoutField = parent.Fields[FieldIDs.LayoutField];
needs to be changed to:

Field layoutField = parent.Fields[FieldIDs.FinalLayoutField];