How to speed up Sitecore application startup?

Is your Sitecore application having slow start-up time and want to improve it? The main reason behind slowness is bigger Prefetch Cache. Application's startup time is directly proportional to size of Prefetch Cache set.

If you set Bigger Prefetch, it gives slow startup, but it can give you better performance while opening Content Editor or Page Editor because your items' data are already fetched from Database to Prefetch Cache.

In reverse, if you get Smaller Prefetch, it gives fast startup, but it can give you less performance while opening Content Editor or Page Editor because your items' might not be fetched to Prefetch from database. Thus, setting bigger or smaller amount of Prefetch, both have their own pros and cons.

Prefetch Cache Best Practices

If prefetch is customized according to our use of pages of site, it will give you the best performance. For that you have to findout three things:
- Which are the pages used the most in your site like Homepage.
- Which are the pages, whose children are accessed frequently.
- Which kind of pages(templates) are used the most.
Then, try to Prefetch all those items which are used in these pages.

For example,
- Homepage is the most frequently visited page, then you should prefetch Home item and its immediate children.
- Similarly suppose News pages are visited frequently, then you should prefetch News Template and their children too.

How to configure Prefetch Cache

Open the prefetch cache settings under the App_Config/Prefetch/ folder. For example /App_Config/Prefetch/Web.Config:

  
  300MB

  
  100 

  
  

  
  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX }

  
  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

See how these configurations will work:
  • <cachesize>300MB</cachesize>
    describes Sitecore will do prefetch upto 300MB.
  • <template desc="mytemplate">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}</template>
    Defines that items of the specified template will be prefetched.
  • <item desc="myitem">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX }</item>
    Defines that the specified item will be prefetched.
  • <children desc="childitems">{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}</children>
    Defines that specified children of the given item will be prefetched.
  • <childlimit>100</childlimit>
    Defines a limit to the number of children to include in the prefetch cache.

The Sitecore Prefetch Cache is a bit of a gray area. But, the above settings work great and surely help you to improve application startup.

If you are new to Sitecore cache, refer How Sitecore Caching Work and Performance Improvement Techniques.

Enjoy quick start up!!

Why my Sitecore Media Item created in multiple languages?

Have you ever faced that you upload a single media file to Sitecore and it gets created in multiple languages? This is not strange but expected behavior in Sitecore. Let's see how.

Check Media.UploadAsVersionableByDefault setting in your web.config. If it is false, then uploaded media item will be created in all those languages which exist under /sitecore/system/languages. This media item will use unversioned template /sitecore/templates/System/Media/Unversioned/File template, so the Blob(Media) and its common details would be shared across all language versions. See below image.



This option is really helpful when you want to use common media files across multiple languages content pages as the media is shaerd across all languages.


Where, if you have this setting as true, then each media item will be generated in default language only. This media item will use versioned template /sitecore/templates/System/Media/Versioned/File template, so the Blob(Media) and its all details would be distinct across languages. See below image.



This option is really helpful when you want to use different media files for different language content pages.

We can choose whether we need versioned or unversioned media. While doing Upload File (Advanced), Sitecore asks to select Make Uploaded Media Items Versionable checkbox. If the checkbox is selected, it will create versioned media, otherwise will create unversioned media items. See below image:



You want to upload media items in Sitecore with your selected languages only? Refer my new post: Upload sitecore media items in selected languages.

Sitecore partial cache clear programmatically

Sitecore is already smart enough to do cache clearing automatically. But in many cases, we might need to do manually clear different cache for particular items. We can do partial cache clear as below for any item we want whether it is in Prefetch Cache, Data Cache, Item Cache, StandardValue Cache, HTML Cache, etc.

Let's see how we can clear different cache.

Clear Item level Cache - Prefetch Cache, Data Cache, Item Cache, Standard Value Cache

