Securing Sitecore connection strings

There are scenarios where we don’t want to compromise with the security of our application resources, this includes Connectionstring.config file as example, If someone compromised CD servers, they will have access to Connection string file and can use the details in a wrong way.

There are ways we can secure the connection string in Sitecore, in this blog post I would like to give an example of one of the approach which can be used:

Please see the sample code snippet, to encrypt and decrypt  connection string file.

Configuration config = WebConfigurationManager.OpenWebConfiguration(“~”);

// Get the connectionStrings section.
ConnectionStringsSection section = config.GetSection(“connectionStrings”) as ConnectionStringsSection;
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
}
else
{
section.SectionInformation.ProtectSection(“DataProtectionConfigurationProvider”);
}
// Save changes to the Web.config file.
config.Save();

Few points to note and consider:

  • This approach uses System.Web.Configuration namespace to work.
  • We access application’s web.config file via OpenWebConfiguration method.
  • We access connectionStrings section of the web.config file via GetSection method.
  • Encrypt and decrypt the sections.
  • Save the changes.

This is how the connection string.config file looks before encryption:

<?xml version=”1.0″ encoding=”utf-8″?>
<connectionStrings>
<!–
Sitecore connection strings.
All database connections for Sitecore are configured here.
–>
<add name=”core” connectionString=”user id=user;password=password;Data Source=(server);Database=Sitecore_Core” />
<add name=”master” connectionString=”user id=user;password=password;Data Source=(server);Database=Sitecore_Master” />
<add name=”web” connectionString=”user id=user;password=password;Data Source=(server);Database=Sitecore_Web” />
<add name=”analytics” connectionString=”mongodb://localhost/analytics” />
<add name=”tracking.live” connectionString=”mongodb://localhost/tracking_live” />
<add name=”tracking.history” connectionString=”mongodb://localhost/tracking_history” />
<add name=”tracking.contact” connectionString=”mongodb://localhost/tracking_contact” />
<add name=”reporting” connectionString=”user id=user;password=password;Data Source=(server);Database=Sitecore_Analytics” />
</connectionStrings>

After encryption, this is how the file looks:

<?xml version=”1.0″ encoding=”utf-8″?>
<connectionStrings configProtectionProvider=”DataProtectionConfigurationProvider”>
<EncryptedData>
<CipherData>
<CipherValue>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</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>

If we want to decrypt the section, we can use UnprotectSection()  and can review the connections, once we are good we can again encrypt the setting using ProtectSection() method.

We can also secure the setting using aspnet_regiis.exe tool.

I hope this helps someone, who is looking for something similar, please let me know for any questions on this, happy to discuss more.

Happy learning 🙂

MongoDB authentication in Sitecore

Securing application data is critical for any client and business, and the same principle applies to Sitecore application as well.

One of the most important component of Sitecore is MongoDB, which is where we store all Experience(xDB) related data, MongoDB was shipped into Sitecore’s ecosystem from Sitecore 7.5, and it’s very important to make sure the data stored in xDB is secured, and only authorized uses has access to the data.

Recently, we heard about thousands of MongoDB data being hacked, so what’s the reason behind it? any guess? it’s simple- all those DBs were not configured to be secure and anyone can access it.

It would be great if MongoDB installation itself comes with an option, where we can secure our data while installing it, like how we do it for SQL.

Even though, we can go back and secure the data  by setting up users/roles and permissions, but it’s always great to do it it first place.

We also have to see and make sure that Connection string used for MongoDB is all protected with credentials, so that only authorized users can access it.

