Saturday, 19 November 2016

Error: The Command InsertSitecoreBucketLink is not implemented yet

Leave a Comment
Recently I’ve faced strange issue while working with Sitecore 8.1 update 3 solution. I was unable to insert bucket link while working with RTE. I was getting an error message as "The Command InsertSitecoreBucketLink is not implemented yet". The Same error was occurring on vanilla Sitecore 8.1 update 3 solution as well.


I’ve created a support ticket with Sitecore support team and they have registered the described issue as a bug in the Sitecore 8.1 update 3 version. To resolve the issue, they have provided a hotfix patch. Reach out to Sitecore support and use the reference number 107388 to get the required files. Below are the steps to apply the patch:
  1. Put the attached Sitecore.Support.107388.dll assembly into the \bin folder.
  2. Back up the \sitecore\shell\Applications\Buckets\MiniResults.aspx file and replace it with the attached one.
  3. Back up the \sitecore\shell\Controls\Rich Text Editor\RichText Commands.js file and replace it with the attached one.
  4. Clear your browser cache.
Note: This issue is present with Sitecore 8.2 initial release as well.

Comments and suggestions are most welcome. Happy coding!  
Read More...

Tuesday, 15 November 2016

Part 3: Sitecore 8.2 with SOLR 6.2

Leave a Comment
Hello, Sitecore enthusiasts! This is the third article of Sitecore 8.2 with Solr 6.2 blog series.

Configuring Sitecore to work with our Solr instance

With Sitecore 8.2, search and indexing no longer require a third-party DI container to enable Solr and there is no need to install a Solr support package. 

Disable Lucene Config File

Make sure all Lucene search related configuration files are disabled and Solr search configuration files are enabled. Follow below steps to switch configuration files so that Solr is enabled and Lucene is disabled: 
  1. Navigate to the website Include folder: \Website\App_Config\Include\ and disable the following Lucene configuration files by adding .disabled to the file name extension:
    • Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config
    • Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.Xdb.config
    • Sitecore.ContentSearch.Lucene.Index.Analytics.config
    • Sitecore.ContentSearch.Lucene.Index.Core.config
    • Sitecore.ContentSearch.Lucene.Index.Master.config
    • Sitecore.ContentSearch.Lucene.Index.Web.config
    • Sitecore.ContentSearch.Lucene.Indexes.Sharded.Core.config
    • Sitecore.ContentSearch.Lucene.Indexes.Sharded.Master.config
    • Sitecore.ContentSearch.Lucene.Indexes.Sharded.Web.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Lucene.Index.Master.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Lucene.Index.Web.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Lucene.IndexConfiguration.config
    • Sitecore.Marketing.Lucene.Index.Master.config
    • Sitecore.Marketing.Lucene.Index.Web.config
    • Sitecore.Marketing.Lucene.IndexConfiguration.config
    • Sitecore.Speak.ContentSearch.Lucene.config
  2. Navigate to \Website\App_Config\Include\FXM and disable the following Lucene configuration files by adding .disabled to the file name extension:
    • Sitecore.FXM.Lucene.DomainsSearch.DefaultIndexConfiguration.config
    • Sitecore.FXM.Lucene.DomainsSearch.Index.Master.config
    • Sitecore.FXM.Lucene.DomainsSearch.Index.Web.config
  3. Navigate to \Website\App_Config\Include\ListManagement and disable the following Lucene configuration files by adding .disabled to the file name extension:
    • Sitecore.ListManagement.Lucene.Index.List.config
    • Sitecore.ListManagement.Lucene.IndexConfiguration.config
  4. Navigate to \Website\App_Config\Include\Social and disable the following Lucene configuration files by adding .disabled to the file name extension:
    • Sitecore.Social.Lucene.Index.Analytics.Facebook.config
    • Sitecore.Social.Lucene.Index.Master.config
    • Sitecore.Social.Lucene.Index.Web.config
    • Sitecore.Social.Lucene.IndexConfiguration.config
  5. Navigate to \Website\App_Config\Include\ContentTesting and disable the following Lucene configuration files by adding .disabled to the file name extension:
    • Sitecore.ContentTesting.Lucene.IndexConfiguration.config