Suppose, we want to clear Prefetch cache, Data Cache and Item Cache for /sitecore/content/Homepage/
    string itemPath = "/sitecore/content/Homepage/";
    Item home = Sitecore.Context.Database.GetItem(itemPath);

    public void ClearItemLevelCache(home)
    {
        // Clear item's Item Cache
        Sitecore.Context.Database.Caches.ItemCache.RemoveItem(home.ID);

        // Clear item's Data Cache
        Sitecore.Context.Database.Caches.DataCache.RemoveItemInformation(home.ID);

        // Clear item's Standard Value Cache
        Sitecore.Context.Database.Caches.StandardValuesCache.RemoveKeysContaining(home.ID.ToString());

        // Clear item's Prefetch Cache
        CacheManager.GetSqlPrefetchCache(home.Database.Name).Remove(home);
    }

    public static Cache GetSqlPrefetchCache(string database)
    {
      return Caching.CacheManager.FindCacheByName("SqlDataProvider - Prefetch data(" + database + ")");
    }

Clear Sitewise Cache

Suppose, we want to clear cache for Context site.
    SiteContext site = Context.Site;

    public void ClearSiteCache(SiteContext site)
    {
        SiteCaches siteCache = site.SiteCaches;

        // Clear HTML Cache
        siteCache.HtmlCache.Clear();

        // Clear Registry Cache
        siteCache.RegistryCache.Clear();

        // Clear ViewState Cache
        siteCache.ViewStateCache.Clear();

        // Clear FilteredItemsCache
        siteCache.FilteredItemsCache.Clear();

        // Clear XSL Cache
        siteCache.XSLCache.Clear();
    }

Clear other Sitecore level Cache

Similarly we can also clear PathCache, AccessResultCache, etc. as below:
    Caching.CacheManager.GetPathCache(Sitecore.Context.Database).Clear();
    Caching.CacheManager.GetAccessResultCache().RemovePrefix(database.Name);
Sitecore.Caching.CacheManager provides all functions for getting and clearing all caches.

Update Sitecore Item programmatically

There are two ways where you can put an item in editing mode and update its fields.

1. Sitecore.Data.Items.ItemEditing

2. Sitecore.Data.Items.EditContext (Deprecated)

If you are saving any item field without using above statements, it might give you exception that Item was not in Edit Mode. Let's see how we can update item

Sitecore.Data.Items.ItemEditing

See below code which allows to save any item.
    Sitecore.Data.Database masterDB = Sitecore.Configuration.Factory.GetDatabase("master");
    Sitecore.Data.Items.Item home = masterDB.GetItem("/sitecore/content/Home");

    //Begin Editing Sitecore Item
    home.Editing.BeginEdit();
    try
    {
        home["Title"] = "Title from Code Behind";

        // This will commit the field value
        home.Editing.EndEdit();
    }
    catch (Exception)
    {
        //Revert the Changes
        home.Editing.CancelEdit();
    }
This function has three variants, means it allows to item save in two different options.
item.Editing.EndEdit()
This save will actually do 3 steps:
  1. Save item
  2. Update item statistics, means updates Modified Date, Modified By User, etc. statistics information of item
  3. It will execute events related to Item Save.
item.Editing.EndEdit(updateStatistics, silent)
This save will allow us to choose which operations to do. This is going to save item same as above. But it will do update statistics or execute events or not depending on the parameters passed.

If we pass updateStatistics as false, it will not update Modified Date and Modified By fields. This is really useful when we need to update items in background. This will update item in read-only mode. If we pass true, then it will update this information.

If we pass silent as true, it will temporarily disable events. So, event this item's save will not be logged in EventQueue.

Below is the code to understand what EndEdit does:
public bool EndEdit()
{
    return this.EndEdit(true, false);
}

public bool EndEdit(bool updateStatistics, bool silent)
{
    bool flag2;
    bool readOnlyStatistics = this.m_item.RuntimeSettings.ReadOnlyStatistics;
    try
    {
        if (!updateStatistics)
        {
            this.m_item.RuntimeSettings.ReadOnlyStatistics = true;
        }
        if (!silent)
        {
            flag2 = ItemManager.SaveItem(this.m_item);
        }
        else
        {
            using (new EventDisabler())
            {
                flag2 = ItemManager.SaveItem(this.m_item);
            }
        }
    }
    finally
    {
        this.m_item.RuntimeSettings.ReadOnlyStatistics = readOnlyStatistics;
    }
    return flag2;
}

Sitecore.Data.Items.EditContext

Note: Sitecore EditContext is deprecated,  and Sitecore team recommends using ItemEditing (1st approach).