As part of this blog post, i would like to cover the steps which we can follow and make our Sitecore application more secure.

  1. Create MongoDB User
    1. Follow the below command to create the user.
    2. db.createUser({user: “mongoadmin”,pwd: “mongoadmin”,roles: [ { role: “userAdminAnyDatabase”, db:”admin” },{ role: “root”, db:”admin” }]})
    3. We just created a new mongouser- “mongoadmin” under database “admin”, and has given all rights to this user by assigning role “root“.
  2. Verifying the User
    1. If we want to verify that user gets created or not, we can use the following command for the same:
    2. db.auth(“mongoadmin”,”mongoadmin”)
    3. This should return 1, if the user is authenticated.
    4. We can also see the list of all users by running following command:
    5. db.getUsers()
  3. Assigning specific roles to unique collections
    1. We shouldn’t be giving “root” level access to the user, and it should be more specific to the database and collection.
    2. For example: we can give read and write access to analytics database in Sitecore.
    3. In order to do that, please login to mongo shell and switch to admin.
    4. use analytics
      db.createUser({user: “mongouser”,pwd: “mongopassword”,roles: [ { role: “readWrite“, db:”analytics” }]})

    5. In this case we created a new user called “mongouser” and assigned “readWrite” role to it, and is specific to “analytics” database.
    6. In the same way, we can do it for other three databases also.
  4. Connection string updates
    1. This is how the default connection string looks like:
    2. <add name=”analytics” connectionString=”mongodb://localhost:27017/sample_analytics” />
      <add name=”tracking.live” connectionString=”mongodb://localhost:27017/sample_tracking_live” />
      <add name=”tracking.history” connectionString=”mongodb://localhost:27017/sample_tracking_history” />
      <add name=”tracking.contact” connectionString=”mongodb://localhost:27017/sample_tracking_contact” />

    3. After making updates to connection string, and adding required username and password details to it, this is how it looks:
    4. <add name=”analytics” connectionString=”mongodb://mongoadmin:mongoadmin@localhost:27017/sample_analytics?authSource=admin” />
      <add name=”tracking.live” connectionString=”mongodb://mongoadmin:mongoadmin@localhost:27017/sample_tracking_live?authSource=admin” />
      <add name=”tracking.history” connectionString=”mongodb://mongoadmin:mongoadmin@localhost:27017/sample_tracking_history?authSource=admin” />
      <add name=”tracking.contact” connectionString=”mongodb://mongoadmin:mongoadmin@localhost:27017/sample_tracking_contact?authSource=admin” />

    5. This is how the format looks like:
    6. mongodb//[username:password@]host[:port]/database?authSource

If we are trying to access MongoDB without passing valid credentials, we get this error in the log, please see the screen shot for ref:

MongoAuthenticationFailed

Once we pass the valid credentials, this error will go off.

It’s always a good practice to authenticate MongoDB in local environment as well, this helps us in setting the habit for it and we can uncover any issues well in advance.

I hope this helps in getting the understanding about how we can secure and authenticate MongoDB, and how to create users/permissions for the same.

There is a great article in MongoDB documentation, around setting up auth for Mongo and setting up users, creating roles for the same, please consider reviewing this as well, this is great source of information.

https://docs.mongodb.com/manual/tutorial/enable-authentication/

Thanks, and please let me know for any questions, happy to discuss more.

Happy learning 🙂

Changing data directory for MongoDB in Sitecore

As part of my MongoDB Blog series part 1, we discussed how we can Install MongoDB and we used “C” drive as default Installation location for it.

But as a best practice and considering scalable environment, we shouldn’t be using “C” drive to store any application data, it should be reserved only for system files, so that if we need to upgrade the OS or need to repair existing Installation, our application data is still safe.

We have done this for one of the implementation, and it’s always better to do this in early phase of the development.

We can always go back and change the default data directory location for MongoDB in Sitecore, and can use mongo config file which we created for Installing MongoDB.(Please refer MongoDB Blog series part-1 for more details)

This is how it was before:

mongoconfig

Let’s use another drive to store data and logs for MongoDB, in this case it’s “G

mongoconfigrevised

From the above screenshot we can see that, the data and log folder points to “G” drive now, and rest of the configuration is all same.

If you Installed MongoDB as a service, your service still points to “C” drive, but your data and log will be stored in “G” drive.

If you want to copy over existing data from “C” to “G” (in this example), make sure to stop your service, copy your data from “C” to “G”(in this example) and restart MongoDB Service.

This is good from maintenance perspective, and easy to manage afterwards.

I hope this helps someone, who is looking for something similar.

Thanks, and please let me know for any questions and any feedback, happy to discuss more.

Happy learning 🙂

Sitecore MongoDB Blog series: Part 3-Creating custom contact facets

In previous blog post, we gone through introduction of MongoDB with Sitecore which includes scaling, contacts and understanding MongoDB queries.

In this blog post we will go through and understand, how to create a custom contact facet and how to deploy it to Sitecore.

By default there are facets which Sitecore uses, and you can find the details here:

\App_Config\Include\Sitecore.Analytics.Model.Config

