Extend Commerce Entity Views

To extend commerce entity view you need to have a look on Commerce Views service

The Commerce Views service is provided by the Sitecore.Commerce.Plugin.Views
plugin.

Commerce views are also designed to feed directly into a dynamic data-driven business tool experience. You can activate, extend, or remove functionality in the business tools through custom-developed plugins, without having to modify the out-of-box plugins or modify the source code of the business tools themselves. This approach dramatically improves upgradability.

In the Sitecore Commerce architecture, this view layer is provided on the server side, instead of the client side.In this way you don’t need to have frontend knowledge. This allows standard Commerce plugins to extend existing views and add new views.

Commerce views are exposed via the Authoring API. This Authoring API is based on OData.

The EntityView is the core Commerce artifact that supports views.

An EntityView represents a flattened, dynamic service response focused on supporting a dynamic user experience.

The EntityView provides a business user experience that is completely customizable and extensible. The EntityView allows the business user to take actions and dynamically updates the view without requiring significant intelligence or customization of the user experience itself.

The EntityView is a simple POCO class that provides a property bag. The EntityView can have child EntityViews. You can build out more complex views as needed.

A Composite EntityView includes a master view and child views.

The master view represents the overall page itself. It normally does not contain properties, but could. The master view contains a list of child views that each represent a section of the user interface. It also contains a list of actions that can be executed against the entity. An example of a child view is the Details section of a page. For example, on an Order page, the child view is the section that presents the order confirmation identifier, the date, and so on.

In the next example you will find how to add to sellable items  the first image from product “Images” field.

 

 

Add a policy where you keep the value of the CM server.

Add the policy to the PlugIn.Habitat.CommerceAuthoring-1.0.0.json .

Inject the pipeline block which extend the entitiy view after PopulateEntityViewActionsBlock :

Implement the PopulateSellableItemImages pipelineblock:

 

 

 

 

 

 

Advertisements

Commerce Computed Indexfield

Computed fields allow you to add entirely new fields in your search indexes, in addition to those of Sitecore.

To create a computed index field for commerce entities you need to follow next steps:

  1. Create your own class which inherits from : Sitecore.Commerce.Engine.Connect.Search.ComputedFields.BaseCommerceComputedField

2. Customize the class to meet your particular needs.

The “JToken entity” object contains few information about your sellableitem (in the below example is a sellableitem from SXA)

3. Add the Computed Field in the Configuration:

 

 

Sitecore Commerce Icons

Ten years ago when I started working with Sitecore, one of the first thing I learn it was how to select icons for items templates.

In Sitecore Commerce is a bit different how to choose icons for entity views.You don’t have a picker for icons.

Icons in Sitecore Commerce are stored in Bizfx tools in the root folder in SitecoreIcons.*.svg file.

bizfxtool

To view all the icons from the Bizfx toool you can use  http://fontello.com/

You can drag and drop and select the icons .

fontello

 

After you select the SVG file you will see icons available for Sitecore Commerce.

BizfxIcons

Using Fontello you can search for icons :

calendarclock

To create an entity view with a selected icons you have use :

var newEntityView = new EntityView
{
Name = “CustomEntityView”,
DisplayName = “CustomEntityView”,
Icon = “calendar_clock”,
ItemId = “CustomEntityViewId”
};

 

The result for on Commerce Dashboard is :

CustomEntityView

In the next blog I will explain how to add a new EntityView to CommerceDashboard

 

Field Validators on Experience Editor

On Sitecore 8 I added few fields validators.
Everything works perfectly on Content Editors but not on Experience Editor.

On config files we have next setting:


<!--
  WEB EDIT ENABLE VALIDATION
            If true, the Page Editor will execute item and field validation rules whenever a user tries to save items in the Page Editor.
            Only 'Critical' and 'Fatal' validators are evaluated, and item validation rules are executed for the current context item only.
            Field validation rules are only executed for fields that the current user can modify in the Page Editor.
            Default value: true
      
-->
<setting name="WebEdit.EnableValidation" value="true" patch:source="Sitecore.ExperienceEditor.config"/> 
 

but is ignored on Experience Editor.

I found a new solution switching Experience Editor from Speak UI to Sheer UI.
How to switch it :

Modify on App_Config\Include\Sitecore.ExperienceEditor.config
mvc.renderPageExtenders pipeline

1. Comment out the following line in the:

<pageextender type="Sitecore.ExperienceEditor.Speak.Ribbon.PageExtender.RibbonPageExtender, Sitecore.ExperienceEditor.Speak.Ribbon" />
[/soucecode]
2. Uncomment the following lines:
 