Enable Solr Config File

  1. Enable the Sitecore.ContentSearch.Solr.*.config files by removing .example/.disabled from the file name. Configuration file extension should be .config.
    • Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config
    • Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.Xdb.config
    • Sitecore.ContentSearch.Solr.Index.Analytics.config
    • Sitecore.ContentSearch.Solr.Index.Core.config
    • Sitecore.ContentSearch.Solr.Index.Master.config
    • Sitecore.ContentSearch.Solr.Index.Web.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Solr.Index.Master.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Solr.Index.Web.config
    • Sitecore.Marketing.Definitions.MarketingAssets.Repositories.Solr.IndexConfiguration.config
    • Sitecore.Marketing.Solr.Index.Master.config
    • Sitecore.Marketing.Solr.Index.Web.config
    • Sitecore.Marketing.Solr.IndexConfiguration.config
    • Sitecore.Speak.ContentSearch.Solr.config
  2. Navigate to \Website\App_Config\Include\FXM and enable below configuration files by removing .example/.disabled from the file name:
    • Sitecore.FXM.Solr.DomainsSearch.DefaultIndexConfiguration.config
    • Sitecore.FXM.Solr.DomainsSearch.Index.Master.config
    • Sitecore.FXM.Solr.DomainsSearch.Index.Web.config
  3. Navigate to \Website\App_Config\Include\ListManagement and enable below configuration files by removing .example/.disabled from the file name:
    • Sitecore.ListManagement.Solr.Index.List.config
    • Sitecore.ListManagement.Solr.IndexConfiguration.config
  4. Navigate to \Website\App_Config\Include\Social and and enable below configuration files by removing .example/.disabled from the file name:
    • Sitecore.Social.Solr.Index.Master.config
    • Sitecore.Social.Solr.Index.Web.config
    • Sitecore.Social.Solr.IndexConfiguration.config
  5. Navigate to \Website\App_Config\Include\ContentTesting and and enable below configuration files by removing .example/.disabled from the file name:
    • Sitecore.ContentTesting.Solr.IndexConfiguration.config

Configure Solr specific settings in configuration file:

Open Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config file and update below settings:
  1. Specifying a Solr Service Address: This is the base url of Solr server. Update this accordingly.
  2. <setting name="ContentSearch.Solr.ServiceBaseAddress" value="http://localhost:8090/solr" />
  3. Enabling a Search Provider: This setting tells that which provider is currently being used. Enable the Solr as below:
  4. <setting name="ContentSearch.Provider" value="Solr" />

Rebuild search index

Perform below steps to rebuild the Sitecore search indexes:
  1. In the Control Panel, and click Indexing manager.
  2. Click Select all, and then click Rebuild.
  3. Indexes should be rebuilt without error.
That's it! Sitecore and Solr are configured now. In upcoming blog posts, I'll cover few common search techniques or functionalities using Solr as search provider. Comments and suggestions are most welcome. Happy coding!
Read More...

Friday, 11 November 2016

Part 2: Sitecore 8.2 with SOLR 6.2

Leave a Comment
Hello, Sitecore enthusiasts! This is the second article of Sitecore 8.2 with Solr 6.2 blog series.

Configuring Solr to use with Sitecore

Generate an XML Schema for Solr

Solr needs a defined XML schema when working with documents. Follow below steps to generate Solr Schema XML file:
  1. Duplicate basic_configs folder under C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets and rename duplicated folder as sitecore_configs.
  2. Verify that that you have a file named schema.xml under the C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs\conf folder. If you don't have a schema.xml file under the folder then you will need to perform below extra steps, as explained in solution 2 of the Solr Compatibility Table:
    • Create schema.xml file by duplicating and renaming the managed-schema file present in C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs\conf folder
    • Switch to ClassicIndexSchemaFactory by adding the following line in the end to the SolrConfig.xml file present in C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs\conf folder:
      <schemaFactory class="ClassicIndexSchemaFactory" />
  3. Open schema.xml file and make the following changes:
    • Enclose all <field> and <dynamicField> elements in a <fields> tag.
    • Enclose all <fieldType> elements in a <types> tag.
  4. Save schema.xml and also create a backup file of schema.xml.
  5. Log into your Sitecore instance.
  6. Navigate to Sitecore Control Panel.
  7. In the Control Panel, click Generate the Solr Schema.xml file link in Index section.
  8. In the dialog window, change the source file and target file to point to the newly created schema file (C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs\conf\schema.xml) and click the ‘Generate’ button.
  9. Sitecore will create a modified schema.xml file, using the schema.xml file we created as a baseline in above steps and add all its necessary Solr specific fields needed for indexing, unique keys etc. 
  10. Open the newly generated schema file (C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs\conf\schema.xml) and add below line:
    <fieldType name="pint" class="solr.TrieIntField" docValues="true" precisionStep="0" positionIncrementGap="0" />