<entities>
<contact>
<factory type=”Sitecore.Analytics.Data.ContactFactory, Sitecore.Analytics” singleInstance=”true” />
<template type=”Sitecore.Analytics.Data.ContactTemplateFactory, Sitecore.Analytics” singleInstance=”true” />
<facets>
<facet name=”Personal” contract=”Sitecore.Analytics.Model.Entities.IContactPersonalInfo, Sitecore.Analytics.Model” />
<facet name=”Addresses” contract=”Sitecore.Analytics.Model.Entities.IContactAddresses, Sitecore.Analytics.Model” />
<facet name=”Emails” contract=”Sitecore.Analytics.Model.Entities.IContactEmailAddresses, Sitecore.Analytics.Model” />
<facet name=”Phone Numbers” contract=”Sitecore.Analytics.Model.Entities.IContactPhoneNumbers, Sitecore.Analytics.Model” />
<facet name=”Picture” contract=”Sitecore.Analytics.Model.Entities.IContactPicture, Sitecore.Analytics.Model” />
<facet name=”Communication Profile” contract=”Sitecore.Analytics.Model.Entities.IContactCommunicationProfile, Sitecore.Analytics.Model” />
<facet name=”Preferences” contract=”Sitecore.Analytics.Model.Entities.IContactPreferences, Sitecore.Analytics.Model” />
</facets>
</contact>
</entities>

In this specific example, we will show how to add a custom string value to existing contact card, we can call this Facet “Education

In order to create a custom Facet, we need following components:

  1. Interface (that’s used to create a contract/facet)
  2. Implementation
  3. Configuring the system to use new Facet.

Interface:

Education is the Facet, and the Education property we define for this is Element for this Facet,so we need to create Facet and Element interface.

Here is IProfileEducationFacet Interface, this should inherit IFacet.

IProfileFacet

Next step is to create IProfileEducationElement Interface, here is the sample snippet for the same:

IProfileEducationElement

Implementation:

Once we have Interfaces created for Facet and Element, next step will be to create class that can implement those interfaces.

ProfileEducationFacet class

ProfileFacet

ProfileEducationElement class

ProfileEducationElement

 

Once the Facets and Elements are created, next step will be to register these Facets and Elements in Sitecore, we also call this deploying to Sitecore.

In order to deploy these facets and Elements, we can either update the default configuration file, or we can also create a patch file, which will have changes specific to Education Facets.

Here is the patch file for ref:

FacetDeployPatch

<configuration xmlns:patch=”http://www.sitecore.net/xmlconfig/”&gt;
<sitecore>
<model>
<elements>
<element patch:after=”*[@interface=’Sitecore.Analytics.Model.Entities.IBehaviorProfileValue, Sitecore.Analytics.Model’]” interface=”Sample._Classes.xDBProfile.Elements.IProfileEducationElement, Sample.Sitecore”
implementation=”Sample._Classes.xDBProfile.Elements.ProfileEducationElement, Sample.Sitecore” />
<element patch:after=”*[@interface=’Sitecore.Analytics.Model.Entities.IBehaviorProfileValue, Sitecore.Analytics.Model’]” interface=”Sample._Classes.xDBProfile.Facets.IProfileEducationFacet, Sample.Sitecore”
implementation=”Sample._Classes.xDBProfile.Facets.ProfileEducationFacet, Sample.Sitecore” />
</elements>
<entities>
<contact>
<facets>
<facet patch:after=”*[@name=’Preferences’]” name=”Education” contract=”Sample._Classes.xDBProfile.Facets.IProfileEducationFacet, Sample.Sitecore” />
</facets>
</contact>
</entities>
</model>
</sitecore>
</configuration>

Getting and setting properties are done using GetAttribute and SetAttribute methods retrieved from Sitecore.Analytics.Model.Framework.Element and Sitecore.Analytics.Model.Framework.Facet.

Happy learning 🙂

Understanding Clones in Sitecore

There are scenarios when we want to replicate/duplicate entire content tree/individual items and create another structure in same Sitecore Instance, we also want to make sure that content can be shared from parent item to new item, in these scenarios and cases we can make use of Sitecore Cloning which helps to achieve the same.

Clone:

A clone is an item that is not just a copy of the original item, but one that inherits the field values from the original item. If we update a field in the original item, the corresponding field in the clone is also updated, this helps in implementing content sharing across sites/items in the same Sitecore Instance.

What can be cloned:

Here are the following items which can be considered for cloning:

  1. Complete site
  2. Section of site
  3. Individual Item

How to clone an Item:

In order to create a clone, please follow the following steps:

  1. Select the item which you want to clone from content tree.
  2. From the configure tab, click Cloneclone-tab
  3. From Clone Item dialog box, please select the location where you want to create the cloned item.
  4. Clone-Target
  5. Click Clone.
  6. Now go to the cloned item, and you will observe the “original value” next to the field, which explains that value for this field is inherited from parent/original item.clone-original-field-values

How to Unclone an Item:

In order to Unclone an item in Sitecore, please follow the below steps:

  1. Select the Item from content tree which you want to Unclone.
  2. Click on Unclone, from the configure tab.Unclone-tab
  3. Once we Unclone an Item, this item becomes an individual item which can be managed separately.

Breaking the Inheritance for Cloned Item:

As i mentioned above that we can Unclone an item, by which that item becomes a new item which can be managed separately.

But, we can also break the inheritance on field level, in order to break inheritance on the field level, just go to clone item and update any specific field value.

Once we update specific field value manually for any clone item, that field won’t share/inherit the value from parent/original item.

This is helpful in cases where certain field values to be shared from parent item, and certain field values managed separately in clone item.

Unclone-field value

In the above screen shot we can see that “Teaser” doesn’t show any “original value” text because the value was updated directly in the cloned item, but “Main Content” still inherits it from parent item.

Few points to note:

  • Before we take a decision what item/section should be clone, we need to do understand our content strategy.
  • For example- If we have to create a microsite which should be based on parent site, we can go for cloning, but, we also have to understand what are the different sections that needs to share the content, if only certain pages needs to be shared, we don’t have to clone the entire content tree(site), rather we can just clone specific pages/items.
  • Another example can be navigation, we want the navigation to be same for all the sites, but content differs, in this case we can just clone Navigation Items and not pages/items.
  • We can make use of field value inheritance, if the content of the clones items needs to be different, we can break the inheritance and add specific content to cloned item.

I hope this will help someone who is trying to do understand how clones work in sitecore, please let me know if you have any feedback or questions, happy to help.

Happy learning 🙂

Content managed favicon in Multisite Sitecore solution

There are scenarios when we want to configure content managed favicons for multiple sites in the same instance of Sitecore.

I have implemented this for one of our client, so thought of sharing the same with the community.

In my case, we have separate Site settings node created, which has all site related information, from the below screen shot you can see we created a new field called “Fav Icon” which is of file type.

FavIconField

Once we have the field available, content authors can content managed the fav icon based on the site requirement, please see the screen shot for ref:

Favicon

In the below code snippet, we are trying to fetch the sitenode based on start node(home node), and once we have sitenode, we are fetching site settings node from where we can get “Fav Icon” Url value.

 public static Item ContextWebsiteRoot
 {
   get
   {
     Item contextItem = null;
     Item webSiteContext = null;
     if (Sitecore.Context.Site != null && Sitecore.Context.Database != null)
     {
        Item homeNode = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
        webSiteContext = contextItem.Parent;
        // Use webSiteContext to get "Fav Icon" url...
        // We don't have to use .Parent, if "Fav Icon" field is created directly 
        // under home node.
     }
     return webSiteContext;
   }
 }

In my case we don’t have the Fav Icon in the site home node, so we need to add some rule to get the correct item, and then reading “Fav Icon” field, but just in case, if you are trying to add “Fav Icon” field directly in home node, you don’t need to fetch any parent Item.

Here is the simplified version of it, when “Fav Icon” is added to home node.

 Item contextItem = null;
 Item webSiteContext = null;
 if (Sitecore.Context.Site != null && Sitecore.Context.Database != null)
   {
      Item homeNode = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.StartPath);
      var siteFavIcon= contextItem["Fav Icon"];
   }

 

I hope this helps someone who is trying to implement something similar.

Happy learning 🙂

Sitecore best practice and guidelines

There are several useful articles and blogs about #Sitecore best practices, but I am trying to put together my learning on this area. Sitecore has different components shipped within it i.e “analytics“, “workflows“,”personalization” and others.

Before starting or working on any application, our main focus should be to understand application as a whole and not just part of it, believe me this is a key for overall success of your implementation, try to get involved and get more and more information about the solution as a whole.Once you have a big picture in mind, it’s easy to work on small features and then for integrations.