<pageextender type="Sitecore.Layouts.PageExtenders.PreviewPageExtender, Sitecore.ExperienceEditor" />
<pageextender type="Sitecore.Layouts.PageExtenders.WebEditPageExtender, Sitecore.ExperienceEditor" />
<pageextender type="Sitecore.Layouts.PageExtenders.DebuggerPageExtender, Sitecore.ExperienceEditor" />
 

If you have a Mvc Solution you need to change Sitecore.MvcExperienceEditor.config
1. Uncomment the page extenders below and comment the “SPEAK-based” Experience Editor ribbon processors to switch to old SheerUI-based Experience Editor ribbon.

 
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderPageEditorExtender, Sitecore.Mvc.ExperienceEditor"></processor>
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderPreviewExtender, Sitecore.Mvc.ExperienceEditor"></processor>
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderDebugExtender, Sitecore.Mvc.ExperienceEditor"></processor>
    

2. Comment next pipeline

   <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.SpeakRibbon.RenderPageEditorSpeakExtender, Sitecore.Mvc.ExperienceEditor"></processor>
   

Goals in a multisite solution

Yesterday it was a question on Community how to implement Goals in a multisite solution: https://community.sitecore.net/developers/f/9/t/1913

And if I write few blog posts about multisite I said to write also a blogpost about implementing goals in a multisite solution.

My site structure is :

Countries

My goals structure is :

Step 1 :

Modify site definition like. I added a new property to sites “goalsFolder”

  <site name="countrythree" patch:before="site[@name='website']" hostName="countrythree.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countrythree" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="en" goalsFolder="countrythree" />

  <site name="countrytwo" patch:before="site[@name='website']" hostName="countrytwo.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countrytwo" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="en" goalsFolder="countrytwo" />


  <site name="countryone" patch:before="site[@name='website']" hostName="countryone.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countryone" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="de-de" goalsFolder="countrytwo" />

  <site name="sitecoremvc-base" patch:before="site[@name='website']" hostName="*" enableTracking="true" virtualFolder="/" physicalFolder="/" rootPath="/sitecore/content" startItem="/home" database="web" domain="extranet" allowDebug="true" cacheHtml="true" htmlCacheSize="50MB" registryCacheSize="0" viewStateCacheSize="0" xslCacheSize="25MB" filteredItemsCacheSize="10MB" enablePreview="true" enableWebEdit="true" enableDebugger="true" disableClientData="false" cacheRenderingParameters="true" renderingParametersCacheSize="10MB" />
  

Step2:
Change type of command with name “anylitics:opengoals” from Sitecore.Analytics.config
into:

  <command name="analytics:opengoals" type="Sitecore.Analytics.OpenGoals,SitecoreDemo" patch:source="Sitecore.Analytics.config"/>

Step3:
Create a new class OpenGoals:

    using Sitecore;
    using System;
    namespace SitecoreDemo.Analytics
    {
      [Serializable, UsedImplicitly]
      public class OpenGoals : OpenTrackingField
      {
        // Methods
        protected override string GetUrl()
        {
            return "/sitecore/shell/~/xaml/Sitecore.Shell.Applications.Analytics.TrackingField.Goals.aspx";
        }
       }
    }
    

4. Create a new xaml file name it Goals.xaml and add it to folder: /Sitecore/Shell/Override

      <?xml version="1.0" encoding="UTF-8" ?>
<xamlControls xmlns:x="http://www.sitecore.net/xaml" xmlns:ajax="http://www.sitecore.net/ajax" xmlns:rest="http://www.sitecore.net/rest" xmlns:r="http://www.sitecore.net/renderings" xmlns:xmlcontrol="http://www.sitecore.net/xmlcontrols" xmlns:p="http://schemas.sitecore.net/Visual-Studio-Intellisense" xmlns:asp="http://www.sitecore.net/microsoft/webcontrols" xmlns:html="http://www.sitecore.net/microsoft/htmlcontrols" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <Sitecore.Shell.Applications.Analytics.TrackingField.Goals x:inherits="SitecoreDemo.Analytics.GoalsPage,SitecoreDemo">

    <Sitecore.Controls.DialogPage runat="server" Header="Goals" Text="Select the goals that you want to associate with the selected item.">
      <AjaxScriptManager runat="server"/>
      <ContinuationManager runat="server" />
      <Script runat="server" Src="/sitecore/Shell/Applications/Analytics/TrackingField/TrackingField.js" />


