Pages

Thursday, October 2, 2014

Sitecore's HeartBeat.aspx for Load Balancer Health Checks

Sitecore includes a HeartBeat page so that you can point your loadbalancer's health check at it to determine if that current machine is healthy and should take traffic.  It is a very simplistic health check but it is probably sufficient for basic Sitecore implementations.

The functionality of the included HeartBeat.aspx will enumerate all of your connection strings and try to make a simple connection over to the database.  If everything checks out Sitecore will generate a blank page with a standard HTTP 200 response.  If there are any issues connecting to any of the databases this page will return an HTTP 500 response.

There are two issues you need to be aware of if you are using this page.

Machine.Config Connection String
NET 4.5 typically configures a default ASP.NET membership provider connection string in the machine.config.  This typically points to .\SQLEXPRESS and thus out of the box the heartbeat page will fail on servers that do not have SQL Express installed.

The best approach is to just clear connection strings before you add in your Sitecore connection strings.  You could take the approach of editing the machine.config but that may not be as maintainable.
  • Clear existing connection strings before loading your Sitecore Connection Strings
    • Open \App_Config\ConnectionStrings.config
    • Add <clear /> directly under the <connectionStrings> node
Active Directory or other non-database Connection Strings
If you have your Sitecore instance configured to use the Active Directory Module you are probably adding your Active Directory connection strings to your main ConnectionStrings.config file.  These will fail the database check since they are not database connection strings.

The best way to resolve this issue to add a Sitecore setting to exclude specific connection strings from the Heart Beat check.  This setting is not configured in the default Web.Config file that is configured by Sitecore.  You can add it by including this patch config:

Thursday, September 11, 2014

Sitecore patches showModalDialog issues in Sitecore 6.4 through 7.0

Recently users working in older versions of Sitecore CMS have noticed that some features of the CMS stopped working in the latest version of Chrome (version 37+). The root cause of the issue was that Google has deprecated the showModalDialog() function that Sitecore relied on in versions 7.0 and previous. Starting in Sitecore 7.1 the functionality has been changed and is not an issue.

Up until yesterday Sitecore was recommending that all users either upgrade to 7.1, stop using Chrome, or apply a short-term fix to Chrome to temporarily re-enable this deprecated feature (see this blog post for more details -> http://www.bugdebugzone.com/2014/08/sitecore-modal-pop-ups-are-not-working.html?m=1).

Today Sitecore has updated it's support KB article (https://kb.sitecore.net/articles/581527) to include patches for versions 6.4 through 7.0. The patches appear to modify several Javascript files and shim in a Support DLL to modify the codebehind for several aspx/ascx files as well. This method seems to be fairly lightweight approach to fixing the issues in these older browsers and should not add much if any additional complexity to future upgrades.

If you are unable to upgrade to 7.1 (Note: if you are upgrading you should really consider moving to 7.2 update-2), then these patches seem like a good options to resolve issues with browsers that remove the showModalDialog() function.

Links to patches:
KB Article 581527

Saturday, September 6, 2014

Boost newer documents in Sitecore 7 and Solr 4

Sitecore 7 search backed by Apache Solr make for a very powerful and flexible search solution.  Unfortunately Sitecore's search abstraction layer was built to have consistency when using any underlying search technology.  This results in some unique features that are available in Solr not being included in the Sitecore 7 ContentSearch API.

If you are looking to boost your search results by a publication date (or any date field for that matter) the general recommendation from a Solr perspective is to utilize a function query as outlined in the SolrRelevancyFAQ.  Unfortunately Sitecore's API does not offer any way out of the box to generate a function query.  Digging into Solr.NET (which Sitecore's Solr implementation makes use) you are able to utilize LocalParms to attach a function query as part of your search request.  Since this is specific to Solr.NET and not something available in Lucene it is not something that has made it into Sitecore's ContentSearch API.

In order to extend Sitecore's ContentSearch to get this type of feature proved challenging and required a good deal of the ContentSearch code to be re-written.  Knowing that the supportability of such customization would be difficult to maintain between Sitecore versions I opted to look for a different approach.

Since Sitecore has limited options to manipulate what is actually be sent over to Solr I discovered the _val_ hook that Solr provides as part of FunctionQuery.  This will allow us to embed a function query inside of the actual search query.  We will be able to utilize this as a field in Sitecore so that we won't require any customization to the ContentSearch code.

Creating the Search Model
You will need to create a search model that utilizes Sitecore.ContentSearch.SearchTypes.SearchResultsItem as its base class.  It isn't necessary to use the base class but it will get you all of the standard Sitecore fields already defined.

Code:

Update Solr Schema
You will need to manually define "_val_" in your Schema.xml so that Sitecore does not attempt to make it a dynamic field.  To do this we will add the _val_ field to the <fields> node in your Solr Core's schema.xml.  Without doing this Solor will pick this up as a string field and append the _s suffix.  Please remember you will either need to re-load this Solr Core or restart Solr so it picks up the new Schema.xml.

schema.xml
<fields>
<field name="_val_" type="string" />
...snip...
</fields>

Date Boost Search Query
Now that your model is setup you just need to define the DateBoost Predicate.  This will be added to your GetQueryable Linq statement.  I am utilizing Sitecore's Predicate Builder to make the code more readable.

Code:
The date boost function query is utilizing the recommended function from the SolrRelevancyFAQ which is recip(ms(NOW, {FieldName}), 3.16e-11, 1, 1) where {FieldName} is replaced with your Sitecore Field name.  Please note you need to use the full dynamic field name that Solr knows about here which likely ends in a _tdt if you are accessing one of Sitecore's standard Date/Time fields.  The recip function can be adjusted based on how aggressive you wish to have the date boosting.  How much boosting you will need will depend on what other fields you are searching on, other boosting happening on the fields or document, and what your requirements are for how much impact document date has on the score it receives.

