Pub - Professional Sitecore Development PDF
Pub - Professional Sitecore Development PDF
Introduction
Advertisements
Chapter 1
Introducing Sitecore
Sitecore is a complete ASP.NET development platform and web content
management system (CMS). Sitecore is the leading ASP.NET web CMS
available worldwide today. Its unique open architecture, diverse
capabilities, and extensibility make it the most advanced CMS on the
market. Sitecore developers generally agree that they can deliver more
value on their projects in less time using the Sitecore product suite than
using any other system.
Sitecore is a high-performance, scalable, extensible ASP.NET web CMS
that generates all output dynamically and uses the same components and
system architecture for both content and application pages. Sitecore does
not limit the markup you can generate or the technologies that you can
use, such as XHTML (eXtensible HyperText Markup Language), HTML5,
CSS Cascading Style Sheets (CSS), and Asynchronous JavaScript and
XML (AJAX).
The Sitecore CMS provides at least the following array of facilities for
managing complex and dynamic websites:
Flexible, hierarchical data storage
APIs and points of configuration and extension, including hooks into
the user interface, pipelines, event handlers, and much more
A layout engine that dynamically assembles and caches ASP.NET
control trees, making it easier to implement a consistent solution by
reusing code and content than an inconsistent solution by cutting and
pasting
The concept of devices, which enable different presentations of
individual content items under varying conditions
Security, including authentication, authorization, role, and profile
management based on ASP.NET membership providers
Workflow and separation of unpublished content from published
content
Visual comparison of differences between versions of field values
A media library for managing binary assets
A rules engine for browser-based configuration of dynamic logic
Optional modules for additional functionality, most importantly the
Digital Marketing System (DMS) described in Chapter 10
Developer tools such as the free Sitecore Rocks extension for
Microsoft Visual Studio
Sitecore keeps content and presentation separate until runtime, when it
merges the two based on the context of the user (their personal profile and
access rights), the request (the content item identified from the requested
URL), and potentially other criteria such as the type of device that
requested the page. Based on this information, the layout engine assembles
a hierarchy of presentation controls, and then determines whether to
execute each or retrieve output cached previously under equivalent
processing conditions.
You can think of Sitecore as providing an extension to ASP.NET itself,
including browser-based user interfaces, abstract data storage facilities,
complete application programming interfaces (APIs), and opportunities
for configuration, extension, and customization.
Logging In
To log in to Sitecore, access the URL /sitecore on a Sitecore instance in
one of the browsers supported by Sitecore (generally, a current version of
Microsoft Internet Explorer, Google Chrome, Mozilla Firefox, or Apple
Safari (see the Sitecore Installation Guide at http://bit.ly/pv7X3B for
information about supported browsers in your version of Sitecore). For
example, the URL of the login page for the instance of Sitecore that I used
while writing this book is http://sitecorebook/sitecore.
If you previously logged in with the Remember Me option, accessing /sitecore may not
take you to the Sitecore login page, instead taking you directly into a Sitecore user
interface. In this case, you can access the login page at /sitecore/login.
To select one of the Sitecore user interfaces, click Options. Figure 1.1
shows the Sitecore login page.
Figure 1.1
This book assumes that you are familiar with all three CMS user
interfaces available from the Sitecore login page:
The Page Editor (see Figure 1.2), for nontechnical content
contributors.
The Content Editor (see Figure 1.3), for more advanced content
managers.
The Sitecore desktop (see Figure 1.4), for administrators, advanced
content managers, and developers. The image shown in Figure 1.4
appeared after clicking the Sitecore button ⇒ Development Tools ⇒
Keyboard Map, which provides some context by opening the
Keyboard Map application.
The Sitecore desktop functions like a windowing operating system, but runs in a browser.
In this book, the term desktop generally refers to the Sitecore browser-based desktop
unless otherwise indicated, such with the phrase Windows desktop.
Figure 1.2
Figure 1.3
Figure 1.4
Many of the instructions in this book require that you use the Content
Editor. To launch the Content Editor, use a browser to access the Sitecore
login screen at /sitecore. For example, if the URL of the Sitecore
instance is http://sitecorebook, access http://sitecorebook/sitecore. Figure
1.1 shows the Sitecore login screen.
You can use the Content Editor as a standalone application, or you can
use the Content Editor within the Sitecore desktop. To choose between
these approaches, click Options on the Sitecore login screen. Login
options appear on the login screen as shown in Figure 1.5.
Figure 1.5
Enter your authentication credentials. To use the Content Editor as a
standalone application, double-click Content Editor. The Content Editor
appears as shown in Figure 1.6.
Figure 1.6
Alternatively, to use the Sitecore desktop, enter your authentication
credentials and double-click Desktop on the Sitecore login screen. The
Sitecore desktop appears as shown in Figure 1.7.
The photograph shown in Figure 1.7 is of a lighthouse at the Danish Trekroner Fort (see
http://bit.ly/ABmTge). Sitecore initially developed and continues to engineer much of the
CMS in Denmark. Sitecore desktop background images distributed with the CMS are
similar to the desktop background images provided with the Microsoft Windows
operating system, but are intended for use within the Sitecore browser-based desktop.
Figure 1.7
Click the Sitecore button in the lower-left corner of the Sitecore desktop.
The Sitecore menu appears as shown in Figure 1.8.
Figure 1.8
Click Content Editor. The Content Editor appears within the Sitecore
desktop as shown in Figure 1.9.
Figure 1.9
Embedded Applications
From within each of the Sitecore user interfaces, and especially from
within the Sitecore desktop, you can access additional Sitecore
applications. These applications include the following:
Marketing Center — Configure marketing programs and tracking
elements to help understand who is visiting the site, what brought
them there, and which programs and content are most engaging.
Media Library — The Media Library is just the Content Editor with
the Media Library tab selected, exposing a repository for binary assets
such as images and video.
I am not aware of any task that you can perform in the Media Library that you cannot
accomplish by navigating to the /sitecore/media library branch in the Content Editor.
Due to (arguably) better usability, some users may prefer to access the Media Library to
work with media items rather than the Content Editor.
I am not aware of any task that you can perform in the Template Manager that you
cannot achieve by navigating to the /sitecore/templates branch in the Content Editor.
Due to (arguably) better usability, some developers may prefer to access the Template
Manager to work with data templates rather than the Content Editor.
When possible, use Microsoft Visual Studio, especially with Sitecore Rocks, in favor of
the Developer Center.
Sitecore Components
Sitecore is an ASP.NET application that provides a layer between the
developer and the ASP.NET framework, including components such as
databases.
Follow Microsoft best practices for Internet Information Services (IIS) and ASP.NET
security, performance, and scalability, load testing, hardware requirements planning,
and other administrative considerations.
Sitecore Databases
Each Sitecore instance depends on some number of Microsoft SQL Server
or Oracle relational databases. You can install the database server on the
same machine as the web server. For production, you should use one or
more separate, dedicated database servers to host the Sitecore databases.
You can use the free Express versions of Microsoft SQL Server and Oracle in
development, test, and potentially additional non-production environments. Because you
write code against a Sitecore API layer that abstracts the underlying storage mechanism,
you can even use different database vendors in different environments, unless you write
code that interacts directly with the database.
Technically, the root subdirectory of the website (its document root) and each
subdirectory can expose an ASP.NET application, and each application can use a
separate application pool. Sitecore does not support applications in subdirectories.
As described further in this book, features including the Sitecore configuration factory
support Web.config include files. Web.config include files allow you to patch the actual
/web.config file. This book describes the Web.config file in relation to features that
support include files, but includes a leading slash and applies a style (/web.config)
when referring to the actual /web.config file itself. Web.config include files can only
apply to elements within the /configuration/sitecore section.
Data Subdirectory
Sitecore uses the subdirectory specified by the dataFolder variable in the
Web.config file to store data files such as its license, logs, and Lucene
search indexes.
Sitecore Rocks
Developers working with Visual Studio and the Sitecore ASP.NET CMS
should use the Sitecore Rocks (http://sitecorerocks.net) extension for
Visual Studio. Most Sitecore developers use Visual Studio and can benefit
greatly from this free tool from Sitecore.
Install Sitecore Rocks on the development workstations on which you install Visual
Studio.
Information Architecture
Introducing Information
Architecture
All web content management systems include two major components:
Facilities to define data structures that allow CMS users to enter site
content
Facilities to present that data in those structures as a website
This chapter focuses on the former component; Chapter 3, which
describes the Sitecore layout engine and data access APIs, focuses on the
latter.
You can think of information architecture as a model for the structure of
the data behind a web solution. Information architecture includes both
high-level structures — defining the relationships among managed sites,
their home pages, sections, applications, and pages, as well as other
features of the solution — and low-level details, defining individual page
types and the properties of individual data elements and other features
within those pages. The information architecture can describe security,
workflow, archiving, validation, and related requirements, and can even
specify the presentation components required to render specific types,
sections, pieces, and other aspects and groupings of content.
Information architecture may be the most critical component of a web
solution. You cannot implement an optimal solution without solid
information architecture, let alone enhance that solution over time. The
user interface of a website begins to look stale as time passes, but the
information architecture of that solution can have a longer life if you can
apply a new presentation layer to the existing data.
Because definitions for some Sitecore terms result in circular references
(for example, items depend on data templates, which depend on items,
which depend on data templates), the following list provides a quick
overview of key terminology explained in subsequent sections of this
chapter:
Item — An item is a data record, similar to an instance of a class in
object-oriented programming (defined using the class keyword in
C#).
Data template — A data template defines the structure of a type of
items, much like a class or structure in object-oriented programming.
Data template field — A data template consists of some number of
data template fields, which are similar to properties of a class or
members of a structure in object-oriented programming.
Standard value — Each data template can specify standard values for
each field defined in the template and any of its base templates, much
as constructors and other initialization code can set property values in
object-oriented programming.
Base template — Each data template can inherit from any number of
base data templates, much as a class can inherit from a base class and
implement interfaces in object-oriented programming.
Standard template — Most data templates inherit from this standard
data template, as all classes eventually inherit from the
System.Object class in .NET.
Sitecore facilitates hierarchical information architectures. Most
developers are familiar with relational databases, but most websites are
hierarchical — a home page contains sections, sections contain
subsections and pages, and subsections contain nested subsections and
pages. Hierarchical information architectures can assist in securing
sections and subsections of the site; you can use security inheritance to
deny anonymous users read access, or to grant write access for a CMS role
to an entire section or subsection.
Items in the information architecture have implicit relationships with
other items, such as the parent/child relationship and the preceding-sibling
and following-sibling relationships. Items also have explicit relationships
with other items, such as when an image field in a content item contains a
reference to a media item.
Sitecore uses the information architecture to determine the URLs of
content items. URLs include the name of the item preceded by the names
of its ancestors. For example, the default URL of the
/sitecore/content/home/section/subsection/page item is
/section/subsection/page.aspx relative to the
/sitecore/content/home item that represents the home page for the
default managed site.
Most Sitecore solutions use the information architecture to drive
navigation for the site. In such cases the information architecture typically
matches the visual structure of the website exactly. For example, the
children of the home item might represent sections that appear in a top
navigation component. When the user clicks an element in the top
navigation, taking the browser to that section, the items representing
subsections and pages within the clicked section could appear in the left
navigation. Other solutions use techniques such as faceted search, which
presents a default navigational structure based on content classification
characteristics along multiple dimensions, and allows visitors to navigate
in a variety of ways rather than using a single taxonomy, often through the
application of filters that eliminate elements in that navigational structure
that the visitor deems irrelevant.
Sitecore Items
Sitecore items represent individual resources within the CMS. Items can
represent any type of data, such as a page, section, paragraph, or metadata
attribute. Each item contains a number of properties common to all
languages and versions of the item, such as its name and ID. In addition to
content elements, Sitecore uses item to manage system and configuration
components.
Make item names unique among siblings. Sitecore does not require this, but provides a
validator that you can use to enforce this rule.
Each item can contain any number of field values that can vary by
language and by version within each language. Each item exists within a
hierarchy of items in a Sitecore database. The path of an item identifies its
location within the hierarchy. Sitecore assigns a globally unique identifier
(GUID, or just ID) to each item.
Sitecore does not differentiate content from metadata or control data.
Each item can contain fields for content, metadata, system data, and
potentially other types of data. You can use items to implement metadata
and other taxonomies or to manage any data that you can represent in a
hierarchy.
Like files, items contain data, but like subdirectories, items can contain
other items. This means that you do not have to think about whether
something is a subdirectory or a file when you create it; in Sitecore, you
create an item regardless of whether you need to store data or contain
other items. That item might not have any children today (making it like a
file), but it could have children in the future (making it like a
subdirectory). Either way, each item can contain field values and other
items. If you need to change the fields that appear in an item, you can add
fields to the data template associated with the item, or update the item to
use a different data template.
You can use the Sitecode.Data.Items.CustomItem abstract class as a
base class for your classes that represent different types of items. For
more information about this approach, see Chapter 3. Many solutions
benefit from the implementation of .NET classes to represent various
types of Sitecore items. You can use the
Sitecore.Data.Items.CustomItemBase class as a base class for your
classes that represent different types of items. Sitecore Rocks has features
that you can use to generate classes from data templates, or you can use
either the CustomItemGenerator (http://bit.ly/xzjzP3) Sitecore Shared
Source project or the CodeGen (http://bit.ly/w8ppkd) Sitecore Shared
Source project for this purpose.
For more information about many of the concepts described in the
remainder of this section, see The Sitecore Guide to Reusing and Sharing
Data (http://bit.ly/pjNlqG).
Sitecore does not store different values for each language in fields that you mark as
shared.
I recommend that you register languages before you use them. That way, you can iterate
the language definition items even if no versions exists in those languages in your
content items, and you can retrieve metadata about languages consistently from those
definition items.
Having many versions in any number of languages for an item can reduce
performance, especially when you work with items that contain a large number of
fields, or fields that contain a large number of links. For information about a
solution that uses a scheduled process to remove old versions of items, see my blog
post at http://bit.ly/kq4Jmp.
Figure 2.2
You may not find the API that removes a version where you expect it.
The following code removes the oldest version of the context item:
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
item.Versions[item.Versions.GetVersionNumbers()
[0]].Versions.RemoveVersion();
Many examples in this book use the context item exposed by the Sitecore.Context.Item
static property. I used this shortcut to avoid repeatedly explaining and reproducing code
to retrieve a database and an item within that database. Using the context item should
work, but does not always provide the most logical example. You can apply any
technique demonstrated for the context item to any item (any instance of the
Sitecore.Data.Items.Item class).
Instead of hard-coding field names or IDs, which can increase maintenance effort, create
static classes like the Sitecore.FieldIDs class with properties to expose the IDs of your
data template fields. For the same reason, you can create classes like the
Sitecore.ItemIDs class to store the IDs of specific items, and like the
Sitecore.TemplateIDs class to store the IDs of your data templates.
Item Properties
To control the data type of an item, how that item appears in the user
interface, how you can refer to that item in code, and the item's
relationships with other items in the database, each item defines all of the
properties in the following list:
Name — The name of the item, which is not necessarily unique, even
among its siblings.
Key — The lowercase of the item name, which is not necessarily
unique, event among siblings.
Path — The names of the item and its ancestors in document order,
separated by the slash (/) character. (Sitecore does not store the path
in the item, but constructs the path dynamically based on its location
in the content tree, from the top of the hierarchy down.)
Data Template — The data template, or structure definition,
associated with the item. (A property of the item contains the ID of its
data template.)
ID — The unique identifier for the item. (An item has the same ID in
the Master database and all publishing target databases, and may also
exist in the Core database with the same ID.)
In addition, most items can define values for numerous additional fields
defined by the standard data template from which almost all other data
templates inherit.
Sitecore item names have two fundamental purposes: to identify
Sitecore items within the item hierarchy, and to provide default URLs for
content items. These purposes are sometimes at odds: you might not want
space characters in URLs, but whitespace helps users identify items in the
CMS. One solution to this dilemma is to use the __Display Name
(Sitecore.FieldIDs.DisplayName) field defined in the Appearance
section of the standard template. If that field has a value, Sitecore user
interfaces show the display name of the item; otherwise the name of the
item appears. Display names also allow different values for different
languages.
To set the display name of an item, do the following:
1. Select the item in the Content Editor.
2. Click the Home tab, and then click Display Name in the Rename
group. A prompt appears.
3. Enter the new display name for the item, and then click OK. The
prompt disappears and you return to the Content Editor.
Sitecore provides for item name validation using the following settings
in the Web.config file:
Remember that by the conventions used in this book, Web.config can refer to Web.config
include files, where /web.config refers to the actual /web.config file. For more
information about Web.config include files, see my blog post at http://bit.ly/j5Ms7C.
Item Structure
Sitecore can represent items in a number of formats, including:
Browser-based user interfaces such as the Content Editor
Native database storage
Objects in memory (the Sitecore.Data.Items.Item class and its
relatives)
XML containing all field values in all versions in all languages, with
or without descendant items
XML containing only the structure of items, including field
definitions but not including language information, versions, or field
values, as used by XSL (eXtensible Style Sheet) renderings
Serialization files used for source control of items in databases as
well as exchange with other Sitecore instances
Package entries used to exchange items in databases with other
Sitecore instances
You can use some of these formats to export data. For example, to access
the XML representation of an item from .NET, you can use the
GetOuterXml() method of the Sitecore.Data.Items.Item class that
represents an item. The first parameter to this method specifies whether to
include descendants of the item in that XML. To access the XML
representation of items available to XSL renderings, pass a
Sitecore.Data.Items.Item.Item object to the
Sitecore.Configuration.Factory.CreateItemNavigator() static
method and retrieve the OuterXml property of the
Sitecore.Xml.XPath.ItemNavigator object that it returns. From an XSL
rendering you can use an <xsl:copy-of> element to write the XML
representation of an item and its descendants to the output stream, and
then view the source of the rendered page in a browser. For example, to
render the XML representation of the context item visible to XSL, you can
use the following code in an XSL rendering:
<xsl:copy-of select="$sc_currentitem" />
Remember that Sitecore APIs automatically apply access rights for the context user. Items
to which the context user does not have read access do not appear in either object or
XML representations. If code or a requested URL attempts to access an item to which the
context user does not have read access, Sitecore returns an error message or behaves as
if that item does not exist.
For more information about XSL renderings and the layout engine, see
Chapter 3. For an example of using a layout to access the XML
representation of items using a browser, see my blog post at
http://bit.ly/p0q9Ge.
If you render XML over HTTP, remember to set the
System.Web.HttpContext.Current.Response.ContentType property to text/xml so that
you can easily use a browser to view that XML. Of the techniques that you can use to
format items, handlers as defined within the /configuration/sitecore/customHandlers
element of the Web.config file may be most appropriate for this purpose. Handlers are
more efficient than Web Forms.
Definition Items
Definition items specify the properties of system components such as
devices renderings used by the layout engine, and even components such
as data templates, sections, and fields. Definition items use the same
technical infrastructure as content items, which the layout engine renders
as pages of managed sites, but definition items do not have URLs and do
not contain layout details to inform the layout engine how to render those
items. For example, when you register a new language, Sitecore creates a
language definition item to store properties of that language. A definition
item represents a logical construct in the system, and its fields define
properties of that construct.
Because of their simplicity and versatility, Sitecore uses items to
represent every type of information it can. Sitecore uses items to represent
or define:
Folders and content, including Really Simple Syndication (RSS) feeds
Media folders and media items
Presentation components, including devices, layouts, renderings, and
placeholder settings
URL alias definitions
Term translations
Publishing target database definitions
Language definitions
Configuration settings, including layout presets, security presets, and
various other types of information not specifically mentioned in this
list
Rules engine configuration, including conditional rendering rules
Data validation features
Child item sorting rule definitions
Scheduled task details
Data template and standard values definitions
Interface for editing user profiles
Sitecore user interface components, including the data template field
types
Workflow processes definitions
Instead of using items to store information about items in workflows, Sitecore uses items
only to define workflow processes, and stores information about items in those workflows
directly to a relational database. Similarly, while the CMS stores security access rules in
items, Sitecore uses security providers to manage most attributes of users and roles, and
the default providers store that information directly to a relational database.
Insert Options
Insert options control the types of items that users can insert beneath
existing items. Insert options can include data templates, branch
templates, and command templates. You can use insert options to restrict
the information architecture and to control what types of items users can
create beneath existing items, but more importantly, you can apply insert
options in standard values to define insert options for all items of a
specific type.
Whenever possible, instead of defining insert options in individual items, define insert
options in the standard values of your data templates.
Branch templates allow users to insert predefined structures consisting
of some number of items. When you use a branch template to create an
item, Sitecore copies all descendants of the branch template definition
item, and then expands tokens such as $name not just in the standard
values for the data templates behind those items, but in the names of those
items as well. For more information about tokens such as $name, see the
section of this chapter about standard values.
Along with standard values, branch templates replace masters, which Sitecore used in
versions prior to CMS to 6.0. Earlier versions used masters to constructor new items and
hierarchies of items and to define insert options. Branch templates support features
beyond those previously supported by masters. For example, a branch template
definition item can have more than one child, meaning that you can implement a branch
template to insert multiple sibling items simultaneously rather than inserting a single root
item as required by masters.
To control access to the Insert from Template option that appears with
insert options in Sitecore user interfaces, configure access rights for the
/sitecore/content/Applications/Content
Editor/Menues/New/Insert from Template [sic] item in the Core
database. You cannot use the uiGetMasters pipeline to control access to
the Insert from Template option.
Insert options rules use the rules engine to determine insert options
dynamically. In the context of insert options, one benefit of insert options
rules is that you can define insert options dynamically through a browser-
based user interface instead of assigning insert options declaratively or
determining insert options programmatically with code in uiGetMasters
pipeline processors. You can define global insert options rules under the
/sitecore/system/Settings/Rules/Insert Options/Rules item
using the System/Rules/Insert Options Rule data template. A
processor in the uiGetMasters pipeline invokes insert options rules while
determining effective insert options for an item.
Insert rules (not to be confused with insert options rules described in the
previous paragraph) also determine insert options dynamically. Unlike
insert options rules, which apply when determining effective insert options
for all items, insert rules apply only to the individual items in which you
select them. Insert rules depend on definition items under the
/sitecore/system/Settings/Insert Rules item that use the based
System/Branches/Insert Rule data template. Configure insert rules
where you declare insert options (click the Configure tab in the Content
Editor, and then click Assign in the Insert Options group). For more
information about insert options, see my blog post at http://bit.ly/Hc4hta.
Sorting Items
In addition to sorting items manually, you can select a rule for sorting the
children of an item, sometimes called the subitem sorting rule (although
sometimes the term subitems includes all descendants).
For each item, Sitecore stores a numeric sort order value in the
__Sortorder field (Sitecore.FieldIDs.Sortorder) defined in the
Appearance section of the standard template. Sitecore user interfaces,
developer APIs, and XML representations order lists of items by their sort
order values. When you invoke commands in the user interface to sort
items, Sitecore calculates and applies new sort order values for the
affected items (and potentially their siblings). In some cases, such as to
control the visual order of sections defined in a data template and the base
templates in its inheritance chain, you may need to view standard fields
and set the value of the sort order field manually.
If you do not manually sort the children of an item, Sitecore
automatically applies the sorting rule specified in the __Subitems
sorting field. The default sorting rule sorts items by name, but you can
select alternative child sorting rules, and even implement your own child
sorting rules for each item.
To select a child sorting rule for an item, do the following:
1. Click the Home tab in the Content Editor. Click the square icon next
to the group name Sorting in the Sorting group. The Set the Sorting for
the Subitems dialog appears as shown in Figure 2.3.
2. Select the desired child sorting rule in the Sorting field in the Set
the Sorting for the Subitems dialog, and then click OK. The Set the
Sorting for the Subitems dialog disappears, and you return to the
Content Editor.
Remember to publish children, siblings, and parents after operations that change the sort
order values of items, or when the order of items in the content delivery environment
erroneously differs from the order of items in the content management environment.
Figure 2.3
For an example that implements the
System.Collections.Generic.IComparer<Sitecore.Data.Items.Item
> interface to sort items by a field value, and registers that comparer as a
child sorting rule, see the FieldValueComparer (http://bit.ly/yuboXs)
Sitecore Shared Source project.
If you use .NET 3.5 or later, you can LINQ (Language-Integrated Query,
http://bit.ly/woQJ2a) to sort items. In your code, add a using directive for
the System.Linq namespace:
using System.Linq;
Then you can add .OrderBy() and .OrderByDescending() clauses to
various types of lists. For example, you can sort by a property of the
Sitecore.Data.Items.Item class, such as the display names of the
children of the context item:
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
foreach(Sitecore.Data.Items.Item child in
item.Children.OrderBy(x => x.DisplayName))
{
// process child
}
You can also sort items by the value of a field:
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
foreach(Sitecore.Data.Items.Item child in
item.Children.OrderByDescending(x => x["FieldName"]))
{
// process child
}
For more information about sorting items, including how to sort with
XSL and an XSL extension library for sorting, see my blog posts at
http://bit.ly/ndc9no and http://bit.ly/oJTFXf. Read the comments on those
blog posts for some warnings about sorting in multilingual Sitecore
solutions.
Managing ItemURLs
While Sitecore provides default logic to determine and resolve URLs for
items, you may need to implement custom URLs for your solution, such as
to add query string parameters or resolve URLs with custom logic. There
are two major considerations for managing URLs with Sitecore:
Configuring the solution to generate URLs that meet your
requirements
Configuring the solution to correctly map those URLs to the
corresponding items in the database
The first component typically involves the link provider specified by the
type attribute of the
/configuration/sitecore/linkManager/providers/add element
named sitecore in the Web.config file. To override the link provider,
create a class that inherits from the class specified by the type attribute of
this <add> element, and update that attribute to reference your class. The
second consideration typically involves a processor in the
httpRequestBegin pipeline defined in the Web.config file that, among
other things, parses URLs to determine the context item. You can add
processors to and override existing processors in this pipeline to set the
Sitecore.Context.Item static property as required for your solution.
For more information about managing links with Sitecore, see The
Sitecore Guide to Dynamic Links (http://bit.ly/ri6Oww).
Attributes of the link provider do not affect the URLs of Sitecore media items.
For an example that overrides the default link provider with the
following features, see the LinkProvider (http://bit.ly/AeRE0O) Sitecore
Shared Source project:
Where one exists, use the alias for an item instead of its path.
Include the trailing slash (/) character in URLs when possible.
Convert all characters in the path part of the URL to lowercase.
Include the language in URLs for some sites, but not others.
To determine the friendly URL of a content item, call the
Sitecore.Links.LinkManager.GetItemUrl() static method. For
example, to access the URL of the context item:
Publishing expands clones in the Master database to create actual items in publishing
target databases. The IsClone() method of the Sitecore.Data.Items.Item class, which
you can use to determine whether an item in the Master database is a clone, does not
return true for items in publishing target databases.
Alias Items
You can use aliases to provide additional URLs for content items. An alias
URL is typically shorter than the default friendly URL for an item, and
often used for print campaigns or other forms of marketing. To create or
manage aliases for an item in the Content Editor, click the Presentation
tab, and then click Aliases in the URL group.
Aliases involve definition items under the /sitecore/system/Aliases
item that use the System/Alias data template. If a requested URL
matches the path to an alias definition item, the AliasResolver processor
in the httpRequestBegin pipeline sets the context item to the item
specified by the Linked item field in the Data section of that alias
definition item.
Aliases support nesting. You can create the
/sitecore/system/Aliases/Section item using the Common/Folder
data template, and the /sitecore/system/Aliases/Section/Page item
using the System/Alias data template to define the alias URL
/Section/Page.aspx for an item elsewhere in the content tree.
If you do not use aliases, you can disable aliases by setting the
AliasesActive setting in the Web.config file to false, or by removing
the AliasResolver processor from the httpRequestBegin pipeline.
Wildcard Items
Sitecore wildcard items match all HTTP requests that do not match the
names of any siblings of the wildcard definition item. A wildcard is an
item with a single asterisk (*) as the only character in its name. Otherwise,
wildcard items are just like any other item. You can apply security, layout
details, workflow, and other features to wildcard items. You can use them
for various purposes, most commonly to integrate data from external
systems, in which case the part of the URL matched by the wildcard
typically corresponds to an identifier in the external system.
For example, if the /products item contains a wildcard item
(/products/*) and no other children, Sitecore sets the context item to
/products/* for any URL that would otherwise correspond to a child of
the /products item, such as /products/ProductID.aspx. Presentation
components specified for the wildcard item parse the requested URL (in
the Sitecore.Context.RawUrl static property) to determine the
requested ProductID, and render information about that product from the
external system. If needed, wildcards support nesting, such as
/Products/*/* to match URLs such as
/Products/Category/ProductID.aspx. If multiple presentation
components in a page depend on the ProductID, the first presentation
control to parse the URL, or preferably a custom processor in the
httpRequestBegin pipeline, can store the product identifier in the
visitor's ASP.NET session, in the Sitecore.Context.Items static
collection, or elsewhere for subsequent presentation components to access.
If you use the Sitecore.Context.Items static collection, be sure to use a key that Sitecore
will never use, and use programming facilities such as constants to avoid hard-coding
that key in multiple components.
Sitecore automatically sets the context item when the requested URL
matches only the wildcard definition item, but your presentation
components must generate links using appropriate URLs, such as to
contain the product ID instead of the asterisk (*) character. In other words,
you have to generate URLs that trigger the wildcards even though no items
by those names exist at those paths in the Sitecore database.
For more information about wildcards, see my blog post at
http://bit.ly/p1C8RD.
Many CMS products use the term template to describe presentation components. Some
CMS products use the term template for both data capture and presentation components.
Sitecore uses it only for data capture components, and uses terms such as layout, layout
details, and renderings to describe presentation components.
To edit the data template associated with an item, select the item in the Content Editor,
click the Configure tab, and then click Edit in the Template group.
Figure 2.4
Data Template Sections
A data template consists of zero or more data template sections, which
group the fields defined by the data template. A definition item for a data
template can contain any number of children that represent data template
sections, each section contains any number of fields. Data template
sections simply collect and order fields for the following purposes:
To group fields logically for data entry
To make it easier for users to locate fields in items
To avoid presenting a monolithic data entry form for CMS users
To group fields for reuse by other data templates, such as base
template with no items based directly on that base template
Sort the definition items for fields that CMS users access most frequently to the top of
each section, and sort the definition items for sections that users access most frequently
to the top of each data template.
When a data template and one or more of its base templates contain a
section by the same name, Sitecore user interfaces show a single section
containing all of the fields defined by the data template and in all sections
of its base templates that define sections by that name.
Base templates are simply data templates inherited by other data templates.
In some cases, the names of data template fields appear in code. You
may want to apply a naming convention for data template fields, such as to
exclude whitespace characters. In such cases, apply titles to data template
fields for greater usability.
The definition item for the standard values of data templates is simply an item based on
that data template stored as a child of the definition item for the data template, where the
name of that child is __Standard Values.
Analytics
The field types in the Analytics category support features of the Customer
Engagement Platform (CEP) provided by the Digital Marketing System
(DMS). This book does not describe these field types because you should
not use them in your own data templates.
Simple Types
The field types in the Simple Types category implement typical data entry
components such as Checkbox, Date, Datetime, Image, and File, Integer,
Multi-Line Text, Rich Text (HTML), and Single-Line Text.
The Image field type lets you select an image from the media library; the File field type
lets you select any file, such as a .pdf.
Sitecore stores values for most of these field types as simple text, using
the ISO (International Organization for Standardization) format
yyyyMMddTHHmmss for dates, and XML elements for images and files. For
an explanation of the characters in date format strings, see
http://bit.ly/Ajmy6f.
Depending on how you access field values, they may contain XML entities in place of
special characters, such as & in place of an ampersand (&) character.
List Types
Most of the field types in the List Types category let the user select one or
more items, while the Name Lookup Value List and Name Value List types
allow the user to enter key/value pairs. With a Name Value List, the CMS
user enters both keys and values. With a Name Lookup Value List, the
CMS user enters keys and selects an item from a drop-down list to
associate with each of those keys.
The Droplist and Grouped Droplist field types allow the user to select a
single item and store the name of that item. Droplist allows the user to
select a child of the item specified by the Source property of the field;
Grouped Droplist allows the user to select a grandchild of the Source item,
where the children of that source item represent categories containing
those items.
To avoid weak references, use field types that store IDs rather than names. For example,
use the Droplink field type, which stores the ID of the selected item, rather than the
Droplist field type, which stores only its name. Whenever you present data to a user,
include item paths instead of or in addition to IDs.
The Grouped Droplink field type in the List Types category, as well as
the Droplink and Droptree field types in the Link Types category that
follows, allow the user to select an item. Sitecore stores the ID of the
selected item as the value of the field.
The Checklist, Multilist, Treelist, and TreelistEx field types allow the
user to select zero or more items. Sitecore stores a list containing the IDs
of those items separated by pipe (|) characters.
Of the field types that allow the user to select more than one item, the TreelistEx field type
performs best and has as wide a range of capabilities as any other field type.
Link Types
The Link Types category of contains field types that can store a reference
to a single Sitecore item, a single external URL, or another type of link
such as an anchor within the page or an email address.
The Droplink field type allows the user to select a single item from a
drop-down list, and stores the ID of that item.
The Droptree field type allows the user to select a single item from a
tree structure, and stores the ID of that item.
The General Link field type allows the user to specify an internal,
external, JavaScript, anchor, or email address, and stores that value and
other properties of that link as an XML element.
Sitecore clones use the Version Link field type, which stores a reference
to a database, item ID, language, and version number in a proprietary
format.
Developer Types
The Developer Types category contains field types intended for Sitecore
developers.
The Icon field type allows the user to select an image from Sitecore's
icon library, and stores that value as a relative path.
Sitecore provides an extensive icon library in the /sitecore/shell/Themes/Standard
subdirectory under the document root of the IIS website hosting the instance. You can use
these images royalty-free on the sites that you manage.
System Types
Other than the File Drop Area and possibly Rules field types, the field
types in the System Types category are primarily for the Sitecore
application itself, and not intended for your data templates. You can use
these field types in your own data templates, but their details are beyond
the scope of this book.
The File Drop Area field type uses Web-Based Distributed Authoring
and Versioning (WebDAV — see http://www.webdav.org) to associate
media with content items.
The Rules field type lets you use the rules engine in custom processing
contexts.
Deprecated Types
Sitecore includes the field types in the Deprecated category for internal
use, but does not provide technical support for their use in your solutions.
The IFrame field type can often provide the same functionality as a custom field type, and
presents less of a learning curve for CMS developers.
Publishing operations that include a version of an item include all values in shared fields
and fields of the published language that you do not version, regardless of the workflow
state or publishing restrictions associated with other versions of that item.
The Reset Blank property in each data template field controls whether
Sitecore resets that field to its standard value when a user enters an empty
string in that field. If you do not check the Reset Blank checkbox (as by
default), Sitecore stores an empty string in the field when the user clears
the value of that field. If the Rest Blank property is checked, Sitecore
instead resets the field to its standard value.
Standard Values
Standard values define field values that apply to all items based on a data
template that do not override those values. All items based on a data
template automatically contain its standard values, but each item can
override standard values for individual fields.
You can create a standard values item for each data template. The
standard values item for a data template is just an item based on that data
template, stored as a child of the data template definition item, with the
name __Standard Values.
To create or edit the standard values item for a data template, do the
following:
1. Select the data template in the Content Editor or Template Manager.
2. Click the Options tab, and then click Standard Values in the
Template group.
Standard values items inherit standard values defined in base templates,
recursively. For example, if template B inherits from template A, and
template A defines a standard value for a field, items based on template B
share that standard value for that field, unless those items or standard
values for B override the standard value defined for that field by Template
A. If A inherits from another template, the standard values for that
template apply to A and hence B and any items associated with B.
Just as clones do not inherit the value of the __Source
(Sitecore.FieldIDs.VersionLink) field defined in the Advanced
section of the standard template from the cloned item, items do not inherit
the value of the __Source field from the standard values of the data
template associated with those items. Standard values apply to all other
fields, but item creation and save operations often override standard
values for the same fields that Sitecore resets for clones (previously listed
in Table 2.1).
Always define at least layout details (see Chapter 3), insert options, and
initial workflow (see Chapter 9) in the standard values for each data
template. If you need to override standard values for a large number of
items, you can create a data template that inherits from the existing
template, apply alternate standard values for that inheriting data template,
and associate those items with that inheriting template.
Set the icon for a data template in the data template itself, not in its standard values.
When you create an item, Sitecore expands the following tokens in the
standard values for the data template, resulting in field values in the item
that override the standard values for those fields:
$name — The response from the user to the prompt to name the new
item
$id — The ID of the new item
$parentid — The ID of the parent of the new item
$parentname — The name of the parent of the new item
$date — The system date in yyyyMMdd format
$time — The system time in HHmmss format
$now — The system date and time in yyyyMMddTHHmmss format
You can always determine the values for these properties of the item at
runtime, but you may want to use these tokens to store the values at
creation time, in case the user moves or otherwise changes the data. For
example, the __Created (Sitecore.FieldIDs.Created) field defined in
the Statistics section of the standard template stores the creation date and
time for each item. Your presentation code can use this field, for example
as the release date of a news article, but the user cannot easily change its
value. If you create a Datetime field in your data template, and set its
standard value to $now, Sitecore will set that field as it sets the __Created
field defined in the standard template. Unlike the __Created field that
most users cannot update, CMS users can subsequently change the value
of your Datetime field like any other field. Regarding the $name token,
you may want to store the name originally entered by the user, perhaps
using the display name property of the item, in case the user or the system
subsequently changes the name of that item.
To add your own expanding tokens for use in standard values, do the
following:
1. Create a class that inherits from the class specified by the
MasterVariablesReplacer setting in the Web.config file in your
Visual Studio project.
2. Override the Replace() and ReplaceField() methods to call the
corresponding methods in the base class and then perform your
replacements.
3. Update the MasterVariablesReplacer setting in the Web.config
file to specify the signature of your class.
If the value for a field in a version of an item is null, Sitecore retrieves
the standard value for that field. In this context, Sitecore differentiates
between null (equivalent to a missing row in the database) and an empty
string. An empty string is a value like any other. A null value specifically
indicates that a field should contain its standard value.
To reset a field to its standard value, first select the item containing the
field in the Content Editor.
For clones, these operations reset the field to the current value in the cloned item.
To reset any other field to the standard value defined for the item's data
template or by the cloned item, follow these steps:
1. If the standard template defines the field, select the View tab in the
Content Editor, and then select the Standard Fields option in the View
group.
If you show standard fields, remember to hide them afterward to improve performance
and usability, as well as to make an inadvertent error in one of those fields less likely.
2. Click the Versions tab and then click Reset in the Fields group. The
Reset Fields dialog appears as shown in Figure 2.5. The fields left side
of this dialog shows the current values of fields in the item; the right
side shows the standard values for those fields. If you elected to show
the fields defined in the standard template, they appear in the Reset
Fields dialog.
If you reset a field to its standard value, and that standard value contains a token such
as $name, the value of the field will contain that token rather than the value expanded
when you originally created the item
3. Check the checkboxes for the fields to reset in the Reset Fields
dialog, and then click Reset. The Reset Fields dialog disappears and
you return to the Content Editor.
4. If the standard template defines the field, select the View tab, and
then clear the Standard Fields checkbox in the View group.
To override the logic that Sitecore uses to determine standard values, override the class
specified by the type attribute of the
/configuration/sitecore/standardValues/provider/add element named sitecore in the
Web.config file.
Figure 2.5
if (title.ContainsStandardValue)
{
// the context item contains the standard value for the
field named Title.
}
Avoid circular template inheritance. A data template should never inherit directly or
indirectly from itself.
If a data template inherits from two base templates that define different
standard values for a field inherited from a common base template, the
standard value for that field in the template that inherits from those two
base templates may contain either value.
Not all fields defined by the standard template logically apply to all items in which they
appear. For example, layout details typically apply only to items under the home item of
one of the managed sites, but you can apply layout details to any item. It is your
responsibility to use the fields defined by the standard template correctly.
Technically the standard template does not define any fields. Instead it
specifies a number of base templates, each of which defines a different
section that contains several fields. These base templates inherit from the
null template.
The following may be confusing and irrelevant, or it may be useful and
interesting. Sitecore uses items based on data templates to define data
templates and their components. A data template definition is a hierarchy
of items rooted at a template definition item, which may contain a
standard values item based on the data template as well as some number of
section definition items, each containing field definition items. This
means that Sitecore uses data templates to define the structure of
definition items for data templates, section definition items, and field
definition items. As mentioned previously in this section, these data
templates do not inherit from the standard template or the null template,
but only from a subset of the base templates used by the standard template
that are useful for these types of definition items. Additionally, the
standard template does not inherit from itself.
To specify that a data template does not inherit from the standard
template or any other data template, do the following:
1. Select the definition item for the data template in the Content Editor
or Template Manager, and then select the Content tab.
2. Select the View tab, and then check the Raw Values checkbox in the
View group.
For more information about validation, see The Sitecore Data Definition
Reference (http://bit.ly/nmGuiB), The Sitecore Client Configuration
Cookbook (http://bit.ly/qS8Dc1), and my blog post at http://bit.ly/pxabIE,
which links to a number of resources that include sample validators.
Managing Multilingual Solutions
Sitecore lets you translate your managed sites into any number of
languages for any number of regions and cultures. Your site visitors from
multiple regions and cultures often speak a single language with various
distinctions. You can vary content within a single language to present
specific variations of content to visitors from specific regions and
cultures. Specifically, you can translate each field of each item for any
number of language and region/culture combinations, and present content
from one or more language and region/culture combinations on each page
according to your requirements.
Because the Sitecore user interfaces are components of a Sitecore
solution, they support internationalization just as your solution supports
internationalization. To select a language to display in CMS user
interfaces, on the Sitecore login screen, client Options to display the
Options panel, and then select a language from the User Interface
Language drop-down list.
You may prefer to leave the default English language alone and register new English
languages for other cultures as described previously in this chapter.
If you implement multiple languages, you should always let the user
select from the available content languages to override the current context
language.
Figure 2.7
Determining the Context Language
The LanguageResolver processor in the httpRequestBegin pipeline
determines the context language (the Sitecore.Context.Language static
property) for the duration of each request. Subsequently, Sitecore accesses
versions of items in that language by default. The
Sitecore.Context.Language provides a value even before the layout
engine invokes the httpRequestBegin pipeline for the HTTP request.
Under some conditions, the value of the Sitecore.Context.Language
static property differs before and after invocation of the
LanguageResolver processor.
Within Sitecore CMS user interfaces such as the desktop and the Content Editor, the
context language is the CMS client language, and the content language (the
Sitecore.Context.ContentLanguage static property, also called the current language in
this book) is the language of content edited within that user interface.
A URL can specify the context language in at least the following ways,
where that specification matches the name of a language definition item
under the /sitecore/system/Languages item in the context database:
From the sc_lang query string parameter, such as sc_lang=en for the
default region-neutral English language
From the path, such as /en/section/page.aspx for the default
English
From the language associated with the context site (the language
attribute of the corresponding
/configuration/sitecore/sites/site element in the Web.config
file) triggered by the requested URL
If the requested URL does not specify a language using a the sc_lang
query string parameter or the first step in the path, and the language
attribute of the /configuration/sitecore/sites/site element in the
Web.config that represents the context site does not specify a value for the
language attribute, Sitecore sets the context language to the value
specified by the DefaultLanguage setting in the Web.config file.
You can configure multiple managed sites with different values for the
hostName and language attributes of the
/configuration/sitecore/sites/site elements in the Web.config file.
If you do this, set the languageEmbedding attribute of the
/configuration/sitecore/linkManager/providers/add element
named sitecore in the Web.config file to false to prevent Sitecore from
ever including the language in URLs. Otherwise, set the value of that
languageEmbedding attribute to always to prevent Sitecore from
generating multiple URLs for a single item (with and without the language
in the path or query string). To allow the user to select a language, you
must provide links or other features in the page that trigger the appropriate
URLs for those languages.
Sitecore can use a cookie to store the user's language selection. For
example, if the URL of an incoming HTTP request specifies a language in
the path or query string, Sitecore sets that language as the context
language, and issues a cookie to the client to store that language selection
so that links to other pages on the site do not need to indicate the language.
You can use additional techniques to determine the user's preferred
language, typically in a pipeline processor to precede, replace, or follow
the default LanguageResolver process in the httpRequestBegin pipeline.
For example, you can do the following:
Evaluate the HTTP_ACCEPT_LANGUAGE HTTP header for preferred
languages.
Evaluate the language preference in the profile of a known user.
For more information about how Sitecore determines the context
language, including an example pipeline processor that overrides that
logic, see my blog post at http://bit.ly/qOV7sg. For an example of a web
control that links to all languages that contain a version of an item, see my
blog post at http://bit.ly/omG5Fd. For more information about web
controls, see Chapter 3.
Managing Media
Use the Sitecore media library to manage binary media, including images,
PDFs and other files. Media items are like any other items based on data
templates. You can access the media library that contains media items by
clicking the Media Library tab at the bottom of the Content Editor, by
clicking the Media Library command on the Sitecore menu in the desktop,
or by navigating to the /sitecore/media library item in the Content
Editor. The Media Library application is the Content Editor application
with the content tree rooted at the /sitecore/media library item, where
Sitecore manages media. When you upload a file into the media library,
Sitecore creates a media item with fields containing metadata about that
file.
By default, Sitecore stores the binary components of media library items
in a database using the field named Blob in the File section of the media
item. Sitecore developers refer to such media items as database media.
Alternatively, you can configure Sitecore to store the binary components
of media items on the filesystem. Sitecore developers refer to such media
items as file media. In the case of file media, Sitecore stores the binary
component of the media item in the file specified in the File Path field in
the File section of the media item.
Sitecore uses media items to represent both database media and file media. File media
that CMS users manage and reference in content differ from files on the file system that
developers manage and reference from code components.
In some cases, such as that of very large binary assets, Sitecore stores
media items as file media automatically. Because Sitecore advises against
the use of file media in favor of database media, this book does not
describe file media.
When you upload a .zip file into the media library using the advanced user interface for
uploading media, you can choose to extract the contents of that file to create media
folders and media items based on its contents instead of creating a single media item
representing the .zip file.
You do not have to use the Sitecore media library for every media
resource in a Sitecore solution. The media library is for media managed by
CMS users. If you do not require CMS services such as security,
translation, versioning, locking, publishing, and workflow, and cannot
benefit from additional features such as Sitecore media caching and
dynamic image manipulation, you can store resources on the filesystem
without using the media library, especially media used by developers
rather than CMS users.
Changes to items in Sitecore databases and changes to the contents of files typically
follow different deployment processes. Changes to items typically follow a publishing or
workflow process; changes to files typically follow a release management process.
Under the default configuration, Sitecore can publish any media item at any time,
including updates to those items.
In general, the information architecture of the media library should follow the
conventions used by the content information architecture. The names and locations of
folders in the media library should match those of corresponding content items. To
increase performance and usability, prevent media folders from containing hundreds of
media items.
Media URLs
Sitecore constructs the URL for a media items much as it constructs the
URL for a content item: based on the path to and name of the media item.
Media URLs begin with the ∼/media prefix (as specified by the
Media.MediaLinkPrefix setting in the Web.config file), continue with the
path to the media item relative to the /sitecore/media library item,
and end with the .ashx extension. For example, the default URL of the
/sitecore/media library/Images/MyImage item would be
∼/media/Images/MyImage. The ∼/media prefix triggers the Sitecore
media request handler, which processes query string parameters and media
metadata, resizes images if required, and serves the HTTP response.
If you change the value of the Media.MediaLinkPrefix setting in the
Web.config file, you should duplicate the
/configuration/sitecore/customHandlers/handler element in that
file with a value of ∼/media/ for the trigger attribute below that existing
<handler> element, and update the trigger attribute of the new
<handler> element to the new value of the Media.MediaLinkPrefix
setting. Also, add a
/configuration/sitecore/mediaLibrary/mediaPrefix/prefix
element to the Web.config file with a value attribute containing the value
of the Media.MediaLinkPrefix setting.
The .ashx extension in the URLs of Sitecore media items causes IIS to
service the HTTP request with ASP.NET instead of attempting to serve a
file from disk. If your configuration of IIS uses ASP.NET for requests for
media extensions, such as .jpg and .pdf, to replace the .ashx extension
in media URLs with the original file extension of the media item, set the
Media.RequestExtension setting in the Web.config file to an empty
string. By default, Sitecore does not output a leading slash (/) as the first
character in media URLs. Browsers interpret such URLs relative to the
current page rather than relative to the document root of the IIS website.
While IIS and hence Sitecore resolve these relative URLs correctly, they
can result in multiple URLs for a single media item. More importantly,
especially in deep information architectures and solutions with very long
item names, such URLs can exceed IIS limitations for URL length.
// use url
}
Do not set the Media.UseItemPaths setting in the Web.config file to false. Doing so
causes media URLs to contain the IDs of media items with curly braces ({}) and dashes
(-) removed rather than media item paths and names.
If you use the media upload watcher to import large quantities of media, to help ensure
success and to avoid overwhelming the system, import in small batches and monitor the
Sitecore logs during the resultant processing. If you move or rename files and
subdirectories under the subdirectory specified by the MediaFolder setting, the media
upload watcher creates new media folders and items but does not move or rename
existing media items. If you delete files and subdirectories from the subdirectory specified
by the MediaFolder setting, the media upload watcher does not delete the corresponding
media items. If you move, rename, or delete items created from files and subdirectories
written to the subdirectory specified by the MediaFolder setting, Sitecore does not move,
rename, or delete the corresponding subdirectories and files from the subdirectory
specified by the MediaFolder setting.
The media upload watcher depends on a running ASP.NET worker process. Before you
add files or subdirectories to the subdirectory specified by the MediaFolder setting in the
Web.config file, use a browser to request an ASP.NET resource, such as the homepage of
the site, to ensure that ASP.NET is active.
WebDAV
You can use WebDAV to enable CMS users to drag and drop files from
their remote desktops into the Sitecore media library.
The File Drop Area field type uses the media library and WebDAV.
Media Types
When you create a new media item, Sitecore uses configuration data for
that type of media as defined by the
/configuration/sitecore/mediaLibrary/mediaTypes/mediaType
element in the Web.config file with a value for the extensions attribute
that matches the original extension in the file name. If no such element
exists, Sitecore uses media type configuration data from the
/configuration/sitecore/mediaLibrary/mediaTypes/mediaType
element in the Web.config file with a value for the extensions attribute
that includes an asterisk (*).
When you change a MIME type associated with a media type in the Web.config file,
Sitecore does not update the MIME type associated with existing media items of that type.
To do that, update the value of the MIME type field in the Information section of existing
media items of that type.
If Sitecore cannot determine the MIME type for a media item, it uses the
value of the <mimeType> element within the
/configuration/sitecore/mediaLibrary/mediaTypes/mediaType
element in the Web.config file with a value for the extensions attribute
that includes an asterisk (*) character.
Media Path Provider
The media path provider implements APIs that translate file paths to
media item paths and media item paths to file paths. To customize how
Sitecore determines the name and path to use for a new media item when a
CMS user uploads a file into the media library or with the media upload
watcher, override the media path provider as follows:
1. Create a class that inherits from the type specified by the type
attribute of the
/configuration/sitecore/mediaPath/providers/add element
named default in the Web.config file.
2. Override methods in the base class according to your requirements,
typically by calling the corresponding methods in the base class and
then altering their results.
3. Update the type attribute of the
/configuration/sitecore/mediaPath/providers/add element
named default in the Web.config file to the signature of your class.
Caching Media
Sitecore manages a cache on the filesystem for some types of metadata
and the binary components of media items automatically. For each
managed site, Sitecore creates a subdirectory under the subdirectory
specified by the Media.CacheFolder setting in the Web.config file, and
stores media cached for that site in that subdirectory. Sitecore caches
media items after it applies transformations, such as after it resizes
images. To prevent Sitecore from caching media for a managed site, set
the cacheMedia attribute of the /configuration/sitecore/sites/site
element in the Web.config file that defines that site to false. To disable
media caching for all sites, set the Media.CachingEnabled setting in the
Web.config file to false.
You might see some performance improvement if you replicate the media cache between
instances in load-balanced environments, but otherwise each instance will build its own
media cache as needed.
Sharing Content
You can easily share field values, items, branches of items, content in
external systems, and other resources among presentation controls, pages,
external systems, and other components. When rendering any item, almost
every Sitecore solution includes data from other items in the repository.
Sitecore provides the following facilities to allow you to share content as
described elsewhere in this chapter or the remainder of this book:
Standard Values — All items based on a data template automatically
share any standard values defined for that data template.
Data Sources — You can pass the same data source item to multiple
presentation controls or to presentation controls used by multiple
pages, devices, or other components to indicate from where those
components should retrieve shared data.
Rendering Properties — Layouts, sublayouts, and layout details can
pass parameters including item paths and IDs to presentation controls,
reusing those values among multiple pages.
Conditional Rendering — With conditional rendering you can
dynamically apply common data source items and rendering
properties to presentation controls.
Selection Fields — You can create fields in your data templates to
allow users to specify items for any number of presentation
components to reuse on any number of pages.
Devices — Presentation components can generate markup around, and
format individual field values to meet requirements for, specific
devices and general categories of devices, such as web browsers and
mobile devices.
Syndication — RSS feeds typically reuse existing items that
represent pages on a managed site.
Aliases — Aliases reuse the same context item at different URLs.
Publishing Targets — You can publish any item to any number of
publishing target databases to use that data in different environments.
Cascading Style Sheets (CSS) — Presentation components can
determine CSS to apply at runtime, reusing items, presentation
components, or both with different styling.
I use the term presentation for markup and the term styling for CSS.
Sitecore expands snippets when you insert them into the RTE. If you subsequently change
a snippet definition, Sitecore does not update the values of Rich Text fields in which you
previously inserted that snippet.
Sitecore continues to provide the Developer Center application for working with
presentation components in the browser. Considering the productivity it allows for
developers, as well as its intuitive integration with the IDE (Integrated Development
Environment), its extensibility, its vast capabilities, and Sitecore's strong commitment to
its further development, I recommend that you use the Sitecore Rocks extension for
Microsoft Visual Studio rather than the Developer Center.
Where relevant, I use the term “website” to indicate an IIS site, and the term “managed
site” to indicate an individual logical site managed by Sitecore within that website, such
as the default published site named website or the site named shell that provides access
to the Sitecore user interfaces.
Because Sitecore URLs correspond to items in a database, not files and subdirectories on
a filesystem, you cannot configure a subsection of Sitecore to use a separate application.
For additional information about this issue, see “Creating a project in a virtual directory
under Sitecore root” at http://bit.ly/odz5dO.
The ASP.NET application lifecycle triggers additional pipelines, such as the initialize
and shutdown pipelines.
For more information about the ASP.NET page lifecycle, see “ASP.NET
Page Life Cycle Overview” at http://bit.ly/oG9tut.
If you add items to this collection, be sure to use keys that Sitecore would never use.
Some properties of the Sitecore context, such as the context language, database, and
security domain, can depend on properties of the context site. Both the Preview and Page
Editor interfaces set the context site as they would for an HTTP request for a published
site rather than the shell site used to implement the CMS. For these CMS user interfaces,
Sitecore sets the context database to the Master database rather than the publishing
target database those published sites would otherwise use by default.
For more information about the Sitecore context, see The Sitecore
Presentation Component API Cookbook (http://bit.ly/uauNa7) and my
blog post at http://bit.ly/rdpqLA.
Define layout details in the standard values for each data template, and avoid defining
layout details in individual items. If you need to override the layout details defined in a
data template, create a new data template that inherits from the existing base template
and apply new standard values for that data template.
Presentation Components
This section describes the presentation components used by the layout
engine, which include devices, layouts, sublayouts, web controls, XSL
renderings, method renderings, URL renderings, placeholders, and data
sources for presentation components. For more information about the
topics described in this chapter, see The Sitecore Presentation Component
Reference (http://bit.ly/uauNa7).
Layouts, sublayouts, XSL renderings, and web controls include both Sitecore items and
filesystem components. You should check these files in with a source code management
system. You typically deploy such files from a development environment through test
environments to a production content management environment and any number of
content delivery environments. The need to deploy changes to these files can affect whom
you allow to edit these presentation components and the process for their deployment.
Consider how you will migrate changes made by developers and any users that you
allow to update presentation components. For more information on this topic, see
Chapter 9.
Devices
Sitecore devices are logical constructs that allow Sitecore to apply
different presentation components to a content item depending on aspects
of the HTTP request. Devices can represent categories of appliances, such
as personal computers, mobile phones, and tablets. Sitecore devices can,
but do not necessarily, correspond directly to physical products or versions
of products such as the Apple iPad 2. Devices can serve a wide range of
purposes: for example, Sitecore uses layout details for the default device
named Feed to format content for RSS feeds. You can even use devices to
identify different browsers or versions of browsers.
For each HTTP request, the DeviceResolver processor in the
httpRequestBegin pipeline determines the context device from the
sc_device query string parameter (which can specify the name of a
device), by matching query string parameters against values in device
definition items, by matching the user agent transmitted by the browser
against values in device definition items, or from attributes of the context
site.
The default DeviceResolver processor in the httpRequestBegin pipeline does not support
regular expressions. For an example of a similar processor that supports regular
expressions, see http://bit.ly/qjooxr.
Technically, Sitecore uses layout details for the default device to render RSS feed
definition items. Sitecore uses the first rendering added to any placeholder for the Feed
device to specify the presentation control to render items when they appear in RSS feeds.
You can register any number of additional devices, such as one for
mobile phones and another for tablets. You can register devices for
specific hardware or even versions of hardware. You must define criteria
to activate each device. You can associate devices with individual
managed sites, such as a mobile site separate from the default site using
the same content but with a different device. You can use the sc_device
query string parameter to specify the name of a device, or you can define
query string parameters or specify browser client user agent strings to
match in your device definition items. If none of these techniques meets
your requirements, you can implement an httpRequestBegin pipeline
processor to resolve the context device according to your specific
requirements. For an example that uses the Sitecore rules engine and the
Wireless Universal Resource File (WURFL, pronounced wer-ful) database
to determine the context device, see the MobileDeviceDetector
(http://bit.ly/gwryUW) Sitecore Shared Source project. For more
information about WURFL, see http://wurfl.sourceforge.net.
In some cases, you may wish to store the device in a cookie, to avoid the need to re-
recognize the device on each request.
Layouts
Sitecore layouts are ASP.NET Web Forms (.aspx files) that define a
markup superstructure typically shared to a number of pages. You can use
anything in a layout that you can use in a standard ASP.NET web form,
including codebehind. You might have layouts that you use for very
specific purposes, but layouts are generally the most reusable presentation
component. You typically have at least one layout per supported device,
and if needed, another layout for the home page and any other pages that
have unique designs or other requirements.
You can bind presentation controls to a layout (or a sublayout as
described in a subsequent section of this chapter) statically, at design time,
by adding the control to the markup in the .aspx file. Alternatively, you
can bind presentation controls to placeholders in a layout (or a sublayout)
dynamically, at runtime.
For greater reuse of content and code, use Sitecore layouts and layout details rather
than ASP.NET master pages.
Because they are largely interchangeable, I generally use the terms renderings and
presentation controls to include all sublayouts, XSL renderings, and web controls. The
term renderings does not include placeholders, which are technically controls.
In ASP.NET, controls are classes that can write to the HTTP response
output stream to render part of a response to an HTTP request. Using a
browser-based user interface to edit layout details, you can declare which
Sitecore presentation controls to bind to each placeholder for each device,
and you can define caching criteria for each presentation control. You can
use the rules engine to pass parameters to presentation controls and to add
and remove presentation controls at runtime.
If you use ASP.NET controls from a third party, test each to ensure that it functions
correctly with the Sitecore layout engine. You may need to add some controls to the
/configuration/rendering/typesThatShouldNotBeExpanded element in the Web.config
file. In some cases you may need to change the LayoutPageEvent setting in the Web.config
file.
Sublayouts
Sitecore sublayouts provide extensions around ASP.NET web user controls
(.ascx files). Just like layouts, sublayouts support all the features
provided by ASP.NET, including codebehind. Sublayouts suit a number of
purposes:
To render output like any other rendering or control
To implement reusable page subdivisions, such as two-column and
three-column sublayouts within a shared superstructure defined by a
layout
To implement web applications, such as HTML forms
To create collections of controls that you can use in multiple contexts
To dynamically generate any type of output required to service an
HTTP request
Sublayouts are the most versatile type of presentation component. Only sublayouts
support nested placeholders. Unlike XSL renderings, sublayouts support the Visual
Studio debugger.
XSL Renderings
Sitecore makes it easy for you to present content using XSL renderings.
You can use the Sitecore.Web.UI.WebControls.XslFile
(<sc:XslFile>) web control class provided by Sitecore to invoke .xslt
transformation files that can contain a variety of standard XSL elements
and Sitecore XSL extension controls, and can invoke numerous Sitecore
XSL extension methods. Sitecore also makes it easy for you to implement
your own XSL extension methods, though extension controls are more
difficult to implement than extension methods.
Using XSL Renderings Effectively
Considering the following points will help you make better use of XSL renderings:
XSL renderings can be appropriate where nontechnical users must manage
markup outside of content areas managed in the CMS or for developers with
extensive knowledge of XSL.
XSL extension controls are typically just syntactic sugar for invoking XSL
extension methods.
You can implement an entire Sitecore solution without using XSL.
Method Renderings
Method renderings invoke the method specified to the method rendering
control. The method accepts no arguments, and the method rendering
control writes the string returned from the method to the output stream.
Method renderings are uncommon and useful only when you need to invoke an existing
method rather than creating a web control.
URL Renderings
URL renderings invoke the URL specified to the URL rendering control,
and write the contents of the <body> element returned to the output
stream. Unlike URLs specified to the <iframe> HTML element, which the
web client runs, the server invokes URL renderings and transmits the
response to the client as a component of the content of the page.
URL renderings are uncommon and useful only when you need to embed the contents
from one URL in the body of a page generated by Sitecore.
Web Controls
Sitecore web controls are classes that write to the HTTP response output
stream. Classes that implement web controls derive from and extend the
Sitecore.Web.UI.WebControl class, which derives from the
System.Web.UI.WebControls.WebControl class. Web controls are more
lightweight than sublayouts, with only one source code file to manage, and
no need to deploy any source such as .ascx or .cs, but rather only the
compiled assembly (.dll). Sitecore web controls implement the
DoRender() method as required by the programming contract for the
Sitecore.Web.UI.WebControl class, where web controls that derive
directly from System.Web.UI.WebControls.WebControl implement the
Render() method. The reason for this is that the
Sitecore.Web.UI.WebControl class implements caching logic in the
Render() method, which ASP.NET continues to call, and only calls the
DoRender() method in your web controls if the layout engine cannot
retrieve cached output generated previously by the control under
equivalent processing conditions as described in Chapter 6.
You can benefit from creating an abstract base class that inherits from
the default Sitecore.Web.UI.WebControl abstract base class for web
controls, and using your class as the base class for all your web controls
rather than inheriting directly from the Sitecore.Web.UI.WebControl.
Your abstract base class for web controls can do the following:
Implement the GetCachingID() method to support output caching
instead of implementing this in each web control. For example:
protected override string GetCachingID()
{
string id = base.GetCachingID();
if (String.IsNullOrEmpty(id))
{
id = this.GetType().ToString();
}
return id;
}
Implement the Render() method, for example to manage exceptions
from the DoRender() methods of all web controls as described in
Chapter 5
Implement the GetCachingKey() method, for example to add custom
caching criteria to cache keys
If you do not implement the GetCachingID() method, Sitecore cannot cache the output of
your web control.
Rendering parameters templates are simply data templates that you use
to define rendering parameters. Sitecore uses rendering parameters
templates to provide greater usability instead of requiring the user to enter
key/value pairs.
To implement a custom rendering parameters template, follow these
steps:
1. Add parameter definitions to the presentation control code.
Specifically, for XSL renderings, add an <xsl:param> element to
define the parameter name. For web controls, add a public property to
the class that defines the web control. For more information about
defining parameters for presentation controls, see the Sitecore
Presentation Component Reference (http://bit.ly/qdtczd) and the
Sitecore Presentation Component XSL Reference
(http://bit.ly/nEWh5x).
2. Create a data template that inherits from the default rendering
parameters template (System/Layout/Rendering
Parameters/Standard Rendering Parameters) with fields named
after the parameters defined in the presentation control. For
instructions to create a data template, see the Sitecore Data Definition
Cookbook (http://bit.ly/qXSuJD). Figure 3.1 shows an example of a
rendering parameters template named Sample Rendering Parameters
that defines a single parameter named MyItem.
3. In the Content Editor, which you can access as described in Chapter
1, select the XSL rendering, web control, and/or sublayout definition
item(s) that define the parameters specified in the new rendering
parameters data template. In the Editor Options section, in the
Parameters Template field, select the rendering parameters data
template that you created previously. Figure 3.2 shows the
Sample/Sample Rendering definition item configured to use the
Sample Rendering Parameters template.
Figure 3.1
Figure 3.2
To specify a value for the parameter, update layout details for items that
use the presentation control. In the Content Editor:
1. Select the item.
2. Select the Presentation tab.
3. Click Details in the Layout group. The Layout Details dialog
appears as shown in Figure 3.3.
4. Click the rendering for which you want to define the parameter (for
example, the rendering named Sample Rendering previously shown in
Figure 3.3). The Control Properties dialog appears as shown in Figure
3.4.
5. Enter a value in the field that you defined in the rendering
parameters template (My Item in Figure 3.4), and then click OK. The
Control Properties dialog disappears and you return to the Layout
Details dialog as previously shown in Figure 3.3.
6. Click OK. The Layout Details dialog closes and you return to the
Content Editor.
Figure 3.3
Figure 3.4
Presentation Control Definition Item Properties
The data templates for presentation controls (sublayouts, XSL renderings,
and web controls provide a number of fields that you can use to
manipulate how controls operate. You can edit these properties after
selecting the definition item for a presentation control in the Content
Editor. You can see some of these properties in Figure 3.2 shown
previously.
Fields in the Editor Options section of all definition items for
presentation controls serve the following purposes:
Description — Textual explanation or even a graphic representation
of the output of the control so users can use visual representations to
select controls rather than item names.
Parameters Template — Rendering parameters template for the
presentation control, as described in the previous section.
Open Properties After Add — If this checkbox is selected, Sitecore
automatically opens the Control Properties dialog to allow the user to
set additional properties after they add the control to layout details for
an item.
Customize Page — Legacy feature superseded by rendering
parameters templates.
Editable — Controls whether users of the Page Editor can update the
rendering.
Datasource Location — Location from which the user can select a
data source for this presentation control, or under which they can
create such an item.
Datasource Template — Data template required for or to use when
creating a data source item for this presentation control.
Compatible Rendering — Limits the user's choice of presentation
controls to replace this one.
Page Editor Buttons — Commands to expose around the presentation
control in the Page Editor.
Fields in the Caching section of definition items for presentation
controls specify default criteria for the control. For more information
about component caching criteria, see Chapter 6, The Sitecore
Presentation Component Reference (http://bit.ly/qdtczd), and my blog post
at http://bit.ly/ndR0Bz.
The fields that appear in the Data section of definition items for
presentation controls depend on the type of control. Figure 3.5 shows some
of the fields available for a web control.
The fields that can appear in definition items for the various types of
presentation controls include the following:
Namespace — .NET namespace containing the class that implements
a web control
Tag — Name of the .NET class within Namespace that implements a
web control
TagPrefix — ASP.NET prefix associated with the namespace
containing the class identified by Namespace and Tag (matching the
value of the tagPrefix attribute of one of the
/configuration/system.web/pages/controls/add elements in the
Web.config file)
Assembly — .NET assembly (.dll file) containing the class that
implements a web control
Path — Path to the code file for a sublayout or XSL rendering relative
to the IIS document root
Placeholder — Default placeholder for the control
Login control — Alternate control to render if the user has not
authenticated (typically a login control)
Data Source — Default data source item for the presentation control
The Data Source (or Source) property of presentation components is entirely unrelated
to the Source property in definition items for data template fields as described in Chapter
2. The data source of presentation components indicates from where they should retrieve
data while rendering the site; the Source property of a data template field controls
aspects of that field in data templates visible to CMS users.
Figure 3.5
Choosing Presentation Technology
For each presentation control on a page, such as navigational elements or
the footer, you can choose one of the presentation technologies listed in
the previous five sections: sublayout, XSL rendering, method rendering,
URL rendering, or web control. Alternatively, you can standardize on a
single presentation technology for all site components, which has
advantages for maintainability.
Most importantly, XSL renderings can have advantages, but they can
also have significant limitations. While XSL is great for formatting
markup, it is not very good for logic, even simple string parsing. You don't
compile XSL renderings, so you don't get compile-time error reports, only
runtime, and you can't step through XSL renderings using the Visual
Studio debugger. Use XSL only if you already know its syntax, or if you
need to let nontechnical CMS users update markup not stored in items.
Technically, there is no data source for a layout; by convention, the Sitecore context item
is the data source for a layout.
You can use the $sc_item parameter to access the data source of an XSL
rendering. You can use the GetItem() method to access the data source of
a web control. For information about accessing the data source of a
sublayout, see the SublayoutParameterHelper (http://bit.ly/rx1w8I)
Sitecore Shared Source project mentioned previously for accessing
parameters passed to a sublayout.
Rather than accessing the context item directly, always code renderings to access the
data source, even if you expect that the context item and the data will always be the same
item. Multivariate testing, personalization, conditional rendering, and other Sitecore
features can affect the data source, but do not always affect the context item.
Technically, you can store the data source items for a presentation
control anywhere in the content tree. Practically, if the data source items
also represent pages, they should exist beneath the home item of the
managed site to which those pages belong. Otherwise, you can store data
source items in the location of your choice, such as by creating a
/sitecore/content/global folder with subfolders for the various types
of data source items. Alternatively, you can store data source items as
children or deeper descendants of the items that use them.
For more information about presentation component data sources, see
The Sitecore Presentation Component Reference (http://bit.ly/o2TdvV)
and my blog posts at http://bit.ly/n2Xn4X and http://bit.ly/qoKzgS. For
instructions for adding presentation component data sources to Sitecore's
internal link management database, see my blog post at
http://bit.ly/oZ6Z5j.
Global conditional rendering rules that do not apply to most pages consume
unnecessary central processing unit (CPU) capacity and other machine resources.
You can use the Content Editor to define conditional rendering rules for
an individual presentation control. For example, you might want to set the
Winner property of a web control to true if the visitor came to the site by
searching for the term sitecore.
First, to define a conditional rendering rule:
1. Create a conditional rendering rule definition item under the
/sitecore/system/Marketing
Center/Personalization/Rules/Persona item using the
System/Rules/Conditional Rendering Rule data template. For
example, if the visitor came to the site using search terms that
included the search keyword sitecore, you could create a conditional
rendering rule definition item named Searched for Sitecore as shown
in Figure 3.6.
2. Click Edit Rule above the Rule field in the Data section. The Rule
Set Editor appears as shown in Figure 3.7.
3. Select conditions from the list on the left and actions to invoke
under those conditions from the list on the right to add them to the
rule definition at the bottom. For example, click the Where The Search
Keywords String Compares To The Specific Value condition and the
Set Parameters To Value action. Figure 3.8 shows the Rule Set Editor
after a condition and action are selected.
4. In the rule definition at the bottom of the Rule Set Editor, click each
of the links to set values for each parameter. For example, click
Compares To. The Select Comparison dialog appears as shown in
Figure 3.9.
5. Select Contains, and then click OK. The Select Comparison dialog
disappears and you return to the Rule Set Editor. Click Specific Value.
The Enter value dialog appears as shown in Figure 3.10.
6. Enter sitecore, and then click OK. You see the Rule Set Editor.
Click Value. The Enter value dialog appears as shown in Figure 3.10.
Enter winner=true, and then click OK. You see the Rule Set Editor as
shown in Figure 3.11.
Figure 3.6
Figure 3.7
Figure 3.8
Figure 3.9
Figure 3.10
Figure 3.11
Next, to apply the conditional rendering rule to a presentation control,
you may first need to enable personalization features in the Content Editor.
To do so:
1. Click the Sitecore logo in the upper-left corner of the Content
Editor. A menu appears as shown in Figure 3.12.
2. Click Application Options. The Application Options dialog appears
as shown in Figure 3.13.
3. Click the View tab, then select Show the Personalization Section,
and then click OK. The Application Options dialog disappears and you
return to the Content Editor.
Figure 3.12
Finally, to apply the conditional rendering rule to an item in the Content
Editor:
1. Select the item for which to apply the conditional rendering rule.
2. Click the Presentation tab, and then click Details in the Layout
group. The Layout Details dialog appears as previously shown in
Figure 3.3.
3. Click the presentation control. The Control Properties dialog
appears as shown in Figure 3.14.
4. Select the conditional rendering rule in the Personalization section,
and then click OK. The Control Properties dialog disappears and you
return to the Layout Details dialog.
5. Click OK. The Layout Details dialog disappears and you return to
the Content Editor.
For more information about the Sitecore rules engine and conditional
rendering, see Chapter 7, The Sitecore Rules Engine Cookbook
(http://bit.ly/peToK6), and my blog post at http://bit.ly/nvy2fX.
Figure 3.13
Figure 3.14
The FieldRenderer Web Control and the
renderField Pipeline
You can use the FieldRenderer web control
(Sitecore.Web.UI.WebControls.FieldRenderer) to invoke the
renderField pipeline against the value of a field in an item. The
renderField pipeline transforms internal URLs containing IDs for both
media and content items to friendly URLs, and adds inline editing,
debugging, or other features in the Page Editor, the Sitecore browser-based
debugger, and other user interfaces, and otherwise dynamically
manipulates field values at runtime.
If you do not use the FieldRenderer web control to retrieve the values of RTE fields (or
any other construct that invokes the renderField pipeline or the appropriate APIs), field
values could contain URLs with query string parameters containing IDs rather than
friendly URLs. XSL extension controls such as <sc:text> and the sc:field() XSL
extension method invoke the renderField pipeline.
if (Sitecore.Context.PageMode.IsPageEditorEditing)
{
output.Write(Sitecore.Web.UI.WebControls.FieldRenderer.Rend
er(item, "title"));
}
Or in XSL:
<xsl:if test="sc:pageMode()/pageEditor/edit">
<sc:text field="title" />
</xsl:if>
For more information about the page mode, see The Sitecore Client
Configuration Cookbook (http://bit.ly/n7fJbq).
Unless otherwise specified, all APIs described in this book exist in the
Sitecore.Kernel.dll assembly, the Sitecore.Client.dll assembly, or possibly the
Sitecore.Analytics.dll assembly.
Sitecore.Configuration.Factory
You can use the static Sitecore.Configuration.Factory class to
retrieve objects configured using the Sitecore configuration factory, which
Sitecore uses to determine the .NET types to implement specific features.
The static Sitecore.Configuration.Factory class includes methods
such as the following:
GetDatabase() — Retrieve a named database
GetDatabaseNames() — Retrieve a list of the names of all databases
GetDatabases() — Retrieve all databases
GetDomain() — Retrieve the named Sitecore security domain
GetDomainNames() — Retrieve a list of the names of all security
domains
GetIDTable() — Retrieve the IDTable used to map Sitecore IDs to
identifiers in external systems
GetItemComparer() — Retrieve a comparer that implements the
child sorting rule for an item
GetLinkDatabase() — Retrieve the links database
GetMasterVariablesReplacer() — Retrieve an object that replaces
tokens in standard values, and branch templates (including the names
of items in branch templates) on item creation
GetSiteNames() — Retrieve a list of the names of the managed sites
GetSite() — Retrieve information about the named site using the
same class as Sitecore.Context.Site
For examples that use the Sitecore.Configuration.Factory class, see
the following sections. For more information about the configuration
factory, see Chapter 7.
Sitecore.Data.Database
The Sitecore.Data.Database class represents a Sitecore database, such
as the Master or Core database or a publishing target database. You
typically access the context database (Sitecore.Context.Database), the
content database (Sitecore.Context.ContentDatabase, for use in
Sitecore user interface components), or a named database. For example, to
access the context database, you can use code based on the following:
Sitecore.Data.Database context = Sitecore.Context.Database;
To access the Master database by name:
Sitecore.Data.Database master =
Sitecore.Configuration.Factory.GetDatabase("master");
Always use Sitecore APIs to access Sitecore databases. Avoid SQL queries directly
against a Sitecore database.
The name of the database that you pass to the GetDatabase() method of
the Sitecore.Configuration.Factory static class is not the name of the
database on the database server. The argument passed to this method is a
token that maps to the actual database connection string (for SQL Server,
defined in the /App_Config/ConnectionStrings.config file under the
document root subdirectory of the IIS website hosting the Sitecore
solution). Using tokens instead of actual database connection information
allows the same code to run in different environments, with different
connection string information for those tokens.
Sitecore.Data.Items.Item
The Sitecore.Data.Items.Item class represents an item in a Sitecore
database. Presentation components typically access the context item, the
data source item for the presentation component, and/or any other specific
items either hard-coded, passed to the presentation component as
parameters, stored in fields of the item or in items somehow related to the
item, or otherwise determined.
Sitecore ignores character case when retrieving items. Whenever possible, reference
items by ID rather than by path.
if (field == null)
{
// field does not exist
return;
}
text = field.Value;
// text is either a value or an empty string
Sitecore lazily loads the Fields collection of the Sitecore.Data.Items.Item class, which
means it may not contain standard values or null values for fields with no standard
value, and may not contain other inherited field values such as cloned field values. To
force Sitecore to load all field values for an item, call the ReadAll() method of the Fields
property of the Sitecore.Data.Items.Item class.
Sitecore.Data.ID
The Siteore.Data.ID class represents the unique identifier of a Sitecore
item. To retrieve an item, you can pass an object of type
Sitecore.Data.ID to the GetItem() method of the
Sitecore.Data.Database class.
Sitecore.Data.Items.EditContext,
BeginEdit(), and EndEdit()
Before you can update an instance of the Sitecore.Data.Items.Item
class, Sitecore requires that you either enter a
Sitecore.Data.Items.EditContext class or that you invoke the
BeginEdit() method of the Sitecore.Data.Items.Item class before the
change and the EndEdit() method afterward. For example, to update the
field named FieldName in the /sitecore/content/home item in the
Master database:
Sitecore.Data.Database master =
Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Diagnostics.Assert.IsNotNull(master, "master");
Sitecore.Data.Items.Item home =
master.GetItem("/sitecore/content/home");
Sitecore.Diagnostics.Assert.IsNotNull(home, "home");
using(new Sitecore.Data.Items.EditContext(home))
{
item["FieldName"] = "value";
}
Code that creates or updates items should run only in the content management
environment (not in the content delivery environment), and should update the Master
database (or in some rare cases, the Core database). If you write only to a publishing
target database such as the default Web database, subsequent publishing from the
Master database can remove those updates.
You can also use the Sitecore.Data.Fields.Field class and the other
classes in the Sitecore.Data.Fields namespace to update field values.
You can use the Add() method of the Sitecore.Data.Items.Item class
to insert an item based on a data template or any number of items based on
a branch template under an existing item. For example, to add a child
named ChildName under the /sitecore/content/home item in the
Master database using the same data template as that
/sitecore/content/home item, you can use code based on the following:
Sitecore.Data.Database master =
Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Diagnostics.Assert.IsNotNull(master, "master");
Sitecore.Data.Items.Item home =
master.GetItem("/sitecore/content/home");
Sitecore.Diagnostics.Assert.IsNotNull(home, "home");
Sitecore.Data.ID template = home.TemplateID;
Sitecore.Data.Items.Item child = home.Add("ChildName",
template);
You can then place the item in an editing state and update field values as
described in the previous section.
For information about importing content into the Sitecore ASP.NET
CMS, see my blog post at http://bit.ly/qnihna.
Sitecore.Data.Items.CustomItem
You can use the Sitecore.Data.Items.CustomItem abstract class as a
base class for your own classes that represent items based on specific data
templates. For example, if you have a data template for news articles,
instead of accessing articles with the Sitecore.Data.Items.Item class,
you can create a class that inherits from the
Sitecore.Data.Items.CustomItem class and exposes properties that
encapsulate access to the underlying item and its fields, such as a string
for the title and a Datetime for the article date.
The InnerItem property of the Sitecore.Data.Items.CustomItem
class specifies the Sitecore.Data.Items.Item associated with the
Sitecore.Data.Items.CustomItem object. Typically, your constructor
sets the InnerItem property. Your class should then provide getters for the
relevant fields of the data template. For convenience, you can provide a
method to convert from Sitecore.Data.Items.Item to your type
implicitly, as shown here:
namespace SitecoreBook.Data.Items
{
using System;
if (String.IsNullOrEmpty(parse))
{
return DateTime.MinValue;
}
return Sitecore.DateUtil.IsoDateToDateTime(parse);
}
}
}
}
NewsArticleItem.cs
Sitecore ID Constants
To reduce hard-coding, especially of item paths, Sitecore provides a
number of static classes that expose properties that act as constants to
define the IDs of elements. The following list includes the most important
classes of this type:
Sitecore.FieldIDs — IDs of common fields, primarily defined by
the standard template
Sitecore.ItemIDs — IDs of system items
Sitecore.TemplateIDs — IDs of system data templates
For example, to retrieve the /sitecore/content item in the context
database, you can use code based on the following:
Sitecore.Data.Database db = Sitecore.Context.Database;
Sitecore.Diagnostics.Assert.IsNotNull(db, "db");
Sitecore.Data.Items.Item item =
db.GetItem(Sitecore.ItemIDs.ContentRoot);
To maximize performance, whenever possible, use item IDs rather than paths. If you use
a path, Sitecore must determine the associated ID, which is often unnecessary. If you
know the path or ID of the item, using the GetItem() method of the
Sitecore.Data.Database class is the best technique for selecting an item.
You can also access items relative to other items, such as by using the
Parent and Children properties of the Sitecore.Data.Items.Item class
to access the parent or children of the item, or the Axes property that
exposes methods such as GetDescendants().
For more information about Sitecore queries, including their syntax and
examples, see The Sitecore Data Definition Reference
(http://bit.ly/jIUdfw) and “Using Sitecore Query” (http://bit.ly/ofjlX0) on
the Sitecore Developer Network (SDN).
Sitecore fast query requires Microsoft SQL Server (as opposed to Oracle).
For more information about Sitecore fast query, including its syntax,
significant limitations, and examples, see http://bit.ly/o0uXDn.
foreach(Sitecore.Search.Index index in
config.Indexes.Values)
{
if (index != null)
{
index.Rebuild();
}
}
To rebuild the links database, follow these steps in the Sitecore desktop:
1. Click the Sitecore button at the bottom left, and then click Control
Panel from the menu that appears. The Control Panel appears as
previously shown in Figure 3.15.
2. Click Database. The Control Panel refreshes to show database
commands.
3. Click Rebuild the Link Database. If a welcome dialog appears, click
Next. The Rebuild Link Database dialog appears as shown in Figure
3.19.
4. Select the databases for which to rebuild internal links database
records, and then click Rebuild. The user interface refreshes for some
time to indicate the status of the rebuild process, and then displays a
summary of the process.
5. Click Finish. The Rebuild Link Database dialog disappears and you
return to the Control Panel in the desktop. You can close the Control
Panel.
Figure 3.19
You can use the Rebuild() method of the
Sitecore.Globals.LinkDatabase static property to rebuild the links
database for a single Sitecore database. For example, to rebuild the links
database records for all Sitecore databases, you can use code such as the
following:
foreach(Sitecore.Data.Database database in
Sitecore.Configuration.Factory.GetDatabases())
{
Sitecore.Globals.LinkDatabase.Rebuild(database);
}
Sitecore does not maintain records in the links database for the data
sources of presentation components. Worse, layout details store the paths
to data source items rather than storing their IDs. If you rename, move, or
delete the data source of a presentation control, Sitecore does not prompt
you to update the data sources of presentation components that use that
item to the new path. For a sample event handler that updates paths in
layout details to IDs, see the Sitecore Developer Network (SDN) forums
thread at http://bit.ly/qsngmX. To configure Sitecore to maintain records
in the links database for the sources of presentation components, see my
blog post at http://bit.ly/oZ6Z5j. This solution does nothing for dynamic
data sources such as queries, relative paths, and conditional rendering.
Recursion
You can use recursion to access the relatives of an item. You can process
each descendant of an item, or you can process the ancestors of an item.
You can process items in document order (from a root element down) or
reverse document order. You can either include or exclude the root item
for processing. You can sort sibling items to control the order of
processing at each level in the information architecture.
To process all descendants of an item in document order, write a
recursive method that accepts an instance of the
Sitecore.Data.Items.Item class and calls itself for each child of that
item, as shown here:
Then pass an item to the recursive method. For example, to process the
context item and all its descendants:
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
RecurseDescendant(item);
To process items in reverse document order, move the processing to
after the foreach loop.
To exclude the item itself from processing, pass each of its children to
the recursive method. For example, to process only the descendants of the
context item:
Sitecore.Data.Items.Item item = Sitecore.Context.Item;
Sitecore.Diagnostics.Assert.IsNotNull(item, "item");
if (item.Parent != null)
{
RecurseAncestor(item.Parent);
}
// process item…
}
RecurseAncestors.cs
Sitecore CMS provides the Visual Sitecore Service. Sitecore Rocks can install the Hard
Rock Web Service.
For more information about Sitecore web services, see The Sitecore Web
Service Reference (http://bit.ly/y09xcC). For information about
implementing web services that invoke Sitecore APIs, see The Sitecore
Presentation Component Cookbook (http://bit.ly/nDo0Ek).
The Source field in the Data section of RSS feed definition items (which
may have the title Items in some versions of Sitecore) specifies which
items to include in a feed. In the Source field you can specify an
individual item or a Sitecore query. If you specify an item, the feed can
include any descendants of that item that define layout details for the
System/Feeds/FeedRenderer web control for the Default device. Feeds
sort and retrieve only the newest items automatically.
Feed entry items can use any data template. Layout details for the Feed
device for feed entry items pass parameters to the
System/Feeds/FeedRenderer web control (or any control that inherits
from the Sitecore.Web.UI.WebControls.FeedRenderer class) to
specify the control to render the feed entry item and the fields in the data
template for that control to render (using the TitleField, BodyField, and
DateField presentation control parameters). To configure presentation for
a feed entry item, click the Design command in the Feeds group, on the
Presentation tab of the Content Editor.
Avoiding Issues with RSS Feeds
The following tips will help you avoid potential problems with the RSS feeds you
create.
Unlike most commands, which update the item selected in the Content Editor, the
Design command in the Feeds group updates layout details in the standard values
item for the data template associated with that item. If you use a derivative of the
System/Feeds/FeedRenderer web control, the Design command adds the default
System/Feeds/FeedRenderer web control as the first presentation control in layout
details for the device named Feed. Use the Design command to configure the
default System/Feeds/FeedRenderer web control, specify TitleField, TextField, and
DateField, and update layout details to use the alternate FeedRenderer; thereafter
do not use the Design command for that item.
The System/Feeds/FeedRenderer web control or its derivative should be the first
presentation component listed in layout details for the Feed device.
The Caching.SmallCacheSize setting in the Web.config file limits the size of the
cache for RSS feed output. If Sitecore does not cache your RSS feeds, you may
need to increase the value of this setting. This setting does not appear in the
default Web.config file, which may result in a default value smaller than you need
to cache your RSS feeds.
Sitecore client RSS feeds use a different infrastructure from public RSS feeds.
Sitecore Security
This book does not describe how to secure the ASP.NET infrastructure hosting your
Sitecore solutions. For some helpful pointers in this regard, see The Sitecore Security
Hardening Guide (http://bit.ly/swFfRp).
Access Rights
Access rights control which users can access features and functions of the
CMS environment and on the managed websites. You can apply access
rights for users or roles. To simplify maintenance, you should apply access
rights for roles, unless that would require you to create numerous roles
containing individual users to achieve the same end.
Sitecore stores access rule definitions in each item using the
__Security (Sitecore.FieldIDs.Security) field defined by the
standard template. To get an idea of how Sitecore serializes access rights,
apply access rights to an item, view the standard fields, view raw values,
and investigate the value of this field (titled Security) in the Security
section. To see rights that you apply in the content management appear in
the content delivery environment, publish the items containing updated
security descriptors.
If you set the embedAclInItems attribute of the
/configuration/sitecore/authorization/providers/add element in the Web.config file to
false, Sitecore stores access rights in the AccessControl table of the database specified
by the connectionStringName attribute of that element. If this attribute in both content
management and content delivery environments specifies the same database, then you do
not need to publish updates to access rules, and changes take effect immediately. If these
attributes specify separate databases, you must implement a strategy to replicate changes
from the database used by the content management environment to the database(s) used
by the content delivery environment.
While all access rights can affect both CMS users and visitors to the managed web sites,
most access rights apply primarily in the content management environment. The
item:read access right is an exception, and is particularly important in the content
delivery environment, where it controls which items visitors can access.
You can add custom access rights to use for your own purposes. For an example that
describes how you can implement a custom access right to control whether a user can
publish each individual item, see my blog post at http://bit.ly/q9FQvl.
Inheriting Access Rights
By default, each item automatically inherits access rights from its parent.
If you do not specify access rights for an item, it inherits access rights
from its parent; the access rights defined for the parent apply to the item.
If you do not specify access rights for the parent item, then access rights
defined for the parent item of that parent (the grandparent) apply to that
item (the grandchild), and so on to the top of the content tree. For a more
detailed explanation of how Sitecore applies inherited access rights, see
the next section, “Evaluating Access Rights.”
As described in subsequent sections, you can use the Security Editor or
the Content Editor to disable security inheritance for any item, meaning
that the item no longer inherits access rights from its parent. For
instructions to grant and deny rights, and to enable and disable inheritance,
see the section “Setting Access Rights.” When applying inherited access
rights for the item or any of its descendants, after processing an item that
disables security inheritance to its descendants, Sitecore stops evaluating
access rights. If the item and its inheritance chain do not grant an access
right, Sitecore denies that right by default. In addition to disabling access
right inheritance completely for an item, you can also disable inheritance
for individual access rights for individual users and roles.
If the inheritance chain to the root item or to an item that disables
security inheritance does not allow an access right for a user or any of that
user's roles, Sitecore denies that right by default. After you break security
inheritance for an item, unless you have granted access rights to specific
roles or users, only administrators can access that item until you grant
access rights to additional roles or users.
Access rights assigned to a user override rights assigned to their roles. If you allow or
deny a right to a user, you allow or deny that right for that user regardless of whether
you allow or deny that right to any of their roles.
When the item explicitly denies the access right to any of the roles
that contain the user, the system denies the access right.
When the item explicitly allows the access right to any of the roles
that contain the user, the system allows the access right.
When the item explicitly disables security inheritance for the access
right, the system denies the access right.
If none of the previous conditions result in allowance or denial of the
access right, and the item does not disable inheritance of that access
right from its parent item, Sitecore evaluates the same criteria
sequentially on the ancestors of the item, starting with the parent of
the item and progressing towards the top of the tree. Sitecore stops
evaluating access right inheritance at the nearest ancestor that
disables security inheritance, respecting options for disabling
inheritance for individual users, roles, access rights, and the entire
item.
Figure 4.1
As you can see, a user's explicit rights override the rights provided by a
user's roles, and Sitecore stops evaluating security inheritance as soon as it
finds a reason to allow or deny the right.
The Sitecore security infrastructure implicitly and automatically affects
almost all operations on Sitecore items. If a presentation component
attempts to access an item to which the context user does not have read
access, Sitecore behaves as if that item does not exist. If the user somehow
requests the URL of a restricted item, Sitecore redirects the browser to the
URL of the friendly error page specified by the NoAccessUrl setting in the
Web.config file.
By default, Sitecore applies the access rights of the context user. Most
importantly, the read access right controls whether the user can access an
item in any way. If the context user does not have read access to the item
specified by the first argument to the GetItem() method of the
Sitecore.Data.Database class, that method returns null rather than a
readSitecore.Data.Items.Item object. Other item access techniques
return null or exclude items from lists.
Ensure that each Sitecore.Data.Items.Item is not null and contains
at least one version in the context language (by checking the Count
property of the Versions property of the item) before using that item in
your code, such as when you retrieve items specified in the field of
another item or from a search index. For example, given the ID of the item
in the query string parameter named sc_item, the following code confirms
that the context user can read that item from the context database:
string id =
Sitecore.Web.WebUtil.GetQueryString("sc_item");
if (!String.IsNullOrEmpty(id))
{
Sitecore.Data.Database db =
Sitecore.Context.Database;
Sitecore.Diagnostics.Assert.IsNotNull(
db,
"db");
Sitecore.Data.Items.Item item =
Sitecore.Context.Database.GetItem(id);
Alternatively, you can also use the Content Editor to apply access rights.
To do so, click the Security tab in the Content Editor, and then click
Assign in the Security group. Because its primary selection is an item, the
Content Editor is most efficient when you need to set access rights for an
individual item or a small number of items, especially when you need to
apply access rights for a number of users or roles. The Security Editor is
more efficient when you need to apply access rights for a number of items
or a branch, especially when you repeatedly apply access rights for an
individual account.
When you need to apply a consistent pattern of access rights to more
than one item, first consider whether you can instead use security
inheritance. Otherwise, consider scripting the application and (potentially)
the maintenance of access rights, including updates and publishing. If you
must apply the same access rights to a number of items through the user
interface, consider using the Content Editor to copy and paste the raw
value of the __Security (Sitecore.FieldIDs.Security) field defined in
the standard template, instead of using the Security Editor to apply the
same access rights repeatedly. If you choose to use the Security Editor,
minimize the number of times you must select a account by setting access
rights for each account on a number of items, and then moving on to the
next account, rather than setting access rights item by item.
Do not confuse the field:read access right with the item:read access right or the
field:write access right with the item:write access right. Field access rights defined in
definition items for data template fields control which users can read and write values in
those fields of items to which they also have the corresponding item access rights. You
would not normally define item access rights in definition items for individual data
template fields, where they control which users can update those definition items as
opposed to updating fields in items based on those data templates.
You should grant rights to read fields to any account to which you grant rights to write
those fields. You can grant read access to everyone, and grant write access to specific
roles and even users.
Figure 4.5
Figure 4.6
Figure 4.8
CMS user interfaces such as the Content Editor apply the field:read
and field:write access rights to items that include such data template
fields. To support data template field access rights in user interfaces such
as the Page Editor, your presentation components must respect data
template field access rights. You can use the CanRead and CanWrite
properties of the Sitecore.Data.Fields.Field class to determine
whether a user can read and write to a field. The following code
demonstrates how to confirm that the context user has read and write
access to the Title field in the context item, as well as read and write
access to the context item itself.
Sitecore.Data.Items.Item item =
Sitecore.Context.Item;
Sitecore.Diagnostics.Assert.IsNotNull(item, "item");
if
(Sitecore.Security.AccessControl.AuthorizationManager.IsAll
owed(
item,
Sitecore.Security.AccessControl.AccessRight.ItemWrite,
Sitecore.Context.User))
{
Sitecore.Data.Fields.Field title =
item.Fields["title"];
Sitecore.Diagnostics.Assert.IsNotNull(title,
"title");
if (title != null
&& title.CanRead
&& title.CanWrite)
{
// the context user has write access to the field
}
}
CanWriteTitle.cs
Sitecore.Security.AccessControl.AccessRuleCollection();
foreach (Sitecore.Security.AccessControl.AccessRule
existingRule
in item.Security.GetAccessRules())
{
if (existingRule.Account.Name != account.Name
|| existingRule.Account.AccountType !=
account.AccountType
|| existingRule.AccessRight != right)
{
updated.Add(existingRule);
}
}
Sitecore.Security.AccessControl.AccessPermission.Deny;
updated.Add(Sitecore.Security.AccessControl.AccessRule.Crea
te(
account,
right,
Sitecore.Security.AccessControl.PropagationType.Any,
permission));
Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Diagnostics.Assert.IsNotNull(master,
"master");
Sitecore.Configuration.Factory.GetDomain("extranet");
Sitecore.Diagnostics.Assert.IsNotNull(extranet,
"extranet");
Sitecore.Security.AccessControl.AccessRight.SiteEnter,
false /*allow*/ );
}
}
}
DenySiteAccessToExtranetAnonymous.cs
I implemented this as a web control for my own convenience, but you can call equivalent
methods from other types of components.
In some contexts, the terms role and group are largely interchangeable. Groups often
belong to operating systems, while roles often belong to applications. In Sitecore a group
is a collection of commands in the Ribbon of a user interface such as the Content Editor.
Excluding the fact that you can apply access rights to group definition items to control
who can access those groups of commands in user interfaces, in Sitecore, groups have
nothing to do with security.
Users
Users are individual people with authentication credentials for a Sitecore
solution, whether in the CMS or on one or more of the published websites.
A user can be a member of any number of security roles.
You can use the Sitecore.Security.Accounts.User class to access a
user. You can use the static Exists() method of this class to determine
whether a user exists in a domain. For example, the following code shows
how to determine if the default user named admin exists in the Sitecore
security domain:
if
(Sitecore.Security.Accounts.User.Exists("sitecore\\admin"))
{
Sitecore.Diagnostics.Log.Error(
"grant admin to a real user and remove the default
Sitecore\\admin user.",
this);
}
You can use the static
Sitecore.Security.Accounts.User.FromName() method to retrieve a
user by name. The first argument to this method specifies the user name,
including the name of the security domain that contains the user. The
second parameter tells the system whether to update its internal record of
when the user last accessed the solution. For example, the following code
shows how to determine whether the default admin user exists in the
Sitecore security domain:
Sitecore.Security.Accounts.User admin =
Sitecore.Security.Accounts.User.FromName("sitecore\\admin",
false);
Sitecore.Diagnostics.Assert.IsNull(admin, "sitecore\\admin
exists");
The System.Web.Security.MembershipUser class provides an
alternative means of accessing users that you can use if the
Sitecore.Security.Accounts.User class does not provide functionality
that you require. Important methods in the
System.Web.Security.MembershipUser class include:
ChangePassword() — Change the password associated with the user
to a new value (requires the existing password).
ChangePasswordQuestionAndAnswer() — Change the security
question and answer associated with the user to new values (requires
the existing password).
ResetPassword() — Reset the password associated with the user to
a random string (requires the answer to the security question
associated with the user).
UnlockUser() — Unlock the user after that user has reached the
limit for invalid login attempts.
For example, you can pass the name of a user (including the security
domain) to the static GetUser() method of the
System.Web.Security.Membership class to retrieve that user as a
System.Web.Security.Membership object. The following example
accesses the context user as an instance of that class:
Sitecore.Security.Accounts.User user =
Sitecore.Context.User;
Sitecore.Diagnostics.Assert.IsNotNull(user, "context
user");
System.Web.Security.MembershipUser membershipUser =
System.Web.Security.Membership.GetUser(user.Name);
Conversely, you can use the static FromName() method of the
Sitecore.Security.Accounts.User class to retrieve a
Sitecore.Security.Accounts.User object based on the UserName
property of a System.Web.Security.MembershipUser object. Sitecore
does not provide a method to access all known users on the system. You
can use the static GetAllUsers() method of the
System.Web.Security.Membership method to iterate all users using
System.Web.Security.MembershipUser objects, and convert each to a
Sitecore.Security.Accounts.Account object only if needed, as in the
following example:
foreach(System.Web.Security.MembershipUser membershipUser
in System.Web.Security.Membership.GetAllUsers())
{
Sitecore.Security.Accounts.User user =
Sitecore.Security.Accounts.User.FromName(membershipUser.Use
rName, false);
// process user
}
Alternatively, theGetUsers() method of the
Sitecore.Security.Domains.Domain class returns all of the users in that
security domain. You can use the GetDomainNames() method of the static
Sitecore.Configuration.Factory class to retrieve the names of all
security domains, and the GetDomain() method of that class to retrieve a
security domain by name. The following example web control
demonstrates how to use these methods to iterate all users in all domains,
which is functionally equivalent to using the GetAllUsers() method of
the System.Web.Security.Membership class. You can determine which
approach performs better for your load of users and purpose, including
sorting, filtering, and any additional requirements. The GetUsers()
method of the Sitecore.Security.Domains.Domain class may be more
efficient than the GetAllUsers() method of the
System.Web.Security.Membership class when you need to iterate the
users in a single Sitecore security domain.
namespace SitecoreBook.Web.UI.WebControls
{
public class ListDomainsAndUsers :
Sitecore.Web.UI.WebControl
{
protected override void
DoRender(System.Web.UI.HtmlTextWriter output)
{
// iterate the names of all Sitecore security domains
foreach(string domainName
in Sitecore.Configuration.Factory.GetDomainNames())
{
// retrieve the domain object
Sitecore.Security.Domains.Domain domain =
Sitecore.Configuration.Factory.GetDomain(domainName);
output.WriteLine("</ul>");
}
else
{
output.WriteLine(" (no users)");
}
}
}
}
}
ListDomainsAndUsers.cs
User Profiles
Each user has a profile, which can define any number of properties
specific to that user, such as the user's full name and e-mail address. You
can update user profiles in the User Manager. To access the User Manager,
log in to the Sitecore desktop, click the Sitecore button, click Security
Tools, and then click User Manager. Figure 4.9 shows the User Manager.
Figure 4.9
To optimize performance, as shown in the example, invoke the Save() method of the
Sitecore.Security.UserProfile class after updating multiple profile properties rather
than after setting each property.
Be sure to make this change in the Core database rather than the Master database, or
the fields will not appear in the User Manager.
Anonymous Users
Each security domain can contain a user named Anonymous to represent
all visitors who access the solution without providing authentication
credentials. Sitecore ensures that the Anonymous user exists in all security
domains that require such a user. You do not need to create or delete
Anonymous users in any security domain. The Anonymous user in each
security domain can have either no access or limited read access to the
solution, but should not have read access to everything, and should have
write access to nothing.
While Anonymous is a user, it actually represents a class of visitors who
access the solution without authenticating. This class includes both actual
visitors and robots such as search engines. For this reason, the Anonymous
user is an exception to the rule that you should always apply access rights
for roles rather than for users — the Anonymous user functions something
like a role. One easy way to deny access to all users who have not
authenticated is to deny access to the Anonymous user.
You can use the method of the
GetAnonymousUser()
Sitecore.Security.Domains.Domain class to access the Anonymous
user for a security domain.
There is no Anonymous user in the Sitecore security domain, as all CMS users must
authenticate to access the system.
Context User
The context user is the user associated with the current HTTP request. For
each HTTP request, the UserResolver processor in the
httpRequestBegin pipeline determines the context user. If the
UserResolver processor cannot identify a known user, the context user is
the Anonymous user in the security domain associated with the context
site.
You can access the context user through the static
Sitecore.Context.User property. For example, the following code
shows how to check for the context user safely:
Sitecore.Diagnostics.Assert.IsNotNull(Sitecore.Context.User
, "context user");
Sitecore.Security.Accounts.User = Sitecore.Context.User;
Roles
A role is a collection of users. Roles simplify the application of access
rights by grouping users.
The Sitecore.Security.Accounts.Role class represents a security
role. Use the following methods in the classes specified to perform
essential tasks with this class:
Sitecore.Security.Accounts.Role.Exists() — Determines if a
role exists.
Sitecore.Security.Accounts.Role.FromName() — Retrieves a
role, much like the static FromName() method in the
Sitecore.Security.Accounts.User class described in the previous
section, but without the second argument that indicates whether to
update the internal record indicating when the account last accessed
the solution.
Sitecore.Security.Accounts.Role.IsMember() — Determines
whether a user is a member of a role. The first parameter specifies the
account, which can be a Sitecore.Security.Accounts.User or
Sitecore.Security.Accounts.Role class. The second parameter
indicates whether to return true if
Sitecore.Security.Accounts.Role is the global Everyone role or
the Everyone role for the domain associated with the user. The third
parameter indicates whether to apply nested roles as described in a
subsequent section of this chapter.
System.Web.Security.Roles.CreateRole() — Creates a role.
Include the security domain name with the role name that you pass as
the argument to this method.
System.Web.Security.Roles.DeleteRole() — Deletes a role.
Depending on the number of roles, the number of users, and whether
you use nested roles as described in a subsequent section of this
chapter, this operation can take some time.
To access the roles associated with a user, you can use the Roles
property of the Sitecore.Security.Accounts.User class, which exposes
the Sitecore.Security.Accounts.UserRoles class. The
Sitecore.Security.Accounts.UserRoles class exposes the Add(),
Contains(), Remove(), and RemoveAll() methods, which add a user to a
role, determine whether a user's roles directly include another role (not
respecting nested roles as described in a subsequent section of this
chapter), remove a user from a role, and remove a user from all roles,
respectively. The Sitecore.Security.Accounts.User class exposes the
IsInRole() method to determine whether a user is a member of a role,
respecting nested roles as described in a subsequent section of this chapter.
When you delete a role, Sitecore does not update access rules defined in
items to reflect that deletion. Because the role does not exist, such access
rules are irrelevant, and cannot apply. While this means that you can
restore access rights by recreating the role, it continues to appear in user
interfaces, which could confuse users. You are responsible for updating
access rights in items that refer to deleted roles. The most common means
of doing so are the following:
A manual process in the Sitecore user interface
A scheduled process to iterate all items and remove access rights
assigned to roles that no longer exist
An event handler, pipeline processor, or other solution to remove
access rights when a user removes a role
The example scheduled agent shown in Listing 4.2 removes access rules
associated with users and roles that do not exist for all items in the
database(s) specified to the class as a configuration parameter.
Sitecore.Configuration.Factory.GetDatabase(dbName);
Sitecore.Diagnostics.Assert.IsNotNull(database,
"datbase " + dbName);
Sitecore.Diagnostics.Log.Info(
this + " : begin processing database " + dbName,
this);
this.RemoveInvalidAccessRights(database.GetRootItem());
Sitecore.Diagnostics.Log.Info(
this + " : completed processing database " +
dbName, this);
}
}
if (modified)
{
item.Security.SetAccessRules(updated);
}
In this agent:
The Databases property specifies a list of databases from which to
remove access rights that specify users and roles that do not exist.
The Sitecore scheduling engine invokes the Run() method of the
agent.
The Run() method invokes the recursive
RemoveInvalidAccesssRules() method for the root item in each
database specified by the Databases property.
The recursive RemoveInvalidAccesssRules() method sets the
modified flag to indicate whether the item contains invalid access
rules, creates the updated list to contain valid access rules for the
item, and then iterates the access rules for the items adding valid rules
to the updated list and setting the modified flag in the case of an
invalid rule.
If the item contains invalid access rules, the agent logs a warning and
updates the access rules for the item to those specified in the updated
list.
The RemoveInvalidAccessRules() method calls itself for each child
of the item, recursively.
To schedule this agent to run approximately once daily, add a
/configuration/sitecore/scheduling/agent element to the
Web.config file based on the following example that will remove invalid
access rules from the Master and Core databases:
<agent
type="Sitecore.Sharedsource.Tasks.RemoveInvalidAccessRules,
assembly"
method="Run"
interval="1.00:00:00">
<databases hint="list">
<database>master</database>
<database>core</database>
</databases>
</agent>
RemoveInvalidAccessRules.config
You do not need to include publishing target databases such as the Web in the list of
databases. Updating the Master database and publishing those changes to the
publishing target databases corrects this issue in those target databases.
For more information about scheduling tasks with Sitecore, see my blog
post at http://bit.ly/shQhEG. For more information about passing
parameters to types specified in the Web.config file, see my blog post at
http://bit.ly/A7Ae1s.
Everyone Roles
The Everyone role automatically contains all users in a security domain,
including the Anonymous user. Each security domain can contain an
Everyone role. An additional Everyone role associated with no security
domain contains all users in all security domains. You can use the
Everyone role to allow an access right to all members of a domain.
You cannot use the Everyone role to deny an access right to Sitecore administrators. A
user with the User Is Administrator check box selected on the General tab of the user's
profile has all access rights to all items, regardless of the access rights defined for those
items. Unless you implement custom code to block functions at runtime rather than using
access rights, you cannot deny those functions to Sitecore administrators.
You do not need to create or delete the Everyone role in any security
domain. Technically, you can remove or rename the Everyone role in each
security domain by updating the
/App_Config/Security/Domains.config file according to the comments
in that file, but I advise against making such changes without specific
direction from Sitecore's customer service department.
The Everyone role is virtual, and does not exist in the role management
provider. If you use the static Exists() method of the
Sitecore.Security.Accounts.Role class to check whether the Everyone
role exists, that method returns false. The list of roles associated with
each user never includes the Everyone role. You can use the
GetEveryoneRole() method of the
Sitecore.Security.Domains.Domain class to access the Everyone role
in a security domain.
Nested Roles
Sitecore supports nested roles, meaning that roles can be members of other
roles, or that each role can contain other roles. Nested roles can simplify
security configuration in some scenarios, such as when some roles are
subsets of others. Figure 4.11 shows the nesting of roles within the
Sitecore Client Users role in the Sitecore security domain.
Figure 4.11
As the diagram depicts, the various roles listed on the right, from
Sitecore Client Administrators through Sitecore Client Publishing, are all
members of the Sitecore Client Users role, as are the Sitecore Client
Authoring and the Sitecore Client Developing roles. Stated in reverse, the
Sitecore Client Users role contains these roles. The Author role is a
member of the Sitecore Client Authoring role, and hence an indirect
member of the Sitecore Client Users role. The Developer role is a member
of both the Author role and the Sitecore Client Developing role, and hence
an indirect member of the Sitecore Client Users role.
You can use the static
Sitecore.Security.Accounts.RolesInRolesManager class to configure
nested roles. You can access the static RolesInRolesSupported property
of this class to determine whether the solution supports nested roles.
Relevant static methods in the
Sitecore.Security.Accounts.RolesInRolesManager class are:
IsRoleInRole() — Determines whether a role contains a nested role
AddRoleToRole() — Adds a nested role to a role
RemoveRoleFromRole() — Removes a nested role from a role
GetRolesInRole() — Retrieves roles nested within the role. This
method optionally includes roles nested within the requested roles, no
matter how deep the nesting becomes.
Security Domains
Security domains segregate groups of security accounts, such as CMS
users and users of the published websites. Each user and role exists within
a domain.
Each /domains/domain element in the
/App_Config/Security/Domains.config file configures a Sitecore
security domain. You can update this file to add or remove security
domains and to update properties of existing security domains.
Sitecore includes three default security domains:
Sitecore: Contains the CMS accounts
Extranet: Contains accounts for the published websites
Default: Acts as a default security domain for accounts that do not
belong to either of the other security domains
The Sitecore.Security.Domains.Domain class represents a Sitecore
security domain. You can use the static Sitecore.Context.Domain
property to access the context domain, which is the security domain
associated with the context site. If the context site is null, or does not
specify a security domain, the Sitecore.Context.Domain property
returns the default Sitecore security domain specified by the
/App_Config/Security/Domains.config file.
Alternatively, you can use the static
Sitecore.Configuration.Factory.GetDomain() method to access a
named domain. For example, you can use the following code to access the
domain named extranet:
Sitecore.Security.Domains.Domain extranet =
Sitecore.Configuration.Factory.GetDomain("extranet");
Sitecore.Diagnostics.Assert.IsNotNull(extranet,
"extranet");
While these techniques are as secure as the code you write within the contained blocks of
code, whenever possible, use access rights to provide CMS users with access to the items
they need to perform their responsibilities, and to provide visitors to the published sites
with read access to the items appropriate to their levels of privilege.
if (Sitecore.Security.Accounts.User.Exists(username))
{
Sitecore.Security.Accounts.User apiUser =
Sitecore.Security.Accounts.User.FromName(username,
false);
using (new
Sitecore.Security.Accounts.UserSwitcher(apiUser))
{
// code to execute as the user named API in the
Sitecore security domain
}
}
Because they exist outside the /configuration/sitecore element in the /web.config file,
you cannot use a Web.config include file to configure these elements.
Error Management
// lazy-loading representation of
/configuration/system.web/customErrors
public static CustomErrorsSection Config
{
get
{
if (_config == null)
{
System.Configuration.Configuration config =
WebConfigurationManager.OpenWebConfiguration("/");
_config =
(CustomErrorsSection)config.GetSection("system.web/customErr
ors");
Sitecore.Diagnostics.Assert.IsNotNull(_config,
"customErrors");
}
return _config;
}
}
500.ToString(System.Globalization.CultureInfo.InvariantCultu
re));
return _error500Url;
}
}
// if the /configuration/system.web/customErrors
element is absent
if (Config == null)
{
return true;
}
if (!String.IsNullOrEmpty(Sitecore.Context.RawUrl))
{
result += System.Environment.NewLine
+ this.GetType().ToString()
+ " : Original URL : "
+ Sitecore.Context.RawUrl;
}
if (HttpContext.Current != null
&& HttpContext.Current.Request != null
&&
!String.IsNullOrEmpty(HttpContext.Current.Request.RawUrl))
{
result += System.Environment.NewLine
+ this.GetType().ToString()
+ " : Current URL : "
+ HttpContext.Current.Request.RawUrl;
}
return result;
}
}
}
Listing 5.2 defines the
SitecoreBook.Exceptions.CustomExceptionBase abstract class from
which you can derive any number of classes that represent specific types of
exceptions. Each such deriving class can invoke the GetLogMessage()
method in this abstract base class, which attempts to add the type of the
exception and the URL associated with the current HTTP request to the
result of calling the ToString() method in the System.Exception class
from which the SitecoreBook.Exceptions.CustomExceptionBase class
derives. Where you trap such exceptions, you can write the value returned
by the GetLogMessage() method to the Sitecore log or elsewhere to include
the exception type and the requested URL in error messages whenever
possible.
You can create any number of classes that derive from the
SitecoreBook.Exceptions.CustomExceptionBase class to represent
specific types of exceptions. For example:
namespace SitecoreBook.Exceptions
{
public class ActualException :
SitecoreBook.Exceptions.CustomExceptionBase
{
public ActualException(string message) : base(message)
{
}
}
}
When you experience an error condition that you cannot manage or would
like to handle at a higher level, throw an exception as shown in the
following example:
throw new SitecoreBook.Exceptions.ActualException("Error
message");
try
{
// invoke the XSL transformation and write the
output to the output stream
base.DoRender(writer);
writer.Close();
if (!String.IsNullOrEmpty(this.Path))
{
message += " (" + this.Path + ")";
}
Sitecore.Reflection.ReflectionUtil.SetProperty(xslFile, str,
parameters[str]);
}
// exception message
string message = this._lastException.Message;
// details about the exception
string details = this._lastException.ToString();
this.RenderError(ex.Message,
ex.GetType().ToString(), ex.ToString(), output);
}
}
if (String.IsNullOrEmpty(id))
{
id = this.GetType().ToString();
}
return id;
}
}
}
In the SitecoreBook.Web.UI.WebControl prototype abstract base class
for web controls shown in Listing 5.7:
The CacheAfterExpiration property controls whether the layout
engine can cache the output generated by this instance of the control.
The DisableErrorManagement property controls whether to apply the
custom error management logic to this instance of the control.
The overridden Render() method calls the Render() method in the
Sitecore.Web.UI.WebControl abstract base class and exits if
DisableErrorManagement is true.
If DisableErrorManagement is not true, the Render() method
constructs a temporary System.Web.UI.HtmlTextWriter, opens a
try...catch block, and passes that temporary writer to the existing
Render() method in the Sitecore.Web.UI.WebControl abstract base
class, preventing that method from writing directly to the output
stream.
If no exception occurs, the Render() method writes the content of the
temporary System.Web.UI.HtmlTextWriter object to the actual
output stream and exits.
In the case of an exception, the Render() method uses the
Sitecore.Web.UI.ErrorHelper static class shown in Listing 5.1 to
interrogate the mode attribute of the
/configuration/system.web/customErrors element in the
Web.config file to determine whether to redirect to a friendly error
management page.
If the error helper does not redirect the client, the Render() method
calls the RenderError() method in the
Sitecore.Web.UI.WebControl abstract base class, which determines
whether and how to render information about the exception.
If the CacheAfterException property is true, the overridden
RenderError() method replicates the functionality of the
RenderError() method in the Sitecore.Web.UI.WebControl abstract
base class without setting the flag that indicates an error occurred,
which would otherwise prevent Sitecore from caching the output of this
instance of the control.
If the CacheAfterException property is false, the overridden
RenderError() method calls the RenderError() method in the
Sitecore.Web.UI.WebControl abstract base class, signaling that an
error occurred and preventing the layout engine from caching the
output of this instance of the control.
The GetCachingID() method returns the value returned by the
GetCachingID() method in the Sitecore.Web.UI.WebControl
abstract base class, or the namespace and name of the class if that
value is null or an empty string. While this method does not relate to
the purpose described in this section, I assume that you might want to
cache the output of any web control, so you might as well include this
implementation in the base class for all web controls. If you know you
do not want to cache the output of a web control, do not configure
caching for that web control as described in Chapter 6.
Depending on which additional methods of the
Sitecore.Web.UI.WebControl class and its base classes your web controls
implement and where you experience or expect to experience exceptions in
your solution, you can follow a similar pattern to provide error control at
other phases in the ASP.NET lifecycle. For example, similar to what you
can do for sublayouts, you can override the CreateChildControls()
method of the System.Web.UI.Control abstract base class for all controls.
The System.Web.UI.Control class is an eventual base class for the
Sitecore.Web.UI.WebControl class. The CreateChildControls()
method is just an example; this method handles only one phase in the
ASP.NET page lifecycle that might concern you. Your override can add
exception management to any phase(s) of the ASP.NET page lifecycle in all
web controls that do not implement methods to handle those phases. When
your control experiences an exception, you can set something similar to the
_lastException variable used in the sublayout example to avoid calling
the DoRender() method of your web control if an exception occurs in that
control earlier in the page lifecycle. You would need to use try...catch
blocks to trap exceptions in all methods of any web controls that actually
implement methods to handle such lifecycle phases.
Because web controls inherit from a base class that contains all the
required features, you do not have to add a line to update any layouts or
sublayouts, add a line to any configuration file, or update any line to the
/App_Config/Prototypes.config file. This solution for handling errors in
the render phase of the ASP.NET lifecycle applies automatically to all web
controls that inherit from the SitecoreBook.Web.UI.WebControl abstract
base class shown in Listing 5.7, whether you bind those controls statically
in code or dynamically using layout details.
Sitecore.Diagnostics.Log.Error(customException.GetLogMessage
(), this);
HttpContext.Current.Server.ClearError();
}
}
The code for the Page_Error() method shown in Listing 5.9, intended
for use in the code-behind of layouts, traps all exceptions that reach the
page level due to no trapping at any lower level. This Page_Load() method
implementation uses the
System.Web.HttpContext.Current.Server.GetLastError() method to
retrieve the most recent exception. If the exception derives from the
SitecoreBook.Exceptions.CustomExceptionBase abstract base class for
exceptions shown in Listing 5.2, this Page_Load() method implementation
calls the GetLogMessage() method of that exception, writes the result of
that method call to the Sitecore log, and then invokes the
System.Web.HttpContext.Current.Server.ClearError() method to
clear that exception. Otherwise, it allows the exception to bubble up to the
next layer that can handle exceptions.
This solution will not trap every possible error that could occur while
processing a layout, such as if the Inherits, CodeBehind, or CodeFile
attributes of the Page directive of a layout (.aspx file) specify classes that
do not exist.
For compile-time error detection, avoid inline code in the global.asax file by creating and
compiling a class and updating the default global.asax file to use that class. For
instructions, see the “How to Trap Application Exceptions” section of The Sitecore
Presentation Component API Cookbook (http://bit.ly/r76c6K).
To increase system security, never allow a value of Off for the mode attribute of the
/configuration/system.web/customErrors element in the /web.config file. Otherwise,
when an error occurs, you could expose information that attackers could use in attempts
to compromise the system.
// extension method
public static class SiteContext
{
// the name of the notFound attribute of <site> elements
in the web.config file
public const string NotFoundAttribute = "notFound";
Sitecore.Security.AccessControl.AuthorizationManager.IsAllow
ed(
notFound,
Sitecore.Security.AccessControl.AccessRight.ItemRead,
Sitecore.Context.User);
Sitecore.Diagnostics.Assert.IsTrue(
allowed,
"context user access to 404 item");
return notFound;
}
}
}
The SitecoreBook.Sites.SiteContext static class shown in Listing
5.10 defines the GetNotFoundItem() extension method for the
Sitecore.Sites.SiteContext class provided by Sitecore. For more
information about extending classes provided by Sitecore with additional
methods, see my blog post at http://bit.ly/ntowNQ. In this class shown in
Listing 5.10:
The NotFoundAttribute constant defines the name of the attribute of
/configuration/sitecore/sites/site elements in the Web.config
file that can contain the path to the item that handles the 404 condition
for each managed site.
The GetNotFoundItem() extension method retrieves the attribute
named by the NotFoundAttribute constant from the
Sitecore.Sites.SiteContext argument passed to the method
implicitly using the first argument (me). That argument abstracts the
/configuration/sitecore/sites/site element in the Web.config
file that defines the context site. If no such attribute exists in that
<site> element, the GetNotFoundItem() method returns null to
indicate that the site does not override Sitecore's default logic for
handling the 404 condition.
If the attribute named by the NotFoundAttribute constant exists in
that /configuration/sitecore/sites/site element, the
GetNotFoundItem() method constructs the full path to that item. To do
so, it uses the StartPath property of that
Sitecore.Sites.SiteContext object, which combines the rootPath
and startItem attributes of that <site> element to specify the home
item for that managed site.
The GetNotFoundItem() method throws an exception if the item at
that path does not exist in the context database or if the context user
does not have read access to that item. Otherwise, it returns that item.
You may have noticed that the code in Listing 5.10explicitly calls the
Sitecore.Security.AccessControl.AuthorizationManager.IsAllowed() static method to
determine if the context user can access the 404 item for the context site. While the
GetItem() method of the Sitecore.Data.Database class returns null if the context user
cannot access the item specified as the first argument to this method, because the
UserResolver processor in the httpRequestBegin pipeline determines the context user,
Sitecore cannot establish a proper security context before it invokes that pipeline.
Therefore, the security context for the httpRequestBegin pipeline is undefined, and you
can assume it runs in the context of a user with administrative rights. Processors in this
pipeline perform explicit security checks as done in Listing 5.10, and since you will call
the method in that listing from an httpRequestBegin pipeline processor or in any methods
that you invoke from such processors.
Add a new pipeline processor to apply the site-specific 404 item after the
default ItemResolver in the httpRequestBegin pipeline defined in the
Web.config file. Listing 5.11 provides sample code for such a processor.
For optimal performance, exit processors as soon as you determine that the processing
context is irrelevant.
This processor does not handle managed sites that define the
virtualFolder attribute as anything other than slash. In such cases,
the Process() method exits immediately and the httpRequestBegin
pipeline continues.
If the requested URL is empty, indicating a request for the home page
of the context site, or if that URL is an external page, or maps to a file
on the file system, the processor cannot handle that condition and the
Process() method exits immediately and the httpRequestBegin
pipeline continues.
If none of the conditions described previously apply, the processor sets
the context item to the item that handles the 404 condition for the
context site using the GetNotFoundItem() extension method for the
Sitecore.Sites.SiteContext class defined in Listing 5.10. If the
definition for the context site does not define the notFound attribute
evaluated by that method, then the context item continues to be null,
and the httpRequestBegin pipeline applies its default logic for
handling the 404 condition by redirecting to the URL specified by the
ItemNotFoundUrl setting in the Web.config file.
For items that handle the 404 condition, you can statically or dynamically
bind a presentation control to a placeholder in the layout or a nested
sublayout to set the HTTP status code for the response to 404. The example
in Listing 5.12 provides a web control that generates no output, but sets the
HTTP status code of the response to 404.
While it would be convenient to set the status code in the httpRequestBegin pipeline
processor shown in Listing 5.11, that pipeline runs too early in the ASP.NET page lifecycle
for this to work. If you set the response status code in that processor, IIS or ASP.NET
handles the 404 condition with their own logic, preventing the layout engine from
applying layout details defined in the item you specify to handle the 404 condition.
Listing 5.12: A presentation control to set the HTTP status in the response
to 404
namespace SitecoreBook.Web.UI.WebControls
{
using System.Web.UI;
Although you should not cache the output of this web control and this control is unlikely to
experience exceptions at any phase in the ASP.NET page lifecycle, the
SitecoreBook.Web.UI.WebControls.SetNotFoundStatus web control could inherit from the
SitecoreBook.Web.UI.WebControl prototype abstract base class shown in Listing 5.7
instead of the Sitecore.Web.UI.WebControl class as shown in Listing 5.12.
Finally, create items to handle the 404 condition under the home item of
each managed site for which you want to apply this custom 404
management logic, and set the notFound attribute of the corresponding
/configuration/sitecore/sites/site elements in the Web.config file
to the paths to those items relative to the home items of those managed
sites. For example, set the notFound attribute to /notfound (with the
leading slash but without the .aspx extension) to trigger the child of the
home item named notfound. If you do not set the notFound attribute for
one of the managed sites, Sitecore redirects to the URL specified by the
ItemNotFoundUrl setting in the Web.config file for 404 requests associated
with that managed site, which results in a client or server redirect
depending on the value of the RequestErrors.UseServerSideRedirect
setting in the Web.config file.
Some apparent error conditions, specifically the HTTP 404 (not found)
condition, do not always indicate errors. You can sometimes use the 404
management facilities of IIS and ASP.NET to your advantage. For example,
IIS versions prior to 7 that added the integrated mode for application pools,
IIS did not use ASP.NET to handle all HTTP requests, but used ASP.NET
only for URLs with certain extensions such as .aspx. You could set the IIS
404 page to a URL such as /default.aspx to trick IIS into triggering
ASP.NET for all requests that did not map to files within the document root.
For another example httpRequestBegin processor, see the
Sitecore.Sharedsource.Pipelines.HttpRequest.NotFoundSearchRes
olver processor in the PageNotFound (http://bit.ly/yyGqrh) Sitecore
Shared Source project, which attempts to determine search keywords from
the requested URL.
For more information about handling the HTTP 404 condition with Sitecore, see The
Sitecore Guide to Handling HTTP 404 (http://bit.ly/nFMNTd).
System Outages
Sitecore depends on the underlying platform, which includes Microsoft
Windows, IIS, ASP.NET, supporting relational databases, and of course the
underlying hardware, including network facilities. If any of these elements
does not function properly, Sitecore cannot function. If the databases are
unavailable, Sitecore is unavailable. Although certain Sitecore features,
such as agents configured in the Web.config file, continue to run while
ASP.NET is running, they fail if they attempt to access a Sitecore database
or various Sitecore APIs. Research and implement best practices and tools
for handling scheduled and unscheduled application outages on the
ASP.NET platform, including external monitoring software and services.
While this book covers the most important topics on the subject, space does not permit a
comprehensive guide to optimizing the performance of the technology platform. For
information about optimizing these technologies, see Improving .NET Application
Performance and Scalability (http://bit.ly/xMTm7r; ISBN 978-8120326989) by Microsoft
Press.
Utility Caches
Sitecore provides a number of caches for different purposes. In general,
other than defining appropriate size limits as described later in this
chapter, you can ignore the utility caches included here only for
informative purposes. Sitecore provides most of these caches to improve
the performance of Sitecore CMS user interfaces such as the Content
Editor. Such utility caches include the following:
Client Data Store cache — This cache stores information about
authenticated users, including user names and properties.
Security caches — The IsUserInRole, UserProfile, and AccessResult
(security) caches store information about whether users are members
of roles, user profiles, and access rights for items.
Viewstate cache — This cache stores information about the state of
ASP.NET controls.
Registry cache — Sitecore user interfaces use the registry cache for
various purposes, such as to store the ID of the item selected by each
user in the Content Editor.
XSL caches — Sitecore associates an eXtensible Stylesheet Language
(XSL) cache with each managed site to store the transformation .NET
objects used to implement XSL renderings.
The XSL cache does not contain the output of XSL transformations, but the objects used
to implement those transformations. The output cache for each managed site described in
a subsequent section of this chapter can contain cached output from XSL renderings. If
your solution depends on XSL renderings, and especially if it uses XSL renderings
extensively, then you should not ignore the XSL cache. In that case, the XSL cache can
significantly improve performance by minimizing the number of load and process
operations to build transformation objects for XSL renderings.
This is not a comprehensive list of all utility caches — only those that
may interest typical Sitecore developers. You can generally ignore any
cache not specifically mentioned in this chapter. This book does not touch
upon these caches beyond the information provided here. For a complete
list of the caches in use on a Sitecore instance, access the cache
administration page on that instance (a subsequent section of this chapter
provides more information about this tool).
Database Caches
To minimize round trips to the database, Sitecore caches data about items
in each database at a number of layers. These database caches can
drastically affect the performance of a Sitecore solution, both at startup
and throughout the lifecycle of the application. Sitecore automatically
maintains these database caches for each database throughout the lifetime
of the application.
Prefetch Caches
Prefetch caches contain information about items that the system typically
accesses during or immediately subsequent to starting the CMS. Sitecore
loads the prefetch caches during application initialization or immediately
thereafter. Prefetch caches optimize performance immediately subsequent
to application startup, but loading too much data into a prefetch cache can
adversely affect the time required for the application to initialize. Prefetch
caches provide the first caching layer between the application and the
database. Each prefetch cache contains data from a single data provider,
such as the data provider associated with each Sitecore database.
Each entry in a prefetch cache contains data for a single item returned by
the data provider associated with the cache. Each such entry contains field
values for all versions of the item in all languages available from that
provider. Because the Master database can contain multiple versions for
each language, the size of the prefetch cache typically exceeds that of the
corresponding caches for each publishing target database, which contain
only one version in each language for each item. Entries in these caches
can contain information about items related to that item, such as its parent
and children.
The .config files in the /App_Config/Prefetch subdirectory of the
document root of the IIS website control the prefetch caches. The names
of these files match the names of the corresponding database; for example,
the /App_Config/Prefetch/Core.config file controls the prefetch cache
for the Core database. Sitecore merges the information in these files with
global prefetch cache configuration definitions in the
/App_Config/Prefetch/Common.config file. Together, these
configuration files limit the size of the prefetch caches, control which
items to load into each of these caches, and dictate whether to include
information about the children of items in each of these caches.
The default /App_Config/Prefetch/Web.config file, which defines
prefetch cache settings for the default publishing target database named
Web, contains the following XML by default:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<cacheSize>10MB</cacheSize>
<template desc="alias">{54BCFFB7-8F46-4948-AE74-
DA5B6B5AFA86}</template>
<template desc="layout">{3A45A723-64EE-4919-9D41-
02FD40FD1466}</template>
<template
desc="xsl rendering">{F1F1D639-4F54-40C2-8BE0-
81266B392CEB}</template>
<item desc="home">{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}
</item>
<children desc="main items">{110D559F-DEA5-42EA-9C1C-
8A5DF7E70EF9}</children>
</configuration>
If your CMS users complain of slow performance, you may want to adjust configuration
of the prefetch cache for the Master database (in the
/App_Config/Prefetch/Master.config file) to include the items accessed most frequently
in the content management environment. You can use the cache statistics page described
in a subsequent section of this chapter to tune caches.
Data Caches
Data caches contain information from all the data providers defined for a
database. Under the default configuration, each representation of a
database depends on a single data provider that connects to an actual
database, but it is possible for such a database representation to retrieve
data from multiple providers. For example, you could implement a data
provider that retrieves information from an external product information
management (PIM) or order management system and represents that data
as if it were native to the Master database. The data cache could contain
data retrieved from all the providers defined for a representation of a
database.
Data caches retrieve data from database prefetch caches where such
caches exist, and therefore contain the same information but in a different
format. When Sitecore purges data from a prefetch cache, it also purges
corresponding data from the data cache that depends on that prefetch
cache. Not all data providers implement prefetch caching; database data
caches are especially important for such providers.
Similar to prefetch caches, entries in database data caches represent
individual items, and each entry contains field values for all versions in all
languages available for an item, as well as the relations between that item
and other items. Unlike prefetch caches, Sitecore does not prepopulate
data caches at application initialization, but rather as the application
(specifically, the item caching layer) demands data from the data provider.
Data caches use .NET classes that provide extremely fast access to
maximize performance while protecting data providers, which typically
abstract database servers, from constant requests.
After your solution is up and running, performance can often benefit
from data cache tuning as described later in this chapter. Specifically,
when monitoring cache utilization indicates that a data cache has reached
its size limit, assuming sufficient available memory, you should increase
the size limit for that cache.
To specify a default size limit for all database data caches, set the
Caching.DefaultDataCacheSize setting in the Web.config file. To
specify a size limit for the data cache for an individual database, set the
value of the
/configuration/sitecore/database/data/cacheSizes/data element
in the Web.config file, where the value of the id attribute of the
/configuration/sitecore/database element containing that <data>
element matches the logical name of the database.
Item Caches
Each entry in a database item cache represents an individual version of an
item in a single language using the well-known
Sitecore.Data.Items.Item class. Most Sitecore developers access items
using this class, implicitly accessing an item cache rather than accessing a
database directly. Therefore, automatic caching of objects using the
Sitecore.Data.Items.Item type with a well-populated item cache can
really make a Sitecore solution fly.
Item caches retrieve data from data caches. When Sitecore purges data
from a data cache, it also purges corresponding data from the item cache
that depends on that data cache. Sitecore does not populate item caches at
application initialization, but rather as the application demands data.
To specify a default size limit for all database item caches, set the
Caching.DefaultDataCacheSize setting in the Web.config file. To
specify a size limit for the item cache for an individual database, set the
value of the
/configuration/sitecore/database/data/cacheSizes/item element
in the Web.config file, where the value of the id attribute of the
/configuration/sitecore/database element containing that <item>
element matches the logical name of the database. To disable all database
item caches, perhaps because you suspect item caching as the cause of an
issue you are troubleshooting, you can set the
Caching.ItemCachingEnabled setting in the Web.config file to false.
Sitecore does not track the exact size of item caches; it approximates the
amount of memory consumed to determine whether each cache has
reached its size limit. To estimate the size of each item cache, Sitecore
multiplies factors, including the number of entries in the cache, the value
specified by the Caching.AverageItemSize setting in the Web.config
file, and the load factor initially defined by the Caching.LoadFactor
setting in the Web.config file. The Caching.AverageItemSize setting in
the Web.config provides an estimate of the average size of each entry in
the item cache. The Caching.LoadFactor setting in the Web.config file is
simply a factor that Sitecore uses to adjust cache size estimates. Before
the number of entries in the cache exceeds the configured size limit for the
cache divided by the product of Caching.AverageItemSize and the load
factor, Sitecore begins to evict entries from the cache. Increasing the value
of either of these two settings reduces the number of items Sitecore can
store in the cache before reaching its size limit. Your solution may benefit
from an accurate Caching.AverageItemSize estimate, which depends on
your unique solution. For more information about these settings, see The
Sitecore Cache Configuration Reference (http://bit.ly/qYIAia) and the
comments above these settings in the Web.config file.
The Caching.LoadFactor setting affects Sitecore's size estimates for all caches stored in
memory, but the Caching.AverageItemSize setting affects only the item caches.
if (knownItem != null)
{
return knownItem.Children[childName];
}
return null;
}
A slightly more efficient, and arguably more maintainable,
implementation would leverage the path cache as shown here:
private void Sitecore.Data.Items.Item GetKnownChild(
Sitecore.Data.Database database,
string childName)
{
return database.GetItem("/sitecore/content/knownitem/" +
childName]);
}
These two examples achieve the exact same result, but the former
accesses the children of the known item, whereas the latter accesses an
individual child item directly using its path. The second version can
therefore utilize the path cache during subsequent reads of children under
the same known item, which is more efficient than accessing its children.
While some readers may intuit this relative advantage, others might
assume a performance advantage from using the known item that Sitecore
caches automatically, and potentially its cached children as well (in reality,
Sitecore may confirm the children each time you access them). Together,
minor optimizations like this can add up to dramatically increased
performance.
Storing site media caches under /App_Data prevents IIS from serving cached media files
directly. While it is unlikely that an attacker could determine the URL of a cached media
file, moving the media cache to a subdirectory that IIS does not protect could allow
attackers to access cached media directly, increasing the attack surface and thereby
reducing security.
If you specify an alternate subdirectory for a media cache, update elements within the
Sitecore.Tasks.CleanupAgent /configuration/sitecore/scheduling/agent element in
the Web.config file to ensure that the process to remove old entries from the media cache
includes that subdirectory.
For the published site to benefit from output caching, you should
configure output caching for each presentation component. Sitecore does
not cache the output of a rendering unless you instruct it to do so and
optionally define the conditions under which to generate multiple entries
in the output cache for that rendering. To minimize both the number of
times Sitecore invokes each rendering and the amount of memory used by
the output cache, cache the output of each rendering by the fewest possible
criteria described in the following paragraphs.
While you can configure default (implicit) caching options for a
rendering in the Caching section of the definition item associated with the
rendering, I prefer to explicitly define caching options for each use of each
rendering. To configure caching options in the layout details of the
standard values for a data template or an individual item, follow these
steps:
1. Select the item in the Content Editor. For instructions on how to
access the Content Editor, see Chapter 1.
2. Select the Presentation tab, and then click Details in the Layout
group. The Layout Details dialog appears as shown in Figure 6.1.
3. Click the rendering for which to configure caching options. The
Control Properties dialog appears as shown in Figure 6.2.
4. To enable output caching for the rendering, select the Cacheable
checkbox. Until you select the Cacheable checkbox, Sitecore will not
cache the output of the rendering, and you cannot select additional
caching options (the Vary By options).
5. Click OK. The Control Properties dialog disappears and you return
to the Layout Details dialog.
6. Click OK again. The Layout Details dialog disappears and you
return to the Content Editor.
You should also define caching options where you bind presentation controls statically
and programmatically. To define caching options for presentation controls that you bind
statically, set the Cacheable attribute and the appropriate VaryBy attributes of the control
to true. To define caching options for presentation controls that you bind
programmatically, set the Cacheable property and the VaryBy properties of the control to
true before reaching the rendering phase of the ASP.NET lifecycle.
Figure 6.1
Figure 6.2
Note the distinction between the cache ID, which identifies the presentation control, and
the cache key, which identifies the presentation control, the Vary By caching options
selected for that control, and current values of those options.
After you select the Cacheable checkbox in the Layout Details dialog as
described previously, you can select additional checkboxes to vary by
additional criteria, which effectively adds those criteria to the cache key.
Because the output of most renderings depends on the data source of the
rendering, you are most likely to select the Vary by Data checkbox, which
causes the key to contain the ID of the data source item for the rendering.
You can select the Vary by Device checkbox to include the name of the
device in the cache key. Selecting Vary by Login causes the cache key to
contain a flag that indicates whether the user authenticated; you can use
this option for renderings that generate different output based on whether
the user is anonymous or known. If you select Vary by User, the cache key
includes the login name of the context user, which means that the
rendering can generate and cache different output depending on the
specific user who has authenticated.
Because it results in cache entries specific to each user, selecting the Vary by User option
can increase memory utilization, especially on systems with large numbers of concurrent
users. Apply this option with caution.
The Vary by Parameters option results in a cache key that contains any
key/value parameters passed to the rendering. The Vary by Query String
option causes the cache key to contain any query string parameters in the
URL for which Sitecore invoked the rendering.
When you publish changes from the Master database to a publishing
target database, on the local instance Sitecore clears the output cache for
the managed sites listed under the
/configuration/sitecore/events/event/handler element in the
Web.config file for the <event> element named publish:end. On remote
content delivery instances, publishing clears the output caches for the sites
listed for the publish:end:remote event. For more information about
remote content delivery instances, see The Sitecore Scaling Guide
(http://bit.ly/oKvYuN).
Publishing clears all entries from the output caches. To make the best use of entries in
output caches, minimize publishing frequency.
if (String.IsNullOrEmpty(id))
{
id = this.GetType().ToString();
}
return id;
}
Sitecore does not allocate memory for caches at initialization; it creates new entries in
each cache until it reaches the limit for each.
Generate some load against your solution before evaluating the cache
administration page, and then click Refresh in the page to populate the
table. You can click Clear All in the cache administration page to clear all
of the Sitecore caches in memory completely.
Use the cache administration page to tune the size limits for each cache.
When you determine that the utilization of a cache has approached or
exceeded its size limit, consider increasing that size limit if available
RAM permits. You can use the CacheTuner Sitecore Shared Project
(http://bit.ly/xCHKCH) to help identify caches that could benefit from
larger size limits.
The table displayed by the cache administration page contains the
following columns as shown in Figure 6.3.
Name — Name of the cache, which can indicate the database or
managed site associated with the cache in addition to the type of data
it contains
Count — Number of entries currently in the cache
Size — Approximation of total memory consumed by the cache
Delta — Approximation of the amount of memory consumed by the
cache since you last clicked Refresh
Because this page uses an ASP.NET postback to compute cache size deltas, always click
Refresh instead of using the page reload feature of your browser.
While efficient utilization of site output caches can dramatically increase performance,
these caches should not provide the foundation of your optimization effort, especially for
solutions that publish frequently.
Adding capacity for Sitecore cannot help to scale that solution if the bottleneck is a
dependency on a database or integrated external application.
Most of the work you will do to scale your Sitecore solutions involves
scaling your hosting infrastructure, including the following:
Hardware sizing, both in terms of individual machine capacity and the
number of servers
Firewalls and load balancing, which involves hardware and software
to secure the solution and spread the load between those servers
Database server scalability and optimization
Network infrastructure capacity, both local area network (LAN) for
connections to the database and wide area network (WAN) for the
connection to the Internet
Many of the specific details involved in scaling a Sitecore solution
depend on the unique performance profile of that solution. For example, a
solution requires less hardware for an equivalent load if the code is
efficient and you can cache the output of most renderings, as opposed to
the same solution with inefficient code and without output caching.
Additionally, a complex solution might require more hardware than a
simple solution.
Always consider scalability to support traffic in excess of anticipated load over a short
time duration at your peak traffic periods. Other than cost (licensing, hardware, network
bandwidth, administration, power, and so on), it cannot harm your solution to acquire
more capacity than you expect to need under peak load.
Scaling Infrastructure
Before scaling Sitecore into multi-instance environments, you need to
understand the infrastructure of a Sitecore environment. You can deploy
Sitecore in a nearly unlimited number of configurations; this section
describes some of the most common approaches.
As mentioned in Chapter 1, each Sitecore instance depends on an
ASP.NET application, which consists of an Internet Information Services
(IIS) website using ASP.NET (Application Server Pages with .NET)
running on the Microsoft Windows operating system. A Sitecore
environment consists of one or more such instances. A single Sitecore
instance can host a content management environment for CMS users and
any number of managed sites for visitors in the content delivery
environment integrated by default into that instance. Each instance
depends on one or more database servers, where multiple instances can
share databases on those servers, and different instances in a single
environment can use different databases. Regardless of which database
vendor you use, the principles involved in scaling that infrastructure are
the same, though Oracle and SQL Server name the corresponding
technologies differently and use different tools for these purposes.
One of the first steps to scaling and securing your Sitecore solution is to
separate the content management environment, typically inside your LAN,
from the content delivery environment, typically in a periphery network.
To scale further, add instances to one or both of these environments. Most
solutions begin by scaling the content delivery environment to meet site
visitor load; you can scale the content management environment if you
have a very large number of concurrent CMS users, to offload publishing
overhead to a single content management instance (in the case of frequent
publishing or very large content databases), and to provide failover in that
environment.
Load Balancing
After separating the content management environment from the content
delivery environment, the most common technique to scale Sitecore
solutions involves load balancing. Load balancing uses two or more
Sitecore instances to serve a common solution. Sitecore allows you to load
balance the content management environment, the content delivery
environment, or both. To support load balancing, enable a scalable
infrastructure as described previously, and follow best practices for
scalability of ASP.NET solutions.
When you decide to load balance a solution, you face a number of
choices. Primarily, you can balance using Microsoft Network Load
Balancing (MS NLB) built into the Microsoft operation system, or you can
use external load-balancing hardware from a number of vendors such as
BIG-IP, Citrix, Cisco, and Barracuda. The Sitecore CMS does not limit
your options for load-balancing software and hardware that do not affect
the software platform. That said, if you plan to immediately or eventually
scale beyond two Sitecore instances, you should use load-balancing
hardware. Such hardware provides greater application failure detection
and failover management. MS NLB relies on the network stack to detect
hardware failure in order to implement such transitions; it may not detect
and remove an instance from the balance in case of application failure.
While Sitecore solutions can employ clustering technology, it does not
require such solutions. You can scale your Sitecore solutions simply by
adding servers and instances side-by-side to the balance in each
environment, where the load-balancing solution routes HTTP requests to
the most appropriate server determined from configuration of the balance
and current system loads.
In addition to scalability, load balancing supports high availability; if
one of the instances in the balance fails, the load balancer routes traffic to
any of the remaining instances. For many Sitecore customers, scalability
and high availability in the content delivery environment are more
important than the same features in the content management environment.
Hence, the most common environment to balance is content delivery. The
basic principles in scaling either environment are similar, but also
consider publishing from the content management environment. The
following sections describe aspects of load balancing specific to each
environment.
To test failover and other load balancing features, you need balanced test environments
similar to your production environments.
I strongly recommend that you disable support for storing the binary content of media
items on the file system rather than in the database. If you decide that you must store
media on a file system, however, I recommend that you consider integration with edge
caching systems and CDNs as an alternative to file media. The
/App_Config/Include/ScalabilitySettings.config.example Web.config include file most
commonly used to enable Sitecore scalability disables file media by default by setting the
Media.DisableFileMedia setting to true.
The same session management concerns can apply to the content delivery environment if
you use session state there. Unlike the content delivery environment, Sitecore actually
requires InProc in the content management environment, whereas InProc is simply an
optimization in the content delivery environment. Wherever you use InProc, you should
enable server affinity in the load balancer.
Scaling Publishing
Publishing involves the transfer of updated items from the Master
database used in the content management environment to one or more
content delivery databases that support one or more content delivery
environments. Not only does publishing clear caches, but it can be a CPU-
intensive process in the content management environment that can affect
the performance of the publishing instance. For more information about
publishing, see Chapter 9.
A number of factors can trigger publishing operations, such as when a
CMS user chooses to publish through the graphical user interface, when a
content item reaches a given state in a workflow, on a regular basis using a
scheduled process, and if you write custom code that invokes APIs that
publish. You should make an effort to minimize the number of publishing
operations required to support your solution. Experience has shown that
many organizations publish an excessive number of items more frequently
than needed. Specifically, CMS users are often unaware of the preview
functionality built into the CMS, and often publish changes, review them
visually, continue editing, and publish again. Considering that publishing
consumes resources and clears entire output caches, this approach is
unnecessarily harmful to performance and hence the scalability of both the
content management and content delivery environments.
You can take two steps to improve the performance of a Sitecore
solution that involves frequent or large publishing operations. The first
step is to work with your editorial staff to reduce the frequency of
unnecessary publication. If CMS users use the edit-publish-check-edit
process described previously, you will likely experience performance
challenges regardless of your hosting infrastructure, the quality of your
code, and anything else you attempt to improve performance, capacity, and
scalability. Educate your CMS users to use the preview functionality of the
CMS, and spend your development resources ensuring that the preview
features closely mimic visual aspects of the published sites. In some cases,
you can implement features available in previewing modes that exceed
those available on the published sites, such as by improving CMS
performance and usability by allowing CMS users choose whether to
display page components that use Adobe Flash.
To get the most productivity in your development environments, you should take a similar
approach when you update code. Every time you build your solution, Sitecore
reinitializes, which is worse for performance than clearing all caches. Though it requires
more engineering discipline than changing small amounts of code and building, you will
benefit from changing significant amounts of code and then evaluating the impact of
those combined changes.
In some cases, you may even want to limit the number of users with
rights to publish, and instead use an incremental, scheduled publishing
operation, and possibly a workflow action to publish when users have
completed all changes. This approach strongly encourages CMS users to
preview their changes instead of publishing them, reducing stress on the
system. Because CMS users often want to know when their changes will
publish, you can build visual indicators into the desktop, the Content
Editor, and even the Page Editor, such as countdowns to indicate when the
next publishing operation will occur.
The second step to improve the performance of the content management
environment in a solution that involves frequent or large publishing
operations is to dedicate a content management instance to publishing
operations, and to remove that instance from the balance. With this
approach, you offload expensive publishing operations to an instance
committed only to publishing operations, so that publishing does not
consume resources on the content management instances accessed by
CMS users. A significant number of Sitecore installations, especially
those with very large content repositories, use this approach to mitigate
the effect of publishing operations in the content management
environment. To set the publishing instance, in the content management
environment, configure the PublishingInstance setting in the
Web.config file, typically in the
/App_Config/Include/ScalabilitySettings.config.example file
after renaming that file to ScalabilitySettings.config to activate that
configuration.
Virtualizing Sitecore
Virtualization software enables multiple virtual machines to run on a
single physical machine, and it can enable a single virtual machine to span
multiple physical machines. Numerous Sitecore customers use the CMS
software in virtualized environments for both small-scale and large-
capacity solutions. Virtualization provides a number of advantages for
server administration, scalability, redundancy, and cost reduction by
helping an organization utilize a greater percentage of available machine
resources.
Sitecore has no requirements that you cannot address with virtualized
hardware, though you should ensure that you allocate enough actual
hardware to each virtual machine as required by Sitecore. For specific
hardware requirements for each physical or virtual instance of your
version of Sitecore, see The Sitecore Installation Guide at
http://bit.ly/pv7X3B, noting that optional components such as the Digital
Marketing System (DMS) can require additional resources. The choice of
virtualization software can also affect performance of the virtualized
environment.
Sitecore content delivery instances are often excellent candidates for
hardware virtualization. While virtualization of the web server and the
database server should not directly affect Sitecore itself, you should be
aware that Sitecore solutions tend to implement many small, parallel
transactions with the database. Sitecore content databases do not typically
place an untoward level of stress on database servers. The features of
Sitecore that you use, such as complex authorization rules in the content
delivery environment and especially the use of DMS, can increase the
number of database transactions. Therefore, the performance of storage
subsystems on the database server can affect the performance of the
Sitecore solution, so it is not always advantageous to virtualize the
database server.
Edge Caching and Content Delivery
Networks
You can use edge caching devices and content delivery networks (CDNs)
to scale your Sitecore solutions. These technologies reduce the number of
HTTP requests for the content delivery environment to service, and can
place web servers closer to the clients that request resources, reducing
network response time, especially for image-intensive sites and large,
static, binary assets such as video. Both technologies effectively offload
request processing from the Sitecore instances to the edge caching and
CDN systems.
With edge caching, you deploy content to separate servers near the
production content delivery environment. You can use a load balancer such
as Citrix NetScaler (http://bit.ly/yc7add) to direct specific HTTP requests
from Internet users to the caching servers instead of the Sitecore instances,
or you can use dedicated caching technologies such as Varnish
(https://www.varnish-cache.org) and Squid (http://www.squid-cache.org).
With CDNs, you cache resources using technologies that are not part of
your infrastructure, instead using an external service that you purchase.
CDNs often use specific URLs to differentiate resources that you manage
as opposed to those that the CDN can cache, typically using separate
Domain Name System (DNS) entries for each of these systems. On the
first HTTP request for a resource, the CDN requests the asset from the
Sitecore content delivery environment, and then caches it locally to
service subsequent requests. CDNs are most valuable for audiences with a
wide geographic spread, as larger networks synchronize cached content
automatically across servers around the globe. With this approach, content
consumers retrieve media from the caching servers closest to their
individual locations, reducing network transit time for those assets.
You can use edge caching and CDNs for any static files, including those
that you do not manage in the Sitecore media library, such as JavaScript
(.js files), Cascading Style Sheets (.css files), and images referenced
directly by developers in code and retrieved from the filesystem rather
than referenced by managed content and retrieved from the media library.
Some solutions enable “minification” of resources such as CSS and
JavaScript, removing whitespace to reduce file size and hence network
download time. You can also use CDN and edge caching technologies for
binary material stored in the media library, which can dramatically
improve performance of the overall solution.
Because edge caching systems and content delivery networks are
unaware of Sitecore security, you should not use these technologies for
resources that you secure. Additionally, if you use the Digital Marketing
System (DMS) described in Chapter 10 to track the download of binary
assets, you should not use edge caching or CDNs for those resources, nor
should you cache any material externally for which the organization may
need to measure access. For example, you may want to cache product
images but not whitepapers and other resources that you wish to monitor.
Some Sitecore customers use edge caching for textual content managed
in Sitecore. While this approach increases performance and hence
scalability, especially for sites with massive traffic volumes, it reduces the
potential for dynamic aspects of the solution such as per-user
personalization. Before caching such content, consider the implications
carefully. Certain edge caching technologies, such as NetScaler, can
support personalization and similar features, but it can take some work to
achieve your goals without adversely affecting Sitecore features.
The Sitecore log files, which record Sitecore activity, are completely separate from the
IIS log files, which record web client access to the solution.
<appender name="AuditFileAppender"
type="log4net.Appender.SitecoreLogFileAppender,
Sitecore.Logging">
<file value="$(dataFolder)/audit/audit.{date}.txt"
/>
<filter type="log4net.Filter.StringMatchFilter">
<regexToMatch value="ˆAUDIT" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%4t %d{ABSOLUTE} %-5p
%m%n" />
</layout>
</appender>
AuditFileAppender.config
Depending on the configured logging verbosity level, you can use the
Audit(), Debug(), Error(), Fatal(), Info(), and Warn() methods of the
Sitecore.Diagnostics.Log static class to write messages to the system
log. You can also use the Error() and Fatal() methods to log exceptions.
All log entries contain at least the time, the verbosity level, and a message,
and exceptions include a stack trace and information about any nested
exceptions.
When writing a message to the Sitecore log, I like to include the name of
the class writing the message to make it easier to find my own messages in
the log. For methods that require an owner parameter, I generally pass
this, which is the class that generated the error message. For example:
Sitecore.Diagnostics.Log.Info(this + " is a horrible way to
debug.", this);
For more information about Sitecore logging, see my blog post at
http://bit.ly/qYym7S. That blog post includes links to additional posts that
describe how write to your own separate log files, move old log files from
the default subdirectory at application initialization, log to a SQL Server
database instead of files, and integrate with the log4net dashboard, which
provides a graphical user interface for investigating logs generated with
log4net.
Rendering Statistics
You can use the rendering statistics page to identify underperforming
renderings and renderings for which you may be able to improve output
cache configuration, by enabling output caching or caching output by
fewer Vary By options, for example. To access the rendering statistics
page, navigate a browser to /sitecore/admin/stats.aspx on your
Sitecore instance, such as http://sitecorebook/sitecore/admin/stats.aspx.
In load-balanced environments, the rendering statistics page shows information for the
individual instance on which the page runs rather than all instances in the balance.
Generate load before reviewing the rendering statistics page. You can
click links at the top of the rendering statistics page to filter the data by
managed site. Figure 6.5 shows how the rendering statistics page appears
after clicking the website link to exclude data for other managed sites.
The table displayed by the rendering statistics page contains the
following columns as shown in Figure 6.5.
Rendering — Identifier for an individual presentation control
Site — Context site associated with data presented in this row
Count — Total number of uses of this control by this site since
application initialization
From cache — Number of times the layout engine retrieved output
for this control from cache instead of invoking the control
Avg. time (ms) — Average duration of an invocation of the control
Avg. items — Average number of items accessed during an invocation
of the control
Max time — Maximum duration of a single invocation of the control
Max. items — Maximum number of items accessed during an
individual invocation of the control
Total time — Total duration of all invocations of the control
Total items — Total number of items accessed while processing the
control
Last run — Date and time the layout engine last invoked the control
Figure 6.5
While it may appear that a single request exceeded one or more thresholds, in some
cases, other system activity at the same time — including that required to service
concurrent HTTP requests — could utilize processing time, access items, and consume
memory that would appear to be associated with that HTTP request. Specifically,
Sitecore initializes itself during the first HTTP request after the application pool restarts,
which can consume time and memory, and access a large number of items. Threshold
warnings immediately after an application pool restart may be invalid. After restarting
an application pool, to initialize Sitecore load a page other than the suspect page, and
then load the suspect page to see if it generates a threshold warning.
To configure Sitecore to log such threshold warnings, set the value of the
<ShowThresholdWarnings> element of the StopMeasurements processor
in the httpRequestEnd pipeline defined in the Web.config file to true,
and optionally override the default values of the <TimingThreshold>,
<ItemThreshold>, and <MemoryThreshold> elements of that processor to
define the thresholds for these criteria that you deem appropriate for your
solution.
Debugging in a Browser
You can use the Sitecore browser-based debugger remotely or locally to
troubleshoot and diagnose issues with your solutions, as well as to find
opportunities for further performance optimization, without installing any
software. To access the Sitecore debugger, log into the Sitecore desktop,
click the Sitecore button, and click Debug from the menu that appears.
The Sitecore debugger opens in a new browser window that resolves the
Sitecore context as it would in the content delivery environment. Under
the default configuration, the debugger accesses the
/sitecore/content/home item in the Web database using the
configuration defined for the /configuration/sitecore/sites/site
element in the Web.config file named website. The icon at the far right of
the gray bar that appears at the top of the debugger contains an icon to
show or hide the debugging Ribbon. Figure 6.6 shows the debugger as it
appears after clicking that icon.
Figure 6.6
Using the Modes group on the debugger Ribbon, you can enable or
disable inline editing with the Edit command and switch between the
Preview and Debug interfaces. Using the Profile group in the debugger
Ribbon, you can enable or disable performance profiling and access a
high-level performance profile for the page. The profile attempts to
identify hot spots, which are the components that appear to perform worst.
Using the Trace group in the debugger Ribbon, you can enable or disable
low-level tracing and access a low-level trace for the page. When you
enable profiling or tracing, the debugger renders the profile or page trace
after the page body as shown in Figure 6.7.
The profile and trace can contain error messages that do not otherwise appear on the
page, such as if you attempt to bind a presentation component to a placeholder that does
not exist.
Figure 6.7
Using the Open group in the debugger Ribbon, you can access the
ASP.NET trace for the current page, which is separate from the trace that
Sitecore maintains.
You can use the Info() method of the Sitecore.Diagnostics.Tracer
static class to write to the trace from a .NET presentation component, as
shown in the following example:
Sitecore.Diagnostics.Tracer.Info(this + " : debugging
message");
You can use the equivalent sc:trace() XSL extension method to write
to the trace from an XSL rendering, as shown in this example:
<xsl:value-of select="sc:trace('debugging message')" />
The trace indicates whether Sitecore invoked each presentation
component or instead retrieved cached output generated previously by that
component under equivalent processing conditions based on output
caching settings (Vary By options) that you specify for that component.
Using the Rendering group in the debugger Ribbon, you can enable and
disable Borders and Information. With Borders enabled, Sitecore adds
visual borders around each presentation component. With Information
enabled, Sitecore adds green triangle icons to each presentation
component. Hover over these rendering information icons to see
information about individual presentation components, which includes
tabs to show performance profiles, cache settings, and output generated by
individual controls. The example shown in Figure 6.8 shows the Details
tab for the default Sample Rendering XSL.
When showing rendering information, Sitecore never retrieves the output of a
presentation component from the output cache, but instead executes each presentation
component for each HTTP request. To see the impact of caching, you must clear the
Information checkbox in the Rendering group.
Figure 6.8
If you use XSL renderings, note that Sitecore caches the objects used to
apply the XSL transformation objects as well as the output of XSL
transformations. A trace message such as the following indicates that the
layout engine retrieved output for a control from cache:
Finished rendering "/xsl/sample rendering.xslt" (using
cache).
A trace message such as the following indicates reuse of a cached XSL
transformation object:
Xslt file loaded from cache.
For more information about the Sitecore browser-based debugger, see
my blog post at http://bit.ly/n6x0QL. For instructions to add a command to
the Content Editor Ribbon to debug the selected item in the content
database rather than always debug the home item in a publishing target
database, see Chapter 7.
Follow the instructions in this section to debug with Internet Information Services rather
than debug with the native web server built into Visual Studio.
If you do not clear the Show All Files option before attempting to attach to the
application pool process, Visual Studio may try to read all files under the document
root when you start debugging, and either fail or seriously underperform. To
address this issue if you happen to forget, restart Visual Studio and clear the Show
All Files option.
3. Click the Debug menu, and then click Attach to Process. The Attach
to Process dialog appears.
4. Select the Show Processes From All Users checkbox.
5. Select the Show Processes In All Sessions checkbox.
6. Select the appropriate instance of the w3wp.exe or aspnet_wp.exe
process.
Alternatively, you can configure the start page for your Visual Studio
project:
1. In Solution Explorer, expand your project and then double-click
Properties. The project properties pane appears.
2. Click the Web tab.
3. Under Servers, select Use Custom Web Server.
4. Under Use Custom Web Server, for Server Url, enter the URL of the
home page of the Sitecore solution (such as http://sitecorebook), or the
page to debug (such as http://sitecorebook/mypage.aspx).
5. Close the project Properties pane to save the changes.
6. To start debugging, press Ctrl+F5, or click the Debug menu and then
click Start Debugging.
Spelunking Sitecore
This section describes various aspects of the Web.config file that you can
investigate to understand, configure, extend, and troubleshoot Sitecore
solutions. It then explains how you can disassemble compiled .NET
assemblies (.dll) files to achieve an approximation of the source code
used to compile the CMS and supporting products.
Use of the patch: prefix is just a convention. You can use any prefix that you map
appropriately. If the location of elements defined in a Web.config include file relative to
existing elements is unimportant, that Web.config include file does not need to define any
such prefix.
You can use the following tokens with the patch: prefix:
patch:before — As shown above, insert a new element before the
specified element
patch:after — Insert an element after the element specified by the
XPath expression
patch:instead — Replace the element specified by the XPath
expression
patch:delete — Remove the element specified by the XPath
expression
patch:attribute — Define or replace the attribute specified by the
XPath expression
For more information about Web.config include files, see my blog post
at http://bit.ly/qp0vps.
Reflecting on Sitecore
This section describes how you can use software products to disassemble
Sitecore and other .NET assemblies (.dll files) to view an approximation
of the source code compiled into those files. Disassembly can be
invaluable to both troubleshooting and development, especially when
extending Sitecore solutions. If you are not familiar with disassembly, this
may be the most important section of this book for you to read.
Check your Sitecore end-user license before disassembling any Sitecore product. For
any questions about your rights, contact your regional Sitecore representative. If you do
not know whom to contact, see http://bit.ly/AFaRil. In no case does any Sitecore license
permit you to reverse engineer Sitecore software to develop competing products. Nothing
in this section or elsewhere in this book authorizes you to reverse engineer Sitecore
products except as indicated by Sitecore's end-user licenses.
Because the disassembler must guess at the original syntax from the IL
(intermediate language) contained in the assembly, disassembly results in
only an approximation of the original source code, not a line-by-line exact
replica of that source. The disassembler cannot expose comments and
other non-essential aspects of the original code removed by the compiler,
which can also optimize code in ways you might not expect. For example,
the compiler converts certain types of loops to goto statements with labels,
and can convert method calls to inline code. Additionally, Sitecore
intentionally obfuscates some assemblies to protect its intellectual
property.
With Sitecore and ASP.NET, you can use a number of languages that can
compile into .NET assemblies. Sitecore internally uses the C# language,
and for a variety of reasons I generally recommend that customers use C#.
Most example code for Sitecore, including everything in this book, uses
C#. You may want to confirm that the software you choose to decompile
can generate output in C#, and you should have at least a reading
competency in C#. If necessary, you can compile C# samples to IL, and
then decompile from IL to your preferred language.
The RedGate company (www.red-gate.com) distributes the .NET
Reflector software product (www.reflector.net) for investigating .NET
assemblies. This book describes RedGate's .NET Reflector (also called
Reflector) because it is most familiar to me, but you can use any such tool
that you prefer. Reflector uses reflection to interrogate the structure of
compiled code, but much more important, it disassembles IL to source
code that you could use to compile the interrogated assembly.
To investigate Sitecore assemblies, launch Reflector, and then use
standard Windows features to open the assemblies (.dll files) that you
wish to investigate from the /bin subdirectory of the document root of the
IIS website hosting your Sitecore solution, starting with those that your
Visual Studio project references. Most Sitecore developers primarily use
APIs in the Sitecore.Kernel.dll assembly, which mostly contains back-end
code. You could also use classes in Sitecore.Client.dll, which contains user
interface code, and Sitecore.Analytics.dll, which contains code most
relevant to the Digital Marketing System (DMS) described in Chapter 10.
When you open an assembly, Reflector may prompt you to open
dependent assemblies as needed, or may open such assemblies
automatically. For performance and usability, you may wish to limit the
number of open assemblies. To close an assembly, select it in the tree and
press the Delete key. For your convenience, when you close and restart
Reflector, it reloads the assemblies that you had opened previously.
If your Sitecore solutions employ both .NET and XSL, in addition to
reviewing The Sitecore XSL Presentation Component Reference
(http://bit.ly/qsVzvR), you can learn more about XSL extension methods
such as sc:field() by disassembling the Sitecore.Xml.Xsl.XslHelper
class in the Sitecore.Kernel.dll assembly.
Sitecore typically translates XSL extension controls such as <sc:text> in XSL renderings
to call methods in the Sitecore.Xml.Xsl.XslHelper class.
For convenience and your own education, you may wish to open
additional assemblies, such as the HtmlAgilityPack.dll assembly, which
contains the HTML Agility Pack (HAP) implementation described in
Chapter 7. After you open assemblies, you can expand contained
namespaces and types in the assembly tree frame on the left. Figure 6.9
shows Reflector after opening some common assemblies, navigating to the
static constructor for the Sitecore.Context class, and double-clicking
that member to disassemble (decompile) it.
Always review the constructors for any classes that you disassemble. Otherwise, you can
spend a significant amount of time investigating other methods and never find the logic
that you actually need to examine.
Figure 6.9
Unless you have a stack trace or something else to identify the types that
you need to investigate, you will likely need to search. Using Reflector,
you can search for the name of a type, for the name of a member of a type,
or for specific tokens in the code. If you know or can guess the name of
the type (most commonly a class) but not the namespace that contains that
type, or you do not care to navigate to the type, you can search for a type
by name. If you know or can guess the name of a member (most
commonly a method or property) but not the name of the type containing
that member, you can search for a member by name. If you would like to
search the code for a string, such as the name of a pipeline to see what
invokes that pipeline, you can search for a token.
To initiate a search, press F3 to show the search bar. By default,
Reflector searches for types with names that match the value you enter. To
search for a member, press Ctrl+M (for member). For example, you can
review the Web.config file to identify a setting, and then search for a
member of the same name as that setting to locate the type that exposes
that setting as a member. To search for a token in code, such as the name
of a pipeline, press Ctrl+S (for string). To revert to searching for a type,
press Ctrl+T (for type). Once you find an item to investigate further,
double-click it in the search results, and then disassemble it and review the
source code.
Another useful feature of Reflector enables you to find all usages of a
type or member. To do so, select the type or member in the tree on the left,
and then press Ctrl+R or right-click and select Analyze from the context
menu that appears. In the Analyzer pane that opens, expand the type, and
then expand Used By. As shown in Figure 6.10, a very large number of
types use the Sitecore.Context class.
Figure 6.10
You can expand these types in the Analyzer pane as well, providing
something like a list of all possible stack traces that can lead to that type
or member.
This section really just skims the surface of what you can achieve with
Reflector, highlighting the features that I use most frequently. You can
download add-ins from http://bit.ly/yNd4VH to extend Reflector with even
more functionality. For maximal productivity, I recommend that you
devote some time to reading about and working with this or another
disassembly tool of your choice.
Before manually altering a Sitecore database using either of the techniques described in
this section, back up the database so that you can restore it if your efforts actually
worsen the problem. Always be cautious when working directly with a Sitecore database,
even with the tools described.
The first solution requires Visual Studio and the free Sitecore Rocks
extension for Sitecore developers (http://sitecorerocks.net). Using these
tools, you can connect to any Sitecore instance without accessing a
Sitecore browser-based user interface, which enables you to correct issues
using Sitecore Explorer. For more information about Sitecore Rocks, see
my blog post at http://bit.ly/z4HjP0.
The second solution does not require Visual Studio and Sitecore Rocks,
which are not always available or may not be able to connect to the
Sitecore instance experiencing the issue. You can use the database browser
tool to investigate Sitecore databases using a very lightweight browser-
based user interface. Sitecore does not support or document this tool, but
provides it so that you can address issues such as that described
previously, specifically under direction from the Sitecore customer service
department. To access the database browser, navigate your web browser to
/sitecore/admin/dbbrowser.aspx on the Sitecore instance, such as
http://sitecorebook/sitecore/admin/dbbrowser.aspx.
While pipelines are just one example of components that you can
address with the configuration factory, they provide a good example of this
functionality. Sitecore implements numerous features with pipelines,
which a subsequent section of this chapter describes in detail. These
include the httpRequestBegin pipeline described previously in this book,
such as in Chapter 5. Sitecore invokes the httpRequestBegin pipeline
when it begins processing each HTTP request. The configuration factory
reads pipeline definitions from the Web.config file. The
/configuration/sitecore/pipelines/httpRequestBegin element in
the Web.config file defines the httpRequestBegin pipeline using a series
of nested <processor> elements. Each <processor> element specifies a
.NET class that contains a method that implements that step in the
pipeline. When Sitecore invokes a pipeline, it invokes those methods in
the order of the elements in the Web.config file that define the pipeline.
You can update the Web.config file (or preferably, add Web.config include
files) to:
Override the types used to implement processors in a pipeline
Remove processors from a pipeline
Add custom processors to a pipeline
Change the order of processors in a pipeline
Declaratively pass parameters to pipeline processors
The configuration factory uses type signatures to identify the .NET types
that implement features. A type signature consists of a namespace, a type
name (such as the name of a class), and the name of the assembly
containing that class (following a comma (,) and without the .dll
extension):
NamespaceName.TypeName, AssemblyName
In some cases, Sitecore uses a separate field or attribute for the assembly name; and in
some cases, separate fields or attributes for the namespace and the type name.
In some versions of Sitecore, each repeated element in a Web.config include file must
have a unique value. For example, in place of the sequence <element /><element />,
you could use a convention such as <element unique=“1” /><element unique=“2” /> to
ensure that each element has a unique value in the attribute named unique.
In some cases, the configuration factory returns an object that works like
another configuration factory. For example, as described in Chapter 5, you
cannot use the configuration factory directly to specify the control types
that Sitecore binds to placeholders to implement sublayouts. The default
value of the type attribute of the
/configuration/sitecore/renderingControls/control element in
the Web.config file specifies the
Sitecore.Web.UI.SublayoutRenderingType class. The configuration
factory instantiates an instance of that type, which works as a factory to
return instances of the actual type that implements sublayouts
(Sitecore.Web.UI.WebControls.Sublayout by default). You can
override the type specified by such elements to return instances of your
overrides for the types returned by factories of this kind.
In addition to the /web.config file and Web.config include files, for
some features Sitecore uses fields in items in databases to specify types
and parameters. Some Sitecore products, such as Sitecore E-Commerce
products, use the Microsoft Unity Application Block for dependency
injection. For more information about dependency injection in general, see
http://bit.ly/1511WG. For more information about the Microsoft Unity
Application Block, see http://unity.codeplex.com. For more information
about dependency injection with Sitecore, see my blog post at
http://bit.ly/r1rwBr. For more information about the Sitecore
configuration factory, see my blog post at http://bit.ly/n6mr29.
To use the extension method, add a using statement for the namespace
containing the extension class, and then you can invoke the method as you
would any other method on the extended class. For example, use the
following to determine the Twitter account associated with the context
site:
using Sitecore.Book.Sites
...
Sitecore.Sites.SiteContext siteContext =
Sitecore.Context.Site;
string twitterAccount = siteContext.GetTwitterAccount();
You can use this approach to define an attribute for the Google Analytics
account ID, error pages, or any other property of each managed website.
For more information about implementing extension methods with
Sitecore, see the Library (http://bit.ly/vhoFOK) and the PageNotFound
Sitecore Shared Source projects (http://bit.ly/vIoNwP), as well as my blog
posts at http://bit.ly/ntowNQ and http://bit.ly/r9Wsgw.
Leveraging the Sitecore User
Interface Framework
You can extend the Sitecore user interface using commands, ribbons,
context menu entries, and Web Forms (.aspx files), and using Sitecore-
specific user interface framework components. In fact, the Sitecore user
interface framework probably deserves at least one book of its own.
Always consider the effect of the context site on other aspects of the Sitecore context,
such as the context database. When you access a published site, the context site is that
published site and the context database is a publishing target database such as the Web
database associated with that site. When you access a Sitecore user interface such as the
Content Editor or the browser-based desktop, the context site is the site named shell, the
context database (Sitecore.Context.Database) is the Core database (which controls the
Sitecore applications presented by the site named shell through which you access those
interfaces), and the content database (Sitecore.Context.ContentDatabase) is the Master
database. When you select a database using the database icon in the lower-right corner
of the desktop, you change the content database, not the context database. In Sitecore
user interfaces such as Preview and the Page Editor, the context site is the published site,
but the context database is the Master database. In the browser-based debugger, the
context site is the published site and the default context database is the publishing target
database. This distinction is especially important to Sitecore user interface components.
The context database configures the application; the content database contains the data
managed by the context user.
Extending Ribbons
For many reasons, including familiarity, capability, manageability,
consistency, and usability, Sitecore browser-based user interfaces such as
the Content Editor borrow the ribbon user interface paradigm from the
Microsoft Windows operating system.
A ribbon consists of tabs. If a ribbon consists of only one tab, the tab
names may not appear in the ribbon. Clicking a tab shows a strip
consisting of groups containing related commands that you can click to
invoke specific functions. Groups are simply visual containers for
commands; you can use the same group on multiple strips and the same
command in multiple groups. Some commands display an interface, while
others update data in the background and may subsequently refresh the
user interface. Some commands expose drop-down menus, while some
trigger flyouts, modal dialogs, or other user interfaces.
return base.QueryState(context);
}
Showing and hiding commands on the ribbon depending on the selected item can
distract users by changing the ribbon as they navigate from item to item. Instead of
hiding commands, disable them, or create a custom tab for the command and associate
that tab with the data template(s) to which that command applies.
To define which of the CMS users can access each command, Sitecore
defines default access rights for the Sitecore client roles to the command
definition items and the group definition items that contain those
commands. To control access to features without increasing any
administrative burden, add users to Sitecore client roles. If the default
access rights do not meet your requirements, you can create custom client
roles, set access rights for those roles, and add users (and nested roles) to
those roles.
You can rearrange, duplicate, remove, and add commands to a ribbon.
For example, you can add a command to the ribbon in the Content Editor
to debug the selected item in the content database. For more information
about the Sitecore debugger, see Chapter 6. By default, the Debug
command on the Sitecore menu in the desktop simply opens a new
browser window with a URL that contains query string parameters to
enable all debugging features. Under the default configuration, the
debugger runs against the home item of the default managed site named
website in the default publishing target database named Web. The custom
implementation of the Debug command described in this section is a bit
more complicated, as it must determine whether to debug a specific item
in a specific database, and if so, which item and database to debug.
I like this example for a number of reasons. One of the best ways to
enhance existing functionality is to create a class that inherits from the
existing implementation of a feature, and then override methods of that
class as required. Like most enhancements to Sitecore, instead of starting
from scratch, the solution described in this section leverages something
already provided by Sitecore: not just the debugger itself, but the
system:debug command used by the Debug button on the Sitecore menu,
defined by the /sitecore/content/Documents and settings/All
users/Start menu/Right/Debug item in the Core database.
By default, the type attribute of the /configuration/command element
named system:debug in the /App_Config/Commands.config file
indicates that this command uses the
Sitecore.Shell.Framework.Commands.System.Debug class in the
Sitecore.Kernel.dll assembly. This class inherits from the
Sitecore.Shell.Framework.Commands.Command abstract base class that
defines a contract for commands.
The Execute() method of the
Sitecore.Shell.Framework.Commands.System.Debug class contains
logic to invoke the debugger. The default implementation always opens a
new browser window using the same protocol (HTTP or HTTPS) and
hostname of the current browser window, no path, and the following query
string parameters to enable debugging and specific debugging features:
sc_debug — Disable or enable Sitecore debugging
sc_prof — Disable or enable page profiling
sc_trace — Disable or enable page tracing
sc_ri — Hide or show rendering information
After you click Debug on the Sitecore menu in the desktop and Sitecore
opens the debugger, you can set each of these query string parameters to 0
or 1 to disable or enable the related feature, respectively, or you can use
the corresponding features in the ribbon that appears in browser window
hosting the debugger.
Under the default configuration, when Sitecore processes the HTTP
request from this new browser window, the request matches the
/configuration/sitecore/sites/site element named website in the
Web.config file, and the SiteResolver processor in the
httpRequestBegin pipeline sets the context site based on that site
definition. You can add the sc_site query string parameter set to the
name of a /configuration/sitecore/sites/site element in the
Web.config file to specify an alternate site to debug.
The database attribute of the /configuration/sitecore/sites/site
element named website in the Web.config file specifies the publishing
target database named Web by default, so the DatabaseResolver
processor in the httpRequestBegin pipeline sets the context database to
that database. You can add the sc_database query string parameter set to
the name of an alternate database to debug.
Because the URL in the browser window that the Debug command opens
does not include a path (only the query string parameters such as those
used to enable the debugger and its specific features as listed previously),
the ItemResolver processor in the httpRequestBegin pipeline sets the
context item to the home item defined for the context site
(/sitecore/content/home by default). To specify the ID of the item to
debug, you can add a path or the query string parameter named
sc_itemid. Alternatively, you can use a browser bookmark or otherwise
navigate to the page to debug.
In other words, the debugger always opens to the home page of the
default published site using the published database (the Web database by
default). It may be convenient to click a command to debug the item
selected in the Content Editor using the content database (the Master
database by default, or whichever database you select in the desktop). The
custom implementation shown in Listing 7.1 adds the sc_itemid,
sc_database, and sc_lang query string parameters to specify the item,
database, and language to debug, respectively.
Listing 7.1: Debug custom implementation, Debug.cs
using System;
namespace SitecoreBook.Shell.Framework.Commands.System
{
[Serializable]
Sitecore.Context.ClientPage.ClientResponse.CheckModified(fa
lse);
Sitecore.Data.Items.Item item = context.Items[0];
url.Add("sc_database", item.Database.Name);
url.Add("sc_itemid", item.ID.ToString());
if (includeLanguage)
{
url.Add("sc_lang", item.ID.ToString());
}
}
// if the user has not selected an item,
// if there is a content database, debug that
database
// using the content language
else if (Sitecore.Context.ContentDatabase != null)
{
url.Add("sc_database",
Sitecore.Context.ContentDatabase.Name);
if (includeLanguage)
{
url.Add("sc_lang",
Sitecore.Context.ContentLanguage.Name);
}
}
public override
Sitecore.Shell.Framework.Commands.CommandState QueryState(
Sitecore.Shell.Framework.Commands.CommandContext
context)
{
// if the user has selected at least one item
if (context.Items != null
&& context.Items.Length > 0
&& context.Items[0] != null)
{
// if that item does not specify a layout for any
device, disable this command
if (!this.HasLayoutForAnyDevice(context.Items[0]))
{
return
Sitecore.Shell.Framework.Commands.CommandState.Disabled;
}
}
return base.QueryState(context);
}
Sitecore.Pipelines.GetContentEditorWarnings.GetContentEd
itorWarningsArgs
args)
2. Invoke the
Add() method of the
Sitecore.Pipelines.GetContentEditorWarnings.GetContentEdi
torWarningsArgs (GetContentEditorWarningsArgs for the
remainder of these instructions) argument passed to the Process()
method. The Add() method returns a
Sitecore.Pipelines.GetContentEditorWarnings.GetContentEdi
torWarningsArgs.ContentEditorWarning (ContentEditorWarning
in the remainder of these instructions) object that contains information
to appear in the warning displayed to the user.
3. Set the Title and Text properties on the ContentEditorWarning
object.
4. (Optional) Set the Icon property of the ContentEditorWarning
object.
5. (Optional) Set the HideFields property of the
ContentEditorWarning object to prevent the user from updating the
item.
6. (Optional) Set the IsExclusive property of the
ContentEditorWarning object to prevent other warnings from
appearing (in which case, your code should call the AbortPipeline()
method of the GetContentEditorWarningsArgs argument passed to
the Process() method to prevent Sitecore from invoking additional
processors in the pipeline).
7. (Optional) Set the IsFullScreen property of the
ContentEditorWarning object to cause the warning to consume the
entire editing pane in the Content Editor.
8. (Optional) Invoke the AddOption() method of the
ContentEditorWarning object to add commands for the user to
invoke in order to resolve the condition that resulted in the warning.
9. Add a
/configuration/sitecore/pipelines/getContentEditorWarning
s/processor element in the Web.config file with a type attribute
containing the signature of your class.
For more information about Content Editor warnings, see my blog post
at http://bit.ly/mYOQXT. That blog post provides an example processor
for the getContentEditorWarnings pipeline that warns the user if the
selected item, the latest version of that item in the current language, or the
current revision of that item in that language does not exist in all
publishing target databases, and includes a command to refresh the user
interface. That blog post also links to another example processor for the
getContentEditorWarnings pipeline that notifies CMS users in the
Content Editor before a code deployment.
As demonstrated in the section of this chapter about the rules engine, you can use the
rules engine to configure Content Editor warnings. Content Editor warnings generated
by the rules engine cannot expose commands to help the user address the issue.
The names of the XML files do not always match the names of the applications they
implement. Try to determine the XML file that implements a feature by locating the
corresponding item(s) in the Core database, and validate your guess before you
investigate that file too closely.
4. Select the Presentation tab, and then click Details in the Layout
group. The Layout Details dialog appears. Note the layout specified
for the Internet Explorer device, which in this case actually represents
all browsers, and then click Cancel. The Layout Details dialog
disappears and you see the Content Editor.
5. Select the /sitecore/layout/Layouts/Control
panel/Licenses/License overview item, which is the layout
specified for the Internet Explorer device. Note the value in the
Control field in the Data section.
6. Select the Master database using the icon in the lower-right corner
of the Sitecore desktop.
When a CMS user invokes this application, Sitecore uses the .xml file
with the name specified in the Control field of the Data section of the
layout definition item. Sitecore locates this file by checking for its
existence in the subdirectories specified by the folder attributes of the
/configuration/sitecore/controlSources/source elements in the
Web.config file. Sitecore uses the file from the first subdirectory specified
in which a file by that name exists. Under the default configuration,
Sitecore uses the file from the /sitecore/shell/override subdirectory
if it exists, or from another subdirectory of the /sitecore/shell
subdirectory otherwise, making it easy to copy a file from another
subdirectory of /sitecore/shell to /sitecore/shell/override to
override a CMS UI component. In this case, the first matching file is
/sitecore/shell/Applications/Licenses/LicenseOverview/License
Overview.xml.
To customize the licensing overview UI, follow these steps:
1. Copy
/sitecore/shell/Applications/Licenses/LicenseOverview/Lic
enseOverview.xml in Visual Studio to the
/sitecore/shell/Override subdirectory, and add the
/sitecore/shell/Override/LicenseOverview.xml file to your
Visual Studio project.
For UI components that use .aspx files rather than XML interfaces, back up the
original file and edit it in place, rather than copy the file to
/sitecore/shell/Override. Whether you edit a file in place or copy it to the
/sitecore/shell/Override subdirectory, add that file to your source code
management system.
You can also override the code-beside for XML components. Your class
can expose properties that correspond to elements in the XML file, where
the type of the property is the same as the type of the element, and the
name of the property is the value of the ID attribute of that element. For
example, the class shown in Listing 7.2 inherits from the default
implementation of the code-beside for the Licenses dialog. To use it,
compile this class into your project and update the Type attribute of the
/control/LicenseOverview/FormPage/CodeBeside element in the
/sitecore/shell/override/LicenseOverview.xml file to the signature
of that class.
For legacy reasons, some places in Sitecore may display the text Content Manager in
place of the Content Editor.
The Path field in the Data section of that item references the
/sitecore/shell/applications/Content Manager/default.aspx file,
which implements the Content Editor. You can update the markup in this
file or, just as you could in an XML control, you can specify an alternate
code-behind. The default implementation of the Content Editor uses
pipelines, including the renderContentEditor,
getContentEditorFields, getContentEditorSkin, and
getContentEditorWarnings pipelines. To minimize the chance of issues
occurring during upgrades, use these pipelines whenever possible rather
than customize the Content Editor.
Whether you log in to the Content Editor or access the Content Editor
within the Sitecore desktop, Sitecore uses the
/sitecore/content/Applications/Content Editor item in the Core
database. If you log in to the Content Editor, Sitecore directs the browser
to the path /sitecore/shell/Applications/Content%20editor.aspx
on the Sitecore server. This path triggers the
/configuration/sitecore/sites/site element named shell in the
Web.config file, which specifies the Core database as the default database,
and Sitecore maps the URL to the item. In the definition for the Content
Editor command on the Sitecore menu in the desktop, the Application
field in the Data section references the
/sitecore/content/Applications/Content Editor item. When you
click that command, Sitecore loads the same URL used by the standalone
Content Editor into an HTML <iframe> element within the desktop.
Engaging the Rules Engine
The Sitecore rules engine provides a browser-based user interface that you
can use to define logic and apply it under specific conditions in the CMS
and the content delivery environment. The rules engine can associate rules
with events and operations, where a rule consists of a number of
conditions and a number of actions. When the event occurs, the rules
engine evaluates the conditions and if the result is true, it invokes the
actions. For example, you can define a rule that specifies that after an
event, such as saving an item, under some condition, such as whether the
item is associated with a specific data template, the rules engine invokes
an action to update a field in that item.
Sitecore maintains information about rules in rule definition items using
the Rule field type, which stores information about the conditions, actions,
and parameters that you can pass to each. The location in the content tree
determines the event that triggers some types of rule definition items, but
you can add any number of fields of type Rule to your own data templates
to define a rule in any type of item to use for your own purposes. Like any
other field, the conditions and actions that appear in a field of type Rule
depend on the Source property of that field, which specifies an item in the
content tree. Use different data templates for different types of rules to
apply a different Source property to the Rule field so that you can define
conditions and actions for various kinds of rules in other locations.
Like so many things in Sitecore, conditions and actions involve
definition items that contain fields specifying the .NET class that
implements the component, and metadata about that component. Create
condition and action definition items in folders under the
/sitecore/system/Settings/Rules item using the
System/Rules/Condition and System/Rules/Action data templates,
respectively.
You can create rule definition items beneath the following items to
invoke under each of the conditions described:
/sitecore/system/Settings/Rules/Content Editor
Warnings/Rules — Use the rules engine to create Content Editor
warnings.
/sitecore/system/Settings/Rules/Insert Options — Use the
rules engine to define insert options.
/sitecore/system/Settings/Rules/Item Deleted/Rules —
Define rules to invoke after a user deletes an item.
/sitecore/system/Settings/Rules/Item Saved — Define rules to
invoke after a user saves an item.
/sitecore/system/Settings/Rules/Version Removed/Rules —
Define rules to invoke after a user removes a version.
Certain tokens in the Text field in the Data section of condition
definition items affect the user interface where CMS users select the
condition and enter its parameters. If the word if, when, or where appears
in the Text field, when presenting that value to the user, the word is a link
that enables the user to reverse the condition to except, except when, or
except where.
A sequence of tokens within square brace ([]) characters enables the
CMS user selecting the condition to specify four parameters — separated
by commas (,) — to pass when evaluating the condition. These four
parameters within the braces specify the following, where the position of
each parameter defines its purpose:
The name of a property of the .NET class that implements the
condition. Before evaluating the condition, the rules engine sets that
property to the value specified by the user who defines the rule.
An empty string, or the name of an item beneath the
/Sitecore/System/Settings/Rules/Common/Macros item that
controls the user interface the CMS user sees when defining a value
for the parameter. For example, to activate a user interface allowing
the user to select an item from the content tree, specify the value
tree.
An empty string, or parameters to pass to the user interface specified
by the macro. For example, to specify the /Sitecore/Content/Home
item as the root for a selection tree, enter
root=/sitecore/content/home.
The text to display until the CMS user specifies a value for the
parameter.
Define global conditional rendering rules under the
/sitecore/system/Settings/Rules/Conditional Renderings/Global
Rules item. For more about conditional rendering, see Chapter 3.
Rather than write something here similar to existing resources, including
those listed at the end of this section, I think a few visuals can truly assist
you in understanding the rules engine. One simple example uses an action
to generate a Content Editor warning message under the condition defined
by the rule. To define a rule that can generate a Content Editor warning
message in the Content Editor, follow these steps, but select conditions
and actions and enter parameters appropriate for your requirements:
To use the rules engine to generate Content Editor warnings:
1. Select the /sitecore/system/Settings/Rules/Content Editor
Warnings/Rules item in the Content Editor.
2. Insert a rule definition item using the System/Rules/Content
Editor Warning Rule data template.
3. Click Edit rule above the Rule field in the Data section. The Rule
Set Editor appears as shown in Figure 7.3.
In the Rule Set Editor, you can enter text under “Select the conditions for the rule”
to filter the list of condition definition items to only those with a specific value in the
Text field.
4. Click the conditions that should trigger your warning from the list
at the left.
5. Click the Show Content Editor Warning: Title, Text action from the
list at the right. Figure 7.4 shows the Rule Set Editor after clicking the
Where True (Actions Always Execute) condition and the Show
Content Editor Warning: Title, Text action.
You can click links in the Rule description (such as the word Where in Figure 7.4) to
reverse conditions (such as to Except Where).
6. Click Title and then Text to enter values for those properties of the
warning in the rule description.
7. Click OK to close the Rule Set Editor and return to the Content
Editor. When the condition is true, the warning appears at the top of
the editing pane as shown in Figure 7.5 (at step 6 in these instructions,
I entered This is the title for the Title parameter and This is the text
for the Text parameter).
For more information about the rules engine and conditional rendering,
see The Sitecore Rules Engine Cookbook (http://bit.ly/skDqss) and my
blog post at http://bit.ly/vb5rOA. That blog post links to additional
resources, such as my blog post about using the rules engine in a custom
context to set the context device (http://bit.ly/n2X3Pz) and my blog post
about using the rules engine to control item names (http://bit.ly/qn0w1l).
Figure 7.3
Figure 7.4
Figure 7.5
Validating Data
As mentioned in Chapter 2, you can validate individual fields and entire
items. You can use validation for a surprising number of purposes. To
implement validation, create a validator for field values or entire items,
and then apply that validator to the fields or items.
Whether you validate a field or an item, the process is the same:
1. Create a class with the [Serializable] attribute that inherits from
the Sitecore.Data.Validators.StandardValidator abstract class.
2. Implement the default constructor and a constructor with two
arguments to support serialization.
3. Implement the Evaluate() method to validate the field or item. If
the data is valid, then return
Sitecore.Data.Validators.ValidatorResult.Valid. If the data is
invalid, set the Text property defined by the
Sitecore.Data.Validators.BaseValidator abstract class from
which the Sitecore.Data.Validators.StandardValidator class
inherits to a helpful message and return the value returned by calling
the GetMaxValidatorResult() method.
4. Implement the GetMaxValidatorResult() method to return a
value of the Sitecore.Data.Validators.ValidatorResult
enumeration that defines the highest validation error level applied by
the validator.
5. Implement the Name property to define a friendly name for the
validator.
6. Register a validation definition item in Sitecore to define
characteristics of your validator.
7. Select your validation definition item in fields of the Validation
section of the items to which the validator should apply.
The main differences between field validators and item validators are as
follows:
Field validators validate the values of fields, which can contain
changes that the CMS user has not yet saved. Item validators always
validate saved items.
Field validators validate the ControlValidationValue property
defined in the Sitecore.Data.Validators.BaseValidator abstract
class. Item validators validate the value in the item returned by the
GetItem() method.
You create field and item validator definition items in different
locations.
You select field and item validator definition items in the Validation
section of different types of items.
In addition to the examples in the following sections, you can find
numerous item field validators in the Sitecore Stuff (http://bit.ly/uyoiCw)
Shared Source project.
Validating Fields
Field validators apply to values in individual fields. When a field contains
invalid content, a bar appears next to the field in the Content Editor. The
color of the bar indicates the severity of the error.
You can use the field validator shown in Listing 7.3 to ensure that all
anchor (<a>) elements in all Rich Text Editor field values contain title
attributes with values.
Validating Items
Item validators apply to entire items, including all fields of the item. You
can validate conditions about all fields, all fields of a given type, a
specific combination of fields, values in other items, or any other logic
you require. For an example of an item validator that ensures that the
value of one date field follows the value in another date field, see my blog
post at http://bit.ly/rzYwVl.
For example, to help ensure that users do not create links to items that
Sitecore cannot render to a browser, the item validator shown in Listing
7.4 ensures that all items (excluding media items) referenced in all RTE
(Rich Text Editor) fields contain some form of layout details.
if (item == null)
{
this.Text = "Item does not exist";
return
Sitecore.Data.Validators.ValidatorResult.FatalError;
}
try
{
link = Sitecore.Links.DynamicLink.Parse(href);
}
catch (Sitecore.Web.InvalidLinkFormatException)
{
// the href does not reference an item that exists
return null;
}
Multiples of 24 hours, such as 24:00:00 or 48:00:00, evaluate to 0 hours. You can prefix
the number of hours with a number of days, such as 1.00.00.00 for 24 hours.
Set the polling frequency to half or less of the smallest value for the interval attribute in
all /configuration/sitecore/scheduling/agent elements defined in the Web.config file.
Publishing clears caches, which can affect performance. For optimal performance, do
not schedule frequent publishing unnecessarily.
Handling Events
Numerous operations in Sitecore raise events. Sitecore invokes any
number of handlers for each event. The name attribute of each
/configuration/sitecore/events/event element in the Web.config
file defines an event. The type attribute of each <handler> child of the
/configuration/sitecore/events/event element specifies the type
that implements a handler for that event; the method attribute indicates the
event handling method in that class. You can remove, override, and add
event handlers, but be careful not to interfere with existing Sitecore
functionality.
Event handlers accept two arguments: an object representing the entity
that raised the event and an instance of the
Sitecore.Events.SitecoreEventArgs class containing event arguments.
Sitecore can pass zero or more parameters to each event. For example,
Sitecore passes the item to save to handlers for the item:saving and
item:saved events. Event handler parameters are positional: You access
these parameters by numerical index, rather than by name. You can use the
static Sitecore.Events.Event.ExtractParameters() argument method
to retrieve a parameter from the Sitecore.Events.SitecoreEventArgs
object passed to the method.
In load-balanced environments, you may need to handle events raised by
remote instances as well. For each event defined in the Web.config file,
such as item:saved, there is also a remote event, such as
item:saved:remote, raised when the event occurs on a remote instance.
Many operations actually raise two separate events: one before or during
the operation (the “ing” event, such as item:saving), and another
afterward (the “ed” event, such as item:saved). If you need to access the
values of fields as they were before an event, or to prevent Sitecore from
triggering other event handlers for the event or from completing the
operation that raised the event (such as update or deletion), use the “ing”
event, such as item:saving. To cancel an event, set the Result property
of the Cancel property of the Sitecore.Events.SitecoreEventArgs
argument to false as demonstrated in the following example. There are
no “ing” remote events, only “ed” remote events.
One common requirement for event handlers and other customizations is
that they should run only for items in specific databases. For example, you
might want an event handler to process only items in the Master database
or the Core database, but not publishing target databases. You can use the
configuration factory to specify the relevant database(s) for event
handlers. You can also use the configuration factory to specify data
templates, item paths, or other relevant processing criteria.
Listing 7.5 provides an example of an item:saving event handler that
prevents users other than one specific user from saving changes to items
previously updated by that user. The
SitecoreBook.Tasks.PreventSaveEventHandler class could contain
event handlers (methods with the signature of an event handler) for
multiple events. Because this event handler depends on parameters (the
username and databases on which to operate) that are not relevant to
handlers for other events, it makes sense to isolate those properties and
this logic into its own class. Because each class can have only a single
event handler of a given name, you might also implement multiple classes
if you need multiple handlers for an event and want to use a method
naming convention such as OnItemSaved() for the item:saved event. The
Username property enables you to specify the security domain and
username. The AddDatabase() method enables you to specify the
databases that this event handler should monitor. The OnItemSaving()
method contains the event handler implementation.
Sitecore.Diagnostics.Assert.ArgumentNotNullOrEmpty(database
, "database");
Sitecore.Diagnostics.Assert.IsNotNull(this._databases,
"_databases");
database = database.ToLower();
Sitecore.Diagnostics.Assert.ArgumentNotNull(updatedItem,
"updatedItem");
You can use a Web.config include file such as the following to insert this
handler before the first existing handler for the item:saving event:
<configuration
xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<events>
<event name="item:saving">
<handler type="SitecoreBook.Tasks.ItemEventHandler,
assembly"
method="OnItemSaving" patch:before="handler[1]">
<username>sitecore\jw</username>
<databases hint="list:AddDatabase">
<database hint="core">core</database>
<database hint="master">master</database>
</databases>
</handler>
</event>
</events>
</sitecore>
</configuration>
PreventSave.config
While this item:saving event handler effectively blocks save operations, it does not
prevent Sitecore from writing a log entry to audit the attempted save operation. Nor does
it prevent the “shrinking” effect in the Content Editor that indicates that save completed,
and it may not function correctly in the Content Editor. If this type of functionality is
important to you, consider overriding commands or implementing a processor for the
saveUI pipeline.
Processing Pipelines
Sitecore uses pipelines to implement a number of features. Each pipeline
implements a single logical procedure, such as defining the Sitecore
context for each HTTP request or generating a list of warning messages
for an item in the Content Editor. Each pipeline consists of a series of
processor classes, where each processor implements one aspect of the
common function defined by the pipeline.
Pipelines and processors support separation of concerns between aspects
of the system, providing for testability, configurability, and extensibility.
You can remove existing processors, override default processors, and add
your own processors, but be sure not to affect default Sitecore
functionality.
Processor classes implement a method named Process() that accepts a
single parameter and returns void. Some pipelines use a class specific to
the pipeline to pass arguments, where that class inherits from the default
Sitecore.Pipelines.PipelineArgs.
To implement a pipeline processor:
1. Create a class that implements a method named Process() in your
Visual Studio project that has the same signature as the other
processors in the pipeline. Your processor can inherit from an existing
processor, and you can add, remove, replace, and rearrange processors
in the pipelines to suit your requirements.
2. Add a <processor> element with the type attribute set to the
signature of your processor to the pipeline definition in the
Web.config file. Use the configuration factory to pass parameters by
setting properties of the class.
Exit the Process() method immediately if the logic contained in the pipeline processor is
not relevant to the processing context.
The httpRequestBegin pipeline does not actually assemble a page. Processors in the
renderLayout pipeline manipulate the ASP.NET control tree, but Sitecore then returns
control to ASP.NET, which assembles the page from the control tree.
You can use the httpRequestBegin pipeline for a number of purposes:
To determine whether Sitecore should process a request, use a specific
handler to process a request, let ASP.NET and IIS process a request
without Sitecore, redirect a request, or otherwise
To rewrite URLs, including mapping legacy URLs to the URLs of
corresponding Sitecore items
To resolve Sitecore context properties, such as the context item, using
custom logic, allowing custom URLs
To enforce canonical URLs
To implement performance diagnostics
To manipulate HTTP headers
To authenticate users, such as to support SSO (single sign-on)
For additional purposes, such as custom HTTP 404 (page not found)
management
For example, you might want to include ETag (Entity Tag — see
http://bit.ly/8cQ8Z3) headers in the HTTP responses for some of your
managed websites. Conveniently, Sitecore updates a unique revision
identifier each time an item changes; you can use the revision identifier as
the ETag to uniquely identify a revision of a version within a language.
The Sitecore.Context.Site static property exposes the context site
determined from the current HTTP request using the
Sitecore.Sites.SiteContext class. The extension class in Listing 7.6
adds the GetETag() method to that class, which returns the value of the
etag attribute that you can add to
/configuration/sitecore/sites/site elements in the Web.config file
that configures each managed site.
<configuration
xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<sites>
<site name="website">
<patch:attribute name="etag">true</patch:attribute>
</site>
</sites>
<pipelines>
<httpRequestBegin>
<processor
type="SitecoreBook.Pipelines.HttpRequest.ETag,assembly"
patch:before="processor[last()]" />
</httpRequestBegin>
</pipelines>
</sitecore>
</configuration>
AddETag.config
You might be amazed by how many challenges you can address with
these techniques, often where you might expect to use an ASP.NET
module or handler. For additional example httpRequestBegin pipeline
processors, see the PageNotFound (http://bit.ly/vIoNwP) Sitecore Shared
Source project.
<configuration
xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<renderField>
<processor
type="SitecoreBook.Pipelines.RenderField.AddLinkTargets,ass
embly"
patch:before="processor[last() - 2]" />
</renderField>
</pipelines>
</sitecore>
</configuration>
AddLinkTargets.config
<configuration
xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<renderLayout>
<processor patch:before="processor[1]"
hint="before"
type="SitecoreBook.Pipelines.RenderLayout.LogControlTree,as
sembly">
<message>before expansion</message>
</processor>
<processor patch:after="processor[last()]"
hint="after"
type="SitecoreBook.Pipelines.RenderLayout.LogControlTree,as
sembly">
<message>after expansion</message>
</processor>
</renderLayout>
</pipelines>
</sitecore>
</configuration>
LogControlTree.config
DMS Pipelines
The Sitecore Digital Marketing Suite (DMS) uses the
/App_Config/Include/Sitecore.Analytics.config web.config
include file to define several pipelines and update pipelines in the
Web.config file provided with the CMS.
DMS pipelines include the following:
automation — Applies engagement automation
startTracking — Invokes the initializeTracker pipeline, parses
tracking as specified by query string parameters, processes tracking
defined for the context item
initializeTracker — Initializes the
Sitecore.Analytics.Tracker class used to implement tracking
parseReferrer — Identifies search engines and search terms
provided by the browser using the referrer HTTP header
trafficTypes — Identifies the traffic type associated with a visit
(referral, organic search, branded search, or otherwise)
createVisit — Records an analytics visit
registerPageEvent — Associates page events, including goals and
failures, with pages
triggerCampaign — Triggers campaigns
processMessage — Processes outbound e-mail messages
DMS updates the following CMS pipelines:
renderLayout — Adds event handlers to support tracking
getContentEditorWarnings — Warns about items missing
marketing profiles
initialize — Initializes tracking and engagement automation
httpRequestBegin — Initiates analytics diagnostics and sets context
items depending on page-level multivariate testing
httpRequestEnd — Applies analytics tracking
sessionEnd — Invokes rules and automations
For more information about important DMS pipelines, including links to
example pipeline processors, see my blog post at http://bit.ly/nPlMqj.
Hook, Pipeline Processor, Event Handler,
or Rule?
In some cases, you can implement the same feature in Sitecore using an
initialization hook, a pipeline processor, an event handler, or the rules
engine. This is especially true for managing what happens when a user or
the system updates data, which can involve the item:saving event, the
item:saved event, the saveUI pipeline, item saved event rules, validation,
and potentially other features. Here are some general guidelines:
Use an initialization hook for system initialization logic that does not
depend on any processing context.
Use events to handle both interactive (UI) and automated (API)
operations.
If you use events, use “ed” events when you can; use “ing” events
only when necessary, such as to cancel an operation.
Use pipelines to interact with the user.
Use the rules engine to provide a browser-based interface to configure
logic, especially for nontechnical business users.
Always remember to consider whether validation can meet your
requirements, rather than more complex approaches that can
adversely interact with Sitecore itself, especially for expensive
operations.
Most operations that update data raise item saved events. Certain
operations raise additional events, such as the creation of an item. In some
cases, you can use either event, such as the creation event or the save event
that follows it. One of the advantages of using save handlers and pipelines
(as opposed to creation or other events or pipelines) is that Sitecore
invokes the save event for each save operation. If you associate an event
handler with item creation, it only runs when you create the item; if the
logic fails or data changes on which the event handler depends, your logic
will not run again. Additionally, you might have to intercept multiple
events, such as creation and renaming. If you handle a save event instead,
your logic runs when the user creates, renames, updates, or otherwise
touches an item, but not when the user duplicates an existing item. Save
handlers are more expensive in terms of compute resources, but more
reliable for handling data changes over time, and easier to implement and
configure if you need to handle multiple events.
For more ideas about choosing between events, pipelines, the rules
engine, and validators, see my blog post at http://bit.ly/nmA1Ov.
For optimal usability, whenever possible, use field, rendering, and placeholder
commands in favor of edit frames around an individual markup element. For more
information about edit frames, see The Sitecore Client Configuration Cookbook
(http://bit.ly/qS8Dc1).
The chrome that can appear around each HTML element, field,
rendering, and placeholder in the Page Editor provide inline editing,
access to layout details, personalization, and other features for these
objects in the Page Editor. Sitecore uses the getChromeData pipeline to
determine which commands to expose in the chrome for each component.
The RenderChromeData processor in the renderField pipeline invokes
the getChromeData pipeline around fields.
To create a Page Editor command for a field, rendering, or placeholder:
1. Create a class that inherits from the
Sitecore.Shell.Applications.WebEdit.Commands.WebEditComma
nd class in your Visual Studio project.
2. Create an entry in the /App_Config/commands.config file
mapping a command code to the signature of your class.
3. Add a button definition item using the System/WebEdit/WebEdit
Button data template in the Core database, under the
/sitecore/content/Applications/WebEdit/Custom Experience
Buttons item, using the Content Editor.
You can use the solution shown in Listing 7.10 to add a Page Editor
command that resets a field to its standard value. As shown in this
example, Sitecore developers often use pipelines to interact with the user
(in this case, to confirm they meant to reset the field).
// command implementation
protected void
Run(Sitecore.Web.UI.Sheer.ClientPipelineArgs args)
{
// validate parameters
Sitecore.Diagnostics.Assert.ArgumentNotNull(args.Parameters
["field"], "field");
Sitecore.Diagnostics.Assert.ArgumentNotNull(
args.Parameters["database"],
"database");
Sitecore.Diagnostics.Assert.ArgumentNotNull(
args.Parameters["language"],
"language");
Sitecore.Diagnostics.Assert.ArgumentNotNull(
args.Parameters["version"],
"version");
Sitecore.Web.UI.Sheer.SheerResponse.Confirm(message);
args.WaitForPostBack();
}
Sitecore.Globalization.Language.Parse(args.Parameters["lang
uage"]);
// field to reset
Sitecore.Data.Fields.Field field =
item.Fields[args.Parameters["field"]];
context.Items[0].Fields[context.Parameters["field"]];
If you click Cancel, Sitecore does nothing. If you click No, Sitecore
discards the changes to the item. If you click Yes, Sitecore saves the item.
In either case, Sitecore then prompts for confirmation as shown in Figure
7.8 before proceeding to reset the field to its standard value.
Figure 7.8
Click OK to reset the field to its standard value. The Page Editor
refreshes to show that the field now contains its standard value. Due to the
QueryState() method implementation, the Reset command does not
appear in the More menu for the field because the field already contains
its standard value.
Don't confuse resetting a field to its standard value with discarding your changes. You
can set access rights on the definition item for the Reset command in the Core database
to control who can invoke that command.
Automated Testing
One famous blogger who writes about unit testing in .NET is Roy Osherove, author of the
book The Art of Unit Testing (ISBN-13: 978-1933988276, Manning Publications). Roy
maintains a current definition of a good unit test at http://bit.ly/n7DqGI. Using Roy's
definition, the techniques covered in this chapter are integration tests, as they are not
isolated from Sitecore and do not run entirely in memory. To avoid confusion between
unit tests and integration tests, and because the difference between the two can be
subjective at times, this book refers to these combined topics as automated tests. When
searching for additional sources to gain a deeper understanding of the material
presented in this chapter, you may find the best results by searching for “unit testing”
rather than “automated testing.”
This is not the case with ASP.NET applications such as Sitecore. Your
code runs in the context of the ASP.NET environment and the Sitecore
application built on top of the ASP.NET framework, which differs
significantly from the context of a command-line tool. The ASP.NET
framework is always at the top of the method call stack for code that you
develop for that environment. Functioning something like a logical layer
between the developer and ASP.NET itself, Sitecore extends the ASP.NET
framework. When designing tests for Sitecore components, you must
consider this context, which generally depends on an HTTP request. Figure
8.2 shows a typical flow of control for a Sitecore application.
Figure 8.2
Some code may depend on the context that invokes that code, such as the
HTTP context exposed to ASP.NET applications by the
System.Web.HttpContext (HTTP context) class provide by the
System.Web.Context.Current property. Sitecore is an ASP.NET
application that services requests sent to it through HTTP, with pieces of
that application heavily dependent upon the HTTP context. To aid in
testing, to the extent possible, endeavor to ensure that no code in your
Sitecore solutions depends on the Sitecore context or the HTTP context.
Specifically, your code should not rely directly upon the Sitecore
context, such as static properties of the Sitecore.Context class. Relying
on the Sitecore context makes the code much harder to test, as you cannot
simply supply the test values to a method or class, but must set up the
Sitecore context before calling the method or class under test.
A well-designed solution exposes an API that you can easily test. This is
in fact one way to measure the quality of the implementation. If the
majority of methods and classes allow you to call them directly from test
code, then that indicates a well-considered architecture abstracted to an
acceptable degree. A bad design can be extremely hard to test, requiring
the developer to implement workarounds for various issues when writing
tests.
As you write code, it is vital to consider how you can test it. For example, when writing a
method, you can access the context item or you can pass the context item to the method.
Not only is a method that accesses the context item more limited than a method that
accepts an item as a parameter, but testing a method that uses the context item is more
difficult than testing a method that accepts an item as a parameter. Small design
decisions like this can lead to code that is much easier to test and reduces testing
requirements. You can find valuable suggestions for writing testable code on the Google
testing blog at http://bit.ly/2UVnhs.
After my initial NUnit installation using the .msi, the NUnit Windows application
(nunit.exe) raised error messages about missing files such as pnunit-agent.exe until I
reinstalled using the .msi and chose the PNUnit Runner option. If you use the .msi to
install NUnit and experience this issue, reinstall NUnit, select the Custom Installation
option, and include PNUnit Runner (Parallel NUnit Runner). The .zip automatically
includes PNUnit. Based on this experience, I would just use the .zip file in the future.
Bless open-source software — I love the idea, but each piece of each version of each
ware usually sneezes on me a few times initially.
Follow these steps to create a new class project for unit tests with the
existing Visual Studio solution or your Sitecore project:
1. Open the existing Sitecore solution in Visual Studio.
2. Right-click the top element in Solution Explorer, which represents
the solution. In the context menu that appears, click Add ⇒ New
Project. The Add New Project dialog appears as shown in Figure 8.3.
3. Select the Class Library project model.
4. In the Name field, enter a name for the unit test project, such as
SitecoreBook.Tests, and then click OK. The Add New Project
dialog disappears and you return to Visual Studio.
5. Optionally, select your new project in the solution explorer and
double-click Properties to enter values in the Assembly name, Default
namespace, and potentially other fields to control project properties.
The examples in this chapter assume the same namespace and
assembly as the test project name: SitecoreBook.Tests and
SitecoreBook.Tests.dll, respectively.
Figure 8.3
To make the NUnit APIs available to the project:
1. To add a subdirectory to your tests project to contain the NUnit
assembly (.dll file) that contains the NUnit APIs your test will use,
right-click the test project in Solution Explorer. In the context menu
that appears, click Add ⇒ New Folder. Name the new subdirectory lib
(short for library).
2. Copy the nunit.framework.dll assembly from the
/bin/framework subdirectory of your NUnit installation subdirectory
to the /lib subdirectory within your test project.
3. Right-click the References element in the test project in Solution
Explorer, and then click Add Reference. The Add Reference dialog
appears as shown in Figure 8.4.
4. Click the Browse tab, navigate to the /lib subdirectory, select the
nunit.framework.dll assembly, and then click OK. The Add
Reference dialog disappears and you return to Visual Studio. Now you
can add test fixtures (classes that contain tests) to your test project. To
indicate that a class in the test project contains NUnit tests, add the
[NUnit.Framework.TestFixture] attribute before the class
definition as shown in the following example:
namespace SitecoreBook.Tests
{
[NUnit.Framework.TestFixture]
public class MyTestClass
{
}
}
Figure 8.4
Alternatively, you can add the following using statement to the class
and then use the [TextFixture] attribute without the namespace:
using NUnit.Framework;
For clarity outside of an integrated development environment (IDE)
such as Visual Studio, except for namespaces under System, this book
always includes namespaces inline rather than relying on a using
directive. Whether you qualify all types with namespaces or include using
directives, when you use a test runner, NUnit attempts to load tests only
from those classes attributed as [NUnit.Framework.TextFixture].
Each test is a method of a test fixture class, which is a class attributed
with [NUnit.Framework.TextFixture]. After attributing the class as a
test fixture, add the [NUnit.Framework.Test] attribute to each method
that you want the test runner to invoke automatically when testing your
solution. Test runners invoke methods decorated with the
[NUnit.Framework.Test] attribute in classes decorated with the
[NUnit.Framework.TextFixture] attribute automatically. You can
include any number of test methods in a single test fixture class. Test
methods do not accept arguments. You can include methods without the
[NUnit.Framework.Test] attribute in a test fixture class, such as to
contain utility routines used by one or more of the actual tests. The test
runner does not invoke such methods directly or automatically. Listing 8.1
provides an example of a single test.
Optionally, you can add the [NUnit.Framework.Category] attribute to your class to define
a category for tests in that class as demonstrated in Listing 8.1. When you use a test
runner to invoke the tests as described later in this chapter, you can select one or more
test categories, or run all tests in all categories. Add the [NUnit.Framework.Category]
attribute to entire test fixture classes; it has no effect if you add it to individual test
methods.
[NUnit.Framework.TestFixture]
[NUnit.Framework.Category("ExampleTests")]
public class ExampleTests
{
[NUnit.Framework.Test]
public void TestOne()
{
// Populate result from calling code under test
string result = "output";
Figure 8.6
Figure 8.7
Several types of extensions for Visual Studio enable you to run tests
directly inside the integrated development environment (IDE). These
include TestDriven.NET (http://testdriven.net), Visual NUnit
(http://bit.ly/cbkhrj) from Ohloh (www.ohloh.net), and ReSharper
(http://bit.ly/ybr42J) from JetBrains (www.jetbrains.com). For example,
ReSharper exposes testing features in the sidebar at the left when editing
test fixture classes that contain NUnit tests as shown in Figure 8.8.
Figure 8.8
Alternatively, you can create a custom test runner using additional
assemblies available in the NUnit release. For instructions to create a
custom test runner that executes within an ASP.NET application, which
gives you access to a complete Sitecore context and APIs, including an
HTTP context, see the section “Testing with an Embedded Test Runner”
later in this chapter.
For brevity and readability, all code in this chapter intentionally omits defensive
constructs. You should check each variable for null and other potential error conditions
in the testing code itself.
You can now use the HAP to parse the page into an XML document as
shown in in the following example:
// Create a new HtmlAgilityPack document
HtmlAgilityPack.HtmlDocument document =
new HtmlAgilityPack.HtmlDocument();
Because the HAP representation differs from the original markup, this approach cannot
test various specifics of the original response, such as the presence, absence, or volume
of whitespace, nor whether the markup contains single quote characters (') or double
quote characters (“) in specific locations. Remember that the HAP may also correct
problems with the markup, preventing you from seeing those issues. Most modern web
browsers perform similar corrections. For more information about this approach, see the
following section.
Assume that the home page should include the following markup and
you want to test only some aspects of only that section of the response (not
including the values of the href attributes, the depth of the <nav> element
in the HTML superstructure, whether this structure includes any
unexpected markup, or various other aspects of the response):
<nav class="primary">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Partners</a></li>
</ul>
</nav>
Many of the tests used in the remainder of this chapter expect this markup format. If you
compile the code provided into a project to develop some experience with testing, you
may want to enter this markup as the value of a field of an item in your Sitecore solution
and publish that item so that the tests can pass. In a development environment, the
/sitecore/content/home item may be convenient for this purpose.
The following code demonstrates how you can traverse the XML
representation of the markup returned by the Sitecore solution to verify
aspects of that markup, such as to find a particular element or set of
elements and ensure that they conform to expectations:
// Find all list items within the primary nav element
XPathNodeIterator elements = nav.Select(
"//nav[@class='primary']/ul/li");
NUnit reports only the first failed assertion in each tested method. If
your class contains multiple test methods, NUnit can report multiple failed
assertions, but only the first such assertion in each method. Because unit
test methods generally should not accept arguments, this can present
limitations when you want to investigate multiple error conditions for a
single test.
One benefit of this approach is complete decoupling of the testing
infrastructure from the technology used to create the web application. You
can use this technique to test solutions built with a technology that does
not expose a public API. You can run the test from a separate IIS website
without Sitecore, and even from a separate server. Unfortunately, this
approach is somewhat tedious and has a variety of limitations as described
in the following section.
Regardless of your testing strategy, remember to decorate classes that contain tests with
the [NUnit.Framework.TestFixture] attribute, and the testing methods in the tested
assembly within those classes with the [NUnit.Framework.Test] attribute. NUnit
automatically invokes all methods with the [NUnit.Framework.Test] attribute in all
classes with the [NUnit.Framework.TestFixture] attribute.
namespace SitecoreBook.Tests
{
using System.Collections.ObjectModel;
[NUnit.Framework.TestFixture]
class TestHomePageWithFirefox
{
[NUnit.Framework.Test]
public void PageTest()
{
// Create a Firefox driver
using (OpenQA.Selenium.Firefox.FirefoxDriver
driver =
new OpenQA.Selenium.Firefox.FirefoxDriver())
{
// Navigate to the page to test
driver.Navigate().GoToUrl("http://sitecorebook");
OpenQA.Selenium.By.XPath("//nav[@class='primary']/ul/li"));
The code used to create this test fixture contains a single test that relies
on Selenium to drive the Firefox browser to access the home page at
http://sitecorebook, uses an XPath expression to locate elements to verify
within the page, and then uses an NUnit assert against the expected
number of elements.
This code instantiates an object of the
OpenQA.Selenium.Firefox.FirefoxDriver class wrapped in a C# using
statement. When the application exits the scope of this using statement,
the .NET Framework automatically closes the driver, which closes the
Firefox window used for the tests and frees any resources it used. You
might see the page load into that window before the browser closes.
Selenium enables you to locate elements on the page using a variety of
techniques. You could alternatively populate the navElements variable in
this example using a CSS selector instead of using XPath. Both techniques
enable you to select zero or more elements in a block of markup such as
XHTML. For more information about CSS selectors, see
http://bit.ly/y3uiAk. The following code demonstrates how to use a CSS
selector to locate the same elements selected with XPath in the previous
example:
ReadOnlyCollection<OpenQA.Selenium.IWebElement> navElements
= driver.FindElements(
OpenQA.Selenium.By.CssSelector("nav.primary ul li"));
You can use Selenium to interact with the elements of the page to test
dynamic behaviors. For example, if a page includes a form that contains a
button with the ID myButton, and the page uses JavaScript to change the
inner text of a <div> element with ID theText to button clicked, you
can use Selenium to locate and “click” the button, which executes the
JavaScript action associated with that button. You can then test the inner
text of the <div>. The following code demonstrates this approach using
the page at http://sitecorebook/form.aspx:
[NUnit.Framework.Test]
public void FormTest()
{
// Create a Firefox driver
using (OpenQA.Selenium.Firefox.FirefoxDriver driver =
new OpenQA.Selenium.Firefox.FirefoxDriver())
{
// Navigate to the page to test
driver.Navigate().GoToUrl("http://sitecorebook/form.aspx");
This test creates a Firefox driver just as in the previous test. It then uses
that driver to navigate the browser to the URL of the page containing the
form to test. After loading that page, the test locates and clicks the button
with ID theButton. In this instance, that simulated click actually occurs
inside the Firefox browser controlled by your test method, and causes any
JavaScript attached to the button to execute. The rest of the test locates the
HTML element with ID theText and verifies that the inner text of that
element is as expected by accessing the element's Text property.
Limitations of the Web Browser Driver
Technique
Testing with a web browser driver overcomes one of the most significant
limitations of testing over HTTP: Because it uses a real browser to execute
the tests, testing with a web browser driver allows tests to account for
JavaScript and dynamic behaviors of the page. However, this technique
does not address the scope limitation common to employing HTTP
directly: The browser loads an entire page to verify a single component of
that page. Use a web browser driver when you need to test HTML forms
and JavaScript.
Running code inside the Sitecore application does not require placing that code in the
same Visual Studio project as your Sitecore solution. You should still maintain a separate
project for testing, and avoid deploying that solution to environments that you do not use
specifically for testing.
The NUnit test runner used thus far executes one or more tests as a
standalone application. To execute NUnit tests inside a Sitecore
application, the test runner needs to run inside the Sitecore application.
For this task, you can use the NUnit API to create a test runner that runs as
an ASP.NET web form inside the Sitecore application.
<html>
<head>
<title>Embedded NUnit Test Runner</title>
<style type="text/css">
body { font-family: Tahoma, Arial, Sans-Serif; font-
size: 12px; }
h1 { font-size: 1.3em; }
h2 { font-size: 1.2em; }
.result { font-weight: bold; font-size: 1.1em; }
.result-pass { color: Green; }
.result-fail { color: Red; }
.pass { background-color: Green; }
.fail { background-color: Red; }
</style>
</head>
<body>
<form id="Form1" runat="server">
<h1>Embedded NUnit Test Runner</h1>
<p>
<asp:Literal runat="server" ID="ltrStats" />
</p>
<p class="result">
<asp:Label runat="server" ID="lblResult" />
</p>
<hr />
<asp:GridView runat="server" ID="gvResults"
OnRowDataBound="RowDataBound"/>
<h2>Category Filter</h2>
<asp:CheckBoxList runat="server" ID="cblCategories"
RepeatDirection="Horizontal"/>
<hr />
<asp:Button ID="Button1" runat="server" Text="Run"
OnClick="RunTests" />
</form>
</body>
</html>
TestRunner.apsx
To implement the code-behind for the embedded test runner web form
you just created:
1. Add the following member variables to the code-behind class.
Various methods of the page populate these variables used to report
the outcome of the tests. The code snippets for this example depend on
classes in the System, System.Collections.Generic, System.Data,
System.Reflection, and System.Web.UI.WebControls namespaces.
If they do not already exist, add using statements for those
namespaces to your class.
// Initialize NUnit
NUnit.Core.CoreExtensions.Host.InitializeService();
if (this.IsPostBack)
{
return;
}
4. Add the LoadTestSuite() method to load the tests from the same
assembly as the test runner:
private void LoadTestSuite()
{
NUnit.Core.TestPackage package = new
NUnit.Core.TestPackage(
Assembly.GetExecutingAssembly().Location);
this.testSuite = new
NUnit.Core.TestSuiteBuilder().Build(package);
}
TestRunner.aspx.cs
this.GetCategories((NUnit.Core.TestSuite)suite.Tests[i],
cats);
}
}
}
TestRunner.aspx.cs
6. Add the RunTest() method that will handle the Click event for the
Run button in the embedded test runner web form:
protected void RunTests(object sender, EventArgs args)
{
// Create a list of any selected categories to filter
by
List<string> selectedCategories = new List<string>();
// Display statistics
ltrStats.Text = string.Format(
"{0} out of {1} tests run in {2} seconds.",
this.executedCount,
result.Test.TestCount,
result.Time);
if (this.failedCount > 0)
{
ltrStats.Text += string.Format(
"<br/>{0} {1} failed",
this.failedCount,
this.failedCount == 1 ? "test" : "tests");
}
if (result.IsFailure)
{
this.lblResult.CssClass = "result-fail";
}
else
{
this.lblResult.CssClass = "result-pass";
}
}
TestRunner.aspx.cs
if (data == null)
{
return;
}
// Set the appropriate CSS class to allow styling
the table cell
args.Row.Cells[1].CssClass = (bool)data.Row["Pass"]
? "pass" : "fail";
}
}
TestRunner.aspx.cs
dr["Pass"] = result.IsSuccess;
if (result.Executed)
{
this.executedCount++;
}
Remember to add tests to your project that contains the embedded test runner.
You may encounter cases for which the lifetime of the test data should
not exceed a single test. In those cases, the test that requires the data
should create and destroy that data. To ensure destruction of the test data,
even in the event of an error or exception in a test, wrap the test code logic
in a try...finally block, and destroy the data in the finally block.
Location of Test Data
You can create temporary or permanent Sitecore items to use solely for
testing purposes. Most items used for testing are temporary. You can
create items for testing in any Sitecore database. While you should create
items not intended for test in the Master database rather than a publishing
target database so that publishing does not delete those items, you
typically want to remove test items shortly after you create them.
Therefore, you can create test data in a publishing target database such as
the default Web database, in which case publishing can clean up the
database if your testing infrastructure fails to delete those temporary
items. If you use the technique described earlier for testing with an
embedded test runner, the test runner operates in the context of the public
website, which defaults to the Web database. There is a slight chance that
publishing operations concurrent with testing could remove items in the
publishing target database while tests run; if you create items in a
publishing target database, avoid publishing while testing.
Managing Implementations
To publish the entire Master database from the Sitecore desktop, follow
these steps:
1. Click the Sitecore button, and then click Publish Site. The Publish
Wizard appears. If the Publish Wizard displays a welcome screen,
click Next. The Settings page appears as shown in Figure 9.4.
2. Select publishing options based on your requirements and as
described in the following sections. You can select the Incremental,
Smart, or Republish publishing mode, one or more languages to
publish, and one or more publishing targets. Then click Publish. When
Sitecore completes publishing, click Finish. The Publish Wizard
disappears and you return to the Content Editor.
Figure 9.4
For more information about publishing with Sitecore beyond that
provided in the remainder of this chapter, see the publishing operations
article at http://bit.ly/r6Phna on the Sitecore Developer Network (SDN).
For ideas about controlling the publication of deleted items, see my blog
post at http://bit.ly/ol09C8. You can also find several Sitecore shared
source modules relevant to publishing at http://bit.ly/vacX7d.
Publishing Modes
Whether you publish an individual item or the entire Master database, you
can select a mode of publishing for the operation. The following sections
describe the publishing modes summarized in this list:
Republish — Publishes all items in the database or only those items
you select to publish, with no exceptions in either case
Incremental — Publishes all items in the database or only those
items you select to publish, in either case excluding items that
Sitecore has not added to an internal list of items that may require
publication
Smart — Publishes all items in the database or only those items you
select to publish, in either case excluding items for which the revision
identifier in the source database matches that in the publishing target
database
Regardless of which publishing mode you choose, Sitecore does not transfer items and
versions of items to the target database if publishing restrictions (including workflow
status) indicate that Sitecore should not publish the item or the version. Subsequent
sections in this chapter describe publishing restrictions and workflow.
Republishing
When you choose to republish, Sitecore publishes each of the items that
you indicate to publish (or all items) from the Master database to the
publishing target database(s), with no exclusions. Republishing is the least
efficient publishing mode. You can use republishing to force Sitecore to
publish all items, such as when you bring a new publishing target database
online or after you add a new language and corresponding content.
Incremental Publishing
When CMS users add and update items, Sitecore adds the IDs of those
items to an internal list of items that may require publication. When you
select incremental publishing mode, Sitecore publishes the items that you
select to publish that also exist in this list, or all items in that list if you
select to publish the entire database. Incremental publishing is typically
more efficient than republishing or smart publishing.
Smart Publishing
Whenever a user updates an item, Sitecore updates its internal revision
identifier for that item in that database to a unique value. When you select
the smart publishing mode, Sitecore compares its internal revision
identifiers for each version of each item that you select to publish in the
Master database against the revision identifiers of the corresponding items
in the publishing target database to determine which items to publish.
Smart publishing is more efficient than republishing, but less efficient
than incremental publishing. You can choose the smart publishing mode
when incremental publishing does not transfer a change that you expect,
without resorting to republishing.
Publishing Restrictions
You can specify publishing restrictions for each item and each version of
each item in each language. Publishing restrictions control whether
Sitecore can publish that item or version, as well as the dates during which
Sitecore can publish the item or version. Additionally, you can specify
publishing targets for an item, which prevent Sitecore from publishing that
item to any other publishing target databases.
Regardless of publishing restrictions, Sitecore does not publish versions associated with
non-final workflow states.
If Sitecore cannot publish an item, it cannot publish any descendants of that item.
Figure 9.5
Publishing Targets
Publishing target databases represent Sitecore content databases to which
you can publish content from the Master database in the content
management environment. Publishing target databases typically support
content delivery environments. A publishing target database involves an
actual database and a publishing target definition item. Whereas the
Master database contains all versions in all languages of all items,
including unapproved changes, publishing targets contain at most one
version of each item in each language, and they do not contain unapproved
content.
Most customers want to publish all items to all publishing targets, which
is what Sitecore does by default. After you add a publishing target,
publishing operations can publish all items to that new publishing target.
Publishing restrictions can associate items with publishing targets,
allowing Sitecore to publish those items only to the publishing targets
selected.
It may not be intuitive, but if you do not select any publishing targets (as by default) on
the Targets tab in the Publishing Settings dialog, Sitecore publishes the item to all
publishing targets. As soon as you start selecting publishing targets for an item, you
actually limit the publishing targets to which Sitecore can publish the item to those
targets that you select. This is important because you do not need to update all your
items after you add a publishing target; Sitecore automatically publishes every item to
every publishing target if you select no targets. If you really do not want to publish an
item to any publishing targets, clear the Publishable check box on the Item tab.
Publishing Media
When you upload a file into the media library, Sitecore encodes its binary
content and stores that data as a record in the Master database. Before you
publish content items that reference a media item, you should publish that
media item.
Excluding the File Drop Area field type, Sitecore does not automatically prevent a user
from publishing content that references unpublished media.
There are multiple potential strategies for publishing media. You could
require users to publish their media before publishing their content, in
which case you might implement validation to alert the user about items
that reference unpublished media (see my blog posts at
http://bit.ly/xVdkT0). If you use workflow for content (which you should,
even if users simply publish their own changes), then you can use a
workflow action to publish related media (see my blog post at
http://bit.ly/ouU37j). Otherwise, you can use event handlers or other
features to publish media immediately after users upload new files or
update existing media items. This last approach works whether you use
workflow or not, but some organizations may not want to publish media
immediately. Therefore, the most comprehensive solution may be to
intercept content publishing to publish media referenced by that published
content. In that case, see my blog post at http://bit.ly/ouU37j.
Before you publish a media item, you must first publish the folder that contains that
media item to ensure that the parent item exists in the target database before the child.
Scheduling Publication
There are two aspects to scheduling publication: configuring publishing
restrictions to control when Sitecore can publish the item (or versions of
that item), and triggering a publishing operation after that time on that
date.
Configuring publishing restriction does not cause Sitecore to publish or
unpublish the item or version at the date and time specified; publishing
restrictions merely control whether Sitecore can publish the item or
version. You must initiate a publishing operation to publish the changes
after reaching the date and time configured in publishing restrictions. You
can publish manually; you can configure the
/configuration/sitecore/scheduling/agent element in the
Web.config file with a value of Sitecore.Tasks.PublishAgent for the
type attribute to publish periodically; or you can implement a more
advanced solution such as the Automated Publisher
(http://bit.ly/A6BHyX) Sitecore Shared Source project. For information
about scheduling processes with Sitecore, see Chapter 7.
Workflow
A CMS workflow typically prevents content from reaching the production
content delivery environment without passing through some combination
of manual and automated process. Such a process can include any number
of editorial and review phases, sometimes delineated by email notification
to the parties involved, as well as automatic content validation and
publishing.
Primary components of the Sitecore workflow system include the
following:
Workflows — Define overall processes
States — Represent steps in workflow processes
Commands — Allow users to transition content items from one state
to another
Actions — Automate functions in the workflow process
Keep your workflow implementation as simple as possible. Minimize the number of
workflows, states, commands, and actions (especially actions that send email). Use
access rights to allow the same workflow to work for multiple departments within the
organization.
Locks do not prevent Sitecore from publishing version of items. Placing a version of an
item in a workflow state that is not final prevents Sitecore from publishing that version.
Workflows
Sitecore workflows define publishing processes for content items as a
sequence of states. When a user creates or edits an item based on a data
template, Sitecore initiates the workflow that you designate as the initial
workflow in the standard values for that data template.
Sitecore follows a specific procedure when you create an item. If the
data template for that item specifies an initial workflow, Sitecore puts the
first version that you create in a language into the initial state of the
workflow specified in the standard values of the data template associated
with that item. When a user that is not a Sitecore administrator edits an
item associated with a final workflow state, Sitecore creates a new version
of that item in that language, and puts that version in the initial state of the
initial workflow associated with that data template.
Specify the initial workflow in the standard values for each data template (Review ⇒
Workflow ⇒ Initial).
Workflow States
Workflows consist of some number of states representing different phases
in the publishing process, such as editorial, review, and published states. A
user's access to a content item depends on the union of their rights to the
content item and its current workflow state. For example, even if you have
write access to an item, if that item is in a workflow state to which you do
not have write access, you do not have effective rights access to the item.
The initial workflow state of a workflow is not the same as the initial workflow for a data
template. The initial workflow selected in the standard values for each data template
specifies the workflow to activate for items based on that data template. The initial
workflow state selected for each workflow specifies the state in that workflow in which to
place items when they enter that workflow.
Final workflow states have no correspondence to initial workflow states. A workflow can
have any number of final workflow states, but designates only one initial workflow state.
Workflow Commands
Workflow commands provide a mechanism for users to move a version of
an item from one workflow state to another. For example, from an
editorial workflow state, an author could select a command such as Submit
to move that content to a review state.
Workflow Actions
Workflow actions invoke .NET code when a version of an item reaches a
specific workflow state or when a user invokes a workflow command. For
example, you can associate an action with the final states of your
workflow to publish the updated content automatically when it reaches
that state, and you can associate an action with a rejection command to
send an email message to the author.
You can associate workflow actions with both workflow states and workflow commands.
By default, Sitecore does not apply a workflow when you delete an item or a version of
an item. Any subsequent publishing operation can publish the deletion. For a discussion
of using workflow to delete items, see my blog post at http://bit.ly/ol09C8.
You can assign the same initial workflow (the landing workflow) in the
standard values of all data templates and use a workflow action to
determine the actual workflow to apply to each item at runtime. For
example, a content item might flow through different workflows
depending on the site, branch, creator, category, or other properties. The
initial state of the landing workflow contains a workflow action to
determine which actual workflow to apply. Assigning this same landing
workflow to all items can reduce administrative effort. More important,
you can trigger specific workflows based on your specific requirements,
meaning you can use landing workflows when you do not know in advance
which workflow to apply to an item or all items based on a data template.
You may want to add the landing workflow action to the initial state of all
workflows, to move the item into a different workflow if conditions have
changed since its last workflow assignment.
The landing workflow need not have a final state, but you should assign permissions and
someone responsible for checking this workflow in the Workbox to ensure that your
workflow action has not failed, leaving items in the initial state of the landing workflow.
Sitecore.Context.ContentDatabase.WorkflowProvider.GetWorkfl
ow(workflowId);
using(new Sitecore.Data.Items.EditContext(item))
{
item[Sitecore.FieldIDs.Workflow] = workflow.WorkflowID;
}
workflow.Start(item);
}
You could use the rules engine to determine which workflow to trigger. For an example
that uses the rules engine in a custom context, see my blog post at http://bit.ly/n2X3Pz.
In this context, I do not mean file-based storage of Sitecore media items, which is an
option that I do not recommend (store your Sitecore media items in the database
whenever possible). Rather, I mean that you can store such files on the filesystem without
any corresponding media item in Sitecore, and reference those assets from code and
markup as you would using a standalone ASP.NET solution rather than the Sitecore
CMS.
Creating a Deployment
To create a deployment, first compile your Visual Studio project(s). Next,
create a folder structure that contains all the new and updated files to
deploy. This folder structure can include layout files (.aspx), sublayout
files (.ascx), eXtensible Stylesheet Language Transformation files
(.xslt), compiled assemblies (.dll), and other new and updated
resources, including JavaScript (.js) and Cascading Style Sheet (.css)
files to deploy to the document root of the Sitecore solution. Then create a
Sitecore package to contain the Sitecore items changed since the previous
deployment. A Sitecore package is a .zip file that contains meta data and
it can contain Sitecore items from any database and files from the
document root. For more information about Sitecore packages, see The
Sitecore Package Designer Administrator's Guide (http://bit.ly/zDvwnv).
To access the Package Designer from the Sitecore desktop, click the
Sitecore button, and then click Development Tools ⇒ Package Designer.
To create a package in Visual Studio using the free Sitecore Rocks
extension for Sitecore developers (http://sitecorerocks.net), select the
items to include in the package using the Sitecore Explorer, right-click one
of those items, select Tools from the context menu that appears, and then
click Create Package. Alternatively, with Sitecore Rocks, you can use the
package keyword to create a package in Query Analyzer. You can include
files in your package. Alternatively, when the time comes, you can simply
copy the file assets manually or using a release management tool.
Depending on the complexity of the deployment, you can use two
techniques to determine which items to include in the package:
Package only the items that you have changed.
Package all the data templates for the solution, ensuring you include
all changes without having to pick each individual item.
Each of these alternatives presents potential problems. When you
package items selectively, you may forget to include an item, which can
cause delays or worse problems for the deployment. If you instead
package all the templates, you may include work in progress not intended
for the current deployment. You may also experience issues if your
environment does not include the latest changes from all developers
working on the project. It is very difficult, if not impossible, to merge
changes from multiple developers by packaging all data templates
comprising the solution. A more reliable approach requires a central
repository for the current versions of all Sitecore items managed by all
developers on the project, similar to a source control system for files.
Upgrading Sitecore
For current CMS releases, Sitecore provides update packages (.update
files) that you can use to upgrade your Sitecore instances through a
browser-based user interface. Unfortunately, Sitecore does not provide a
user interface that allows you to create such update packages yourself.
Always follow all instructions from Sitecore to install each update.
Update packages (.update files) differ from packages that you can create with Package
Designer and Sitecore Rocks (.zip files). Use Package Designer and Sitecore Rocks for
your changes; Sitecore uses update packages for its own system changes.
The distinction between the device and defaultDevice attributes of each managed site
definition is subtle and not commonly understood, but it can be important when you need
to apply different default devices for different managed sites. To determine the context
device for an HTTP request, Sitecore first checks the query string parameter named
sc_device. If the requested URL does not specify that query string parameter, Sitecore
sets the context device to the device specified by the device attribute used in the site
definition associated with the context site. If the device attribute does not exist for that
site, Sitecore sets the context device to the first device definition item under the
/sitecore/layout/Devices item in the context database containing field values that
match the query string or user agent specified in the request. If no device definition item
matches either of these values, Sitecore sets the context device to the first device
definition item with the Checkbox field named Default selected, unless the defaultDevice
attribute exists for the context site, in which case Sitecore sets the context device to the
device named by that attribute.
Each site has a start item that represents the home page for that site. To
determine the start item for a site, Sitecore appends the value of the
startItem attribute of the value of the rootPath attribute. For example,
the default site named site defines rootPath as /sitecore/content and
startItem as /home, leading to a start item at /sitecore/content/home.
Instead of using the Web.config file to define properties of the managed sites, you can use
the Multiple Sites Manager (http://bit.ly/xrDFyD) Sitecore Shared Source project, which
manages site definitions as definition items.
On Beyond CMS
DMS replaces the Online Marketing Suite (OMS), which was available in Sitecore CMS
6.1 through 6.4 and adds a variety of improvements and new features not available in
the OMS.
If you are familiar with Sitecore's Online Marketing Suite (OMS), a prior software
release with a subset of the capabilities provided by DMS, the term visit replaces the term
session, and the term visitor replaces the term global session.
Engagement Analytics
As mentioned previously, engagement analytics is at the heart of DMS.
Engagement analytics consists of a variety of reports and visualization
tools that provide marketers with information about website and campaign
performance, visitor behavior and visit history, as well as a number of
traffic-based reports containing traditional web analytics data.
Engagement analytics differs from most other web analytics systems in
two significant ways: it provides rich, detailed, visit-level statistics and a
qualitative metric termed engagement value.
Traditional web analytics tools generally compress historical data into
aggregate statistics such as total page visits for a given period of time. In
contrast, engagement analytics stores detailed, visit-level data, such as a
record of the individual pages viewed by each visitor. This extra
information enables detailed analysis of visitor behavior patterns and
other features such as predictive personalization.
Measuring engagement value provides a means to assess the quality of
interaction with each visitor instead of merely collecting statistics such as
the number of interactions that occur on the site. For example, a visitor
reading product reviews might view only five pages. The specific focus of
content on those pages may suggest that visitor is more likely to become a
customer in the near term than another visitor who views more pages
containing information about a greater number of products. A visitor who
views information about a small number of expensive products might be a
more valuable prospect to an organization than a visitor who views more
pages about a greater number of inexpensive products. Investigating only
the number of page views leads to a different perspective about the site
visitor than measuring the quality and the quantity of those interactions.
With engagement analytics, you can measure the effectiveness of a
marketing campaign and various other traffic sources as well as the
performance of various marketing channels.
DMS measures engagement value by applying a weighted score to the
crucial conversion events that occur in visitor interactions. CMS users
predefine engagement value points to activities such as a subscribing,
signing up for a newsletter, registering for an event, downloading an asset,
requesting additional information, and purchasing a product. DMS user
interfaces indicate the accumulated value of the activities associated with
visits, campaigns, and other system constructs. Engagement value
provides a common key performance indicator (KPI) to help marketers
make important decisions regarding how to focus their resources toward
specific channels and campaigns. Sitecore offers a complete methodology
for applying optimal engagement values to conversion events, as well as
detailed workshops about best practices for approaching this activity. For
more information about optimizing engagement value, see the Sitecore
Engage website at http://engage.sitecore.net.
DMS provides the following reporting and visualization tools targeted at
different types of CMS users:
Engagement reporting — The simplest of all the engagement
analytics tools, engagement reports contain information about visitor
behavior, campaign summaries, and a variety of traditional web
statistics. Engagement reporting targets content contributors and
marketing users who need detailed information about website traffic
for entire sites and individual pages.
Engagement intelligence — Engagement Intelligence Analyzer
enables web analysts and marketing managers to analyze current
website engagement activity across various channels, campaigns, and
interactions, a capability that traditionally required data analysts. This
feature enables integration of site engagement information with data
from external systems including Customer Relationship Management
(CRM) and loyalty management applications, giving marketers a
more complete view of the customer across all channels. Engagement
intelligence dashboards provide traditional web statistics and
marketing performance analytics.
Marketing Performance Quickview — DMS users can access the
Marketing Performance Quickview application (previously known as
the Executive Insight dashboard) from the Sitecore desktop to
evaluate the performance of traffic sources and campaigns using the
engagement value KPI. The Marketing Performance Quickview
application targets marketing leaders who want a quick overview of
performance of various channels, campaigns, and traffic sources.
The Marketing Performance Quickview application provides access to
the following types of dashboards:
Traffic — Traffic dashboards offer a view into traffic sources, as well
as how different traffic sources perform, such as branded and
nonbranded (organic) search keywords, entry pages, site search
keywords, assets consumed, and goal conversions. With this insight,
marketers can optimize their search engine placement and other
campaign efforts.
Campaigns — Campaign dashboards utilize engagement value scores
to determine and report the level of visitor engagement associated
with each of the campaigns that brought visitors to the site. Marketers
can use this information to obtain insight and optimize campaigns
accordingly.
DMS provides the Engagement Intelligence Analyzer as an online
analytical processing (OLAP) datamart that condenses data from the
Sitecore CEP database(s) into a highly optimized reporting and business
intelligence repository. The Engagement Intelligence Analyzer includes a
comprehensive set of tools that allow marketers to access information in
the datamart quickly and easily. These tools provide visualizations of
common web statistics and marketing performance data, and enable ad hoc
data analysis. To present data, the Engagement Intelligence Analyzer
provides clear, dynamic tables and diagrams including the following:
More than 120 interactive reports encompassing traditional web
statistics along with engagement value
More than 300 printable quick reports that you can export to a
spreadsheet for further analysis
Prototypes for users to create their own dashboards and reports
quickly
Built-in simple trending and mathematic capabilities, such as linear
trends and standard deviations
The capability to trigger email alerts after meeting or exceeding
thresholds
The capability to schedule reports and their distributions via email
The ability to create slides for presentation dynamically
DMS users can filter and segment data on every dimension in the OLAP
cube, which enables them to partition the data set in numerous ways and
investigate anomalies, find causal relationships between various events,
and identify latent trends and patterns in user behavior.
Engagement Automation
Engagement automation enables marketers to nurture customers and
prospects by automating interactions based on the visitor's implicit and
explicit behavior, or with timed triggers (for example, if no interaction
occurs within a given time period, send an email message to the visitor).
You can think of engagement automation as functioning like workflow as
described in Chapter 9, but involving site visitors rather than content
items. Engagement automation enables marketers to create and execute
cross-channel campaigns for site visitors, increasing marketing efficiency
through automation and presenting the audience with relevant content
based on their actions or their state in a given engagement plan.
For example, when users register for access to the website, you could
automatically enter them into an engagement plan that triggers a welcome
email. The system can then check whether the visitor has opened the email
and logged in to the site, and can perform actions based on that response.
If the visitor does not access the site within three days, the system can
automatically send a reminder email. If they access the site, DMS can
track the visitor's activity and begin to personalize content based on their
behavior. For example, if a visitor focuses on a specific area of the site, the
system can automatically show an offer inviting them to download a white
paper about that subject, but requiring the visitor to complete a web form
that asks for different information than they provided when they originally
registered for access to the site. This type of approach enables the
marketer to learn more about the visitor and continue to provide even
more relevant content.
DMS users can configure engagement automation through the Marketing
Center application in the Sitecore desktop. In this application, the user can
design a process flow by dragging states and conditions onto the canvas,
then connect those states, and add actions to execute when users move
from one state to another. Engagement automation conditions and actions
leverage the Rules Engine, which provides numerous predefined
conditions to evaluate a visitor's profile and GeoIP information, and
supporting personalization of the visitor's experience across all pages.
DMS actions can integrate with other channels and systems, such as to
update a record in an external customer relationship management (CRM)
system or to send an email message. Like almost everything that Sitecore
provides, if the default conditions and actions available in DMS do not
meet your requirements exactly, you can implement your own.
DMS users can monitor the progress of automation plans by seeing how
many visitors are in each stage of an engagement plan. They can
determine the number of visitors in each state of the plan, as well as the
success rate and value of a campaign, and then adapt the campaign and
engagement plan based on that information. DMS users can also add
visitors to, remove visitors from, and move visitors between the states in
an engagement plan, and can simulate conditions and actions to test how
various visitors will flow through different engagement states, conditions,
and actions.
Visitor Profiling
You can learn a great deal about people based on their behavior in the
digital world just as you can in the physical world, for example by
observing clothing, body language, and where they focus their attention.
Sitecore DMS provides a rich profiling engine that enables marketers to
understand visitor interests, tendencies, buying behavior, and other
persona characteristics and audience segments to which the visitor
belongs. You can use the profile data collected from visitor interactions in
a variety of ways, such as to target content to each visitor in order to
increase relevancy. Additionally, you can share this information with other
systems, such as CRM solutions, so that it is immediately available to
sales teams and call center agents. You can also use profile data to filter,
segment, and otherwise evaluate campaign performance in reports and
dashboards. These features allow marketers to make better decisions about
how to manage their marketing programs.
Sitecore provides a profiling system that enables nontechnical users to
create and manage profile attributes, and then associate those attributes
with content and functionality that visitors experience in various
interactions across channels. As visitors consume content and
functionality, their profile grows. DMS can aggregate profile data across
many visits into a single data set. DMS users manage profiling in the
Marketing Center, which they access from the Sitecore desktop.
To understand profiling, you must first understand some relevant terms:
A profile defines a category used to specify the type of information by
which to track visitor behavior, such as skill level, product
preferences, and so forth.
A profile key defines an individual attribute related to a specific
profile. For example, if the profile tracks visitor behavior on a website
for a car manufacturer site, a marketer might implement a driver type
profile with profile keys for safety consciousness and exhibitionist
tendencies.
A profile card defines a preset collection of profile key values that
DMS users can apply to content, simplifying the application of
profiles during the content creation process. For example, a DMS user
could apply the predefined “Interested in Family Cars” profile card to
content items to set a high score for profile keys that indicate safety
consciousness.
A profile card – persona defines a profile card used to assign profile
information to personas (fictional characters/archetypes designed to
be similar to real people, with details describing their lives, habits,
backgrounds, interests, and professions).
Content profiling is the assignment of profile values to new or
existing site content using either profile cards or specific values.
A real-time visitor profile contains the unique profile of a visitor
based on the content that visitor consumes on a site in real time.
A pattern defines an easy way to recognize how similar one visitor is
to other typical visitors. DMS matches patterns against each visitor's
profile in real time, and automatically display relevant, personalized
content based on similar behaviors and interests.
After you configure profiles, keys, and cards, you can begin profiling
your content. Once you profile your content, DMS automatically builds a
profile for each site visitor as they access content and site features. DMS
automatically classifies visitors into predefined persona groups, or
segments, but also expresses profile information visually to help
marketers reclassify visitors if desired.
Real-Time Personalization
Personalization targets content and features at visitors to one or many
pages using known information about that visitor. Real-time
personalization reflects the capability to observe visitor behavior and
attributes and dynamically adjusts content, presentation, and functionality
based on that changing data. As discussed in the preceding section, you
can learn a lot by observing visitors in your various channels. In addition
to profiling data (equivalent to digital body language), DMS can react to
visitors based on things they have informed the system about themselves
intentionally or unintentionally. For instance, you can determine the
approximate location of a visitor from the GeoIP record associated with
their visit, you can investigate attributes of the phone or other device they
use to browse your site, and you can account for the gender information
provided when they registered for access. You can use the Page Editor to
configure personalization for any element of any page.
Much like the testing and optimization capabilities, CMS users can
personalize any component on any page without the need for development
resources. To personalize a presentation component in the Page Editor, the
CMS user selects that component on the page and then selects an option
from the menu for that component Selecting that option exposes a dialog
that allows the CMS user to create as many data source items for that
component as needed, and to assign rules that dictate when the component
should apply each data source. Users can personalize just the data source
item, or vary the presentation used to render that content, or both.
Configuring personalization involves selecting rules within the Rules
Editor and entering parameters for the conditions and actions in each rule,
similar to configuring Microsoft Outlook's Out of Office Wizard. DMS
provides dozens of predefined rule conditions and actions, and you can
also develop custom implementations of each. Built-in rules can select
content to render based on GeoIP properties, handle mobile device
displays, target content to various user types or personas, and even vary
content when users match certain behavioral patterns. In addition to
configuring personalization at the page level, you can also configure
personalization for all pages on the site, for each section, and for each
page type using personalization theming.
Campaign Management
Marketing campaigns are the lifeblood of marketing. DMS supports many
types of campaigns, including online advertising campaigns, offline
campaigns, and email campaigns. DMS natively supports tracking
campaigns. Marketers create campaigns in the Marketing Center, which
they can access from the Sitecore desktop. As described in the following
paragraph, you can trigger campaigns in several ways.
For online advertising campaigns, embedding the unique ID of a
campaign in links back to the website triggers the campaign and associates
the visit and all goal conversions and engagement value derived from that
visit with that campaign. For offline campaigns and other situations that
do not involve direct links, you can implement landing pages to trigger the
campaign. When a visitor accesses a page, that visitor's visit becomes
associated with that campaign, including all conversion goals and
engagement value for that visit.
To support email campaigns, Sitecore DMS provides the Email
Campaign Manager (ECM) application described further in this chapter,
enabling DMS users to conduct bulk and individualized email campaigns
integrated with the content management system. Marketers can
personalize email content based on a visitor's known interests, and you can
personalize content on the website based on the visitor's actions in the
email, such as which link they click. Because CMS users access the Page
Editor to create content for email, including images and other media, they
work in a consistent, familiar, user-friendly environment. Once composed,
ECM automatically encodes links within an email to trigger campaigns if
a visitor clicks. The links in an email not only trigger the campaign, but
also support individualization for each visitor, so that you know when each
visitor clicks each link for any campaign.
The engagement automation engine can access ECM to trigger email
distribution based on conditions defined in an engagement plan. CMS
users can monitor email campaign results in the Marketing Performance
Quickview, which indicates how a campaign performs based on the
engagement associated with it. CMS users can also compare the results of
email campaigns with each other and with other campaigns and traffic
sources.
For more information about Email Campaign Manager, see http://bit.ly/ur50cW and
http://bit.ly/tUQ3ne.
Dynamic Segmentation
A fundamental component of marketing campaign management involves
managing lists of members in the audience, or audience segments.
Marketers use these lists to target offers to specific visitors to the website
or recipients of email, and to follow up with those visitors. Traditionally,
marketing systems created lists and segments based on static attributes of
profile data such as mailing address, gender, and age. While marketers can
create and administer visitor lists manually, DMS can also define
segments dynamically and reclassify visitors based on their behavior. As
such, lists and segments support dynamic inclusion or exclusion of
members based on their activities and profile attributes.
Marketers create and manage lists and segments within the Marketing
Center, which you can access from within the Sitecore desktop. The
Dynamic Segmentation tool allows marketers to configure lists in a
manner similar to using personalization rules. Audience segmenting rules
define parameters that determine which visitors to include in each
segment. After creation, you can use dynamic segments for purposes such
as directing email newsletters, marketing campaigns using engagement
automation, and targeting web page content to visitors in specific
segments.
For more information about the Web Forms for Marketers (WFFM) module, see
http://bit.ly/tOhbic and the documentation at http://bit.ly/vqn9ql appropriate for your
version of WFFM.
For more information about ECM, see http://bit.ly/tUQ3ne and http://bit.ly/tUQ3ne and
http://bit.ly/x5fBaS.
Sitecore Foundry
Sitecore Foundry enables you to centrally provision and manage large
numbers of websites, potentially in the thousands. In addition to relevant
capabilities provided by Sitecore CMS, Foundry provides predefined data
templates, presentation components, and other features to make it easier to
deploy new websites. These include functional components such as
discussion forums, event calendars, newsletters, photo galleries, and ad
rotators, as well as site configuration wizards and styling skins. Further,
Foundry automates the process of creating users and roles, as well as
assigning rights, to simplify the process of bringing up a new site for a
new department or other organization. Foundry can also assist in ensuring
visual consistency throughout a large number of websites, including
instantaneous global updates to those components, while providing the
owners of each site with an appropriate level of control.
For more information about the Sitecore App Center, see http://bit.ly/sHgrFZ.
Optional Modules
This section describes the following optional Sitecore modules that you
can license and use in your Sitecore solution:
Active Directory (AD) — Manage user authentication, user profiles,
and roles in Active Directory
Adaptive Print Studio (APS) — Apply personalization to CMS
content to generate print materials
Calendar — Expose event calendars on your managed websites
dtSearch — Integrate the dtSearch crawler for searching your
managed websites
E-Commerce — Implement e-commerce solutions
SharePoint Integration Framework (SPIF) — Integrate between
SharePoint and your Sitecore solutions
Search Engine Optimization (SEO) Toolkit — Analyze and improve
your search engine index ranking
Sitecore Azure — Deploy your Sitecore solutions to the Microsoft
Windows Azure Internet cloud
Active Directory
The Sitecore Active Directory (AD) module is a set of ASP.NET security
providers that allow Sitecore to access users, roles, and user profiles
defined in Microsoft Active Directory. While you can configure the AD
module for CMS users, users of one or more published websites, or both,
most organizations use AD for their internal users in the CMS
environment. Resources defined in AD appear as native functionality,
replacing the default implementation of these features.
The AD module supports single sign-on (SSO). If the operating system
user running the browser has authenticated against the AD security domain
configured in Sitecore, the instance can automatically authenticate the
browser as a CMS user without requiring the user to enter a username and
password at the Sitecore login screen. This works even if the user did not
select the Remember Me check box on the Sitecore login screen when they
previously logged in from that browser.
For more information about the Active Directory module, see http://bit.ly/rMAcPB.
Calendar
The Sitecore Calendar module facilitates the creation of event calendars
within Sitecore solutions. You can apply access rights to each event
definition item to control who can see the event. The Calendar module
provides day, week, and month views, with both read-only and read-write
access. Site visitors can filter the events listed on the calendar, and
Sitecore provides components that enable them to select the day, month,
and year to display.
For more information about the Sitecore Calendar module, see http://bit.ly/vWE73o.
dtSearch
The Sitecore dtSearch module provides preconfigured integration with the
third-party dtSearch search engine so that you can easily expose search
features on the websites that you manage with Sitecore. The dtSearch
indexer generates a search index for the solution, and the dtSearch module
provides presentation controls and APIs to access that index.
For more information about the dtSearch company and its products, see
http://dtsearch.com. For more information about the dtSearch module from Sitecore, see
http://bit.ly/rwRdwz.
E-Commerce Modules
Sitecore provides two optional products that can help you implement
solutions that engage in electronic commerce:
E-Commerce Services (SES) — SES provides a framework for
building e-commerce solutions on the Sitecore platform. SES brings
the benefits of CEP — visitor tracking, segmentation, and behavior-
based content targeting — to commerce sites. SES includes an e-
commerce API that supports integration with external systems such as
ERPs (Enterprise Resource Planning systems). SES also includes a
number of dedicated interfaces for tasks such as merchandising and
order management.
Insite for Sitecore — Built on SES, Insite for Sitecore supports all of
the features of SES along with more advanced, rule-based commerce
features such as pricing, promotions, shipping, and taxation. Insite for
Sitecore also provides an integration framework supporting bi-
directional communication and synchronization with ERP and other
external systems.
Sitecore E-Commerce Services replaces Sitecore E-Commerce Fundamentals Edition
(SEFE). For more information about Sitecore E-Commerce products, see
http://bit.ly/uH4CML.
Sitecore Azure
Sitecore Azure enables you to automate deployment of your Sitecore
solutions to the Microsoft Windows Azure Internet cloud, using SQL
Azure for storage rather than Microsoft SQL Server or Oracle. For more
information about the Microsoft Windows Azure cloud, see
http://bit.ly/Znsdo.
Sitecore Azure provides at least the following benefits:
Unlimited, flexible, near-instantaneous scalability
Real-time database backup and failover
Automated deployment of content and code from content management
to content delivery
Distribution of redundant content delivery infrastructure across
geographies
Reduced total cost of ownership
Sitecore Azure can help to improve solution performance by placing
content delivery servers closer to users in disparate locations, and increase
reliability by providing redundant infrastructure within and between
locations, which also facilitates disaster recovery.
System.Globalization.CultureInfo.CreateSpecificCulture(
Sitecore.Context.Language.Name);
}
}
}
You can use a Web.config include file to add the processor shown in
Listing 11.1 to the httpRequestBegin pipeline, or add a line such as the
following after the existing LanguageResolver in the /web.config file
itself:
<processor
type="SitecoreBook.Pipelines.HttpRequest.SetCulture,
SitecoreBook"/>
When you add a pipeline processor using Sitecore Rocks, it generates a stub Web.config
include file automatically.
For example, if you want to prevent a user from accessing the Sitecore
desktop, you can create a role in the Sitecore domain, for example named
Sitecore Client Desktop Restricted Users, deny that role item:read access
to the /sitecore/content/Applications/Desktop item in the Core
database, and add that user to that role.
If users cannot access the Sitecore desktop, they cannot access the Control Panel to
configure their language, region, and other preferences. An administrator can
accomplish these tasks through the User Manager.
To activate features for the correct component, be sure to right-click the frame on which
to operate, such as the Content Editor or a specific frame within the Content Editor
within the Sitecore desktop.
For example, if you do not own a lock on an item, then Rich Text fields
appear disabled (grayed out). You can scroll and select text in such fields,
but if you right-click a selection, no context menu appears to let you copy
that text to the operating system clipboard. If you hold the Ctrl key while
you right-click, you can use the context menu to copy the text.
You can also hold Ctrl and right-click to view the URL and source code
of a frame, or to refresh a frame (such as to refresh a single application
within the desktop without losing the context of other applications open in
the Sitecore desktop).
This technique does not work for modal dialogs. To view the source of a modal dialog,
press Ctrl+Shift+Alt+Scroll Lock.
Figure 11.5
To see the shortcut for a tab or command, hover the mouse cursor over it in the Content
Editor.
output.WriteLine("<ul>");
output.WriteLine("</ul>");
}
}
}
I used a web control for this example because it is easy for me to implement and test by
binding such a web control to a placeholder in the home item of a development
environment. This approach leaves me with a library of web controls that I can easily
duplicate and use at my convenience. Alternatively, you can invoke code such as this
from any context that you find convenient.
After you identify a keystroke combination not already in use, enter the
text code for that combination into the KeyCode field of the definition
item for that command in the Core database. To specify a keyboard
shortcut for a command in the Content Editor Ribbon:
1. Click the database icon in the lower-right corner of the Sitecore
desktop, and then select core from the context menu so that you can
edit items in the Core database.
2. Open the Content Editor.
3. Navigate to the command definition item, which is a descendant of
the /sitecore/content/Applications/Content
Editor/Ribbons/Chunks item.
4. Set the value of the KeyCode field in the Data section to the text
code for the keystroke combination.
5. Click the database icon in the lower-right corner of the Sitecore
desktop, and then select master from the context menu to return to the
Master database.
To create a keyboard shortcut for a command not in the Content Editor
Ribbon:
1. Click the database icon in the lower-right corner of the Sitecore
desktop, and then select core from the context menu so that you can
edit items in the Core database.
2. Open the Content Editor.
3. Navigate to the /sitecore/system/Settings/Key Map item.
4. Insert an item using the Sitecore Client/Key Map data template.
5. Set the value of the KeyCode field in the Data section to the text
code for the keystroke combination.
6. Set the value of the Click field in the Data section to the command
to execute (from the /App_Config/commands.config file).
7. Click the database icon in the lower right corner of the Sitecore
desktop, and then select master from the context menu to return to the
Master database.
Click the box icon in the upper-right corner of the Rich Text Editor to expand the RTE to
use the full browser window. As always, you can press F11 to cause the browser to use all
available screen space.
For more information about configuring and optimizing the Rich Text
Editor, see the Sitecore Client Configuration Cookbook
(http://bit.ly/qS8Dc1).
You can use clones to manage RTE profiles. For more information about clones, see
Chapter 2.
Ad Hoc Reports
To easily implement ad hoc reports, you can use a temporary XSL
rendering (or save the rendering for reuse later) or Sitecore Rocks. For
example, viewing the raw values for the __Base template field in the
standard template, which defines the base templates for a data templates,
provided the IDs to construct the XSL fragment shown here, which I then
used to identify data templates that inherit from the null template (with ID
{00000000-0000-0000-0000-00000000000}) or from only specific
sections of the standard template.
<xsl:for-each select="//item[contains(sc:fld('__Base
template',.),
‘{646F4B34-708C-41C2-9F4B-2661849777F3}')
or contains (sc:fld('__Base template',.), ‘{F5BC7AE4-F62D-
47CD-9AFB-2C9F85D8313B}')
or contains (sc:fld('__Base template',.), ‘{18420296-D8FC-
4D93-A79E-2A2B0367A92C}')
or contains (sc:fld('__Base template',.), ‘{823ECF5F-AE72-
40B5-BC87-CB425FE7E5F6}')
or contains (sc:fld('__Base template',.), ‘{4D30906D-0B49-
4FA7-969D-BF90157357EA}')
or contains (sc:fld('__Base template',.), ‘{6EF07334-7FBA-
4845-BF0A-CD5B2000C75A}')
or contains (sc:fld('__Base template',.), ‘{6495CF23-DE9C-
48B7-9D3C-05E2418B3CAE}')
or contains (sc:fld('__Base template',.), ‘{AB811AF4-393C-
4A46-ACD7-81D30917E7F4}')
or contains (sc:fld('__Base template',.), ‘{1597272C-C823-
4AAC-86F8-CA9CC4D573B5}')
or contains (sc:fld('__Base template',.), ‘{93F3A8FA-9E5A-
4848-A5AD-42AAD11A4871}')
or contains (sc:fld('__Base template',.), ‘{2491819E-0C61-
4F5A-903C-E10FCD9D302A}')
or contains (sc:fld('__Base template',.), ‘{06F366E6-A7E6-
470B-9EC9-CD29A4F6C8E8}')
or contains (sc:fld('__Base template',.), ‘{00000000-0000-
0000-0000-00000000000}')]">
<strong><xsl:value-of select="sc:path(.)" /></strong>
<ul>
<xsl:for-each select="sc:Split('__Base template', .)">
<li>
<xsl:variable name="item"
select="sc:item(text(),.)" />
<xsl:choose>
<xsl:when test="$item">
<xsl:value-of select="sc:path($item)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="text()" /> does not
exist.
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:for-each>
Overlay Icons
Sitecore displays an icon for each item. You can set the default icon for all
items based on a data template in that data template itself. You can
override the icon defined in the data template for each item. To set the
icon for a data template or an individual item, click the Configure tab in
the Content Editor, and then click the Icon command in the Appearance
group. You can either select an icon from the pallet that appears (defined
by the /App_Config/Icons.config file), or click More Icons at the
bottom of that pallet. In the latter case, the Icon dialog appears, allowing
you to select an icon from all of those available on the system. You can
use the drop-down at the top-left of the Icon dialog to select various
categories of icons from which to select an image. Figure 11.6 shows how
the Icon dialog appears when making a selection from the category drop-
down.
Figure 11.6
The Icon field at the bottom of the Icon dialog shows the path to the icon
that you select.
You can overlay an icon with another icon in the lower-right corner of
the original icon image. To do so, follow this procedure:
1. Determine the relative paths to the two icons that you wish to use by
selecting those icons individually in the Icon dialog and noting the
values in the Icon field for each selection.
2. Enter a value such as the following into the Icon field in the Icon
dialog:
Applications/32x32/warning.png?
overlay=Applications/16x16/help.png
3. Replace the two relative paths shown with those of the icons you
wish to use, where the first (Applications/32x32/warning.png in
this example) specifies the primary icon and the second
(Applications/16x16/help.png in this example) specifies the
overlay icon.
Note the dimensions specified in the relative path to each image —
32x32 for the first image and 16x16 for the second. Use these dimensions
regardless of those identified previously using the Icon dialog (Sitecore
provides all icon images in both dimensions). For more information about
icons, see The Sitecore Client Configuration Cookbook
(http://bit.ly/zG3X6W).
The My Toolbar tab enables you to group commands that you use frequently. Personally,
I move between systems frequently enough that configuration of the My Toolbar tab is
generally not worthwhile.
Working with the Sitecore Debugger
Remember to use the browser-based Sitecore debugger, as well as the
cache and rendering statistics pages, both described in Chapter 6. These
tools can help you to optimize the solution before you deploy it to
production and to monitor and diagnose issues with the solution after
implementation.
In general, you can use the same log-in information (e-mail address and password) for
all the websites that Sitecore manages, including the Sitecore Portal
(http://portal.sitecore.net), the Sitecore Developer Network (http://sdn.sitecore.net), and
the Sitecore Support Portal (http://support.sitecore.net).
Sitecore Training
In addition to being one of the most efficient methods to learn a new
platform, one of the best ways to evaluate a web CMS is to attend
developer training. I strongly recommend that all Sitecore developers
attend as many relevant Sitecore training courses as possible from those
listed at http://bit.ly/vMSXbk. I specifically recommend that .NET
developers complete the following courses in the order listed:
1. SDF: Sitecore CMS Developer Foundations (http://bit.ly/zoIxdH)
2. SND: Sitecore CMS Website .NET Developer
(http://bit.ly/A1Kq0W)
3. DOP: Sitecore CMS .NET Developer Day of Prototyping
(http://bit.ly/yFGThH)
4. AND: Sitecore CMS Advanced .NET Developer
(http://bit.ly/zqHrMY)
If the platform architecture matches the requirements that you used to
analyze the available CMS platforms, and hence to select Sitecore, then
you are likely to remember much of the technical detail provided during
training. Importantly, you must work with the product immediately after
training in order to maintain and enhance that understanding. After
training, I recommend that you spend at least one week implementing a
prototype of your actual solution. Use that time to see what you can
remember, research what you forgot or never learned, participate in the
Sitecore community online, and attempt to build a functional solution that
you may subsequently discard.
Sitecore Partners
To maximize the value of your solution quickly, Sitecore encourages all of
its customers, even those with prior CMS experience, to work with
seasoned Sitecore partners. Some Sitecore partners can provide a full
range of services from requirements analysis, platform selection, visual
design, Search Engine Optimization (SEO), technical implementation, and
integrations such as with social media sites. You may also benefit from
working with a Sitecore partner that has expertise implementing web
solutions for organizations like yours or your specific industry vertical.
The following sections explain how an organization that provides these
types of consulting services can become a Sitecore partner and the benefits
of that partnership.
Becoming a Sitecore Partner
If your company uses Sitecore to implement web solutions for other
organizations, you can almost certainly become a Sitecore partner. To
initiate the partner engagement process, prospective Sitecore partners can
complete and submit the web form found at http://bit.ly/vaOYly. Sitecore
Certified Solution Partners must execute a General Terms of Business
Agreement with Sitecore and must maintain at least one staff member
certified as an ASP.NET developer on the Sitecore platform.
Sitecore Portal
You can use the Sitecore Portal (http://portal.sitecore.net) to register for
access to the Sitecore Developer Network (http://sdn.sitecore.net), update
your personal information and your public profile, and access other
information about your relationship with Sitecore. As described in the
following sections, you can use the portal to configure your subscriptions
to Sitecore mailing lists, which keep you informed with vital information
about Sitecore products. You can also use the portal to reset the password
you use to access the Sitecore Developer Network, the Sitecore Support
Portal (http://support.sitecore.net), and the Sitecore Partner Portal itself.
Sitecore Documentation
Through SDN, Sitecore provides extensive documentation for CMS users
and administrators, but most importantly for developers. You can get most
of the best documentation by clicking the References tab on SDN and then
clicking Sitecore 6. Other documents, such as the installation and
troubleshooting resources that appear on the installation materials pages,
exist elsewhere on SDN. For a single, comprehensive list of current
Sitecore documentation, see my blog post at http://bit.ly/cbpSQs. Where
appropriate, this book contains direct links to these documents.
Of the Sitecore documents available online, I believe that the following
are most important:
The Installation Guides (http://bit.ly/pv7X3B) and Installation
Troubleshooting (http://bit.ly/qmzVpY) materials, as well as the
Browser Configuration Reference (http://bit.ly/qfwYUW)
The Data Definition Reference (http://bit.ly/nmGuiB), the Data
Definition Cookbook (http://bit.ly/oc8F9K), and the Data Definition
API Cookbook (http://bit.ly/ohVWlq)
The Content Reference (http://bit.ly/qd6lUO), the Content Author's
Cookbook (http://bit.ly/qaSgz5), the Content Cookbook
(http://bit.ly/rgtLol), and the Content API Cookbook
(http://bit.ly/oC6wHw)
Sitecore Blogs
As a highly capable and extensible development framework, Sitecore is
both broad and deep. One of the best ways to learn Sitecore is to read blog
posts by people who have been working with the software for years,
especially those who have addressed requirements similar to yours.
Instead of listing individual blogs here, I suggest reviewing the Sitecore
pipe on Yahoo! (http://bit.ly/w0sPlD, or http://bit.ly/sjXeia for the RSS
feed).
Before you file an issue in the Sitecore Support Portal, you can use the
SDN forums to collect information about your issue. Reporting issues on
the SDN forums can have numerous benefits, including the following:
Due to the number of eyes reading SDN forum posts, you can
sometimes get an answer more quickly on the forums than you would
through the Sitecore Support Portal.
The more people who see an issue, the more likely it is that one of
them has seen it before.
Additional perspectives can often lead to superior solutions and
workarounds.
Forum posts inform the developer community about issues.
Other developers can try to confirm your issue in an attempt to
determine whether it is specific to a Sitecore product or version, your
configuration, your solution, or something else.
People more familiar with the Sitecore documentation, release notes,
and known issues will point you to them when appropriate.
The community can search forum threads to identify topics quickly
without needing to file support cases.
If you file a case in the Sitecore Support Portal after posting about it on
the SDN forums, add the case identifier to the forum thread afterwards so
that other developers with the same issue can reference that case.
The Sitecore Customer Service department is not responsible for the Sitecore Developer
Network forums. Any information that you post on the forums should also appear in your
support case. Instead of filing a support case that links to your SDN forum thread,
condense that information to provide succinct details in the text of your support case.
Sitecore Symposium
In 2010, Sitecore initiated its annual conference with in-person events in
Boston and Copenhagen to engage, educate, and motivate Sitecore
developers and partners. Originally named Dreamcore, Sitecore
subsequently renamed this conference as the Sitecore Symposium. The
locations of the conference vary by year.
Each event provides multiple tracks that include customer-oriented
content relevant to both technical and business users. The conference is an
opportunity for members of Sitecore's active and dynamic online
community to interact outside the constraints of web forums and social
media, and to provide feedback directly to those within the Sitecore
organization.
Installing Sitecore
Before you install the Sitecore CMS, always refer to the current Sitecore Installation
Guide (http://bit.ly/pv7X3B), Installation Troubleshooting Guide (http://bit.ly/qmzVpY),
Browser Configuration Reference (http://bit.ly/qfwYUW), release notes including known
issues (http://bit.ly/pyPUPV), and other documentation on the Sitecore Developer
Network (http://sdn.sitecore.net) relevant to your version of the software, including
optional modules.
Ensure that all web clients, web servers, and database servers meet
Sitecore's minimum (and preferably recommended) hardware
requirements. Install Sitecore in development environments first, then
test, and eventually production. Installing Sitecore on the production
servers on day one will have little benefit.
Install Sitecore to an IIS document root directory. Do not attempt to install Sitecore to a
subdirectory or configure Sitecore as a virtual directory. Even if you can get Sitecore to
function in a virtual directory, Sitecore may deny support for such solutions.
Management Studio Express distributed for SQL Server Express is visually and
functionally similar to Management Studio distributed for SQL Server. This book refers to
both applications as Management Studio.
When you install SQL Server, install Management Studio, enable SQL
Server authentication, and create a password for the sa user.
While the general principles described in this section apply to any release of SQL Server,
the specific instructions and screen shots may not match versions released after the
publication of this book.
The installation process has many screens, but you can accept most of
the defaults described in the following instructions to install SQL Server:
1. Run the SQL Server setup program. After extracting files, the SQL
Server Installation Center appears.
2. Click New Installation or Add Features To An Existing Installation.
The SQL Server 2008 R2 Setup window appears at the License Terms
dialog.
3. Accept the license terms and click Next. The Feature Selection
dialog appears as shown in Figure B.1.
4. Under Shared Features, select Management Tools – Basic, and click
Next. The Instance Configuration dialog appears as shown in Figure
B.2.
5. Accept the defaults and click Next. The Server Configuration dialog
appears as shown in Figure B.3.
The Windows security account that you select will own the SQL Server Database
Engine service. In some cases, you may want to change from the default to an
alternate user. You may need to grant filesystem access rights to the database files
for that user.
Figure B.6
Installing Sitecore with the Setup
Program
If you plan to use a single machine as both the database server and the web
server, you can install Sitecore by running the Installation Wizard once on
that machine. Otherwise, you should first run the setup program on the
database server to create the databases, and then run the setup program on
the web server to install Sitecore.
If you cannot run the Sitecore setup program on the database server, you can create the
databases from a .zip file of the Sitecore CMS (the .zip file distributive) as described the
Sitecore Installation Guide (http://bit.ly/pv7X3B).
When you run the Sitecore setup program, review each page of
instructions. To see additional configuration options, such as to select a
.NET Framework version, when you reach the screens on which the
Advanced button appears, click that button to apply additional
configuration options.
These instructions and screen shots describe the installation program for Sitecore CMS
6.5.0 rev. 110818, which may not exactly match other product versions.
If you plan to host databases on the web server, run the Sitecore setup
program on the web server and select Full mode. If you use a separate
database server, instead run the same setup program on the database server
to create the databases (select Database Only) that you use to install
Sitecore on the web server (select Client Only), or you can create the
databases manually from a .zip file provided by Sitecore.
The Sitecore setup program overwrites the SitecoreInstaller.log file
in the subdirectory specified by the %TEMP% environment variable or under
C:\. If installation fails without providing a useful error message, review
the contents of this file and provide it to Sitecore support. The following
steps describe how to start the installation:
1. Start the installation by double-clicking the setup program (.exe
file) in Windows Explorer. After the setup program extracts the
required files, you see the Welcome to the Installation Wizard for
Sitecore dialog.
2. Click Next. The License Agreement dialog appears.
3. Put a check beside I Accept the Terms of the License Agreement
and then click Next. The Installation Type dialog shown in Figure B.7
appears.
4. To install both the databases and the Sitecore application, select
Complete. To install only the databases, select Database Only. To
install only the Sitecore application, select Client Only. Then click
Next. The procedure will continue with the kind of installation you
selected in one of the sections that follow.
Figure B.7
You can select the Launch Sitecore checkbox to open the solution in a new browser
window.
Figure B.11
Figure B.12
Performing a Database Only Installation
If you selected Database Only in the Installation Type dialog as shown in
Figure B.13, the Instance Name dialog shown in Figure B.8 appears.
Figure B.13
Figure B.20
Figure B.21
Figure B.22
Confirm that you can access the solution, which at this point is not
secure. Perform the following steps to deny anonymous access to the
/App_Config, /sitecore/admin, /sitecore/debug, and
/sitecore/shell/WebService subdirectories:
1. Open the IIS Manager shown in Figure B.23, found in the
Administrative Tools folder of the Control Panel or by issuing the
inetmgr command.
2. Expand the tree at the left, expand the new website, select the
subdirectory that you want to modify, and then double-click
Authentication under IIS. The Authentication dialog appears as shown
in Figure B.28.
3. Click Anonymous Authentication, and then click Disable to ensure
that the Status column indicates Disabled, not Enabled as shown in
Figure B.28.
4. Repeat steps 2 and 3 for each of the specified subdirectories.
Figure B.28
Apply filesystem permissions as specified in the Sitecore Installation
Guide (http://bit.ly/pv7X3B). The Sitecore setup program sets the
application pool owner to the local Network Service account. Creating a
new website in IIS Manager creates an application pool associated with
the Application Pool Identity, which uses a virtual Windows account.
Using Application Pool Identities has advantages over assigning
ownership of application pools to the Network Service account. For one
thing, you can more easily identify the ASP.NET worker process
associated with each website when attaching the Visual Studio debugger.
For more information about application pool identities, see
http://bit.ly/s3yDRi and http://bit.ly/sGruB1.
You cannot see virtual accounts in user interfaces in which you apply
access rights. Instead, you can type the name of the account into the user
interface as when assigning filesystem rights as described in this section.
The Application Pool Identity, associated with the application pool named
DefaultAppPool and associated with the default IIS website is IIS
AppPool\DefaultAppPool. This is what you would enter to set rights for
that Application Pool Identity. If you create a website named
SitecoreBook, by default, IIS creates an application pool with the same
name, named after the website (technically, it uses the value that you enter
in the Application pool field of the Add Web Site dialog shown in Figure
B.24, which defaults to the name of the website). The Application Pool
Identity account for that website is the name of the application pool (IIS
AppPool\SitecoreBook), which is what you would enter to set rights for
that Application Pool Identity.
Do not confuse the IIS AppPool prefix, which identifies a domain built into the operating
system for dynamic virtual accounts, with a machine name or a domain name, which
provide domains that contain traditional built-in accounts and accounts such as Network
Service, and accounts that you create such as your personal account.
Figure B.30
The owner of the application pool must have the listed permissions to
the following subdirectories, including read access to ancestors and the
listed access to descendant subdirectories:
%WINDIR%\Globalization — Modify (typically C:\Windows)
%WINDIR%\temp — Modify (typically C:\Windows\Temp)
%PROGRAMDATA%\Microsoft\Crypto — Modify (typically
C:\ProgramData)
The following steps describe how to apply filesystem permissions using
Windows Explorer:
1. Right-click the subdirectory to invoke the context menu.
2. Select Properties. The Properties dialog shown in Figure B.31
appears.
3. Select the Security tab, and then click Edit. The Permissions dialog
shown in Figure B.32 appears.
Figure B.31
Figure B.32
To update filesystem permissions for an account that already has some
explicit access rights to the subdirectory, perform the following steps in
the Permissions dialog:
1. Choose the account in the Group or User Names field.
2. Check the Allow or Deny checkboxes as appropriate, and then click
OK. The Windows Security dialog appears while Windows applies the
permissions, and then you see the Properties window.
3. Click OK to return to Windows Explorer. If you see a Windows
Security dialog asking you to confirm changes to filesystem
permissions, click Yes.
To grant filesystem permissions to an account that does not already have
some explicit access rights to the subdirectory, perform the following
steps in the Permissions dialog:
1. Click Add. The Select Users or Groups dialog shown in Figure B.33
appears.
When checking or setting ownership of an application pool, applying filesystem
permissions, or otherwise working with Windows accounts, be sure to check or
select the local machine or domain before checking or setting the account, for
example in the From this location field in the Select Users or Groups dialog shown
in Figure B.33. Otherwise, you may not find the user or group on which you wish to
operate. In some cases, you may wish to select a Windows security domain and
select a user or group from that domain rather than from the local machine.
2. Type the name of the account in the Enter The Object Names To
Select field, such as Network Service or the name of the Application
Pool Identity. You can click Check Names to validate what you enter.
Alternatively, you can click Advanced to access the Select Users and
Groups dialog, in which you can enter search criteria, click Find Now,
select a user, and then click OK to select an account.
If Windows presents the Name Not Found dialog, click Cancel to dismiss the dialog,
and then in the Select Users or Groups dialog, click Locations and ensure that
Location is the local machine or a Windows security domain according to your
requirements.
Figure B.37
At this point, configuration of the new instance is complete; test the
solution to ensure that it functions. In some cases, you may wish to rebuild
search indexes using the Databases option in the Control Panel of the
Sitecore browser-based desktop.
Figure B.39
Figure B.40
Whenever you work with assemblies in Visual Studio, look for any
broken references identified by triangular, yellow warning icons
containing exclamation points as shown in Figure B.41 while you have
References expanded in Solution Explorer.
Figure B.41
To remove a broken reference, right-click that reference in Solution
Explorer, and then click Delete.
Sitecore projects usually reference the Sitecore.Kernel.dll,
Sitecore.Client.dll, Sitecore.Analytics.dll, and potentially
additional Sitecore and third-party assemblies such as
HtmlAgilityPack.dll and Lucene.Net.dll. All of these assemblies
exist by default in the /bin subdirectory under the document root of the
IIS website.
Perform the following steps to configure the assembly name and default
namespace for the ASP.NET Web Application project:
1. Double-click Properties in Solution Explorer. The project properties
dialog shown in Figure B.42 appears.
2. Click the Application tab. For Assembly name, enter the name of
the assembly, without the subdirectory or the .dll extension. When
you compile your project, Visual Studio automatically copies the
generated assembly to the /bin subdirectory within the /Website
subdirectory.
3. Type the default namespace for the project in the Default namespace
field.
4. Close the project properties dialog.
Figure B.42
To add files and subdirectories that you use to the solution, such as the
/layouts subdirectory and the /xsl subdirectory, or specific files and
subdirectories from within such subdirectories, perform the following
steps in Solution Explorer:
1. Select the project, and then click the Show All Files button shown in
Figure B.43.
2. Right-click each relevant subdirectory or file to display the context
menu.
3. Click Include In Project. To exclude nested subdirectories and files,
right-click them, and then click Exclude From Project.
Figure B.43
When you close the project or exit the application, Visual Studio
prompts you to create a solution. Allow Visual Studio to create the
solution.
After including files and subdirectories in the project, click Show All Files as shown in
Figure B.43. If you leave all files showing, debugging in Visual Studio may fail.
After you create the initial ASP.NET Web Application project, you can
optionally create any number of class library projects within the solution
to encapsulate specific functions, such as to separate libraries of XSL
extension methods and web controls from the layouts, sublayouts, and
code-behind of the solution.
I highly advise anyone using Visual Studio with Sitecore to install Sitecore Rocks, the free
extension to Visual Studio for Sitecore developers. To download Sitecore Rocks, see
http://sitecorerocks.net. For more information about Sitecore Rocks, see my blog post at
http://bit.ly/oZTaZI.
John West works as Chief Technology Officer (CTO) for Sitecore in North
America. Between the year 2000 and the time he joined Sitecore in 2004,
John consulted on approximately twenty significant web content
management system (CMS) implementations including Network
Associates (now McAfee), U.S. Bank, John Deere, Stanford Hospitals and
Clinics, and Intel. During that time, he taught courses on CMS products in
the United States, Europe, and Asia.
While researching the CMS market to replace a legacy CMS, John
identified Sitecore as the leading CMS platform architecture available,
and joined the company immediately after attending developer training.
Initially the only technical employee in North America, John certified
hundreds of Sitecore developers while building the foundations of the
local technical team including IT (information technology) platform
services, presales technical engineering, solution prototypes,
documentation, and support, all while working to promote a vibrant
Sitecore developer community.
John wrote early drafts for a majority of the current technical
documentation about the Sitecore CMS. Including his input on more than
six thousand posts on the Sitecore Developer Network
(http://sdn.sitecore.net), John has interacted with thousands of web
developers working on untold CMS projects around the globe. John has a
strong interest in programmer productivity and is passionate about helping
Sitecore developers learn the product to overcome any challenges.
Although his current responsibilities are primarily those of a consulting
product architect on products including the Sitecore ASP.NET Content
Management System (CMS), Digital Marketing System (DMS), and
Sitecore Azure for deploying Sitecore solutions to the Microsoft Windows
Azure cloud, John considers his primary responsibility to be that of Chief
Customer Advocate. You can access his blog about Sitecore at
http://sitecorejohn.com and follow him on Twitter (http://twitter.com) as
@sitecorejohn.
About the Technical Editors
Acquisitions Editor
Carol Long
Project Editor
Sydney Argenta
Technical Editors
Christie Densmore
Lewanna Rathbun
Copy Editor
Luann Rouff
Editorial Manager
Mary Beth Wakefield
Marketing Manager
Ashley Zurcher
Business Manager
Amy Knies
Production Manager
Tim Tate
Associate Publisher
Jim Minatel
Proofreader
Jen Larsen, Word One
Indexer
Robert Swanson
Cover Image
© iStock / Kemter
Cover Designer
LeAndra Young
Acknowledgments
Because I believe eXtensible Stylesheet Language (XSL) has significant disadvantages for
developers with competency in .NET, this book touches upon, but does not focus on, XSL.
What This Book Covers
This book describes the Sitecore ASP.NET web Content Management
System. While it touches upon underlying technologies and tools
including Microsoft Windows, Internet Information Server (IIS), the
ASP.NET web application server, SQL Server, and Visual Studio, its
primary focus is development with the Sitecore ASP.NET web CMS.
Although much of the information in this book is available through
Sitecore training, in Sitecore documentation, and on the web at large, I
sincerely hope that this attempt at a somewhat comprehensive resource
can help new Sitecore developers orient themselves to the system. At the
same time, a single book cannot provide a completely comprehensive
reference for the entire Sitecore CMS product. Considering the
components and capabilities of the entire Sitecore Customer Engagement
Platform (CEP), which consists of the Sitecore CMS plus the Sitecore
Digital Marketing System (DMS) that provides web analytics, enhanced
personalization, marketing automation, and potentially additional
functionality such as email campaign and web forms management,
Sitecore is a very broad and very deep framework.
This book is not a step-by-step guide to building solutions with Sitecore.
Instead, it contains a very large number of very small facts intended to
improve your capabilities on a wide range of topics. The reader should
have a working knowledge of software development methodologies,
ASP.NET, and the Sitecore ASP.NET CMS user interfaces and fundamental
concepts before reading this book. While reinforcing and adding detail
around existing knowledge, this book attempts to provide the next few
rungs on the ladder towards Sitecore mastery, with pointers to additional
rungs where possible.
I developed this book using Sitecore CMS 6.5.0 rev. 110818 (Update-1),
but most of the information it contains pertains to any 6.x version of
Sitecore. This book includes minor details about other versions of the
Sitecore ASP.NET CMS.
How This Book Is Structured
This book introduces subjects in a logical order that builds on itself. The
sequence of chapters also provides some correspondence to order of
importance, with material early in the book having more significance than
subsequent content. Chapter 1 introduces the ASP.NET web Content
Management System (CMS).
All web content management solutions involve two major components: a
mechanism for representing data and a system of rules to present that data
as part of one or more managed websites. The data is fundamental to the
solution: without data, the presentation layer cannot do anything. The data
of a website, also known as its information architecture, tends to outlive
the visual presentation of that data; data is permanent while code is
fleeting. Therefore, Chapter 2 of this book begins by describing data
infrastructure aspects of the Sitecore CMS, and Chapter 3 proceeds to
explain how you can present that data on your websites.
After you have data and code, the next step often involves restricting
access to those resources. Therefore, Chapter 4 covers the Sitecore
security model. Because all web solutions experience errors, which
attackers can use to compromise the security of the system, Chapter 5
describes error management techniques that you can use with Sitecore.
After you have developed your information architecture and the
components required to present that data, secured that data, and addressed
error conditions, the next common concerns include performance and
scalability. Chapter 6 provides guidance to help you maximize the
throughput and capacity of your Sitecore solutions.
With this background, you are ready to begin customizing and extending
Sitecore in various ways as described in Chapter 7, which focuses on
integration. After you have implemented the majority of your solution,
you can begin testing it using the information provided in Chapter 8.
Chapter 9 focuses on how to manage Sitecore implementations, both
from the perspective of project management and implementation, but also
considering various options for release management to get updates from
your development environment to your production content delivery
environments.
After you have mastered core CMS concepts, you can read Chapter 10,
which includes information about Sitecore products beyond its core CMS.
These products include the Digital Marketing System (DMS) used for web
analytics, experience management, engagement automation, and
monitoring.
Chapter 11 concludes this book with tips, tricks, and best practices for
working efficiently with the Sitecore CMS. This chapter repeats some of
the most important information provided in the preceding chapters, but
also provides details not included anywhere else.
Appendix A lists a wide array of resources available for Sitecore
developers including online materials and in-person events. Appendix B
provides guidance for installing the Sitecore ASP.NET CMS.
Conventions
To help you get the most from the text and keep track of what is
happening, we used a number of conventions throughout the book.
We highlight new terms and important words when we introduce
them.
We show keyboard strokes like this: Ctrl+A.
We show file names and code within the text like so:
persistence.properties
We present code in two different ways:
We use a monofont type with no highlighting for most code
examples.
We use bold to emphasize code that is particularly
important in the present context or to show changes from a
previous code snippet
As described further in this book, features including the Sitecore configuration factory
support Web.config include files that allow you to patch the actual /web.config file. This
book describes the Web.config file in relation to features that support include files, but
includes a leading slash and applies a style (/web.config) when referring to the actual
/web.config file itself. Web.config include files can apply only to elements within the
/configuration/sitecore section.
Source Code
As you work through the examples in this book, you may choose either to
type in all the code manually, or to use the source code files that
accompany the book. All the source code used in this book is available for
download at www.wrox.com. When at the site, simply locate the book's
title (use the Search box or one of the title lists) and click the Download
Code link on the book's detail page to obtain all the source code for the
book. The following icon highlights code that is included on the website:
After you download the code, just decompress it with your favorite
compression tool. Alternately, you can go to the main Wrox code
download page at www.wrox.com/dynamic/books/download.aspx to see
the code available for this book and all other Wrox books.
Errata
We make every effort to ensure that there are no errors in the text or in the
code. However, no one is perfect, and mistakes do occur. If you find an
error in one of our books, like a spelling mistake or faulty piece of code,
we would be very grateful for your feedback. By sending in errata, you
may save another reader hours of frustration, and at the same time, you
will be helping us provide even higher quality information.
To find the errata page for this book, go to www.wrox.com and locate the
title using the Search box or one of the title lists. Then, on the book details
page, click the Book Errata link. On this page, you can view all errata that
has been submitted for this book and posted by Wrox editors. A complete
book list, including links to each book's errata, is also available at
www.wrox.com/misc-pages/booklist.shtml.
If you don't spot “your” error on the Book Errata page, go to
www.wrox.com/contact/techsupport.shtml and complete the form there to
send us the error you have found. We'll check the information and, if
appropriate, post a message to the book's errata page and fix the problem
in subsequent editions of the book.
p2p.wrox.com
For author and peer discussion, join the P2P forums at p2p.wrox.com. The
forums are a Web-based system for you to post messages relating to Wrox
books and related technologies and interact with other readers and
technology users. The forums offer a subscription feature to e-mail you
topics of interest of your choosing when new posts are made to the forums.
Wrox authors, editors, other industry experts, and your fellow readers are
present on these forums.
At http://p2p.wrox.com, you will find a number of different forums that
will help you, not only as you read this book, but also as you develop your
own applications. To join the forums, just follow these steps:
1. Go to p2p.wrox.com and click the Register link.
2. Read the terms of use and click Agree.
3. Complete the required information to join, as well as any optional
information you wish to provide, and click Submit.
4. You will receive an e-mail with information describing how to
verify your account and complete the joining process.
You can read messages in the forums without joining P2P, but in order to post your own
messages, you must join.
Once you join, you can post new messages and respond to messages
other users post. You can read messages at any time on the Web. If you
would like to have new messages from a particular forum e-mailed to you,
click the Subscribe to this Forum icon by the forum name in the forum
listing.
For more information about how to use the Wrox P2P, be sure to read the
P2P FAQs for answers to questions about how the forum software works,
as well as many common questions specific to P2P and Wrox books. To
read the FAQs, click the FAQ link on any P2P page.
Visit www.safaribooksonline.com/wrox38 to get started.
Related Wrox Books