<Style runat="server">
        #GoalsList table tr > td {
          padding: 0 0 10px 0;
        }
      </Style>




<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">


<tr>


<td height="100%">
            <GridPanel Width="100%" Height="100%" runat="server" Background="White">

              <Border runat="server" GridPanel.Style="height:100%" Height="100%">
                <Scrollbox id="GoalsList" runat="server" Height="100%" Padding="0px"/>
              </Border>
            </GridPanel>
          </td>


        </tr>


      </table>


        
        
    </Sitecore.Controls.DialogPage>
  </Sitecore.Shell.Applications.Analytics.TrackingField.Goals>


</xamlControls>

    

5. Create a new class GoalsPage

using Sitecore;
using Sitecore.Analytics;
using Sitecore.Analytics.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Extensions.XElementExtensions;
using Sitecore.Shell.Applications.Analytics.TrackingField;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using SitecoreDemo.Util;

namespace SitecoreDemo.Analytics
{
   [UsedImplicitly]
public class GoalsPage : TrackingFieldPageBase
{
    // Methods
    protected override void OK_Click()
    {
        Packet packet = new Packet("tracking", new string[0]);
        base.AddIgnoreFlag(packet);
        base.AddExistingProfiles(packet);
        base.AddExistingCampaigns(packet);
        if (HttpContext.Current != null)
        {
            List<PageEventItem> pageEventDefinitions = new List<PageEventItem>(from item in Tracker.DefinitionItems.PageEvents.Concat<PageEventItem>(Tracker.DefinitionItems.Goals)
                where item.IsDeployed
                select item);
            base.AddExistingNoneGoals(packet, pageEventDefinitions);
            CheckBoxList checkBoxList = this.GoalsList.Controls[0] as CheckBoxList;
            if (checkBoxList != null)
            {
                TrackingFieldPageBase.GetEvents(packet, pageEventDefinitions, checkBoxList);
            }
            SheerResponse.SetDialogValue(packet.ToString());
            base.OK_Click();
        }
    }

    protected override void OnLoad(EventArgs e)
    {
        Assert.ArgumentNotNull(e, "e");
        Assert.CanRunApplication("Content Editor/Ribbons/Chunks/Analytics - Attributes/Goals");
        base.OnLoad(e);
    }

    protected override void Render(XDocument doc)
    {
        Assert.ArgumentNotNull(doc, "doc");
        this.RenderGoals(doc);
    }

    private void RenderGoals(XDocument doc)
    {
        Assert.ArgumentNotNull(doc, "doc");
        List<string> selected = new List<string>();
        foreach (XElement element in doc.Descendants("event"))
        {
            selected.Add(element.GetAttributeValue("name"));
        }
        CheckBoxList child = new CheckBoxList {
            ID = "GoalsCheckBoxList"
        };
        this.GoalsList.Controls.Add(child);
        System.Web.UI.Page page = TrackingFieldPageBase.GetPage();

        var site = ItemUtil.GetSiteContextForItem(ItemUtil.GetItem(Sitecore.Context.Request.QueryString["id"]));
        var goalsFolder = site.Properties["goalsFolder"];
        if ((page != null) && !page.IsPostBack)
        {
            IOrderedEnumerable<PageEventItem> query;
            if (!string.IsNullOrEmpty(goalsFolder) && Sitecore.Context.ContentDatabase.GetItem(Tracker.DefinitionItems.Goals.Path+"/"+goalsFolder)!=null)
            {
                query = from e in Tracker.DefinitionItems.AllPageEvents
                        where e.InnerItem.Parent.Key.Equals(goalsFolder, StringComparison.InvariantCultureIgnoreCase) && (e.IsDeployed && e.IsGoal) && !e.IsSystem
                        orderby e.DisplayName
                        select e;
            }
            else
            {
                query = from e in Tracker.DefinitionItems.AllPageEvents
                        where(e.IsDeployed && e.IsGoal) && !e.IsSystem
                        orderby e.DisplayName
                        select e;
            }
            TrackingFieldPageBase.RenderCheckBoxList(child, query, selected);
        }
    }

    


    // Properties
    [UsedImplicitly]
    protected Scrollbox GoalsList { get; set; }
}
}

Step6. Create a new class OpenTrackingField

    using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Text;
using Sitecore.Web;
using Sitecore.Web.UI.Sheer;
using Sitecore.Web.UI.WebControls;
using System;
using Sitecore.StringExtensions;