Organize Solr core structure

  1. Copy the sitecore_configs (C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr\configsets\sitecore_configs) folder and paste it in C:\Bitnami\solr-6.2.1-2\apache-solr\server\solr. Rename it to the sitecore_web_index.
  2. For each Sitecore index, we need to repeat above step 1 until we have a set of config directories with the following names:
    • sitecore_web_index
    • sitecore_master_index
    • sitecore_core_index
    • sitecore_analytics_index
    • social_messages_web
    • social_messages_master
    • sitecore_marketing_asset_index_master
    • sitecore_marketing_asset_index_web
    • sitecore_testing_index
    • sitecore_suggested_test_index
    • sitecore_fxm_master_index
    • sitecore_fxm_web_index
    • sitecore_list_index
    • sitecore_marketingdefinitions_master
    • sitecore_marketingdefinitions_web
  3. Once you have configured all the directories, navigate to the Solr admin page.
  4. After login, navigate to Core Admin page.
  5. Fill in the 'name' and 'instanceDir' fields with sitecore_web_index, and press the "Add Core" button to add the core into Solr. 
  6. You should be able to see that sitecore_web_index core is now present in the list of cores available in your Solr instance.
  7. Repeat these steps for all directories created earlier so that we'll have a Solr core for each directory we created.

That's it! Solr is ready to be used with Sitecore. Comments and suggestions are most welcome. Happy coding!
Read More...

Part 1: Sitecore 8.2 with SOLR 6.2

Leave a Comment
Hello, Sitecore enthusiasts! As you may be already aware that Lucene is the default search provider for Sitecore though Solr is recommended search provider in scaled environments. I’ll be writing series of blog posts related to Sitecore search implementation with Solr. I’ll be covering how to setup Solr 6.2 with Sitecore 8.2 instance and few common search techniques or functionalities using Solr as search provider. This is part 1 of Sitecore 8.2 search with Solr 6.2 blog posts series. I am working with Sitecore 8.2 initial release.
  1. Part 1: Installing Solr using the Bitnami Apache Solr Stack
  2. Part 2: Configuring Solr to use with Sitecore
  3. Part 3: Configuring Sitecore to work with Solr
  4. Part 4: Work in progress

Installing Solr using the Bitnami Apache Solr Stack

  1. Download the Bitnami Apache Solr Stack Distribution that provides a one-click install solution for Apache Solr.
  2. Double-click on the installer (bitnami-solr-6.2.1-2-windows-installer.exe for the purposes of this article). The first screen will look like below:
  3. Click Next. In next screen, you should choose the folder to install Bitnami Apache Solr Stack. For this blog post, I am taking default installation path C:\Bitnami\solr-6.2.1-2
  4. Click Next. In next screen, you should create an administrator account for Bitnami Apache Solr Stack.
  5. Click Next. Next screen allows you to define the port that Apache Solr should run on. Choose a port which is not currently in use. For this article, we used port 8090.
  6. Click Next. Next screen shows offering up details about Bitnami Cloud Hosting. For this tutorial, I’ll make it uncheck.
  7. Click Next. Setup is now ready to begin installing Bitnami Apache Solr Stack on your computer.
  8. During the installation, Windows Firewall will alert you that it has blocked some features of this installation. Ensure that the check boxes for Domain networks, such as a workplace network and Private networks, such as my home or work network are checked. Complete this step by clicking the Allow access button.
  9. Once the installation is complete, leave the check box checked and click on Finish button.
  10. Your web browser will open a page like this:
  11. Click on Access Apache Solr link which will pop up one authentication window. Enter credentials of admin account and click Log In.
  12. Solr dashboard will be launched and should look like this:
  13. You now have Solr instance up and running. Now we have to configure Solr to be used with Sitecore.
Comments and suggestions are most welcome. Happy coding!
Read More...

Wednesday, 2 November 2016

Sitecore : Restore archived item programmatically

Leave a Comment
This short blog post contains information about how to restore archived item programmatically in Sitecore 8. Use the below code snippet to achieve the functionality:
void RestoreArchivedItems()
        {
            using (new SecurityDisabler())
            {
                DateTime archiveDate = new DateTime(2016, 11, 1);
                string originalLocationPathPrefix = "/sitecore/content/Home";
                string archivedBy = "sitecore\\admin";

                // get the archive database for the master database
                Sitecore.Data.Archiving.Archive archive = Sitecore.Data.Database.GetDatabase("master").Archives["archive"];

               // get archived items
                var archivedItems =
                    archive.GetEntries(0, int.MaxValue)
                            .Where(entry =>
                                entry.ArchiveDate > archiveDate &&
                                entry.OriginalLocation.StartsWith(originalLocationPathPrefix) && entry.ArchivedBy.Equals(archivedBy, StringComparison.OrdinalIgnoreCase)
                            ).ToList();

                foreach (var archiveItem in archivedItems)
                {
                    // restore the item
                    archive.RestoreItem(archiveItem.ArchivalId);
                }
            }
        }