There are several categories we can have, when we talk about Sitecore best practices:

  1. Template.
  2. Content structure.
  3. Presentation.

Templates: Templates are the base for any Sitecore implementation, templates are grouping of certain fields that make one entity/table in Sitecore, which can have one or more then one field(s). There are few things which we should consider while designing a template.

  • Think about the entity first and all related fields which can be grouped.
  • List down all the fields which needs to be added to a particular entity.
  • Now identity if there are any set of fields which are common to other entities as well, at least to few, if not all, like “Headline”,”Teaser”, “Main Content” or “Image” fields.
  • If you get a list of common fields, then create a new “Base Template” and add all those fields in that template, this is also to make sure we are reusing the template and fields as much as possible.
  • You can use the “Display Name” property to provide a user-friendly name for any item.
  • Always try to group fields in section, this is logic separation of fields, still all the fields comes under same template only.
  • Try to give user friendly name for all sections,fields and templates so that business users/content authors can identify and understand them easily.
  • Always set default values in standard values of template, so that we can prepopulate some of the field values.
  • If there is predefined structure we have to follow, we should always consider branching template, this really helps content authors and they will love you for this.
  • Try to have unique icon added to you template, so that it is easy to recognize.
  • Presentation should be configured in standard values, so that it can be applied to all instances of that template.
  • Creation of “Base Templates” should always be in your radar, so that you can make use of Sitecore inheritance where required.

Content structure: This is the second step where we create items based on the template created, content structure helps content authors to look for the information or details they are interested, here are some of the things that we should consider while creating/designing content structure.

  • As a standard, try not to have more than 100 items under particular node, can be folder or page item, this can impact Sitecore performance.
  • If expecting more than 100, then consider using buckets or if not buckets create folders in a way that it doesn’t exceed more then 100 child per folder/item.
  • Try to have only page items created under home page, this can change, you can read my blog on different options for configuring content tree https://ankitjoshi2409.wordpress.com/2017/02/07/structuring-and-organizing-sitecore-content-in-content-tree/
  • Plan content structure based on site map, place all the items which are accessed using URL as descendants of the website, we should mimic sitemap structure in sitemap as well.
  • Make sure we have security added for items which which should not be accessed by specific user role(s).
  • Indexes should be configured for automatic updates,for better and faster content editor experience.
  • Make sure to consider multi-site environment as well, and create folder accordingly, this also helps in content sharing from one site to another.
  • Try to create folder template for structuring page items, should try for it as much as possible so that we have more control on the tree.
  • Maintain only a few versions of each item in the implementation- this is to improve the performance.

Presentation : Some of the things to consider while setting up the presentation:

  • Page should be Experience editor friendly.
  • Make sure to use Experience editor friendly tags like
  • Sublayout(s) and Rendering(s) should be configured to be cachable for better browsing experience.
  • Rendering should be added to page template standard values,when applied at an item level, any changes to the layouts require a lot of effort to make changes to all items. When applied at standard values, such modifications become easier.
  • Any updates to the specific should be done directly on final layouts, please read my blog for more details- https://ankitjoshi2409.wordpress.com/2017/02/06/sitecore-shared-vs-final-layouts/
  • Rendering should have data source template and data source location defined, this helps personalizing the site and making sure the application is experience editor friendly, this is important configuration for Experience editor.
  • All the components/rendering(s) should have thumbnail image added to it, this helps CAs configuring dealing experience editor nicely.
  • Use placeholders settings and allowed control setting, so that CAs can add/create only those modules which are required for that page design to work.

General Practice:

  • Don’t allow a single template to contain two fields with the same name.
  • Use a source code management system to manage all code,this includes JavaScript and CSS as well.
  • Avoid hard-coding as much as possible so that we don’t have to update the code, if any change required.
  • Use IDs instead of paths/name whenever possible.
  • Avoid using any form of the descendant axix, like GetDescendents
  • Try not to modify Sitecore base files and use Sitecore patching for any updates to config files, this helps in upgrade process if required.
  • Content Editing should be done on the master database, and then pushed to web database.
  • Restrict access to content delivery servers.
  • Use the general best practices of developments applicable to C# with tools like Re-sharper.
  • Set up continuous integration.

As I mentioned before there are lot of articles that has more details on best practices and guidelines, please make sure to read those as well.