The above thing is also possible using Sitecore.Data.Items.EditContext in below manner:

Below is example of Sitecore item save using Default parameters. Here, updateStatistis is by default true and silent is false.
Sitecore.Data.Database masterDB = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.Item home = masterDB.GetItem("/sitecore/content/Home");

//Begin Editing Sitecore Item
using (new EditContext(home))
{
    home["Title"] = "Title from Code Behind";
}
We can also pass parameters of updateStatistics and silent in EditContext like below example.
bool updateStatistics = false;
bool silent = true;
using (new EditContext(home,updateStatistics, silent))
{
    home["Title"] = "Title from Code Behind";
}
We can also pass parameters of checking security or not while updating the item like below.
using (new EditContext(home, SecurityCheck.Disable))
{
    home["Title"] = "Title from Code Behind";
}

Sitecore performance improvement techniques

Most of us might have faced issues with Sitecore performance and slow sitecore instance. Then first step should be referring Sitecore's suggestions: Optimizing Sitecore Performance. If you already referred, here are few more tricks to optimize sitecore performance.

Prefetch, Data and Item Cache tuning

Prefetch, Data and item cache sizes should be configured as needed. You may start with a smaller number of cache size and tune them as you find use of items increasing or depending on performance we get. Sitecore cache tool (/sitecore/admin/cache.aspx) can help us to check Sitecore cache utilization.

Sitecore says: Increase and tune the size of the data, items, and prefetch caches. Bigger caches = better performance. We can change size of cache of whole Sitecore instance using below settings in web.config.

      300MB
      300MB
      5MB
      5MB

Tune the prefetch cache settings under the App_Config/Prefetch/ folder. Sample /App_Config/Prefetch/Web.Config:

  300MB
  
  

  
  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX }

  
  {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}


Below are the cache tuning findings from our own experiences:
  • The more Prefetch Cache, the more time taking in Sitecore Startup, but it might help loading Content Editor and Page Editor faster. Less Prefetch Cache, makes faster startup, but might get slower CE or PE.
  • If you are using separate Publish Instance, keep Prefetch cache as minimum as possible on PI.
  • Caching can be a on-going process until you are not set with your optimized cache settings.
  • Cache Clearing is a very critical process, can slowdown the application. Whenever heavy publishing occurs, template are changed/published, heavy item creation/deletion/updation going on Sitecore, cache clearing occurs, preventing/optimizing these cases can help to prevent cache clearing.
  • Cache size occupied in memory would vary from the cache sizes set in config because it is not easy to estimate .NET object size accurately. So there are chances that dataCache, AccessResultCache, etc. can grow more than its specified value.

If you are newer to Sitecore caching? Read How Sitecore Caching Works. Read more about Sitecore Prefetch Fetch configuration & quick startup.

AccessResultCache Configuration

If you are facing slowness on production/live environments, then setting for AccessResultCache configuration will surely help to gain performance. One of my colleague Muktesh Mehta did a great finding that AccessResultCache clearing happens a lot on live servers, where actually we do not need to check access rights for any user. After confirmation from Sitecore guys, we simply set the value of AccessResultCache to 0 on live servers and finally we defeated the slowness :)

Apply Sublayout Caching

Sitecore allows us to use .NET sublayouts and XSL renderings in Sitecore’s caches to improve performance. We can apply HTML cache using sublayout caching, this improves performance drastically.

When sublayout caching is on, its HTML cache (HTML output) will be cached, all other subsequent requests will be served from the HTML cache itself. So, no more database interactions for the sublayout. :) Just to make a note, HTML cache will be cleared on live server when any publish is done.

See for more details: http://blog.navigationarts.com/caching-via-sitecores-html-cache/

Disable unwanted background Sitecore jobs

Removing unwanted things is as important as doing optimization. Sitecore instance has many jobs/tasks running in background. i.e., urlagent, cleanup agent, etc. We can disable them if they are not useful or increase their time interval to execute. The agents can be found from web.config under <agents> section and the tasks can be found from Sitecore itself on path:/Sitecore/System/Tasks/Commands.

Enable CSS, JS Caching, Compression

Enabling Browser caching and Compression to CSS and JS will give a big performance improvement on page browsing and requests reduction on server.

Prevent use of GetDescendants