namespace SitecoreDemo.Analytics
{
    [Serializable, UsedImplicitly]
    public class OpenTrackingField : Sitecore.Shell.Applications.Analytics.TrackingField.OpenTrackingField
    {
        CommandContext context;
        // Methods
        public override void Execute(CommandContext context)
        {
            this.context = context;
            base.Execute(context);
        }

        protected virtual string GetUrl()
        {
            return "/sitecore/shell/~/xaml/Sitecore.Shell.Applications.Analytics.TrackingField.aspx";
        }

        [UsedImplicitly]
        protected void Run(ClientPipelineArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            Item item = base.DeserializeItems(args.Parameters["items"])[0];
            if (SheerResponse.CheckModified())
            {
                string str = args.Parameters["fieldid"];
                if (string.IsNullOrEmpty(str))
                {
                    str = "__Tracking";
                }
                if (args.IsPostBack)
                {
                    if (args.HasResult)
                    {
                        using (new StatisticDisabler(StatisticDisablerState.ForItemsWithoutVersionOnly))
                        {
                            item.Editing.BeginEdit();
                            item[str] = args.Result;
                            item.Editing.EndEdit();
                        }
                        if (AjaxScriptManager.Current != null)
                        {
                            AjaxScriptManager.Current.Dispatch("analytics:trackingchanged");
                        }
                        else
                        {
                            Context.ClientPage.SendMessage(this, "analytics:trackingchanged");
                            Context.ClientPage.SendMessage(this, "item:refresh(id={0})".FormatWith(new object[] { item.ID.ToString() }));
                        }
                    }
                }
                else if (item.Appearance.ReadOnly)
                {
                    SheerResponse.Alert("You cannot edit the '{0}' item because it is protected.", new string[] { item.DisplayName });
                }
                else if (!item.Access.CanWrite())
                {
                    SheerResponse.Alert("You cannot edit this item because you do not have write access to it.", new string[0]);
                }
                else
                {
                    UrlString urlString = new UrlString(this.GetUrl());
                    urlString.Add("id", context.Items[0].ID.ToShortID().ToString());
                    UrlHandle handle = new UrlHandle();
                    handle["tracking"] = item[str];
                    handle.Add(urlString);
                    this.ShowDialog(urlString.ToString());
                    args.WaitForPostBack();
                }
            }
        }
    }
}
     

Step7.
I am on countryone site and I want to add a new goal to a page.
Is showing me just the goals from countryone folder.

OpenGoalCountry

This code was tested on Sitecore 8.1.

 

Configuring indexes in a multisite solution

In the previous blogpost I wrote about aliases and how to inherit sites from a base site.
Also for the lucene indexes is posible to do it.

We have a Sitecore solution with 3 country sites that have same structure.
(please see below picture)

Countries

We need to create elegant solution for creating indexes for every country.

First step is create base configuration, I create a config file (Sitecore.ContentSearch.Lucene.Index.ZZZConfiguration.config ) that I add into a “ZZZ” folder to be the last in configuration file.

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexTemplates hint="skip">
          <searchIndexTemplate id="$(1)" type="Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex,Sitecore.ContentSearch.LuceneProvider">
            <param desc="name">$(1)</param>
            <param desc="folder">$(1)</param>
            <!-- This initializes index property store. Id has to be set to the index id -->
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <strategies hint="list:AddStrategy">
              <!-- NOTE: order of these is controls the execution order -->
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/rebuildAfterFullPublish" />
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/remoteRebuild" />
            </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>$(2)</Database>
                <Root>$(3)</Root>
              </crawler>
            </locations>
            <configuration ref="contentSearch/configuration/defaultIndexConfiguration | contentSearch/configuration/DefaultIndexConfiguration | contentSearch/indexConfigurations/defaultLuceneIndexConfiguration">
              <documentBuilderType>Sitecore.ContentSearch.LuceneProvider.LuceneDocumentBuilder, Sitecore.ContentSearch.LuceneProvider</documentBuilderType>
              <IndexAllFields>true</IndexAllFields>
              <exclude hint="list:ExcludeTemplate">
                <patch:delete />
              </exclude>
                <include hint="list:IncludeTemplate">
                 <!--add here your templates --> 
              </include>
              <fields hint="raw:AddComputedIndexField">
                 <!--add here your computed index field --> 
              </fields>
 
             </configuration>
          </eventIndexTemplate>
        </indexTemplates>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>
    