I hope this will give you some degree of information, which can be applied while designing any structuring your Sitecore site.

Please feel free to add feedback and comments, happy to discuss more.

Happy learning 🙂

Troubleshooting Sitecore performance and optimization

Most of us might have faced issues with performance and slow Sitecore instance,I would like to share my experience with Sitecore troubleshooting which I have learned over the period of time, these are some of the things which I feel should be checked whenever we see the application has really some performance issues.

Trust Building:
This is one of the key factor of healthy business relation, we should make sure that application/business always meets users expectation, a non performing(from performance standpoint) site can’t guarantee a high ROI.

Here are few things i would like to mention to check the slow performing Sitecore site, and what can be done to fix it.

  1. Logs Reviews: 
    1. This is one of the wonderful feature which is shipped with Sitecore, and we should make use of it to check the performance of the application, regularly checking the logs can help us in fixing the issue well before in time before it becomes critical.
    2. Logs can give us most of the details which includes:
      1. Publishing details.
      2. Schedule task running.
      3. Any code error issue.
      4. Indexing or query issue.
      5. Issue with  MongoDB connectivity.
      6. Issue with SOLR server connectivity.
      7. Issue with SQL server connectivity
    3. Above are some of the details which we can review and proceed our investigation, it’s always better to have something in hand to troubleshoot, instead of randomly looking for something.
  2. Enable JS,CSS Compression:
    1. This helps in boosting the performance of application, by reducing page request to server or browsing the pages.
    2. We can make use of static and dynamic content compression in IIS.compression
  3. Sitecore Debugging:
    1. We should make use of Sitecore debugger tool which can be found in Page editor, this gives a very good understanding and statistics around different components being used in the page.
    2. Helps in understanding which specific component(sublayout/rendering) takes how much time to render on the page.
    3. One of the early troubleshooting which every developer should start doing right from the time we start experiencing performance issue in local development environment.
    4. This tools helps in narrowing down the problem with code,and thus helps in putting all our energy and time in right spot.sitecoredebugsitecoredebugprofile
  4. Sitecore Schedule tasks:
    1. Always try to review the Sitecore schedule tasks, and see if there is any task which is running and which is not expected?
    2. Make sure to review all the agents which is present under <agents> section, in web.config or using custom patch(if used).
    3. Another thing to note, we should also consider updating the frequency of that task execution by updating the time,if schedule task is not required we should disable it.
    4. See if the schedule task is triggering site full publish, this can be a serious issue in production environment,as this can clear all cache which can slow down the site.
    5. Keep close watch on the logs for anything related to schedules tasks.
  5. Indexing Strategy:
    1. Revisit the indexing strategy which is being used in the application, see if the full index rebuild is in place for any item publish event.
    2. Try to update the strategy if it’s not as per the requirement, or if it’s over killing.
    3. Please review this document for anything related to available indexing strategy-  https://doc.sitecore.net/sitecore_experience_platform/setting_up_and_maintaining/search_and_indexing/indexing/index_update_strategies
  6. Image optimization:
    1. I have seen this issue with several applications, just because the images are not properly optimized, they end up taking more resource bandwidth and resulting poor user experience.
    2. Remember, this is the time of mobile, and any poor performing mobile site can be a serious issue to client.
    3. We should always train and educate our client and content authors to make use of optimized images, and trust me they will listen to you.
  7. Indexes:
    1. This is one of the critical and important part of any Sitecore application, try to use indexes as much as possible when it comes to fetching details from the repository or searching of the items based on specific condition and filters.
    2. Try to perform all the operation directly in the query like:
      1. Pagination.
      2. Sorting
      3. Filters
    3. Avoid fetching all the results and then applying business rules to filter it based on specific condition, as I mentioned try to do most of the processing directly in query level.
    4. I had seen issues in application which was not performing well, just because of not making true use of indexes,review you index definition and configuration,and see if it has everything which is expected for it.
    5. Try to use create and use custom indexes for any custom feature, it’s always better to have one.
    6. Use of computed fields can be considered, this helps in executing any complex business logic while querying the results.
  8. Site publish:
    1. We should not trigger complete site publish in production environment,unless and until it’s very much required, this can be a costly operation, as this clears all the cache.
    2. Try to publish only areas which are required, we can trigger full site publish in development environment, but should be done carefully in production.
    3. Use Smart or Incremental Publish.
  9. Caching:
    1. Configure sublayout(s) and rendering(s) to use caching, this can give a real good browsing experience to site users.
    2. Clearing cache is something which should be considered in production environment, when trying to publish items this will clear the cache and can slow down the application performance.
  10. GetDescendants:
    1. Use of GetDescendants is one of the costliest operation we can think off, we should always try using indexes or fast queries if possible and required.
    2. Revisit your code and search if there is any reference to GetDescendants, and update it if required.
  11. No of Items under one node:
    1. Try not to have more items under single node/item, and break it down using several sub folders or items.
    2. This helps in giving good content editor experience.
    3. make use of item buckets wherever applicable.