GetDescendants is a very costly method to list out items. It recursively fetches all items upto the last level under the given item. Even if we need to get all items up to 2nd level, this function will traverse through n level. It does not only list the items but also fetches Item details (by filling DataCache and ItemCache). So, Sitecore Item architecture should be setup in such a way that item details can be fetched from first or second level from where we are fetching items.

Executing Database queries can be a good alternative in few cases like creating Sitemap, getting few fields' details for making tools or generate stats, etc. See more on Sitecore Database Queries to get item details

Prevent frequent publishing

On each publish, Sitecore is is clearing Cache of published or related items. i.e., if an item is published from master to web, Sitecore needs to update this item on web database (live servers). So, Data Cache, Item Cache are cleared for the related items. Also, Html Cache is cleared for the whole site on each publish. So, it is always better to prevent frequent publishing or doing publishing after keeping few minutes interval.

IIS/.NET level changes

  1. Upgrade to IIS 7+
    IIS 7+ gives a drastic improvement in performance compared to older versions.
  2. Upgrade to .NET 4+
    .NET Framework 4+ gives a drastic improvement in performance compared to older versions.
  3. Enable HTTP Keep-alive and content expiration in IIS
  4. Disable IIS ASP debugging in production environments
  5. Read Optimizing IIS performance and ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0 to know more above these settings.

Sitecore - Get items details using Database Query

Sitecore provides Item.GetDescendants() function to fetch all descendants of any item. Sitecore APIs always fetch items with their field values (whether we required them or not) either from database or from cache, so chances of more lengthy database query execution or heavy cache clearing or creation. That's the reason why Sitecore APIs like Item.GetDescendants() or database.GetItem() are slower.