Verification
You will now be able to execute that search and utilize Sitecore's Search logs to view the query that is being sent over to Solr.  You will see that the _val_ hook is being added as expected and you should see that documents that contain the letter "A" that have more recent Publication Dates (a custom field defined on our template) will have a higher score then older documents.  This simple search example works well for our boosting since our scores are normalized around 1.  The more complex your search query the more you may have to adjust the recip() function to get the desired results.

Some additional information regarding Sitecore and search boosting can be found at John West's blog:  http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2013/04/Sitecore-7-Six-Types-of-Search-Boosting.aspx



Thursday, June 13, 2013

Using a Google Search Appliance with a Sitecore Website

Part 1: GSA Setup
In this two part article Jon and I will be discussing what it takes to setup and utilize an existing Google Search Appliance (GSA) with a Sitecore website.  In this first part I will discuss the configuration settings needed for your GSA to crawl your site.  In the second part Jon will go into the details of interacting with the GSA’s API to add seamless integration into your Sitecore website.
The configuration we will be setting up today will be very basic and assumes that the GSA is already configured with the base settings. This configuration is based on version 7.0.14.G 114 of the GSA and we have kept most of the default settings.  We will access the admin console via http://{ip_address}:8000/EnterpriseController.
The following three areas will need to be configured:

Crawl and Index -> Collections

Collections basically are a subset of patterns you want to include or exclude for a particular search.  This will let you refine the search to just the sites you want to include.  For our example we only want the GSA to return results from our new site.  So we’ll create a new Collection and add our site’s URL to the “include content” section.  If you have any Collections configured on the GSA that are setup to include all URLS (“/”) and do not want this site included in that Collection, this would be the time to update that collection to exclude this new site.

Serving -> Front Ends

Front Ends let you define the look and feel of the GSA’s search and results page.  Since we will be working directly against the API and handling the results with custom code in Sitecore, there isn’t much we need to do here.  We will create a Front End just for future use but will keep all the settings at their default values for now.  If we were using the GSA to display results we could configure our basic HTML and CCS settings here, as well as do some further refining of our search results utilizing Filters or Removing URLs.

Crawl and Index -> Crawl URLs

The final step is to tell the GSA to start crawling your site.  We will add our site into the “Start Crawling from the Following URLs” and “Follow and Crawl Only URLs with the Following Patterns” sections.  If you have any requirements to exclude certain content or want to be more granular with your selection, you can use regular expressions to include or exclude content.
These basic steps will get you up and running and ready to start coding against the API.  Our GSA is configured for continuous crawl as you can see in the “Status and Reports -> Crawl Status” section, so after a few minutes we should start seeing results in our collection.

Using LINQPad with Sitecore 7 and Solr

Adam Conn, one of Sitecore’s Technical Architects, has a great blog article titled Getting to Know Sitecore: LINQPad and Sitecore 7.  Unfortunately if you are using Solr for your search implementation there are a few extra steps that are needed to get things running.  Please take a read through Adam’s post as we will be using his base config as a jumping off point.  This post assumes you are using Castle.Windsor for your IoC which is required for Sitecore and Solr.

1)      Configure LINQPad.config as Adam describes.
a. Make sure to update the all of the <sc.include> tags to point to physical paths.  LINQPad will try to include then from the root directory if you are using the default logical paths.
b. I was unable to use the output of Sitecore’s ShowConfig.aspx to load the Sitecore configuration. Every browser I used mangled some the encoded.  You will see configuration errors when you run your Linq query if you are running into this.  I just used the configuration form my web.config as we aren’t doing much to it with Include files.
2)      Add your Solr configuration
a. Open your Sitecore.ContentSearch.Solr.Indexs.config and add everything in the <Sitecore> node to the <Sitecore> node in your LINQPad.config
3)      Open LINQPad
a. Close and restart if you already had it opened so it will read the new config
4)      Press F4 to bring up the Query Properties
a. Verify all the DLLs your project needs are listed in the “Additional References” Tab
    i. I just pulled in everything in my Applications \bin directory
    ii. Make sure you have references to the following
        1. Castle.Core
        2. Castle.Windsor
        3. Castle.Facilities.SolrNetIntegration
        4. This DLL comes with the Solr Support package available on Sitecore’s SDN
b. Add all of your using statements to the “Additional Namespace Imports”
    i. Here is the list I am using
    Castle.Windsor
    Sitecore
    Sitecore.ContentSearch
    Sitecore.ContentSearch.SearchTypes
    Sitecore.Data
    Sitecore.Data.Fields
    Sitecore.Data.Items
    System
    System.Collections.Generic
    System.Diagnostics
    System.Linq
    System.Web
5) For your Query you will need to change the Language to “C# Program” and wire up Castle.Windsor manually.

Please follow this link to copy this code https://gist.github.com/mattgartman/5776350
As you can see the only big change that is required for Solr to work is to wire up Castle.Windsor manually.  This is typically done in your Global.asax file when using Solr with Sitecore.
One thing to note is that I am creating a POCO for my model and I am hiding the Uri property from the bass SearchResultItem class.  I have found that you get a type conversion error with Sitecore 7 and Solr on the Uri property if left to the definition in SearchResultItem.  So we are hiding this property and forcing it to be of type ItemUri.  This may be a configuration issue in our Solr config, or some other bug somewhere along the way.
Have fun with LINQPad!