Few important things to follow:

  1. Write good code.
  2. Proper unit testing.
  3. Get your code reviewed.
  4. Follow best practices.

This helps in fixing some of the issues before it goes to QA.

Please also refer Sitecore recommendation for performance optimization : https://sdn.sitecore.net/Articles/Administration/Sitecore%20Performance/Optimizing%20Sitecore%206%20and%20later/Optimizing%20Performance%20in%20Sitecore.aspx

I hope this helps someone in troubleshooting Sitecore performance issues, please let me know if you have any questions or comments, happy to discuss.

Happy learning 🙂

Creating multiple crawlers for custom Index in sitecore

When we discuss/talk about indexes to be used in sitecore solution, various indexing strategies, no# of indexes, application performance  and etc, following are few things which we should review and discuss first:

  1. What is the search requirements, which depends more on business requirements.
  2. Do we really need indexes?
  3. Can we make use out of the box sitecore APIs to get the data from sitecore?, or extra index set up required.
  4. If index required, can we make use of out of the box sitecore indexes(lucene/SOLR or Coveo)?
  5. Do we need to set up custom indexes?
  6. If custom index(s) needed, what are the different content you want to add to your index?

These are some of the questions which we should think, before discussing anything more or making any call for indexes and it’s setup.

But, i would like to focus on the area where the business justifies the need of indexes and custom indexes to be more specific, and which is mainly this blog is focused on.

Question: Can we make use of sitecore out of the box indexes for any custom implementation?

I would say No to this, as we should always try to architect the solution as loosely coupled as possible, but again it also depends on the requirement sometime, we shouldn’t be thinking about making a new custom index when the custom need is not that complex, and didn’t affect the performance of the application as a whole.

Following are couple of things to consider:

  1. How update index strategy will work based on specific conditions and scenarios.
  2. Any configuration update to the index, which is needed for the custom implementation.

In certain scenarios where we want to make the implementation as clean as possible and want to make sure it didn’t affect the maintenance and updates, I think we can definitely go with custom indexes, and make changes to the settings based on the requirement.

Let’s looks the configuration of default SOLR index:

solr_default_web_index

If you see the locations tag, there exists a crawler which will make sure to index the contents of the applications from specific database and specific location within sitecore, In this specific case it will index everything under sitecore, because that’s what the value we have under Root node.

Now, let’s think about a scenario where we want to index only two locations:

  1. All page items(which has presentation added to it) and
  2. All media items or any page item(s) which are structured outside of home node.
  3. To be more generic, we are trying to add two different locations in index, it can exists within home or outside home.

In order to support this scenario, we can add multiple crawlers for the same index, please see the below config for sample:

solr_multiple_crawlers_index

From the above screen shot you can see we have the same index, but with two crawlers which points to two different locations in sitecore.

Also,we  have to make sure that  both the crawlers in this case use the different name, which is more meaningful to the content type which will be indexed, we have used “PageCrawler“- which index all page items under home node and “MediaCrawler“- which index all media items under media library folder.

Following are the advantages of having multiple crawlers in the same index:

  1. Helps in boosting sitecore/application performance.
  2. Helps in applying business rules directly in the query, like pagination,sorting of pages,as now we get the different types of items from the same index.
  3. Easy maintainance.

Setting up only one crawler, or going with multiple crawlers is something point of discussion and  it mainly depends on the requirements of the application, as in general we should always keep in mind the application performance and maintenance in mind before wiring up any solution to the system.

Reference(s):

  1. https://community.sitecore.net/developers/f/5/t/2112

 

I hope this post can help someone who has some questions on where and how to implement multiple crawlers in sitecore, and indexing question(s) in general.

Happy learning 🙂