Comments and suggestions are most welcome. Happy coding!
Read More...

Friday, 23 September 2016

Customizing PDF download behaviour for Sitecore multisite implementation

Leave a Comment
Recently I got a requirement from my client where I have to customize PDF rendering behaviour for Sitecore multisite implementation. For few websites, PDF files should be rendered in web browser itself and for few websites, web browser should prompt the user to save the PDF files. I am working with Sitecore 8.2 initial release.

PDF rendering behaviour is being managed by <forceDownload> element for PDF file media type under \mediaLibrary\mediaTypes configuration node. This setting can be found in Sitecore.Config file in \Website\App_Config folder. A true value for the forceDownload element causes Sitecore to apply an HTTP "Content-Disposition = attachment; filename=" header when linking to the .ashx URL of the media item, causing the browser to prompt the user to open/save as rather than opening the media item in the browser.


Disabling/Enabling forceDownload behaviour for PDF file will impact all the websites but I need flexibility to disable/enable this behaviour across multiple websites. This behaviour can be achieved in two ways:
  1. Forcing download on client side using HTML 5 download attribute
  2. Override MediaRequestHandler and modify "Content-Disposition" in context response header
  1. Forcing download on client side using HTML 5 download attribute
    Use HTML5 download attribute on your anchor links. The download attribute specifies that the target will be downloaded when a user clicks on the hyperlink. However this attribute is not supported by all the browsers.
  2. Override MediaRequestHandler and modify "Content-Disposition" in context response header
    Below are the steps to implement the desired behaviour across multiple websites:
    • Create a new class library project in visual studio.
    • Add reference to Sitecore.Kernel.dll
    • Add a custom attribute in your site definition. For example, "PdfForceDownloadDisabled"
      <site name="mysite" patch:before="site[@name='website']"
                  virtualFolder="/"
                  physicalFolder="/"
                  rootPath="/sitecore/content"
                  startItem="/MySite"
                  database="web"
                  domain="extranet"
                  allowDebug="true"
                  cacheHtml="true"
                  htmlCacheSize="50MB"
                  enablePreview="true"
                  enableWebEdit="true"
                  enableDebugger="true"
           PdfForceDownloadDisabled="true"
           hostName="local.mysite.com"
                  disableClientData="false"/>
    • Implement a custom Extension method :
      using Sitecore.Diagnostics;
      using Sitecore.Sites;
      using System;
      
      namespace CustomMedia
      {
          public static class UtilityManager
          {
              public static bool PdfForceDownloadDisabled(this SiteContext site)
              {
                  Assert.IsNotNull(site, "Site cannot be null");
      
                  try
                  {               
                      string PdfForceDownloadDisabled = site.Properties["PdfForceDownloadDisabled"];
                      if (!String.IsNullOrEmpty(PdfForceDownloadDisabled))
                          return Convert.ToBoolean(PdfForceDownloadDisabled); 
                  }
                  catch (Exception)
                  {
                      return false;
                  }
                  return false;
              }       
          }
      }
      
    • Override "protected override bool DoProcessRequest(HttpContext context, MediaRequest request, Sitecore.Resources.Media.Media media)" method and modify "Content-Disposition" in context response header.
      using Sitecore;
      using Sitecore.Configuration;
      using Sitecore.Data.Items;
      using Sitecore.Diagnostics;
      using Sitecore.Events;
      using Sitecore.Resources.Media;
      using Sitecore.Resources.Media.Streaming;
      using Sitecore.Web;
      using System.Web;
      
      namespace CustomMedia
      {
          public class MediaRequestHandler : Sitecore.Resources.Media.MediaRequestHandler
          {
              protected override bool DoProcessRequest(HttpContext context, MediaRequest request, Sitecore.Resources.Media.Media media)
              {
                  Assert.ArgumentNotNull(context, "context");
                  Assert.ArgumentNotNull(request, "request");
                  Assert.ArgumentNotNull(media, "media");
                  if (this.Modified(context, media, request.Options) == Tristate.False)
                  {
                      Event.RaiseEvent("media:request", new object[] { request });
                      this.SendMediaHeaders(media, context);
                      context.Response.StatusCode = 0x130;
                      return true;
                  }
                  this.ProcessImageDimensions(request, media);
      
                  MediaStream mediaStream = media.GetStream(request.Options);
      
                  if (mediaStream == null)
                  {
                      return false;
                  }
                  Event.RaiseEvent("media:request", new object[] { request });
                  if (Settings.Media.EnableRangeRetrievalRequest && Settings.Media.CachingEnabled)
                  {
                      using (mediaStream)
                      {
                          this.SendMediaHeaders(media, context);
                          new RangeRetrievalResponse(RangeRetrievalRequest.BuildRequest(context, media), mediaStream).ExecuteRequest(context);
                          //Update Header   - Custom Add             
                          this.UpdateHeader(media, context, mediaStream);
                          return true;
                      }
                  }
                  this.SendMediaHeaders(media, context);
                  this.SendStreamHeaders(mediaStream, context);
                  using (mediaStream)
                  {
                      context.Response.AddHeader("Content-Length", ((long)mediaStream.Stream.Length).ToString());
                      WebUtil.TransmitStream(mediaStream.Stream, context.Response, Settings.Media.StreamBufferSize);
                  }
                  return true;
              }
      
              private void ProcessImageDimensions(MediaRequest request, Sitecore.Resources.Media.Media media)
              {
                  int num;
                  int num2;
                  Assert.ArgumentNotNull(request, "request");
                  Assert.ArgumentNotNull(media, "media");
                  Item innerItem = media.MediaData.MediaItem.InnerItem;
                  int.TryParse(innerItem["Height"], out num2);
                  int.TryParse(innerItem["Width"], out num);
                  bool flag = false;
                  int maxHeight = Settings.Media.Resizing.MaxHeight;
                  if ((maxHeight != 0) && (request.Options.Height > System.Math.Max(maxHeight, num2)))
                  {
                      flag = true;
                      request.Options.Height = System.Math.Max(maxHeight, num2);
                  }
                  int maxWidth = Settings.Media.Resizing.MaxWidth;
                  if ((maxWidth != 0) && (request.Options.Width > System.Math.Max(maxWidth, num)))
                  {
                      flag = true;
                      request.Options.Width = System.Math.Max(maxWidth, num);
                  }
                  if (flag)
                  {
                      Log.Warn($"Requested image exceeds allowed size limits. Requested URL:{request.InnerRequest.RawUrl}", this);
                  }
              }
      
              private void UpdateHeader(Sitecore.Resources.Media.Media media, HttpContext context, MediaStream stream)
              {
                  if (media.Extension.ToLower() == "pdf" && Sitecore.Context.Site.PdfForceDownloadDisabled())
                  {
                      context.Response.Headers["Content-Disposition"] = "inline; filename=\"" + stream.FileName + "\"";
                  }
              }
          }
      }
      
    • In web.config, replace <add verb="*" path="sitecore_media.ashx" type="Sitecore.Resources.Media.MediaRequestHandler, Sitecore.Kernel" name="Sitecore.MediaRequestHandler" />  with the following line:
      <add verb="*" path="sitecore_media.ashx" type="CustomMedia.MediaRequestHandler, {your assembly name}" name="Sitecore.MediaRequestHandler" />
    • Deploy your assembly in bin folder of your Sitecore website.
Comments and suggestions are most welcome. Happy coding!
Read More...

Tuesday, 20 September 2016

Sitecore Commerce Server Manager : Profile Definition 404 Error

Leave a Comment
I’ve been working with Sitecore commerce server manager for a while and recently I have stuck with one error related to Sitecore commerce server manager. I was unable to navigate through Profile Definitions in commerce server manager. I was getting HTTP 404 The webpage cannot be found error.


I’ve checked stack trace in fiddler and found out that http://<server-name>/widgets/profilebldrHTC/ProfileEdit.htm was throwing 404 error.


It seems that Sitecore Commerce Server creates virtual folder named Widgets in the IIS default website. This virtual folder points to C:\Program Files (x86)\Commerce Server 11\Widgets directory.

Follow below steps to resolve the 404 issue:
  1. Open IIS.
  2. Navigate to default website in IIS.
  3. Right click on default website and click Add Virtual Directory.
  4. Enter Widgets in Alias section. 
  5. Enter physical path as C:\Program Files (x86)\Commerce Server 11\Widgets
  6. Click OK.
  7.  Restart default website and refresh Sitecore commerce server manager. 404 error should have been gone now.
Comments and suggestions are most welcome. Happy coding!
Read More...