Thursday, December 14, 2017

Sitecore EXM error after upgrade

After upgrading a Sitecore instances version of the Email Experience Manager (EXM) to version 3.5, the following error appeared when attempting to load the site:
Could not find configuration node: "exm/eds/senderManager"

This can be solved by ensuring the Sitecore.EDS.Core.config (located in \Website\App_Config\Include\EmailExperience) configuration file is enabled.

However if the error is appearing on a content delivery instance, the configuration file above should not be enabled. You should check that only the following email campaign/email experience DLLs are present in the bin folder:
  1. Sitecore.EmailCampaign.Cd.dll
  2. Sitecore.EmailCampaign.Content.dll
  3. Sitecore.EmailCampaign.dll
  4. Sitecore.EmailCampaign.Model.dll
  5. Sitecore.ExM.Framework.dll
It's also worth checking that only the following configurations are enabled in the \Website\App_Config\Include\EmailExperience folder:
  1. Sitecore.EmailExperience.CommitSession.config
  2. Sitecore.EmailExperience.ContentDelivery.config
  3. Sitecore.EmailExperience.Core.config
  4. Sitecore.ExM.Framework.config
  5. Sitecore.ExM.Framework.ContentDelivery.config
Either of the above solutions should solve the error for you.

Wednesday, December 13, 2017

Sitecore TDS error during solution deploy