Now we need to create index config file that inherit from above configuration

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
      <contentSearch>
         <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <!--searchj-->
        <indexes hint="list:AddIndex">
          <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country1" param2="web" param3="/sitecore/content/countryone" />
          <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country2" param2="web" param3="/sitecore/content/countrytwo" />
	  <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country3" param2="web" param3="/sitecore/content/countrythree" />
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
      </configuration>
   

 
You can see I replace $(1),$(2),$(3) from first config file with parameters from second config file.
These are indexes for web database, if we want to create also for master database we need to modify strategy section
Above is the result of our configuration:

Sitecoreindexes

Configuring Aliases in a multi site solution

On the last Sitecore solution I have worked I needed to add aliases for every site.

Default aliases are shared for all sites from the solution.

To acomplish requirements we create under the item  /sitecore/system/Aliases folders for every site.

SitecoreAliases

On site definition for every site we add a new property named alias

<site name=”countrytwo” patch:before=”site[@name=’website’]”
hostName=”countrytwo.sitecoredemo.com”
inherits=”sitecoremvc-base”
rootPath=”/sitecore/content/countrytwo”
startItem=”/”
dictionaryDomain=”{D8BC2E0C-36C5-4128-8F29-352B55E86676}”
language=”en”
alias=”countrytwo”
mvcArea=”countrytwo”

/>

We rewrite AliasResolver to map aliases to sites .

We need to rewrite the entire class Sitecore.Pipelines.HttpRequest.AliasResolver because the methods are private.

   
///<summary>
/// Custom Alias Resolver
/// </summary>


public class AliasResolver : HttpRequestProcessor
{
     ///<summary>
     /// Processes the specified args.
     /// </summary>
     /// <param name="args">The args.</param>
     public override void Process(HttpRequestArgs args)
     {
        Assert.ArgumentNotNull(args, "args");
        //check if aliases are active
        if (!Settings.AliasesActive)
        {
          Sitecore.Diagnostics.Log.Warn("Aliases are not active.",this);
          return;
         }
         Database database = Context.Database;
         if (database == null)
          {
            Sitecore.Diagnostics.Log.Warn("Context database is null",this);
            return;
          }

          if (database.Aliases.Exists(MainUtil.DecodeName('/' +                     Context.Site.Properties["alias"] + '/' + args.LocalPath)) &&                   !this.ProcessItem(args))
           {
              this.ProcessExternalUrl(args);
           }
       }

        ///<summary>
       /// Processes the external URL.
       /// </summary>
       /// <param name="args">The arguments.</param>
        private void ProcessExternalUrl(HttpRequestArgs args)
        {
          string targetUrl = Context.Database.Aliases.GetTargetUrl('/' +    Context.Site.Properties["alias"]+'/' +                                         args.LocalPath);
          if (targetUrl.Length > 0)
            {
              this.ProcessExternalUrl(targetUrl);
            }
         }

         ///<summary>
         /// Processes the external URL.
         /// </summary>
         /// <param name="path">The path.</param>
         private void ProcessExternalUrl(string path)
            {
              if (Context.Page.FilePath.Length > 0)
               {
                 return;
               }
                Context.Page.FilePath = path;
             }

          ///  <summary>
          /// Processes the item.
          /// </summary>
          /// <param name="args">The arguments.</param>
          /// <returns></returns>
          private bool ProcessItem(HttpRequestArgs args)
           {
             ID targetID = Context.Database.Aliases.GetTargetID(MainUtil.DecodeName('/'  + Context.Site.Properties["alias"]                     + '/' + args.LocalPath));
               if (!targetID.IsNull)
                {
                  Item item = args.GetItem(targetID);
                  if (item != null)
                   {
                    this.ProcessItem(args, item);
                   }
                   return true;
                  }
               return false;
             }

          ///<summary>
          /// Processes the item.
          /// </summary>
          /// <param name="args">The arguments.</param>
          /// <param name="target">The target.</param>
           private void ProcessItem(HttpRequestArgs args, Item target)
            {
              if (Context.Item == null)
              {
                 Context.Item = target;
               } 
                    }
       }

We replace default AliasResolver with new one, using a patch file:

   <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"     xmlns:set="http://www.sitecore.net/xmlconfig/set/">
      <sitecore>
         <pipelines>
          <httpRequestBegin>
             <processor type="Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel">
              <patch:attribute name="type">Namespace.AliasResolver,Assembly</patch:attribute>
            </processor>
           </httpRequestBegin>
          </pipelines>
      </sitecore>
  </configuration>   
  

Next blog will be about how to create lucene indexes in a multisite solution.