It is recommended to use Sitecore APIs for development purposes, but still Database Queries can serve better than APIs to get what exactly we need (item's children/descendants and their field values). Database Query should be used only when we need to fetch lots of items in a single call or we need to read few field values for these items.

In such cases, we can make direct queries on database to get performance improvement and get speedy results.

Different SQL Queries

1. Select all children
2. Select all descendants
3. Get path of item
4. Get any field's value
5. Get item's full details with field types

Below queries are performed on Sitecore Training Sample Site.

Select all children

Below query gets children of item '/sitecore/content/Home'. It's GUID is {4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}
SELECT ID, [Name], Created from  [dbo].[Items]
 WHERE [ParentID] = '{4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}'


Select all descendants

Below query gets descendatns of item '/sitecore/content/Home'. It's GUID is {4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}
WITH [Content_Items] AS 
 (
  SELECT [ID], [Name], Created
   FROM [dbo].[Items]
   WHERE ID='{4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}'
  UNION ALL
  SELECT  i.[ID], i.[Name], i.Created
   FROM [dbo].[Items] i
   INNER JOIN [Content_Items] ci ON ci.ID = i.[ParentID]
 )
 SELECT ID, Created
 FROM [Content_Items]

 GO

Get path of item

We can also get full path of item. Suppose, we need to get full path of Home or we need to create SiteMap frequently, this query will be a great option to generate FullPath/URL of each item.

Below is the function we can create to get Full/Relative path of any item. Here, SC_GetPath has two parameters. First parameter is ID which is the item's ID. Second parameter is to get relative path, means from this ID, the path will be generated.
CREATE FUNCTION [dbo].[SC_GetPath] 
(
 @ItemID [uniqueidentifier],
 @RootPath [uniqueidentifier]
)
RETURNS varchar(MAX)
AS
BEGIN
 DECLARE @Result varchar(MAX);

 with scpath(Name, ParentID, id)
 as
 (
  select Cast(a.Name as varchar(MAX)), a.ParentID, a.ID
  from [Items] a
  where a.ID = @ItemID
  union all
  select Cast(b.Name + '/' + c.Name as varchar(MAX)), b.ParentID, b.ID
  from [Items] b
    inner join scpath c on b.ID = c.ParentID
  where c.ParentID is not null
 )

 select top 1 @Result = '/' + d.Name  from scpath d
  where d.ID = @RootPath /*'11111111-1111-1111-1111-111111111111'*/

 RETURN @Result

END

Get full item path
Suppose we need to get full path of item Jobs.
ID of Jobs item: {6C897D6C-CE0C-422D-8955-7113A0E1B8EF}
ID of sitecore item: {11111111-1111-1111-1111-111111111111}

Sitecore, we can make query as below to get path /sitecore/content/Home/Jobs: Here,
SELECT [Name], [dbo].[SC_GetPath] (ID,'{11111111-1111-1111-1111-111111111111}') AS ItemPath 
 FROM [dbo].[Items]
 WHERE [ID] = '{6C897D6C-CE0C-422D-8955-7113A0E1B8EF}'


Get relative item path
Now, to get relative path of item Jobs starting from /Home.
ID of Jobs item: {6C897D6C-CE0C-422D-8955-7113A0E1B8EF}
ID of Home item: {4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}

Sitecore, we can make query as below to get path /Home/Jobs: Here,
SELECT [Name], [dbo].[SC_GetPath] (ID,'{4E7AB8B1-6A39-4C8C-BF5B-816F8105BFFD}') AS ItemPath 
 FROM [dbo].[Items]
 WHERE [ID] = '{6C897D6C-CE0C-422D-8955-7113A0E1B8EF}'

Get any field's value

Getting item's field value depends on its type of field means it is Versioned, Unversioned or SharedField. Each type of field and its values are stored in different table. So, before getting any field's value, it is good to know its field type and based on it we can get execute query.

See how below function helps to return a shared field's value of an item, similarly we can write function for Versioned and Unversioned fields too:
CREATE FUNCTION [dbo].[SC_GetSharedFieldValue] 
(
 @ItemID [uniqueidentifier],
 @FieldID  [uniqueidentifier]
)
RETURNS nvarchar(max)
AS
BEGIN
 DECLARE @Result  nvarchar(max)
 SELECT @Result = value 
  FROM [dbo].[sharedFields]
  where ItemId=@ItemID
  and fieldid=@FieldID
 RETURN @Result
END
Here, Size field's ID is:{6954B7C7-2487-423F-8600-436CB3B6DC0E}. So, for getting media item's size, we can use above function as below. Here, quert list down all child media media of /sitecore/media library/Images/Banners and its ID is: {1D02B586-0B55-4C2F-AED4-A3172B81B0DA}
SELECT ID, [Name], [dbo].[SC_GetSharedFieldValue] (ID, '{6954B7C7-2487-423F-8600-436CB3B6DC0E}') AS FileSize
 FROM [dbo].[Items]
 WHERE [ParentID] = '{1D02B586-0B55-4C2F-AED4-A3172B81B0DA}'

Get item's full details

Below query will help to get all fields' values and their field types like below:
  • All Shared field values
  • All Versioned field values
  • All Unversioned field values
  • All Field Types (Like Single-Line Text, Checkbox, Multilist, etc.)
For getting item's all fields values, we have to make a UNION query on all three types of tables of three different field types. See below query to get item's all details:

DECLARE @ItemId uniqueidentifier 
SET @ItemId = '{0DE95AE4-41AB-4D01-9EB0-67441B7C2450}'
DECLARE @FieldTypeId uniqueidentifier 
SET @FieldTypeId = '{AB162CC0-DC80-4ABF-8871-998EE5D7BA32}' -- Item Id of Field Type in each item

SELECT I.Name, [dbo].[SC_GetSharedFieldValue](I.Id, @FieldTypeId) AS [Field Type],
  S.Value, '' AS [Language], '' AS [Version] FROM SharedFields S, Items I 
 WHERE S.itemid=@ItemId
 AND S.FieldID = I.ID
UNION
SELECT I.Name, [dbo].[SC_GetSharedFieldValue](I.Id, @FieldTypeId) AS [Field Type],
  U.Value, U.Language, '' AS Version FROM UnversionedFields U, Items I 
 WHERE U.itemid=@ItemId
 AND U.FieldID = I.ID
UNION
SELECT I.Name, [dbo].[SC_GetSharedFieldValue](I.Id, @FieldTypeId) AS [Field Type], 
  V.Value, V.Language, V.Version FROM VersionedFields V, Items I 
 WHERE V.itemid=@ItemId
 AND V.FieldID = I.ID
This will return all fields' values as below.
- Shared Fields do not contain Language and Version fields, so we have returned blank.
- Unversioned Fields do not contain Version, so have returned blank as Version.




SQL Database queries faster than Sitecore APIs and better than Sitecore fast query, isn't it?

Sitecore Item alias - Alternate URL

An Alias is an alternate path for an item when browsing the web site. In other terms we can have URL alias in Sitecore.

Suppose, you have an item's URL as:
http://mysite.com/news/2013/cricket/

Now, you want the same page to be opened using some alternate URLs like:
http://mysite.com/cricket-news/
OR
http://mysite.com/news-cricket/

This is quite possible using AliasResolver in Sitecore.

How to configure

We will create two different aliases cricket-news and news-cricket under /sitecore/system/aliases/. Both items will have same configuration, means both will point to content item /sitecore/content/Home/News/2013/Cricket/ So, AliasResolver read these settings and work accordingly.

See below image how alias can be set for this item.

How can we know URL of alternate URL or Alias?

To see if an alias exists, use the database.Aliases.Exists() method. This will check if both the alias exists and the target item exists sd below:
    // Code from Sitecore.Pipelines.HttpRequest.AliasResolver class
    Database database = Context.Database;
    if (database == null)
    {
        Tracer.Warning("There is no context database in AliasResover.");
    }
    else
    {
        if (database.Aliases.Exists(args.LocalPath) && !this.ProcessItem(args))
        {
            this.ProcessExternalUrl(args);
        }
        Profiler.EndOperation();
    }

    private void ProcessExternalUrl(HttpRequestArgs args)
    {
        string targetUrl = Context.Database.Aliases.GetTargetUrl(args.LocalPath);
        if (targetUrl.Length > 0)
        {
            this.ProcessExternalUrl(targetUrl);
        }
    }

    private void ProcessExternalUrl(string path)
    {
        if (Context.Page.FilePath.Length <= 0)
        {
            Context.Page.FilePath = path;
        }
    }


What to do in multisite environment?

In multisite environment, we can still use this functionality. We can customize the AliasResolver processor in HttpRequestBegin pipeline, where the alias items will be stored in Site specific folder, so, the Custom AliasResolver will search aliases in site folder only. We can create a alias folder structure site-wise, something like,
/Sitecore/System/Aliases/Site-A/Alias1
/Sitecore/System/Aliases/Site-A/Alias2
/Sitecore/System/Aliases/Site-B/Alias1
/Sitecore/System/Aliases/Site-B/Alias2

See below snap:

This structure might change depending on what folder structure you follow. See how code will go for Custom AliasResolver:
namespace SitecoreTactics.Pipelines.HttpRequestBegin
{
class CustomAliasResolver : AliasResolver
{
    public new void Process(HttpRequestArgs args)
    {
        Assert.ArgumentNotNull(args, "args");

        if (!Settings.AliasesActive)
        {
            Tracer.Warning("Aliases are not active.");
        } 
        else 
        {
            Sitecore.Data.Database database = Sitecore.Context.Database;
            if (database == null)
            {
                Tracer.Warning("There is no context database in AliasResover.");
            }

            Item aliasItem = getAliasItem(args);
            if (aliasItem != null)
            {
                LinkField linkField = aliasItem.Fields["Linked item"];
                if (linkField != null)
                {
                    Item AliasLinkedTo = Sitecore.Context.Database.GetItem(linkField.TargetID);

                    if (AliasLinkedTo != null)
                    {
                        Sitecore.Context.Item = AliasLinkedTo;
                    }
                }
                else
                {
                    base.Process(args);
                }
            }
        }            
    }

    /// 
    /// Gets the alias item.
    /// 
    /// The args.
    /// 
    private Item getAliasItem(HttpRequestArgs args) 
    {
        string siteName = Sitecore.Context.Site.RootPath.ToLower();

        if (args.LocalPath.Length > 1)
        {
            Item aliasItem = Sitecore.Context.Database.GetItem("/sitecore/system/Aliases/" + siteName + "/" + args.LocalPath);
            if (aliasItem != null)
            {
                return aliasItem;
            }                
        }

        return null;
    }
}
}

Read more about Sitecore alias:

- Sitecore language based Alias
- Sitecore Alias for multisite solution - Marketplace Module