When attempting to deploy a Sitecore (Habitat) solution to a local instance, the following error was appearing for a number of TDS projects:
The "DeploySitecoreItems" task was not given a value for the required parameter "ProjectId".
Several steps were undertaken in attempting to solve this issue:

  • Restart IIS
  • Close and re-open visual studio (and ensure it's running as administrator)
  • Testing the connection on one of the TDS projects to ensure it's configured correctly.
Sitecore TDS test connection
After trying all of these steps the solution would deploy as expected.

Sitecore Instance Manager - packages does not contain Web.config file

When attempting to import a Sitecore solution using Sitecore Instance Manager (SIM), the following error would display:
Wrong package for import. The package does not contain the Website/Web.config file.
Sitecore Instance Manager - missing Web.config file
Looking inside the package, there was a Web.config file inside a Website directory. The version of SIM was the latest at the time (1.5.0.2), and according to the SIM bug tracking this issue was resolved several (minor) releases ago.

It turns out that the Solution that I was trying to import, was generated months ago on a now outdated version of SIM. By re-exporting the solution using the latest version it could then be imported successfully.

If your solution uses Sitecore Experience Accelerator (SXA), you may need to download the QA version of SIM.

Tuesday, December 5, 2017

Sitecore update analyze or installation freezes

When upgrading a Sitecore instance (from version 8.1 to 8.2), the update installation wizard would freeze at a certain point. This was happening with both the analyze and install option, it would always freeze around item number 535 - 540.
Sitecore update installation freezes
The event logs would display no useful information and there was nothing in the Sitecore logs. After attaching procdump to the w3wp process, it was discovered that a stack overflow exception was being raised. The debug diagnostic tool was then enabled (and set to log a full dump for stack overflow exceptions). The dump file showed that New Relic logging was causing a stack overflow each time and causing the update to freeze.

In my case disabling New Relic, allowed the update to work as expected.

Sitecore ValueFactory error after upgrade

After upgrading a Sitecore instance from version 8.1 to 8.2 (update 5) the following error appeared on the web site and Sitecore admin area:
ValueFactory attempted to access the Value property of this instance.
Further down the stack trace there was mention of both MongoDB and analytics:
[InvalidOperationException: ValueFactory attempted to access the Value property of this instance.]
System.Lazy`1.CreateValue() +739
System.Lazy`1.LazyInitValue() +428
MongoDB.Bson.Serialization.Serializers.EnumerableInterfaceImplementerSerializer`2.MongoDB.Bson.Serialization.IChildSerializerConfigurable.get_ChildSerializer() +15
Sitecore.Analytics.Data.DataAccess.MongoDb.DictionaryRepresentationConvention.Apply(IBsonSerializer serializer) +109
Sitecore.Analytics.Data.DataAccess.MongoDb.DictionaryRepresentationConvention.Apply(IBsonSerializer serializer) +120
Sitecore.Analytics.Data.DataAccess.MongoDb.DictionaryRepresentationConvention.Apply(BsonMemberMap memberMap) +33
MongoDB.Bson.Serialization.Conventions.ConventionRunner.Apply(BsonClassMap classMap) +358
MongoDB.Bson.Serialization.BsonClassMap.AutoMapClass() +79
MongoDB.Bson.Serialization.BsonClassMap.LookupClassMap(Type classType) +435
MongoDB.Bson.Serialization.BsonClassMapSerializationProvider.GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry) +234
MongoDB.Bson.Serialization.BsonSerializerRegistry.CreateSerializer(Type type) +174
In this instance, both the web forms for marketers and email experience modules were installed. As per the upgrade instructions, these configuration files were disabled. However a couple of the WFFM configuration files were missed. These files are not all listed alphabetically as they have three naming conventions, so it's easy to miss one:
  • Sitecore.Forms.*
  • Sitecore.MvcForms.config
  • Sitecore.WFFM.*
You may also see the following error if you miss the Sitecore.MvcForms.config file:
Could not find configuration node: /sitecore/wffm/data/perRequestStorage

Thursday, November 23, 2017

A look at the new Forms module in Sitecore 9

Longtime users of the Sitecore Experience Platform will be familiar with the Web Forms For Marketers (or WFFM) module. It's main strength was the ability for content editors and marketers to create rich forms, all without developer intervention. Yet, there were often complaints when it came down to visual styling, customization around multi-page forms along with the need for conditional elements (show this text box if the user selects value X in the drop-down list).

With Sitecore 9, comes the new forms modules and when I say module, it come's out of the box with no separate install! Right away that will excite anyone that has ever had to do a Sitecore upgrade and go through the install of multiple WFFM update packages.

The Forms dashboard

After clicking on the Forms shortcut you will be taken to the new forms dashboard.

Sitecore Forms dashboard
No longer do marketers need to manage their forms via the content editor, where it can become especially difficult when there are a reasonable number of forms and even form variations. This dashboard allows for searching, sorting along with the ability to see forms created by you. The option to download all submitted data for a given form, is available here as well.

On the right hand panel, the selected form shows two key areas of information. Overview displays  statistics on creation, edit date along with where the form is actually being used. Performance has statistics and counters around views, abandonment and even error rates. Both of these features are key for quickly finding out which forms are actually being used and where there is potential loss of conversion (abandonment/error rates).

Forms performance for a given form

Creating a form

From the dashboard, it is then possible to create a new form. This could be a blank form (start from scratch) or via a template - which lets you select an existing form and create a new one based off of that.

The form creation page is a much slicker version of the old WFFM module. Here the familiar form elements are available for selection (text boxes, lists, and so on), but the new drag and drop feature makes for a much easier editing experience.

Sitecore forms drag and drop
When a field is added to the form, there are a number of settings that are available. Aside from the standard validation/field lengths, placeholder text is now supported, as is a CSS class for both the field element and it's label.

General settings for a Sitecore form field
If performance tracking has been enabled for a given form field, then the performance statistics will become available for viewing. Much like the form statistics on the Forms dashboard, this shows field level abandonment rates, error rates and average time spent on the field. This data is extremely valuable for a marketer looking to optimize a given form to lead to higher completion rates.

Performance for a form field
Two versions of a given form could also be A/B tested to see which leads to higher completion rate - this would be done by A/B testing against a goal triggered in the form's submit actions.

Once a submit button has been added onto the form, the submit actions can be selected and configured. The standard save data, page redirect and triggering of marketing items (goals, campaign activities and outcomes) is available, but much like WFFM the real power comes in plugging in a custom submit action.

Perhaps the most exciting feature of all, is the ability to add paging to your form! This has been a long requested feature and is a great way to create wizard-like forms and even make a particularly long form more bearable to the user.

The new page form element
Now a form has been created and saved, it can then be added to a page using the standard forms rendering. This of course can be achieved using both the content editor and the experience editor.

A form added to a page using the MVC Form rendering

Customization of Forms

Much like any part of the Sitecore Experience Platform, the ability to extend or customize the forms module is supported. 
  • Submit action - creation of a custom submit action allows for the data entered into the form to be used as required. Common examples of this might be sending the data to a third party CRM, or custom database.
  • Custom validation - this allows for custom and more complex validations to be done in code. A common example of this may be validating a customer number (even taking into account a field containing customer name).
  • Custom form elements - sometimes business requirements will come up that require a custom form element to be created. An example of this may be a color picker, or perhaps a custom CAPTCHA implementation.
Furthermore it is also possible to edit the output of existing fields (such as the HTML output for a text box). This is not best practice as you are editing core Sitecore files (that will be overwritten during upgrade). In some cases, simply adding styles for form elements/labels may not be enough and this option becomes necessary.

Conclusion

Overall the new Forms module available in Sitecore 9 is an impressive release, that provides an easier interface for marketers to create, manage and monitor performance of their forms. It's worth noting that the aim with the initial release of forms was to match the functionality of the current WFFM offering. No doubt in the future we are going to see some exciting features to come.

Tuesday, November 14, 2017

Sitecore 9 SOLR search example

One of the key features that any web site needs is a strong internal search engine. This posts focuses on how to get a minimal working example of an internal Sitecore search using SOLR in version 9 of Sitecore.
  1. The first step is to create a core for SOLR. This core is an instance of a Lucene index and contains dedicated configurations for that core.
  2. The next step is to create an index configuration for SOLR search, this will contain what data is getting indexed and which fields of that data.
  3. The index is now ready to be rebuilt (to get the data added into it). If the Sitecore admin area shows an error the index configuration XML may not be valid. The rebuild will also give a count of items processed into the index.
  4. Now code can be used to access the SOLR search index and query for a given term. The example below is the full code implementation for search in Sitecore with SOLR and will be explained in detail.
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore.ContentSearch.SearchTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Sitecore.Base.Helpers
{
    public class SearchHelper
    {
        /// <summary>
        /// Complete a search
        /// </summary>
        /// <param name="searchTerm">Search term</param>
        /// <returns>Search results object</returns>
        public static SearchResults DoSearch(string searchTerm)
        {
            var myResults = new SearchResults
            {
                Results = new List<SearchResult>()
            };

            var searchIndex = ContentSearchManager.GetIndex("sitecore_test_index"); // Get the search index
            var searchPredicate = GetSearchPredicate(searchTerm); // Build the search predicate

            using (var searchContext = searchIndex.CreateSearchContext()) // Get a context of the search index
            {
                var searchResults = searchContext.GetQueryable<SearchModel>().Where(searchPredicate); // Search the index for items which match the predicate

                // This will get all of the results, which is not reccomended
                var fullResults = searchResults.GetResults();

                // This is better and will get paged results - page 1 with 10 results per page
                //var pagedResults = searchResults.Page(1, 10).GetResults();

                foreach (var hit in fullResults.Hits)
                {
                    myResults.Results.Add(new SearchResult
                    {
                        Description = hit.Document.Description,
                        Title = hit.Document.ItemName,
                        Url = hit.Document.ItemUrl
                    });
                }

                return myResults;
            }
        }

        /// <summary>
        /// Search logic
        /// </summary>
        /// <param name="searchTerm">Search term</param>
        /// <returns>Search predicate object</returns>
        public static Expression<Func<SearchModel, bool>> GetSearchPredicate(string searchTerm)
        {
            var predicate = PredicateBuilder.True<SearchModel>(); // Items which meet the predicate

            // Search the whole phrase - LIKE
            predicate = predicate.Or(x => x.DispalyName.Like(searchTerm)).Boost(1.2f);
            predicate = predicate.Or(x => x.Description.Like(searchTerm)).Boost(1.2f);
            predicate = predicate.Or(x => x.Title.Like(searchTerm)).Boost(1.2f);

            // Search the whole phrase - CONTAINS
            predicate = predicate.Or(x => x.DispalyName.Contains(searchTerm)).Boost(2.0f);
            predicate = predicate.Or(x => x.Description.Contains(searchTerm)).Boost(2.0f);
            predicate = predicate.Or(x => x.Title.Contains(searchTerm)).Boost(2.0f);

            return predicate;
        }

        /// <summary>
        /// Search item mapped to SOLR index
        /// </summary>
        public class SearchModel : SearchResultItem
        {
            [IndexField("_name")]
            public virtual string ItemName { get; set; }

            [IndexField("_displayname")]
            public virtual string DispalyName { get; set; }

            [IndexField("itemurl")]
            public virtual string ItemUrl { get; set; }

            [IndexField("description")]
            public virtual string Description { get; set; } // Custom field on my template

            [IndexField("title")]
            public virtual string Title { get; set; } // Custom field on my template
        }

        /// <summary>
        /// Custom search result model for binding to front end
        /// </summary>
        public class SearchResult
        {
            public string Title { get; set; }

            public string Url { get; set; }

            public string Description { get; set; }
        }

        /// <summary>
        /// Custom search result model for binding to front end
        /// </summary>
        public class SearchResults
        {
            public List<SearchResult> Results { get; set; }
        }
    }
}
This code is best explained by breaking it down into sections:
  • SearchModel - this is the model that each item in the index is mapped to. It contains a base class with all of the standard Sitecore fields indexed. The items directly on the model are my custom fields in the index. The itemurl field is a clean implementation of the URL of the item/page that uses a Sitecore computed index field.
  • SearchResults - This is a model containing a list of search results (SearchResult model mapped from the SearchModel  with only the fields we need) which is bound to the view. It would normally contain more information such as total results, current page, etc.
  • GetSearchPredicate - Is where the main search logic is built up into a predicate. This is a simple example where like or contains is run on the whole search term. More advanced logic could be added to split a phrase into multiple terms and so on. A predicate can also be made up of multiple predicates if required.
  • DoSearch - The main piece of code to actually run the search. This gets the search index and queries it with the built up predicate. Any hits are mapped through to the cleaner model assigned to the search results view. In this case p;aging is not implemented, but the code to do this is commented out.
This is just an example of a minimal implementation of SOLR search in Sitecore 9 (from a back-end perspective). This can be expanded upon to provide more advanced concepts such as working out the field which is most relevant to the user's query (and displaying this on the front-end) or highlighting the search terms in the results. 

Sitecore Instance Manager (SIM) installation error

When attempting to install the latest version of Sitecore Instance Manager (or SIM), the following error was appearing after entering the SQL Server details:
The SQL Server is configured to use "NTSERVICE\MSSQLSERVER" account which is not supported by current version of SIM. You need to change the SQL Server's user account and click Grant again. The instruction will be provided when you click OK.
This can be resolved using these instructions.
  1. Open the SQL Server configuration manager, this can be done by entering the following into your apps or start bar:
    1. SQLServerManager13.msc in the case of SQL Server 2016
    2. SQLServerManager12.msc in the case of SQL Server 2014
    3. SQLServerManager11.msc in the case of SQL Server 2012
  2. On the right hand side select SQL Server Services and then on the left select SQL Server (MSSQLSERVER). Then right click and click Properties.
  3. Select the Built-in account radio button and in the drop down box below, Network Service
  4. Click OK to close the box and again when promoted that a restart of SQL Server will occur.
SIM will now install correctly without any issues.

Thursday, November 9, 2017

Sitecore SOLR custom fields are not appearing in the index

After setting up a custom index configuration for SOLR in a Sitecore 9 instance, I noticed that the fields in which I had added to the raw:AddComputedIndexField were not present in the index (when viewed under schema in the SOLR admin site).

The index definition XML was valid and the index would built, yet my fields were not present.

After a bit of playing around I notice that the ordering of documentOptions and fieldMap mattered. I originally had them in this order:
<configuration ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration">
 <fieldMap ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap">
   <fieldNames hint="raw:AddFieldByFieldName">
  <field fieldName="title" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
  <field fieldName="description" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
   </fieldNames>
 </fieldMap>
 <documentOptions ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/documentOptions">
   <include hint="list:AddIncludedTemplate">
  <Page>{49E6B85F-02F4-405F-923F-66761933E80F}</Page>
   </include>
   <fields hint="raw:AddComputedIndexField">
  <field fieldName="MyComputedField" returnType="string">Sitecore.Base.Search.MyComputedImageField, Sitecore.Base</field>
   </fields>
 </documentOptions>
</configuration>
Which was incorrect, however swapping to the following order worked.
<configuration ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration">
 <documentOptions ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/documentOptions">
   <include hint="list:AddIncludedTemplate">
  <Page>{49E6B85F-02F4-405F-923F-66761933E80F}</Page>
   </include>
   <fields hint="raw:AddComputedIndexField">
  <field fieldName="MyComputedField" returnType="string">Sitecore.Base.Search.MyComputedImageField, Sitecore.Base</field>
   </fields>
 </documentOptions>
 <fieldMap ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap">
   <fieldNames hint="raw:AddFieldByFieldName">
  <field fieldName="title" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
  <field fieldName="description" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
   </fieldNames>
 </fieldMap>
</configuration>
It was a strange one to get working, so hopefully this post is able to help anyone else that comes across this error.

Sitecore SOLR Error getting file length for [segments_1]

After installing Sitecore 9 and deploying a simple site, I noticed that experience analytics were appearing but no experience profiles were visible. After allowing anonymous experience profile data, the experience profiles were still not visible. Looking into the SOLR admin logs there was a stream of the following error message:
Error getting file length for [segments_1]
 These errors were all for the xDB SOLR core.

Sitecore SOLR - error getting file length

Try rebuilding the index

The first step is to try rebuilding the index. In this case, these steps were followed:
  1. Turn the Windows SOLR service off
  2. Delete the data folder for the core with the error
  3. Turn the Windows SOLR service on
  4. Kick off an index rebuld
    1. For the xDB index, a rebuild has a special set of instructions as opposed to the control panel in Sitecore.
In my case, this did not resolve the issues.

Java Runtime Environment version

When installing SOLR, I had installed the latest version of the JRE (version 9). However SOLR prefers a slightly older version of JRE, version 1.8.0_111 aka jre-8u144-windows-x64. To resolve this error the following steps were followed:

  1. Turn off the Windows SOLR service
  2. Install the correct JRE version - re-8u144-windows-x64.exe
  3. Restart the PC
  4. Uninstall the incorrect, newer version of the JRE
  5. Update the Java_Home system variable to the new folder location of the older JRE
  6. Restart the SOLR service
After following these steps, the errors disappeared and the xDB data appeared correctly.

Wednesday, November 8, 2017

Sitecore 9 no experience profile data

After spinning up a new Sitecore instance and browsing the site under several anonymous sessions I noticed that no data was appearing inside experience profiles.

Sitecore 9 no experience profile data
This occurs because by default xConnect will not index and display anonymous contacts. Sitecore documentation has a great article on a setting change which will allow this data to be index. Then after a rebuild of the xDB search index in SOLR, the data will begin to show.

The setting which gets changes is IndexAnonymousContactData which is located inside the sc.Xdb.Collection.IndexerSettings.xml file inside the xConnect website folder (C:\inetpub\wwwroot\sc9test_.xconnect\App_data\jobs\continuous\IndexWorker\App_data\Config\Sitecore\SearchIndexer in my case).

Sitecore SOLR creating a core for your custom search index

After installing SOLR and connecting it to your Sitecore 9 instance, you may notice that a number of default Sitecore default cores have been added. In SOLR a core is an instance of a Lucene index and contains the configurations for that index. Each index should have it's own core, so for each custom index you wish to create for Sitecore, you must create a core.

To create your SOLR core, in the browser navigate to the SOLR instance. In my case the URL is: https://solr-dev.local:8983/solr/, however the hostname is configured at installation. On the left hand navigation menu, select the Core Admin option, here a list of the default cores are listed.

SOLR default Sitecore cores
Instead of using the GUI to create the core, the following URL will work (which allows the creation of cores to be scripted):
https://solr-dev.local:8983/solr/admin/cores?action=CREATE&name=TEST_CORE&instanceDir=TEST_CORE&configSet=basic_configs
 This has the following parameters:

  • Action - action to perform on the given core
  • Name - name of the core
  • InstanceDir - Folder name for the core
  • ConfigSet - allows configurations to be shared between a number of cores. This is the default that Sitecore indexes use.
Once created, your core is now ready to use:

SOLR new core added
Which is referenced in the XML definition of your custom SOLR index:

SOLR index configuration, core element

Friday, November 3, 2017

Sitecore 9 SOLR custom index configuration

I always find it handy to have a clean example of a custom index configuration ready to use during project development. Below is an example of a custom SOLR index configuration ready to use with Sitecore 9. As with any index I create, it contains sections for templates/fields to be added to the index along with computed index fields.

The standard database and root for crawling are of course included as well.
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:search="http://www.sitecore.net/xmlconfig/search/">
  <sitecore role:require="Standalone or ContentDelivery or ContentManagement" search:require="solr">
    <contentSearch>
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexes hint="list:AddIndex">
          <index id="sitecore_test_index" type="Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider">
            <param desc="name">$(id)</param>
            <param desc="core">sc9test__test_index</param>
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
              <configuration ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration">
    <documentOptions ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/documentOptions">
      <include hint="list:AddIncludedTemplate">
     <Page>{49E6B85F-02F4-405F-923F-66761933E80F}</Page>
      </include>
      <fields hint="raw:AddComputedIndexField">
     <field fieldName="MyComputedField" returnType="string">Sitecore.Base.Search.MyComputedImageField, Sitecore.Base</field>
     <field fieldName="ItemUrl" returnType="string">Sitecore.ContentSearch.ComputedFields.UrlLink,Sitecore.ContentSearch</field>
      </fields>
    </documentOptions>
    <fieldMap ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap">
      <fieldNames hint="raw:AddFieldByFieldName">
     <field fieldName="title" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
     <field fieldName="description" returnType="text" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" />
      </fieldNames>
    </fieldMap>
     </configuration>
            <strategies hint="list:AddStrategy">
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsyncSingleInstance"/>
            </strategies>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>web</Database>
                <Root>/sitecore/content/Home</Root>
              </crawler>
            </locations>
            <enableItemLanguageFallback>false</enableItemLanguageFallback>
            <enableFieldLanguageFallback>false</enableFieldLanguageFallback>
          </index>
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>
This index is named sitecore_test_index and uses the SOLR core sc9test__test_index, don't forget to change these!

The URL of the item is a computed index field called ItemUrl and actually refers to a Sitecore code definition to get the URL.

Sitecore SOLR AddFieldByFieldName The given key was not present in the dictionary

When setting up a new custom index for SOLR in Sitecore 9, I noticed the following error after adding the AddFieldByFieldName section.
The given key was not present in the dictionary
I had incorrectly added the section as a type:
fieldMap type="Sitecore.ContentSearch.SolrProvider.SolrFieldMap, Sitecore.ContentSearch.SolrProvider"
When it should have been added as a ref:
fieldMap ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap"
Fixing this line up, the index would build correctly and the error disappeared. 

Sitecore SOLR: Could not find add method

With Sitecore 9 I came across the following errors when attempting to move my old Lucene based indexes (from Sitecore 8) into SOLR (6.6.2).
Could not find add method: IncludeTemplate (type: Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration)
Could not find add method: ExcludeTemplate (type: Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration)
Could not find add method: IncludeField (type: Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration)
Could not find add method: ExcludeField (type: Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration) 
These method names have all been updated and now will appear as follows:

  • include hint="list:AddIncludedTemplate"
  • include hint="list:AddExcludedTemplate"
  • include hint="list:AddIncludedField"
  • include hint="list:AddExcludedField"
The custom index should work as expected with these updates.

Thursday, November 2, 2017

Sitecore report showing visits with company/business name

One of the benefits to signing up to Sitecore's IP Geo-location service is that an IP lookup is done against each visitor in an attempt to discover their company/business name. Although this is not always accurate (in many cases will actually return the name of the ISP), site visitors from larger organisations will have their company name listed.

This information is not displayed (out-of-box) inside the Experience Analytics areas and will actually need to be enabled (and then viewed in a separate area). The reporting feature is included and working with Sitecore (as of 8.2) but a short-cut needs to be added to the desktop area of Sitecore.

Details for adding this shortcut to the desktop menu are available on this post from Nish Tech. It is very simple and does not require a deploy, nor will it require web site downtime.

Sitecore desktop menu with the newly added Engagement Analytics option
Once this menu item has been added, you can now load up the old experience analytics reporting interface. Under the Recent Activity node in the tree, will be the Latest Visits report. I recommend filtering to a desired time frame and then downloading the report to be massaged in Excel.

Sitecore experience analytics showing organization name

Sitecore FXM Error The page does not belong to a tracked website

When attempting to setup FXM on a local sandbox site, I was noticing the following error in the console/network tab of the browser (when browsing the external site containing the FXM beacon).
The page does not belong to a tracked website.
It also showed the message:
400 (DomainInvalid)
The fix for the error is to publish the external site which was created in FXM, as shown in the image below:
Sitecore FXM - publish external site
Quite a simple mistake, but it may trip someone up who is new to FXM.

Wednesday, November 1, 2017

Creating your first Sitecore 9 Visual Studio solution

So you've now got Sitecore 9 up and running, the next step is to create a solution to allow custom code to be deployed. The following steps will show you how to setup a single project solution, but the concepts will work when adding more projects to form a Sitecore Helix solution.
  1. Firstly, create a new a new web project and ensure the target .NET Framework version is 4.6.2 (see here if 4.6.2 is not available).
  2. For a project template select the Empty option and check the MVC checkbox.
  3. Delete the Global.asax file.
  4. Set the Build Action to None for the Web.Config file.
  5. Add the Sitecore Nuget Feed as a source in Visual Studio.
  6. Add the following nuget packages from the Sitecore feed (I like to use the no reference ones, as the dependent references are often not required).
    1. Sitecore.Kernel
    2. Sitecore.Mvc
    3. Sitecore.Mvc.Analytics
  7. In the Views/Web.Config file add the following two lines (in the namespaces section):
<add namespace="Sitecore.Mvc" />
<add namespace="Sitecore.Mvc.Presentation" />

Now your project is ready to build and deploy to your Sitecore instance. Don't forget to follow the Helix principals!

Setting up .NET Framework 4.6.2 in Visual Studio for Sitecore 9

When attempting to create a new Visual Studio solution for Sitecore 9, I noticed that the .NET Framework 4.6.2 was not available to set as the projects framework version.

I downloaded the offline installer for .NET Framework 4.6.2, however the installer notified me that the version (or a later one) was already installed.

It turns out that one more installation needed to occur to have this version available in Visual Studio. The .NET Framework 4.6.2 Developer Pack once installed allows the framework to be set on a project.

.NET Framework version 6.6.2 in Visual Studio

Tuesday, October 31, 2017

Sitecore 9 SOLR installation and running as a service

When installing Sitecore 9, having SOLR running as a windows service is a required pre-requisite. For those developers like myself that stuck with Lucene for too long, here is how to get SOLR running locally.

  1. Download and install the Java Runtime Environment (JRE)
  2. Set a JAVA_HOME environment variable which points to the java install location
    1. Open up advanced system settings
    2. Click environment variables
    3. Add new
  3. Download SOLR (in this case 6.6.2)
  4. Place the extracted files in the location C:\SOLR
  5. Export a local certificate (in IIS) to a .PFX file, then place this file at the root of the C drive. In my case the file was called local.pfx
  6. Run the following command: "keytool -importkeystore -srckeystore C:\local.pfx -srcstoretype pkcs12 -destkeystore C:\solr\server\etc\solr-ssl.keystore.jks -deststoretype JKS" - this will prompt for the password entered when exporting the certificate. It needs to be run from the Java bin folder (in my case "C:\Program Files\Java\jre-9.0.1\bin").
  7. Open the solr.in.cmd file (located in C:\solr\bin) and un-comment the SSL settings shown below. Ensure you set the password as entered during the key import.
  8. Download NSSM - which will allow us to start SOLR as a service
    1. Place the extracted folder in your program files folder
  9. In the CMD change directory to the NSSM exe (in my case C:\Program Files\nssm-2.24\win64)
  10. Run the command nssm install solr6.6.2
  11. Enter the following information:
  12. Click install service
  13. Now open up services and start the SOLR service
SOLR will now run automatically as a windows service as required by Sitecore 9.

This post is a slight expansion of Installing Sitecore 9 dev environment by Patrick Stysiak.

Monday, October 9, 2017

Sitecore TDS Error GetProjectContentFiles task required parameter ConfigurationToBuild

When attempting to build/deploy a Sitecore solution that used TDS code generation the following error occurred:
The "GetProjectContentFiles" task was not given a value for the required parameter "ConfigurationToBuild". TDS.Master C:\Projects\MyProject\TDSFiles\HedgehogDevelopment.SitecoreProject.targets
I had recently upgraded and then downgraded back again my version of TDS. It appears that the file at "C:\Projects\MyProject\TDSFiles\HedgehogDevelopment.SitecoreProject.targets" was mismatched with my current version of TDS.

Using source control I reset the project back to the latest version (and discarded my changes), which reset the HedgehogDevelopment.SitecoreProject.targets file. This appeared to resolve the issue and the solution built again.

Monday, October 2, 2017

Sitecore EXM - upgrade Cannot use DataAdapterProvider as xDB is disabled

During the upgrade of Email Experience Manager through the versions, the following error was appearing after installing version 3.5
Cannot use DataAdapterProvider as xDB is disabled.
During the upgrade of the core Sitecore product,  two settings were set to false inside the Sitecore.Xdb.Config file. Setting these back to true and the site will load as expected.

  1. Xdb.Enabled
  2. Xdb.Tracking.Enabled
In my case, email experience manager was the last piece of the upgrade puzzle, so these could be enabled again anyway.

Sitecore custom dependency injection breaks after upgrade to 8.2

During an upgrade from version 8.1 to 8.2 of Sitecore, custom dependency injection (Autofac) stopped working after the updated custom code was deployed. Trying to resolve anything would simply return a null and cause the code to break.

It turns out that application start in Sitecore 8.2 has been made internal, which meant the instantiation of this project's dependency injection was not be called. Best practice for Sitecore is not to use App_Start and instead to use the initialize pipeline, as shown below.

The initialize pipeline code:
 
using Sitecore.Pipelines;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace MyProject
{
    public class RegisterContainer : Sitecore.Mvc.Pipelines.Loader.InitializeRoutes
    {
        public override void Process(PipelineArgs args)
        {
            // App Start code here
        }
    }
}
The initialize pipeline patch file:
 
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
      <pipelines>
          <initialize>
              <processor type="MyProject.RegisterContainer, MyProject"
                          patch:before="*[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']" />
          </initialize>
      </pipelines>
  </sitecore>
</configuration>

Friday, September 29, 2017

TDS code generation for content items

Code generation of templates works great with glass mapper and TDS in your Sitecore project, however there are times where content items may need to have classes generated. An example would be system pages or settings, which are serialized/deployed and in which item IDs may be required in other areas of code.

Instead of manually declaring these IDs in a static class like the old days, TDS can generate these classes which makes it a bit more dynamic. This makes use of the itempaths.tt transformation file:



And is as simple as editing the properties on the path where you want content serialized - in this case the content item.


Notice that Code Generation Template has been set for this content item. Now when the coder generation is re-run this content item and it's children all have classes available:


Sitecore TDS code generation error Invalid token this

After upgrading my TDS solution to use the new version 3 of the transformation files, on generation an error message would pop up and the following error appeared in the generated file.
An error occured while generating code for item '/sitecore/templates/MyTemplate'.
T4 Template: C:\Projects\MyProject\TDS.Core\Code Generation Templates\glassv3item.tt
Errors:
Compiling transformation: Invalid token 'this' in class, struct, or interface member declaration
Compiling transformation: Method must have a return type
Compiling transformation: Identifier expected
Compiling transformation: 'GeneratedTextTransformation.Write()' must declare a body because it is not marked abstract, extern, or partial
This error is occurring because the glassv3item.tt template as an extra line added at the bottom of the file. Removing this will allow the code to generate without error.

TDS glassv3item new line
Solution via Ryan Tuck.

Upgrades TDS code generation outputs with wrong DLL reference

After updating Glass Mapper, TDS and the tt transformation files, when re-generating code for all items in my TDS project there were references to the old Glass.Mapper.Sitecore DLL instead of the updated Glass.Mapper.Sc DLL.

TDS code generation old DLL

This error was occurring because the TDS project was setup to use the old transform files instead of the V3 ones. Updating t these V3 versions, fixed the error and the correct references were added to the output.

TDS correct transform templates

Sitecore TDS code generation - failed to resolve include text

After upgrading a Sitecore solution's Glass Mapper to the latest version, installing the latest TDS, along with adding in new code generation templates (tt files). The following error was occurring:
Failed to resolve include text for file:C:\Projects\MyProject\TDS.Core\Code Generation Templates\GeneralExtensions.tt
Looking at the item tree where these templates were added, it appeared that the file was referenced as generalextensions.tt - with all lowercase.


By updating the include references in the other files, this error no longer occurred and code would generate the models as expected. An example of the include to update is:
<#@ include file="generalextensions.tt" #>

Monday, September 25, 2017

Sitecore update file upload request filtering module error

When using Sitecore's update installation wizard to install a new version of Sitecore, I was getting the following error message when trying to upload the update file.
The request filtering module is configured to deny a request that exceeds the request content length.

Request filtering module error message

In the upgrade guide it mentioned the the maxAllowedContentLength setting needed to be updated in the web.config file. This is a setting which controls the maximum file size (in bytes) that can be uploaded to the web server.

Web.config maxAllowedContentLength
In my case, this had been updated (and IIS restarted) which should of allowed a maximum size of 4gb, where the update file was only 1gb. The error was still occurring.

It turns out that the instruction stated "\wwwroot\<instance name>\Website\sitecore\admin\web.config" where I had misread and edited "\wwwroot\<instance name>\Website\web.config".

I can't be the only silly person to make this mistake, hopefully this saves someone else some time :)

Sitecore installation wizard access denied

When installing the Sitecore Update Installation Wizard package (via the standard installation wizard on the Sitecore desktop) I was getting the following error:
Access to path 'F:\install\...'
My computer did not have an F drive mapped and the website was configured to use the the standard wwwroot folder on the C drive.

Sitecore installation wizard - access denied error
It turns out that the three folders for the Sitecore website (Data, Databases and Website) did not have the correct permissions assigned to them. By fixing up the security on these folders, the package was able to install as expected. For some reason, the wizard displayed/tried to use a drive which was not mapped.

Tuesday, September 5, 2017

Sitecore WFFM form reports are empty

On a Sitecore instance running version 8.1 and the web forms for marketers module, the form reports were coming up empty.

Sitecore WFFM form reports empty
Looking at the console on the form reports page (as shown above) there were three 500 errors returned for services used to build up data on the page. The error messages for these three services were as follows:
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult GetFormFieldsStatistics(System.Guid)' in 'Sitecore.WFFM.Services.Requests.Controllers.FormReportsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult GetFormContactsPage(System.Guid, Sitecore.WFFM.Abstractions.Data.PageCriteria)' in 'Sitecore.WFFM.Services.Requests.Controllers.FormReportsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult GetFormSummary(System.Guid)' in 'Sitecore.WFFM.Services.Requests.Controllers.FormReportsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
The first step is to check that the settings items required for the WFFM report queries have been installed correctly. The item at the "/sitecore/system/Settings/Analytics/Report Queries/WFFM" path should have 4 child items.

Sitecore WFFM report queries settings
The next step is to ensure that the WFFM_Analytics.sql file was run on the SQL reporting database at the time of package installation. The following four databases are expected on the reporting/analytics database, if they are not present the SQL file needs to be run:

  1. Fact_FormEvents
  2. Fact_FormStatisticsByContact
  3. Fact_FormSummary
  4. FormFieldValues
Running this script removed the three service errors for me and the form reports started logging/showing data as expected. 

Monday, September 4, 2017

Sitecore TDS The remote certificate is invalid according to the validation procedure error

When trying to do a sync using Hedgehog's Team Development for Sitecore (TDS), it was unable to connect to the local Sitecore instance and the following errors were appearing:
Exception The remote certificate is invalid according to the validation procedure. (AuthenticationException)
Exception The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. (WebException)
This is a similar error to an earlier blog post I wrote about Sitecore rocks getting SSL errors. You need to check what host name the certificate you are using on the Sitecore site is assigned to, in my case it was localhost.

IIS Server Certificates

The the next step was to set this certificate as trusted, which this post covers.

Now by setting the Sitecore Web URL property to https://localhost in the TDS project settings, I was successfully able to sync content into the solution.

TDS Sitecore Web URL