<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Coffee =&#62; Coder =&#62; Code</title>
	<atom:link href="http://adeneys.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://adeneys.wordpress.com</link>
	<description>My ramblings on code, Sitecore and stuff</description>
	<lastBuildDate>Thu, 23 May 2013 23:32:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='adeneys.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Coffee =&#62; Coder =&#62; Code</title>
		<link>http://adeneys.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://adeneys.wordpress.com/osd.xml" title="Coffee =&#62; Coder =&#62; Code" />
	<atom:link rel='hub' href='http://adeneys.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Revolver 2.1 Released</title>
		<link>http://adeneys.wordpress.com/2013/05/16/revolver-2-1-released/</link>
		<comments>http://adeneys.wordpress.com/2013/05/16/revolver-2-1-released/#comments</comments>
		<pubDate>Wed, 15 May 2013 15:31:39 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Revolver]]></category>
		<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">http://adeneys.wordpress.com/?p=404</guid>
		<description><![CDATA[Today I&#8217;m happy to announce the release of Revolver 2.1. You can head on over to the codeflood website to ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2013/05/16/revolver-2-1-released/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=404&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Today I&#8217;m happy to announce the release of <a href="http://www.codeflood.net/revolver/">Revolver</a> 2.1. You can head on over to the <a href="http://www.codeflood.net">codeflood</a> website to get the Sitecore package files right now. These will also be available on the <a href="http://marketplace.sitecore.net">Sitecore Marketplace</a> very soon.</p>
<p>This isn&#8217;t a huge release, but does have some important new features. Let&#8217;s take a look at each of these.</p>
<h3>Support for Sitecore 6.6 (and Sitecore 7)</h3>
<p>Sitecore 6.6 introduced some new security features to make the Sitecore client interfaces more secure. One such feature was to protect against cross site request forgery. Sitecore client UI forms now contain a field named <code>__CSRFTOKEN</code> which contains a token which must be posted to the server on each request.</p>
<p>Revolver 2.1 contains an update to submit this field when you execute a command in the Revolver script window. If you&#8217;ve tried using Revolver &lt;= 2.0 with Sitecore 6.6 and received an error message mentioning something about missing a &#8220;CSRF&#8221; field, then make sure you upgrade to Revolver 2.1 to get the fix.</p>
<p>And although it&#8217;s not released yet, Sitecore 7 is on the horizon, so I&#8217;ve been testing Revolver with the Sitecore 7 release we lucky MVPs have. If you have access to Sitecore 7 and want to install Revolver on it, grab the current 2.1 release for Sitecore 6.6.</p>
<h3>No spell check warning for script window</h3>
<p>A small UI tweak in Revolver 2.1 is to add the <code>spellcheck="false"</code> attribute to the main script window text field to stop browsers from trying to run spell check on the contents of the script window. Most of what you enter in the script window is not plain English, so this tweak removes the sea of red you would have put up with in Revolver &lt;= 2.0 in some browsers.</p>
<h3>&#8220;Does not contain&#8221; operator for expressions</h3>
<p>Expressions in Revolver are like predicates in XPath. They allow defining a condition when using the <code>find</code> command. There are a number of operators available in expressions such as comparing equality, starts with and ends with and check whether a string contains another. One scenario that couldn&#8217;t be implemented with those operators was to check the absence of a token from input. &#8220;Show me items where <code>__renderings</code> doesn&#8217;t contain this ID&#8221;.</p>
<p>The <code>find</code> command also supports testing field values against a regex. Regex is great at finding patterns in text, but not very good at finding the absence of a pattern in text. Hence why I added the &#8220;doesn&#8217;t contain&#8221; (written as <code>!?</code>) operator to expressions.</p>
<p>The scenario I gave above about trying to find items without a specific ID in their <code>__renderings</code> field is exactly why I added this operator. I was trying to locate all items in a Sitecore solution where the <code>__renderings</code> field was populated but didn&#8217;t contain a particular control. With the new operator I can now use a command similar to the following to locate these items:</p>
<pre><code>find -r -e (@__renderings != () and 
  @__renderings !? {885B8314-7D8C-4CBB-8000-01421EA8F406}) pwd
</code></pre>
<p>The above Revolver command will show me the path to all descendant items (from the current context item) that has presentation defined but does not include the control given my the ID <code>{885B8314-7D8C-4CBB-8000-01421EA8F406}</code>.</p>
<h3>Preserve ID when pasting from XML</h3>
<p>Revolver has allowed you to create items from Sitecore item XML for a while now. And now you can select to keep the IDs in the input XML string. Previously Revolver was changing the IDs to ensure there were no item ID clashes. But what if the XML being pasted came from another Sitecore instance and the ID of the items are vital; perhaps they&#8217;re referenced from another XML blob you&#8217;re about to paste.</p>
<p>You can now tell Revolver to keep the IDs but using the <code>-id</code> flag when using the <code>touch</code> command to create the items as follows:</p>
<pre><code>touch -id -x (item-xml)
</code></pre>
<p>where <code>item-xml</code> is actual Sitecore item XML (you can get that using the <code>gi</code> command).</p>
<h3>Conclusion</h3>
<p>Like I said, not a huge release, but now supporting Sitecore 6.6.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/404/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/404/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=404&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2013/05/16/revolver-2-1-released/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>
	</item>
		<item>
		<title>Post item:saved Event Handler Execution</title>
		<link>http://adeneys.wordpress.com/2013/04/10/post-itemsaved-event-handler-execution/</link>
		<comments>http://adeneys.wordpress.com/2013/04/10/post-itemsaved-event-handler-execution/#comments</comments>
		<pubDate>Wed, 10 Apr 2013 04:12:00 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Revolver]]></category>
		<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">http://adeneys.wordpress.com/?p=398</guid>
		<description><![CDATA[Sitecore allows classes to subscribe to particular events so arbitrary code may run when certain &#8220;things&#8221; happen. Possibly one of ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2013/04/10/post-itemsaved-event-handler-execution/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=398&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Sitecore allows classes to subscribe to particular events so arbitrary code may run when certain &#8220;things&#8221; happen. Possibly one of the most often subscribed events is the <code>item:saved</code> event which fires when an item is, you guessed it, saved. Whether through the UI or the API the event will always fire.</p>
<p>This is very handy for changing or cleaning up an item once the author has signaled that they&#8217;re happy with it (by hitting the save button). Just a side note, don&#8217;t do your validation here, use item or field validators instead.</p>
<p>Something that is often done using the <code>item:saved</code> event is to move the item to an appropriate structure. Some may say this is good for SEO, but we do it in Sitecore as a performance measure. Sitecore performance (particularly in the content editor) can degrade if too many items exist under a common parent item. There are various guidelines floating about for the maximum number of child items that should be allowed under a common parent but I generally say try to keep it to less than 100 and definitely less than 200 (less is better).</p>
<p>When we talk about &#8220;structuring&#8221; an item we generally mean placing it into an item hierarchy of several levels. Each level in the hierarchy is related to some aspect of the item. If the item represents a person then the hierarchy levels may represent letters in their name (the person &#8220;John Smith&#8221; goes in <code>/person/s/john smith</code>). If the item is date based the levels may represent elements of the date (an event goes in a year folder, then a month folder such as <code>/event/2013/November/my-event</code>).</p>
<p>Let&#8217;s say we have a news item with a field called <code>News Date</code> which contains the date the news is being reported on. I prefer a separate date for this kind of item rather than inferring the news date from the updated or created fields as news can be authored ahead of time (press release) or may need to have minor updates made that shouldn&#8217;t affect the &#8220;date&#8221; of the item (fix a spelling mistake). Now we want to structure the news in a hierarchy based on the <code>News Date</code> field.</p>
<p>Though this is good for performance we now have a single piece of data replicated in two places; once in the field and once in the structure. We need to ensure these two instances of the same data are kept in sync. And believe me, don&#8217;t trust your authors to ensure they keep the news in the right location.</p>
<p>The easiest way to ensure the date field and structure are kept in sync is by using the <a href="http://marketplace.sitecore.net/en/Modules/News_mover.aspx">News Mover</a> module from the <a href="http://marketplace.sitecore.net">Sitecore Marketplace</a>. This module will move the item to a folder structure based on the date selected in the configured field by hooking into the <code>item:saved</code> event.</p>
<p>Awesome! We&#8217;ve got a way to ensure no news item is created in a flat structure&#8230;but what if we didn&#8217;t anticipate the volume of items beforehand and now we have 700 news items directly under the news root item before the News Mover module was put in place? Adding event handlers after the fact doesn&#8217;t retrospectively execute the handlers for any items.</p>
<p><img class="aligncenter size-full wp-image-400" alt="Unstructured news items" src="http://adeneys.files.wordpress.com/2013/04/unstructured-tree.png?w=590"   /></p>
<p>(OK, not quite 700 items in my example screenshot but you get the idea.)</p>
<p>We need a way to execute the <code>item:saved</code> event for all those items without manually going through and hitting that save button 700 items. We can do that with <a href="http://marketplace.sitecore.net/en/Modules/Revolver.aspx">Revolver</a>!</p>
<p>To process a number of items at once I can use one of the <code>find</code>, <code>query</code> or <code>search</code> commands. For this case I&#8217;ll use the <code>find</code> command as it uses content tree traversal so I can be sure all my items will be processed.</p>
<p>Next I need a way to save the item. This can be done by updating a field value. But I don&#8217;t really want to change anything on the item, I just want to invoke the save event. For setting a field value in Revolver I can use the <code>sf</code> command which also allows me to use the previous field value in the new field value through the token <code>$prev$</code>.</p>
<p>Let&#8217;s put it all together.</p>
<p>First I need to navigate down to my news root item. Let&#8217;s assume this lives at <code>/sitecore/content/my-site/news</code>.</p>
<pre><code>cd /sitecore/content/my-site/news
</code></pre>
<p>Now to execute the find command on all the children of that item.</p>
<pre><code>find (sf -nv __updated ($prev$))
</code></pre>
<p>I&#8217;ve specified no parameters to <code>find</code> so it will process all children. If I wanted all descendants I would need to add the <code>-r</code> parameter. The parameter passed to <code>find</code> (enclosed in brackets) is the command to execute against each matched item; the <code>sf</code> command. This command will set the value of the <code>__updated</code> field to the current (previous) value. Incidentally this actually has no affect as Sitecore will update the field value immediately after we update the field value to show when it was last updated. The <code>-nv</code> parameter causes Revolver to not create a new version before updating the field value. By setting the field value the <code>item:saved</code> event is raised and News Mover can restructure the news items.</p>
<p><img class="aligncenter size-full wp-image-399" alt="Structured news items" src="http://adeneys.files.wordpress.com/2013/04/structured-tree.png?w=590"   /></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/398/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/398/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=398&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2013/04/10/post-itemsaved-event-handler-execution/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/04/unstructured-tree.png" medium="image">
			<media:title type="html">Unstructured news items</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/04/structured-tree.png" medium="image">
			<media:title type="html">Structured news items</media:title>
		</media:content>
	</item>
		<item>
		<title>Always select a publishing target in Sitecore</title>
		<link>http://adeneys.wordpress.com/2013/03/04/always-select-a-publishing-target-in-sitecore/</link>
		<comments>http://adeneys.wordpress.com/2013/03/04/always-select-a-publishing-target-in-sitecore/#comments</comments>
		<pubDate>Mon, 04 Mar 2013 11:12:49 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">http://adeneys.wordpress.com/?p=395</guid>
		<description><![CDATA[At the end of last year I accepted a new position at eDynamic as the CMS Practice Head. And as ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2013/03/04/always-select-a-publishing-target-in-sitecore/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=395&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>At the end of last year I accepted a new position at <a href="http://www.edynamic.net/" target="_blank">eDynamic</a> as the CMS Practice Head. And as such, I&#8217;ll be posting many things on our company blog <a href="http://www.thinkedynamic.com/" target="_blank">Digital Dynamics</a>.</p>
<p>I am happy to say that my first eDynamic blog post has been published, which talks about <a href="http://www.thinkedynamic.com/web-content-management-web-expertise/always-select-a-publishing-target-in-sitecore" target="_blank">always selecting a publishing target in Sitecore</a>. This article talks about various options for making sure content authors always publish their content to a content staging publishing target before publishing the content to the web.</p>
<p>Rather than pollute the web by repeating content on two separate blogs, not to mention diluting the SEO mojo, I&#8217;ll instead post a note here on Coffee =&gt; Coder =&gt; Code so all those interested can find the post.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/395/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/395/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=395&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2013/03/04/always-select-a-publishing-target-in-sitecore/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>
	</item>
		<item>
		<title>SME Review with More Dynamic Roles</title>
		<link>http://adeneys.wordpress.com/2013/02/09/sme-review-with-more-dynamic-roles/</link>
		<comments>http://adeneys.wordpress.com/2013/02/09/sme-review-with-more-dynamic-roles/#comments</comments>
		<pubDate>Sat, 09 Feb 2013 04:32:48 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">http://adeneys.wordpress.com/?p=380</guid>
		<description><![CDATA[When considering content ownership in Sitecore, you realise Sitecore is a bit of a hippy. It&#8217;s not so much about ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2013/02/09/sme-review-with-more-dynamic-roles/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=380&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>When considering content ownership in Sitecore, you realise Sitecore is a bit of a hippy. It&#8217;s not so much about who owns the content, it&#8217;s about everyone working together in collaboration and harmony.</p>
<p>This is evident in the default manner in which workflow works, and how authors push the content from workflow state to workflow state without needing to explicitly state who the content goes to. The workflow works without the authors having to pass the content along the line manually from person to person.</p>
<p>On the whole I think this approach is very good. Don&#8217;t get bogged down with individuals. An individual is a bottleneck. For example, people have a tendency to get sick, or go on holidays, or get distracted by more important things (more important to them anyway). I prefer Sitecore&#8217;s approach of role based workflow actors. Chances are there will be multiple users in the same role, all able to perform those defined actions in workflow. So if Johnny is unavailable, someone else can pick up the slack.</p>
<p>But sometimes we do need to be a bit more strict and rope individuals into the workflow process for various reasons. Take for example a review process of a piece of content where a subject matter expert (SME) must review the content for correctness and SMEs are so varied in their areas of expertise that it&#8217;s not appropriate to create roles for each or to create separate workflow states (or complete workflows) for each.</p>
<p>Well, Sitecore has broken out of the 60&#8242;s and added features to allow strict assignment of content to a user. This appears through the inclusion of the system field <code>__owner</code>. Being a Sitecore standard field (inherited through the standard template) you should interact with this field using the content editor buttons.</p>
<p>To view the existing item owner, look in the Quick Info section (top of the field list).</p>
<p><a href="http://adeneys.files.wordpress.com/2013/02/item-owner.png"><img class="aligncenter size-full wp-image-379" alt="item owner" src="http://adeneys.files.wordpress.com/2013/02/item-owner.png?w=590"   /></a></p>
<p>To change the owner, click the <code>change</code> button in the <code>ownership</code> chunk of the <code>security</code> tab. Clicking this button opens the user select dialog which allows you to search for and select a single user to assign ownership to.</p>
<p>In addition to this field, Sitecore contains a <a href="http://adeneys.wordpress.com/2012/05/09/dynamic-roles-in-sitecore/">dynamic role</a> to refer to the current item&#8217;s owner, the <code>Creator-Owner</code> role. This role will reference the user in the <code>__owner</code> field or if that field is empty it will fallback to the user who created the item (user referred to in the <code>__created by</code> field). We can assign security in workflow to the <code>Creator-Owner</code> role so only the item owner (or creator (or admin)) can act on the item.</p>
<p>Now, this is all sounding pretty good right. But it&#8217;s not quite what we&#8217;re after. Firstly, assignment of ownership of the item is not semantically what I want for the above scenario. The SME shouldn&#8217;t own the content, the content owner should remain as whomever wrote the article initially. I just want the SME to review the content for accuracy. What if we need several SMEs to review the content? The item owner field only allows selection of a single user account. But what I really need is review from a panel of SMEs.</p>
<p>The second issue with using the <code>Creator-Owner</code> role is in how this dynamic role is evaluated. Think about how you might implement the above scenario. You&#8217;d probably allow the <code>worflowstate:write</code> permission to the <code>Creator-Owner</code> role for the appropriate workflow state definition item right? Well, the dynamic role is evaluated against the item on which the security right is defined, in this case, the workflow state definition item. But what we require for our scenario is the item owner of the item in workflow, not the owner of the workflow state definition item, so we can&#8217;t easily implement this scenario using out of the box components.</p>
<p>Instead, we&#8217;ll need to follow the ideas I explored in another recent post of mine (which I also mentioned above), <a href="http://adeneys.wordpress.com/2012/05/09/dynamic-roles-in-sitecore/">Dynamic Roles in Sitecore</a>.</p>
<p>Firstly, I need to add a field to the data template for my items to allow me to select the user accounts that will be the reviewers of that piece of content. To allow specifying multiple accounts for the review I&#8217;ll make use of the <a href="http://marketplace.sitecore.net/en/Modules/Account_Selector_Field.aspx">Account Selector Field</a> from the <a href="http://marketplace.sitecore.net">Sitecore Marketplace</a>. This field allows the user to select multiple accounts using the familiar account selection dialog.</p>
<p>Using the Account Selector Field I&#8217;ll add a field to my base template called &#8220;reviewers&#8221;. Then using the techniques from my previous post I&#8217;ll implement a dynamic role that will read membership from this field. This will allow me to leverage the Sitecore security tools to implement this scenario (and make workflow tools work properly).</p>
<p>Firstly, adding the &#8220;reviewers&#8221; field.</p>
<p><a href="http://adeneys.files.wordpress.com/2013/02/reviewers-field.png"><img class="aligncenter size-full wp-image-375" alt="reviewers field" src="http://adeneys.files.wordpress.com/2013/02/reviewers-field.png?w=590"   /></a></p>
<p>The account selector field has various options to control how it behaves. In the source field I set the following options to allow multiple selection of user accounts only:</p>
<pre><code>AllowMultipleSelection=true&amp;OnlyUsers=true
</code></pre>
<p>Now onto the custom roles provider to expose a dynamic role called &#8216;item-reviewer&#8217;. And just to be different, today I&#8217;ll be writing my sample code in <a href="http://boo.codehaus.org/">Boo</a>.</p>
<pre><code>namespace sc66sb

import System
import Sitecore.Security.Accounts

class ReviewerRoleProvider(SqlServerRolesInRolesProvider):
"""Role provider to expose 'item-reviewer' role"""

    override def GetAllRoles(includeSystemRoles as bool):
        # return normal roles
        for r in super.GetAllRoles(includeSystemRoles):
            yield r

        # return custom role
        yield Role.FromName("item-reviewers")
</code></pre>
<p>The class above extends the <code>SqlServerRolesInRolesProvider</code> and overrides the <code>GetAllRoles()</code> method to return our new <code>item-reviewers</code> role in conjunction with the roles provided by the base class.</p>
<p>In my previous post regarding dynamic roles I was also able to override the <code>IsUserInRole()</code> method to implement the logic of resolving the members of the dynamic role. This worked because role membership was statically determined; the users membership within a role didn&#8217;t change from item to item. In the SME scenario above membership to the dynamic <code>item-reviewers</code> role will change from item to item. The role provider doesn&#8217;t support returning different results per item. So we need to identify another appropriate class to override and insert our custom logic.</p>
<p>Sitecore uses the standard ASP.NET membership model. So to alter the evaluation of permissions a user has in the system I can simply extend the <code>Sitecore.Security.AccessControl.SqlServerAuthorizationProvider</code> class to alter this behavior and update configuration to use my new class.</p>
<pre><code>namespace sc66sb

import System
import Sitecore.Data.Items
import Sitecore.Security.Accounts
import Sitecore.Security.AccessControl

class ReviewerAuthorizationProvider(SqlServerAuthorizationProvider):
"""Authorization provider to evaluate membership in 'item-reviewer' role"""

    _reviewerRole = Role.FromName('item-reviewers')

    override def GetItemAccess(item as Item, account as Account, \
        accessRight as AccessRight):
        res = super.GetItemAccess(item, account, accessRight)
        if res.Permission == AccessPermission.Allow:
            return res

        # if access denied for user, check item reviewers role
        if item["Reviewers"].Contains(account.Name) \
            and account.Name != _reviewerRole.Name:
            res = super.GetItemAccess(item, _reviewerRole, \
                accessRight)

        return res
</code></pre>
<p>In the above code I&#8217;ve overridden the <code>GetItemAccess()</code> method which evaluates the permissions for a specified account for a specified access right to a specified item. Initially the base class method is called to check if the user has access. If not, then I check if the user is included in the <code>reviewers</code> field and if so, return the permissions for the <code>item-reviewers</code> role.</p>
<p>The above customisations now allow an administrator to assign security permissions to our new dynamic role and also resolve access permissions for that dynamic role if the individual user doesn&#8217;t have access and the user is included in the reviewers field.</p>
<p>This covers off item security. But workflow security is a little different. When the <code>item:write</code> access right is resolved, Sitecore internally first checks that the user has <code>item:write</code> access on the item and then also checks to ensure the same account has <code>workflowstate:write</code> access to the current workflow state the item is in.</p>
<p>So why is the above authorization provider not adequate? This is similar to the <code>Creator-Owner</code> issue above. In the above authorization provider the item being checked for the access right holds the <code>reviewers</code> field. But we&#8217;re checking the <code>workflowstate:write</code> access right of the workflow state definition item itself, and the <code>reviewers</code> field is on the item in workflow, not the state definition item. So we&#8217;ll need to tweak the workflow engine to work the way we want.</p>
<p>Unfortunately the default Sitecore workflow class <code>Sitecore.Workflows.Simple.Workflow</code> cannot be overridden for the case above. The class does contain many virtual methods, but I need to override the <code>GetAccess()</code> method which is not virtual.</p>
<p>So instead of overriding the workflow, I&#8217;m going to wrap it as I did in another previous post on <a href="http://adeneys.wordpress.com/2009/03/18/get-your-workflow-in-order/">Get Your Workflow in Order</a>. In that article I showed how the workflow can be wrapped by another class which simply passes the call onto the wrapped workflow, but the methods I want to tweak can be manually written.</p>
<p>Here is my wrapping &#8220;reviewer&#8221; workflow.</p>
<pre><code>namespace sc66sb

import System
import Sitecore
import Sitecore.Data
import Sitecore.Data.Items
import Sitecore.Data.Managers
import Sitecore.Diagnostics
import Sitecore.Globalization
import Sitecore.Security.Accounts
import Sitecore.Security.AccessControl
import Sitecore.SecurityModel
import Sitecore.Workflows

class ReviewerWorkflow(IWorkflow):
"""Workflow implementation which allows use of the special 'item-reviewer' role"""

    _reviewerRole = Role.FromName('item-reviewers')
    _innerWorkflow as IWorkflow
    _database as Database

    Appearance as Appearance:
        get:
            return _innerWorkflow.Appearance

    WorkflowID as string:
        get:
            return _innerWorkflow.WorkflowID

    def constructor(innerWorkflow as IWorkflow, database as Database):
        _innerWorkflow = innerWorkflow
        _database = database

    def GetAccess(item as Item, account as Account, \
        accessRight as AccessRight) as AccessResult:
        res = _innerWorkflow.GetAccess(item, account, accessRight)
        if res.Permission == AccessPermission.Allow:
            return res

        if item["Reviewers"].Contains(account.Name) \
            and account.Name != _reviewerRole.Name:
            res = _innerWorkflow.GetAccess(item, _reviewerRole, \
                accessRight)

        return res

    def GetCommands(item as Item):
        Assert.ArgumentNotNull(item, "item");
        stateID = GetStateID(item)
        if stateID.Length &gt; 0:
            return GetCommands(stateID, item)

        return array(WorkflowCommand, 0)

    private def GetStateID(item as Item):
        Assert.ArgumentNotNull(item, "item")
        workflowInfo = item.Database.DataManager.GetWorkflowInfo(item)
        if  workflowInfo != null:
            return workflowInfo.StateID

        return string.Empty

    def GetCommands(stateID as string):
        return GetCommands(stateID, null)

    def GetCommands(stateID as string, item as Item):
        Assert.ArgumentNotNullOrEmpty(stateID, "stateID")
        cmds = List[of WorkflowCommand]()
        stateItem = GetStateItem(stateID) as Item

        if stateItem != null:
            for cmd in stateItem.Children.ToArray():
                template = cmd.Database.Engines.TemplateEngine.GetTemplate(\
                    cmd.TemplateID)
                userAllowed = AuthorizationManager.IsAllowed(cmd, \
                    AccessRight.WorkflowCommandExecute, Context.User)

                reviewerAllowed = true
                if item != null \
                    and item["Reviewers"].Contains(Context.User.Name) \
                    and Context.User.Name != _reviewerRole.Name:
                    reviewerAllowed = AuthorizationManager.IsAllowed(cmd, \
                        AccessRight.WorkflowCommandExecute, _reviewerRole)

                if template != null \
                    and template.DescendsFromOrEquals(TemplateIDs.WorkflowCommand) \
                    and (userAllowed or reviewerAllowed):
                    cmds.Add(WorkflowCommand(cmd.ID.ToString(), \
                        cmd.DisplayName, cmd.Appearance.Icon, false, \
                        cmd["suppress comment"] == "1"))

        return cmds.ToArray()

    private def GetStateItem(stateId as string):
        iD = MainUtil.GetID(stateId, null)
        if iD == null:
            return null

        return GetStateItem(iD)

    private def GetStateItem(stateId as ID):
        return ItemManager.GetItem(stateId, Language.Current, \
            Sitecore.Data.Version.Latest, _database, SecurityCheck.Disable)

    def Start(item as Item):
        _innerWorkflow.Start(item)

    def Execute(commandID as string, item as Item, comments as string, \
        allowUI as bool, *parameters):
        return _innerWorkflow.Execute(commandID, item, comments, allowUI, \
            parameters)

    def GetHistory(item as Item):
        return _innerWorkflow.GetHistory(item)

    def GetItemCount(stateID as string):
        return _innerWorkflow.GetItemCount(stateID)

    def GetItems(stateID as string):
        return _innerWorkflow.GetItems(stateID)

    def GetState(item as Item):
        return _innerWorkflow.GetState(item)

    def GetState(stateID as string):
        return _innerWorkflow.GetState(stateID)

    def GetStates():
        return _innerWorkflow.GetStates()

    def IsApproved(item as Item):
        return _innerWorkflow.IsApproved(item)
</code></pre>
<p>Most of the methods just pass through to the wrapped workflow, but I override some of the methods. Firstly, I&#8217;ve overridden the <code>GetAccess()</code> method so if the user isn&#8217;t granted the access right desired and the user exists in the reviewer field, then return the permissions of the reviewer role. That handles access to the item when it&#8217;s in workflow. The remaining methods are to do with showing the correct workflow commands to the user. Overriding the command methods was more involved as the OOTB workflow uses many private methods to find the commands, which I also had to implement myself. This all starts with the <code>GetCommands()</code> method and it&#8217;s overloads. In particular, I needed to pass the current item in workflow to the <code>GetCommands()</code> method so I had access to the <code>reviewers</code> field.</p>
<p>The last piece of the puzzle is to override the workflow provider to return our custom reviewer workflow instead of the OOTB workflow.</p>
<pre><code>namespace sc66sb

import System
import Sitecore.Data.Items
import Sitecore.Workflows
import Sitecore.Workflows.Simple

class ReviewerWorkflowProvider(WorkflowProvider):
"""Description of ReviewerWorkflowProvider"""
    public def constructor(databaseName as string, \
        historyStore as HistoryStore):
        super(databaseName, historyStore)

    override def GetWorkflow(item as Item):
        workflow = super.GetWorkflow(item);
        return (ReviewerWorkflow(workflow, Database) \
            if workflow != null else null)

    override def GetWorkflow(id as string):
        workflow = super.GetWorkflow(id);
        return (ReviewerWorkflow(workflow, Database) \
            if workflow != null else null)
</code></pre>
<p>Note how I am simply calling the base class implementation of the overridden methods to get the OOTB workflow, but then I wrap that with the reviewer workflow before returning.</p>
<p>To tie all these customisations into workflow I&#8217;ve added this config patch file to the <code>App_Config\Include</code> folder.</p>
<pre><code>&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt; 
  &lt;sitecore&gt; 
    &lt;rolesInRolesManager&gt; 
      &lt;providers&gt; 
        &lt;add name="sql"&gt; 
          &lt;patch:attribute name="type"&gt;sc66sb.ReviewerRoleProvider, 
sc66sb&lt;/patch:attribute&gt; 
        &lt;/add&gt; 
      &lt;/providers&gt; 
    &lt;/rolesInRolesManager&gt;
    &lt;authorization&gt;
      &lt;providers&gt;
        &lt;add name="sql"&gt;
            &lt;patch:attribute name="type"&gt;sc66sb.ReviewerAuthorizationProvider, 
sc66sb&lt;/patch:attribute&gt;
        &lt;/add&gt;
      &lt;/providers&gt;
    &lt;/authorization&gt;
    &lt;databases&gt;
        &lt;database id="master"&gt;
            &lt;workflowProvider hint="defer" type="Sitecore.Workflows.Simple.WorkflowProvider, 
Sitecore.Kernel"&gt;
                &lt;patch:attribute name="type"&gt;sc66sb.ReviewerWorkflowProvider, 
sc66sb
                &lt;/patch:attribute&gt; 
            &lt;/workflowProvider&gt;
        &lt;/database&gt;
    &lt;/databases&gt;
  &lt;/sitecore&gt; 
&lt;/configuration&gt;
</code></pre>
<p>This config patch file changes the role provider to our custom role provider, changes the authorization provider to our custom provider and changes the workflow provider of the master database to use our custom workflow provider.</p>
<p>Now to see it all in action!</p>
<p>I have duplicated the sample workflow and adjusted security settings as follows:</p>
<table>
<tbody>
<tr>
<th>item</th>
<th>account</th>
<th>access right</th>
<th>permission</th>
</tr>
<tr>
<td>review state item</td>
<td>item-reviewer role</td>
<td>workflowstate:write</td>
<td>allow</td>
</tr>
<tr>
<td>review state item</td>
<td>item-reviewer role</td>
<td>workflowstate:delete</td>
<td>allow</td>
</tr>
<tr>
<td>approve command item</td>
<td>item-reviewer role</td>
<td>workflowstate:execute</td>
<td>allow</td>
</tr>
<tr>
<td>reject command item</td>
<td>item-reviewer role</td>
<td>workflowstate:execute</td>
<td>allow</td>
</tr>
</tbody>
</table>
<p>In addition to the above workflow security I&#8217;ve also granted write, rename, create and delete access rights to the <code>item-reviewers</code> role to the home item and all descendants.</p>
<p>Now when I log in as an SME user, I do not currently have access to the item that is in this workflow in the review state:</p>
<p><a href="http://adeneys.files.wordpress.com/2013/02/sme-no-write-access1.png"><img class="aligncenter size-full wp-image-385" alt="sme no write access" src="http://adeneys.files.wordpress.com/2013/02/sme-no-write-access1.png?w=590"   /></a></p>
<p>Now log in as an admin and add the SME user above to the <code>reviewers</code> field:</p>
<p><a href="http://adeneys.files.wordpress.com/2013/02/add-sme-reviewer.png"><img class="aligncenter size-full wp-image-378" alt="add sme reviewer" src="http://adeneys.files.wordpress.com/2013/02/add-sme-reviewer.png?w=590"   /></a></p>
<p>Then refresh the SME users content editor and voila! The SME user who is included in the <code>reviewers</code> field, but has no direct access of their own, can now edit and review the item.</p>
<p><a href="http://adeneys.files.wordpress.com/2013/02/sme-write-access.png"><img class="aligncenter size-full wp-image-377" alt="sme write access" src="http://adeneys.files.wordpress.com/2013/02/sme-write-access.png?w=590"   /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/380/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=380&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2013/02/09/sme-review-with-more-dynamic-roles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/02/item-owner.png" medium="image">
			<media:title type="html">item owner</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/02/reviewers-field.png" medium="image">
			<media:title type="html">reviewers field</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/02/sme-no-write-access1.png" medium="image">
			<media:title type="html">sme no write access</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/02/add-sme-reviewer.png" medium="image">
			<media:title type="html">add sme reviewer</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2013/02/sme-write-access.png" medium="image">
			<media:title type="html">sme write access</media:title>
		</media:content>
	</item>
		<item>
		<title>Common Redirect Exclusions</title>
		<link>http://adeneys.wordpress.com/2012/11/15/common-redirect-exclusions/</link>
		<comments>http://adeneys.wordpress.com/2012/11/15/common-redirect-exclusions/#comments</comments>
		<pubDate>Thu, 15 Nov 2012 10:44:27 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=372</guid>
		<description><![CDATA[Recently my TDS (Team Development for Sitecore) install started acting funny. And the symptoms didn’t seem consistent between different solutions, ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/11/15/common-redirect-exclusions/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=372&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Recently my TDS (<a href="http://www.hhogdev.com/Products/Team-Development-for-Sitecore/Overview.aspx" target="_blank">Team Development for Sitecore</a>) install started acting funny. And the symptoms didn’t seem consistent between different solutions, so it looked like the issue was to do with those specific installs.</p>
<p>When I tried to perform any operation from my TDS project with Sitecore I would receive an error about the response content type, followed by an error to do with the version of the server components: “The content type text/html; charset=utf-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8)”.</p>
<p><a href="http://adeneys.files.wordpress.com/2012/11/clip_image002.jpg"><font color="#464545"></font><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="clip_image002" border="0" alt="clip_image002" src="http://adeneys.files.wordpress.com/2012/11/clip_image002_thumb.jpg?w=454&#038;h=622" width="454" height="622" /></a></p>
<p>Clicking OK to dismiss this dialog showed the next error to do with the version: “Warning: The version of the sitecore connector is from an older version of TDS”</p>
<p><a href="http://adeneys.files.wordpress.com/2012/11/clip_image0028.jpg"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="clip_image002[8]" border="0" alt="clip_image002[8]" src="http://adeneys.files.wordpress.com/2012/11/clip_image0028_thumb.jpg?w=500&#038;h=188" width="500" height="188" /></a></p>
<p>I tried everything I could think of to fix this issue. I used the “Install Sitecore Connector” option in my project context menu, I compared versions of the ASMX and DLL installed by TDS into my Sitecore folder and copied an updated version from another working Sitecore instance, I also applied a patch which was specific to a revision of Sitecore 6.4.</p>
<p>Eventually I logged the issue with Hedgehog support and they worked through the issue with me.</p>
<p>Now, keep in mind that TDS communicates with your Sitecore solution using a custom web service. The ASMX file resides under a folder called <code>_DEV</code>. Also in this folder is a <code>web.config</code> file containing the access GUID. An assembly is also added to your bin folder which contains the type used by the ASMX file.</p>
<p>Now, the fact that TDS uses a standard web service which communicates over HTTP is what saved me here. Hedgehog support suggested using an HTTP debugging proxy like <a href="http://www.fiddler2.com/fiddler2/" target="_blank">Fiddler</a> to look at the HTTP request and response. Good idea! This allowed me to see what was going on:</p>
<p><a href="http://adeneys.files.wordpress.com/2012/11/tds-request-redirect.png"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="TDS request redirect" border="0" alt="TDS request redirect" src="http://adeneys.files.wordpress.com/2012/11/tds-request-redirect_thumb.png?w=504&#038;h=181" width="504" height="181" /></a></p>
<p>As you can see from the screenshot above, the request for the ASMX was being redirected to a lowercase version of the URL. This redirect strips the SOAP action header so instead of trying to execute a web method, this request turned into a GET request. BTW, this was on TDS 3. When writing this blog post I was testing against TDS 4 and it appeared the SOAP action was not stripped by the redirect, though the result was the same.</p>
<p>Now, you may recall I recently blogged about <a href="http://adeneys.wordpress.com/2012/07/22/redirect-options/" target="_blank">redirect components</a> that can be used with Sitecore? Yeah. Here’s the gotcha. Make sure your redirect rules aren’t overzealous and process system/service requests rather than just limiting themselves to requests for content. The “administrator” modules I wrote about previously are not integrated into Sitecore, so they have no concept of a content request versus a service request. Instead, you’ll have to update your redirect rules so they ignore any requests that aren’t for content. The CMS modules are run from inside the CMS application, so by the time they get a chance to process the request they have already been processed by the CMS and you can be pretty sure that what you’re dealing with is a content request and not a service request which would have aborted before now.</p>
<p>In the above scenario I was using the <a href="http://www.iis.net/downloads/microsoft/url-rewrite" target="_blank">IIS URL Rewrite module</a> and I had a rewrite rule to redirect any request which contained an uppercase character to a lowercase version of the URL. This is a common SEO technique to help with canonicalization of the URLs on your site to ensure search engines don’t accidentally split your page ranking between several URLs differing only by case. This may seem funny to many Windows developers where we have a file system that ignores case, but to the rest of the world, including that of HTTP, case matters in both files and URLs, so search engines see <code>/My-Page</code> as a different URL to <code>/my-page</code>.</p>
<p>To fix the above TDS issue, I could update my rules to ignore anything in the <code>_DEV</code> folder, but a better solution would be to ignore any request for a web service endpoint; ignore any request ending in <code>.asmx</code>.</p>
<p>When creating your redirect rules for administrator modules (those configured outside of Sitecore), keep in mind that all requests will be processed by the redirect module.</p>
<p>Here’s a list of common exclusions you will probably need to work into your redirect rules when using a redirect module with Sitecore:</p>
<ul>
<li>Anything under the <code>sitecore</code> folder </li>
<li>Anything under the <code>temp</code> folder </li>
<li>Anything under the virtual <code>ScriptResource</code> folder </li>
<li>Anything under the virtual <code>WebResource</code> folder </li>
<li>Any URL ending in <code>.axd</code> </li>
<li>Any URL ending in <code>.asmx</code> </li>
<li>Any URL ending in <code>.svc</code> </li>
<li>Anything under the <code>layouts/system</code> folder </li>
<li>Any URL with <code>sc_mode</code> in the query string </li>
<li>Any static resources on disk such as the <a href="http://www.codeflood.net/testrunner/" target="_blank">codeflood embedded test runner</a> (<code>test.aspx</code> file) </li>
</ul>
<p>&#160;</p>
<p>The <a href="http://www.iis.net/downloads/microsoft/url-rewrite" target="_blank">IIS URL Rewrite module</a> allows exclusions to be included in any rule through conditions. For a rule to apply to a request all conditions of the rule must be met. Here’s a sample configuration for a redirect rule for the IIS URL Rewrite module which includes the above exclusions.</p>
<pre><code>&lt;rule name=&quot;Lower Case Rule&quot;&gt;
  &lt;match url=&quot;[A-Z]&quot; ignoreCase=&quot;false&quot; /&gt;
  &lt;conditions&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;^/sitecore&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;^/temp&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;^/ScriptResource&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;^/WebResource&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;\.axd&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;\.asmx&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;\.svc&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{URL}&quot; pattern=&quot;^/layouts/system&quot; negate=&quot;true&quot; /&gt;
    &lt;add input=&quot;{HTTP_URL}&quot; pattern=&quot;\?.*sc_mode&quot; negate=&quot;true&quot; /&gt;
  &lt;/conditions&gt;
  &lt;action type=&quot;Redirect&quot; url=&quot;{ToLower:{URL}}&quot; /&gt;
&lt;/rule&gt;</code></pre>
<p>The “variables” in the input attribute of the condition entries (the names in curly braces) are server variables. You can find a list of common IIS server variables here: <a title="http://msdn.microsoft.com/en-us/library/ms524602%28v=vs.90%29.aspx" href="http://msdn.microsoft.com/en-us/library/ms524602%28v=vs.90%29.aspx">http://msdn.microsoft.com/en-us/library/ms524602%28v=vs.90%29.aspx</a>.</p>
<p>If you’re using the <a href="http://urlrewriter.net/" target="_blank">UrlRewriter.net</a> module, exclusions can be implemented through an <code>unless</code> element in configuration. The <code>unless</code> element is a conditional so no rules inside the <code>unless</code> will be processed unless the conditions of the <code>unless</code> are met.</p>
<p>Below is sample configuration for UrlRewriter.net implementing the same exclusions as above.</p>
<pre><code>&lt;unless url=&quot;^/sitecore|^/temp|^/scriptresource|
  ^/webresource|\.axd|\.asmx|\.svc|^/layouts/system|\?.*sc_mode&quot;&gt;
  &lt;if url=&quot;(?-i)[A-Z]+&quot;&gt;
    &lt;redirect url=&quot;(.*)&quot; to=&quot;http://${HOST}${lower($1)}&quot; processing=&quot;stop&quot;/&gt;
  &lt;/if&gt;
&lt;/unless&gt;</code></pre>
<p>Note here how we only have a single attribute to put the condition in, which is in regular expression format. We could have implemented the IIS URL Rewriter configuration into a single regex as well, but I think splitting it out makes it much easier to read.</p>
<p>One nice aspect of the UrlRewriter.net configuration over the IIS URL Rewriter configuration is that you can wrap all rules in a single <code>unless</code> element, helping reduce the repetition of adding the conditions to several rules.</p>
<p>So next time you’re adding redirect rules, keep in mind the global implications.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/372/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/372/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=372&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/11/15/common-redirect-exclusions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/11/clip_image002_thumb.jpg" medium="image">
			<media:title type="html">clip_image002</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/11/clip_image0028_thumb.jpg" medium="image">
			<media:title type="html">clip_image002[8]</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/11/tds-request-redirect_thumb.png" medium="image">
			<media:title type="html">TDS request redirect</media:title>
		</media:content>
	</item>
		<item>
		<title>Decoupling Through the Sitecore Event Pool</title>
		<link>http://adeneys.wordpress.com/2012/10/21/decoupling-through-the-sitecore-event-pool/</link>
		<comments>http://adeneys.wordpress.com/2012/10/21/decoupling-through-the-sitecore-event-pool/#comments</comments>
		<pubDate>Sun, 21 Oct 2012 12:15:50 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=364</guid>
		<description><![CDATA[There are several ways to allow disparate components in a .net application to communicate. And usually it involves events. Standard ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/10/21/decoupling-through-the-sitecore-event-pool/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=364&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>There are several ways to allow disparate components in a .net application to communicate. And usually it involves events. Standard .net events require a reference to the object exposing the event to connect an event handler to that event, in the following manner.</p>
<pre><code>var someObject = FindObject(); 
someObject.TheEvent += new EventHandler(MyEventHandler);</code></pre>
<p>How that <code>FindObject()</code> method is implemented will depend on the context in which the method will be called (from a control, from a service, etc) and where the object being found resides (who owns it).</p>
<p>Bringing the problem to the realm of Sitecore, let’s start with a solid example.</p>
<p>Let’s say we have 2 sublayouts hosted on a page that need to communicate. The easiest way for one sublayout to find the other would be to expose a method to locate the second sublayout on a component that will host both sublayouts. This could be a parent sublayout if the two sublayouts will always be hosted within that sublayout, or a layout if there is no common parent control layer in the control tree.</p>
<p>The issue with this approach is that it’s quite rigid. Both sublayouts at some point need a common ancestor control to expose the method used to locate the sublayout exposing the event. This ties both sublayouts to that ancestor control for this approach to work. Not to mention the fact that the subscriber sublayout must know about the publisher sublayout and the ancestor control ahead of time.</p>
<p>This approach is tightly coupled, and we know that’s a bad thing…in some situations. On an implementation for a specific site this might be fine as all the components involved are part of the same project. But what if you’re a module developer (like me!) and need to expose events from your component and allow other developers to subscribe where there will not necessarily be a common ancestor control. Or what if you just want to avoid the hassle of all that wiring up?</p>
<p>Enter the Sitecore event pool. The Sitecore event pool allows disparate components to publish and subscribe to events easily. This is because the linking up of the subscriber to the publisher is done through the pool using an event name, thus decoupling the components. Well, loosely coupling them at least.</p>
<p>There are two ways to subscribe an event handler to an event in Sitecore. Firstly events can be subscribed to declaratively through a Sitecore configuration file. Entries in the <code>/configuration/sitecore/events</code> element define the events and show the event handlers for each event. Sitecore defines many events which are fired when things of interest happen in the system such as finishing a publish, adding a new user or saving an item. This is also a perfect example of a good use for decoupled events.</p>
<p>The second way to subscribe to an event is programmatically by calling the <code>Sitecore.Events.Event.Subscribe(string, EventHandler)</code> method. This method allows adding an event handler as a subscriber to an event given the event name.</p>
<p>OK, so that takes care of the subscription to the event, but what about firing the event? It’s as easy as calling the <code>Sitecore.Events.Event.RaiseEvent(string, params object[])</code> method. One thing to note is that the name of the event (the first parameter) is arbitrary. It does not need to be defined in a configuration file.</p>
<p>Let’s put all this into context. Let’s say we have a sublayout which searches for content using a Lucene index. If I wanted to provide more information about the search results, such as a summary, I would normally have to update the sublayout. And if the sublayout was part of a module it complicates the issue as I’m not in control of the code that I need to update.</p>
<p>We can expose the search results from the sublayout doing the heavy lifting by raising an event. Other disparate code, from other modules or project specific, could then subscribe to the event and act on the parameters passed in the event arguments.</p>
<p>Onto the code. First, we’ll define a custom <code>EventArgs</code> class to expose the data relevant to the event.</p>
<pre><code>public class CustomEventArgs : EventArgs
{
  public Item[] Items { get; set; }
}</code></pre>
<p>Now we’ll raise the event in the sublayout that performs the search.</p>
<pre><code>var args = new CustomEventArgs();
args.Items = GetSearchItems();
Sitecore.Events.Event.RaiseEvent(&quot;custom:searchresults&quot;, args);</code></pre>
<p>And we’ll need to subscribe to the event in the summary sublayout.</p>
<pre><code>var handler = new EventHandler(ResultHandler);
Sitecore.Events.Event.Subscribe(&quot;custom:searchresults&quot;, handler);</code></pre>
<p>And the event handler itself.</p>
<pre><code>protected void ResultHandler(object sender, EventArgs args)
{
  var customArgs = Sitecore.Events.Event.ExtractParameter(args, 0)<br />    as CustomEventArgs;
  ResultCount = customArgs.Items.Length;
}</code></pre>
<p>Note how we extract the custom event args from the generic event args of the handler using the <code>Sitecore.Events.Event.ExtractParameter()</code> method.</p>
<p>Now, a little gotcha. When you subscribe to an event it creates a strong reference through the event handler. The strong reference will prevent the object containing the event handler from being eligible for garbage collection and the object will hang around for the lifetime of the application. While the object lives, the event handler will continue to respond to the event being raised. And in an ASP.NET application, with each request an instance of the sublayout codebehind (well, an derivative of the codebehind class) is created. Because previous instances are not garbage collected due to the strong reference, this actually looks like a memory leak. Memory usage will continue to rise over time.</p>
<p>To counter this, we need to ensure any events subscribed to programmatically are unsubscribed from. We can do this by storing the event handler reference in a member variable and unsubscribing from the event at a point later in the request lifecycle.</p>
<pre><code>private EventHandler m_handler = null;

protected void Page_Load(object sender, EventArgs args)
{
  m_handler = new EventHandler(ResultHandler);
  Sitecore.Events.Event.Subscribe(&quot;custom:searchresults&quot;, m_handler);
}

protected void Page_Unload(object sender, EventArgs args)
{
  if(m_handler != null)
    Sitecore.Events.Event.Unsubscribe(&quot;custom:searchresults&quot;,<br />      m_handler);
}</code></pre>
<p>And one more note, using this technique you’ll need to ensure your event subscriptions occur before any events are raised for that event, or you’ll miss handing that call of the event. This is quite easily done by having the subscriptions occur as early as possible, such as in the constructor of the class.</p>
<p>With this technique you now have components which are only loosely coupled, making it much easier to respond to the event.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/364/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=364&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/10/21/decoupling-through-the-sitecore-event-pool/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>
	</item>
		<item>
		<title>Revolver 2, Released and Now Free</title>
		<link>http://adeneys.wordpress.com/2012/10/06/revolver-2-released-and-now-free/</link>
		<comments>http://adeneys.wordpress.com/2012/10/06/revolver-2-released-and-now-free/#comments</comments>
		<pubDate>Sat, 06 Oct 2012 13:15:20 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Revolver]]></category>
		<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=359</guid>
		<description><![CDATA[It’s been a while since the last update to Revolver so this release is long overdue. Today I have released ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/10/06/revolver-2-released-and-now-free/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=359&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>It’s been a while since the last update to Revolver so this release is long overdue. Today I have released version 2 of Revolver, the scripting module for Sitecore. The timing of this release is in preparation for Sitecore Symposium Australia where I’ll be presenting on scripting with Sitecore. Of course I’ll be covering Revolver and I will also be covering other scripting modules available.</p>
<p>Anyway, back to the release.</p>
<p>There have been lots of changes to the module in this update, so let’s cover them off, starting with the biggest change:</p>
<h3>Revolver is Now Free!</h3>
<p>Yes, I have removed the commercial licensing from the module. I am a huge supporter of open source software and I also use many open source tools. So it was kind of odd that I was going against open source and was holding the module as commercial. I’ve still got a bit of clean up I want to do in the codebase before releasing it into the wild, so I’m stopping short of going open source just yet, but I’m allowing it’s use free of charge.</p>
<p>This change in licensing was also encouraged by the other freely available scripting modules out there, the <a href="http://marketplace.sitecore.net/Modules/Sitecore_Rocks.aspx" target="_blank">Sitecore Rocks</a> Power Shell integration, <a href="http://marketplace.sitecore.net/Modules/Sitecore_Rocks.aspx" target="_blank">Sitecore Rocks</a> Query Analyser and the <a href="http://marketplace.sitecore.net/en/Modules/Sitecore_PowerShell_console.aspx" target="_blank">Power Shell Console</a>. It was getting very hard to justify the cost of Revolver given the capabilities of the other modules.</p>
<h3>Search Command</h3>
<p>The new <code>search</code> command allows searching within the Lucene indexes. It works in the same fashion as the <code>find</code> and <code>query</code> commands. The command is used to locate items and then execute some command against each item.</p>
<p>So if we wanted to search for any items that contain “Lorem” in the title field (left over test data anyone?) and just print the path to the item, we could use the following command.</p>
<pre><code>search title:lorem pwd</code></pre>
<p>Note that the fields used in the search are Lucene fields, not Sitecore item fields.</p>
<h3>Comms Notification</h3>
<p>The Revolver application window now has a status bar to tell you when the client app is communicating with the server. This helps inform you about whether Revolver is waiting for your input or if it’s off and processing your data for you.</p>
<p><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;border-top:0;margin-right:auto;border-right:0;padding-top:0;" title="revolver-server-indicator" border="0" alt="revolver-server-indicator" src="http://adeneys.files.wordpress.com/2012/10/revolver-server-indicator.png?w=504&#038;h=366" width="504" height="366" /></p>
<h3>Find using Wildcard Field</h3>
<p>The <code>find</code> command has been updated to allow use of a wildcard field name when matching items on field values. This allows users to search inside all fields which can come in handy when trying to locate items that might contain a token in a number of different fields.</p>
<pre><code>find -f * lorem pwd</code></pre>
<h3>Excluding Standard Values</h3>
<p>Sometimes when you’re searching for content you want to be able to exclude anything coming from standard values. For example, if you want to search for items that have overridden presentation. When using the <code>find</code> command you can pass the new flag <code>-nsv</code> (no standard values) to exclude standard values in the operation, and only assess items on field values they contain.</p>
<p>So to find item’s that have overridden their presentation we could use this command:</p>
<pre><code>find -r -f __renderings .+ -nsv pwd</code></pre>
<h3>Better Version Support</h3>
<p>This version of Revolver has better support for item versions, allowing you to list the various versioned and also change your context to a specific numbered version.</p>
<p>To list the versions of an item:</p>
<pre><code>lsv</code></pre>
<p>To see which version you’re looking at:</p>
<pre><code>pwv</code></pre>
<p>To change to a specific numbered version of an item:</p>
<pre><code>cv 6</code></pre>
<p>The <code>cd</code> command also got an update to make it easier to change your context between languages and versions.</p>
<p>Arguments can now include the language and version you want to change your context to. The language is separated from the item path with a single-semi colon, and the version is separated from the language with a single semi-colon. If the language, path or version is omitted then it won’t be changed. Here’s a few examples.</p>
<pre><code>cd /sitecore/content/home:en:3
cd :de
cd ::6
cd :jp:7</code></pre>
<h3>Launch Content Editor</h3>
<p>In the previous version of Revolver the <code>ce</code> script which could be used to open a content editor with the current context was broken. This has now been fixed and the script renamed to <code>content-editor</code>. So to open a content editor application on the current context item, just type the following:</p>
<pre><code>content-editor</code></pre>
<h3>Better Scripting</h3>
<p>Scripting also got better in this release of Revolver.</p>
<p>The new <code>if</code> command allows simple conditions to be evaluated using the expression syntax used by the <code>find</code> command. This can be used to ensure all the required parameters have been provided to a script.</p>
<p>The new <code>exit</code> command allows a script to bail out if required, such as when a parameter is missing.</p>
<p>The following example shows a check for the first parameter and exits if the parameter is not provided.</p>
<pre><code>if ($1$ = \$1\$) (exit (Missing required parameter))</code></pre>
<p>The <code>if</code> command accepts 2 parameters. The first is the expression to evaluate. In the above example if the parameter is provided then the <code>$1$</code> token will be replaced with the parameter. Note how the dollar signs on the right hand side of the expression are escaped? This prevents the argument from being replaced with the provided parameter, so this expression is checking if the provided parameter was substituted or not.</p>
<p>The second parameter to the <code>if</code> command if the command to execute if the expression evaluates to true.</p>
<p>The <code>exit</code> command accepts an optional message which will be output to the user.</p>
<h3>OOTB Scripts</h3>
<p>Revolver also ships with some handy scripts out-of-the-box:</p>
<table border="0" cellspacing="0" cellpadding="2" width="500">
<tbody>
<tr>
<td valign="top" width="250">Script Name</td>
<td valign="top" width="250">Purpose</td>
</tr>
<tr>
<td valign="top" width="250">ls-scripts</td>
<td valign="top" width="250">Lists the scripts available</td>
</tr>
<tr>
<td valign="top" width="250">content-editor</td>
<td valign="top" width="250">Opens a content editor application with the current item selected</td>
</tr>
<tr>
<td valign="top" width="250">field-info</td>
<td valign="top" width="250">Get extended information about a specific field of an item</td>
</tr>
<tr>
<td valign="top" width="250">replace-in-field</td>
<td valign="top" width="250">Replace a token in a field of an item</td>
</tr>
<tr>
<td valign="top" width="250">set-prompt</td>
<td valign="top" width="250">Sets the default prompt</td>
</tr>
<tr>
<td valign="top" width="250">updates</td>
<td valign="top" width="250">Locates all descendant items that have been updated or created since the given date</td>
</tr>
</tbody>
</table>
<h3>More Help</h3>
<p>Don’t forget that help is built right into Revolver, so you can get more help on any of the commands by using the <code>help</code> command and passing it the name of the command you want help on:</p>
<pre><code>help search
help lsv</code></pre>
<p>Help is also available for scripts. Access it the same way:</p>
<pre><code>help updates</code></pre>
<h3>Go Download It!</h3>
<p>So what are you waiting for? Jump over to the <a href="http://www.codeflood.net/" target="_blank">codeflood</a> website and download Revolver from the <a href="http://www.codeflood.net/revolver/download/" target="_blank">Revolver Downloads</a> page. You’ll also find the module soon on the <a href="http://marketplace.sitecore.net">Sitecore Marketplace</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/359/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/359/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=359&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/10/06/revolver-2-released-and-now-free/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/10/revolver-server-indicator.png" medium="image">
			<media:title type="html">revolver-server-indicator</media:title>
		</media:content>
	</item>
		<item>
		<title>Adding Options to Sitecore Applications</title>
		<link>http://adeneys.wordpress.com/2012/08/26/adding-options-to-sitecore-applications/</link>
		<comments>http://adeneys.wordpress.com/2012/08/26/adding-options-to-sitecore-applications/#comments</comments>
		<pubDate>Sun, 26 Aug 2012 11:53:14 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=350</guid>
		<description><![CDATA[Recently I was asked what I like the most about Sitecore. There are many reason’s I like Sitecore, but one ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/08/26/adding-options-to-sitecore-applications/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=350&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Recently I was asked what I like the most about Sitecore. There are many reason’s I like Sitecore, but one stand out reason is it’s extensibility. I like how I can extend Sitecore’s UI and processes to add my own functionality or change how Sitecore works to meet my client’s requirements.</p>
<p>So, extending the Sitecore UI. On a recent project we had a requirement to provide a utility that was context sensitive. The utility in question was to perform operations on users, so I looked into extending the Sitecore User Manager application. I chose this application cause it already provides the functionality to list and search for users. I can select a user and perform various actions on that user.</p>
<p>Much of Sitecore’s UI is defined in the <code>core</code> database. This is where most of those menus and ribbons that you use every day are defined. When you see an application in Sitecore that contains a ribbon, such as the Content Editor, User Manager, Workbox, etc, those ribbons are defined in the <code>core</code> DB. This is where we can easily extend the applications with our own custom context sensitive commands.</p>
<p>In this article I’d like to add a command to the User Manager to allow me to reset some custom properties for a user. This basic approach can be used to create your own context sensitive application for any of the Sitecore applications mentioned above.</p>
<p>Firstly, we need to create the new ribbon entry to have it appear on the UI. Using the database switcher on the desktop tray, switch to the <code>core</code> database, open the content editor and navigate down to <code>/sitecore/content/Applications/Security/User Manager/Ribbon/Home/Tools</code>. This item is the definition for the tool chunk on the User Manager’s ribbon. Insert a new item based on the template <code>System/Ribbon/Small button</code> and name it “Reset Custom Properties”. Fill in the fields as follows:</p>
<table border="0" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<th valign="top" width="250">Field</th>
<th valign="top" width="250">Value</th>
</tr>
<tr>
<td valign="top" width="250">Header</td>
<td valign="top" width="250">Reset Custom Properties</td>
</tr>
<tr>
<td valign="top" width="250">Icon</td>
<td valign="top" width="250">Applications/32&#215;32/notebook_preferences.png</td>
</tr>
<tr>
<td valign="top" width="250">Click</td>
<td valign="top" width="250">usermanagercust:resetcustomprops</td>
</tr>
</tbody>
</table>
<p>&#160;</p>
<p>The <code>Header</code> and <code>Icon</code> fields are shown on the ribbon. The <code>Click</code> field refers to a Sitecore command which we’ll define in one moment. Your item should look like this:</p>
<p><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://adeneys.files.wordpress.com/2012/08/image.png?w=594&#038;h=484" width="594" height="484" /></p>
<p>The <code>Click</code> field contains the name of a Sitecore command to execute. Sitecore will match this command to a command in the <code>/configuration/sitecore/commands</code> configuration element by name. By default, Sitecore defines all it’s commands in the <code>App_Config\Commands.config</code> file. But we’ll define our command in a config patch file so we don’t update any Sitecore provided files. Create a new file at <code>App_Config\Include\CustomCommands.config</code> and enter the following:</p>
<pre><code>&lt;configuration xmlns:patch=&quot;http://www.sitecore.net/xmlconfig/&quot;&gt;
  &lt;sitecore&gt;
    &lt;commands&gt;
      &lt;command name=&quot;usermanager:resetcustomprops&quot;
        type=&quot;Demo.Commands.ResetCustomProperties,Demo&quot;/&gt;
    &lt;/commands&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;</code></pre>
<p>The <code>type</code> in the command definition refers to the Command type to instantiate and execute. Now onto creating our custom command type. Compile the following code in Visual Studio and drop the resulting assembly into the <code>bin</code> folder. The following code is just the shell of the command, wired up to show everything working.</p>
<pre><code>using Sitecore.Shell.Framework.Commands;
using Sitecore.Web.UI.Sheer;

namespace Demo.Commands
{
  public class ResetCustomProperties : Command
  {
    public override void Execute(CommandContext context)
    {
      SheerResponse.Alert(&quot;ResetCustomProperties&quot;);
    }
  }
}</code></pre>
<p>In the code above we define a new class which implements the abstract class <code>Sitecore.Shell.Framework.Commands.Command</code>. The <code>Execute()</code> method is called when the user clicks the command in the Sitecore UI, so this is where we implement our logic. In the above code, I’m simply telling the client page to display a javascript alert to the user to prove the code was called through the user of the <code>SheerResponse.Alert()</code> method.</p>
<p>Now when I open the user manager in Sitecore I see our new custom ribbon button displayed and if I click it I see the alert message from our command class.</p>
<p><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Custom user editor command" border="0" alt="Custom user editor command" src="http://adeneys.files.wordpress.com/2012/08/custom-user-editor-command.png?w=594&#038;h=424" width="594" height="424" /></p>
<p>The above shows the basics for extending the ribbon with new commands. We could implement the logic to fulfil the command inside the <code>Execute()</code> method, but if we have an operation that will take some time to complete, this approach would provide no feedback to the user and would lock the UI as a postback is processing. To make it more usable and non-blocking we can leverage techniques from my article <a href="http://adeneys.wordpress.com/2011/03/17/long-running-process-options/" target="_blank">Long Running Process Options</a>. The technique I’ll implement for this scenario is using the Progress Box.</p>
<pre><code>using Sitecore.Security.Accounts;
using Sitecore.Shell.Applications.Dialogs.ProgressBoxes;
using Sitecore.Shell.Framework.Commands;

namespace Demo.Commands
{
  public class ResetCustomProperties : Command
  {
    public override void Execute(CommandContext context)
    {
      ProgressBox.Execute(&quot;ResetCustomProperties&quot;,
        &quot;Reset Properties&quot;,
        new ProgressBoxMethod(ExecuteOperation),
        context.Parameters[&quot;username&quot;]);
    }

    protected void ExecuteOperation(params object[] parameters)
    {
      if(parameters == null || parameters.Length == 0)
        return;

      string username = parameters[0].ToString();
      if (!string.IsNullOrEmpty(username))
      {
        var user = User.FromName(username, false);
        if (user != null)
        {
          if (Sitecore.Context.Job != null)
            Sitecore.Context.Job.Status.Messages.Add(
              &quot;Resetting properties for user &quot; + username);

          user.Profile.RemoveCustomProperty(&quot;prop1&quot;);
          user.Profile.RemoveCustomProperty(&quot;prop2&quot;);
          user.Profile.RemoveCustomProperty(&quot;prop3&quot;);
        }
      }
    }
  }
}</code></pre>
<p>In the above code, we’ve used the static <code>Execute()</code> method of the <code>ProgressBox</code> class to create a progress dialog box on the Sitecore client page. The last two parameters of the method are the delegate to run and any parameters to pass. The <code>username</code> parameter in the <code>Parameters</code> property of the command context is set by the User Manager application. The delegate is run inside a Sitecore job. The progress box reads the status of the job and outputs relevant information on the dialog.</p>
<p><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="reset user properties" border="0" alt="reset user properties" src="http://adeneys.files.wordpress.com/2012/08/reset-user-properties.png?w=594&#038;h=424" width="594" height="424" /></p>
<p>So you can see how easy it is to add options to a Sitecore ribbon. For item based commands the <code>Items</code> property of the command context can be used instead of a value from the <code>Parameters</code> property.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/350/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/350/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=350&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/08/26/adding-options-to-sitecore-applications/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/08/image.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/08/custom-user-editor-command.png" medium="image">
			<media:title type="html">Custom user editor command</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/08/reset-user-properties.png" medium="image">
			<media:title type="html">reset user properties</media:title>
		</media:content>
	</item>
		<item>
		<title>Redirect Options</title>
		<link>http://adeneys.wordpress.com/2012/07/22/redirect-options/</link>
		<comments>http://adeneys.wordpress.com/2012/07/22/redirect-options/#comments</comments>
		<pubDate>Sun, 22 Jul 2012 11:38:59 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=345</guid>
		<description><![CDATA[I almost can’t remember the last time I built a website and it was the first for an organisation. The ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/07/22/redirect-options/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=345&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I almost can’t remember the last time I built a website and it was the first for an organisation. The internet is old enough now that everyone already has a website, so new builds now are to replace an existing web presence. Whenever replacing an existing site we need to consider how the changes could impact on Search Engine Optimisation (SEO) and in particular, how to maintain whatever rank your pages have already achieved.</p>
<p>One particular challenge in preserving the page rank is if the information architecture (page structure) of the new site will be different to the old. Search engines aside, you still need to help users of your site find their way in the new site. Perhaps it’s not a new site we’re building but instead we’re binding a new domain to the website and need traffic to be directed through to the new domain. In addition, what about existing incoming site links from other sites and user’s bookmarks. These also need to be preserved.</p>
<p>The most common tool of choice for this challenge is redirects. And more often than not, permanent (301) redirects. A 301 redirect instructs the users browser or the search engine that the particular resource they’ve requested has moved permanently to a different location. This helps the user get to the page they were after at the new location as well as having the search engines update their references to your site and it’s URLs.</p>
<p>There are a plethora of redirect options available when working with a Sitecore project. So which to choose…</p>
<p>The first question to answer is if the content author will be managing the redirects or an administrator. At the simplest, a redirect rule will contain a 1 to 1 relationship between the old page URL and the new page URL. And it only gets more complex from there:</p>
<p>“If the user enters on domain 1 and requests anything from the news section, they should redirect to the news search page with the page name prepopulated in the search field”</p>
<p>Something like the above rule would probably be too complex for a content author (well, a non-technical user) to manage. And after all, that’s not their job anyway. They should be focusing on the content.</p>
<p>Some questions to consider when choosing a redirect option:</p>
<ul>
<li>Will administrators be managing the redirects or CMS users? </li>
<li>Will redirects be done 1 to 1 or will we need to implement complex rules? </li>
<li>Is the target Sitecore item likely to change name or path? </li>
</ul>
<ul>Below is a list of several redirect modules which you could use to help manage the redirect rules.</ul>
<h2>Administrator Modules</h2>
<p>The below modules are more appropriate for administrators or developers as they are both configured through the web.config file (or the IIS admin console for IIS URL Rewrite).</p>
<p>These modules are appropriate for all your complex rules that can cover many cases, or if only the administrator will be managing the rules.</p>
<h3>IIS URL Rewrite</h3>
<p>The <a href="http://www.iis.net/download/urlrewrite" target="_blank">IIS URL Rewrite</a> module is an official Microsoft module for IIS. It allows administrators and developers to manage redirect rules either through IIS itself or through web configuration files. This module is good for complex rules as well as any rule to do with domain redirects. It can also handle request rewriting, presenting your application with a different URL than was requested by the user.</p>
<p>Let me just give you a quick example of when that might be useful. Let’s say we’re adding a language variant to our site. The main English site is hosted at <a href="http://www.mysite.com" rel="nofollow">http://www.mysite.com</a> and now we’re adding a German version at <a href="http://www.mysite.de" rel="nofollow">http://www.mysite.de</a>. Another SEO best-practise is to provide an XML sitemap file to help robots navigate all the pages of your site. A handy module for automatically generating this file in Sitecore is the <a href="http://trac.sitecore.net/SitemapXML" target="_blank">Sitemap XML module</a>.</p>
<p>Now although we can have multiple different sitemap.xml files of different names, all referenced from the robots.txt file, for some reason I want the language specific sitemap.xml files to be served from their respective domains. Using IIS URL Rewrite I can rewrite any requests for the sitemap.xml file for either domain to a different filename. To the outside world it looks like I’ve requested <a href="http://www.mysite.de/sitemap.xml" rel="nofollow">http://www.mysite.de/sitemap.xml</a> but the URL that my application sees is <a href="http://www.mysite.de/sitemap-de.xml" rel="nofollow">http://www.mysite.de/sitemap-de.xml</a>.</p>
<p>Being that this module is an IIS module, it must be installed. It’s also only available for IIS 7. So if you’re working on IIS 6 or previous, or if you don’t have access to install anything on your web server then perhaps the next module can help.</p>
<h3>UrlRewriter.net</h3>
<p>This one has been around a while, but can still come in handy when you’re running on IIS before version 6 or if you can’t install anything on your web server.</p>
<p><a href="http://urlrewriter.net/" target="_blank">UrlRewriter.net</a> is an HTTP Module handling redirect and rewriting rules from within your ASP.NET application. Because it’s a module it doesn’t need to be installed, simply drop the DLL (which you’ll need to compile from source) into the bin folder, some web.config updates and the module will be handling your requests.</p>
<p>I have in some cases had issues with this module cooperating with Sitecore. For example, when a request is made for an item which doesn’t exist in Sitecore and a rule is matched which produces a redirect, Sitecore would override the redirect with it’s own to the “item not found” URL. But seeing as though you need to compile the module from source, you can easily update that source before compiling to complete the current HTTP request before Sitecore get’s a go (call <code>HttpContext.Current.ApplicationInstance.CompleteRequest()</code> after the redirect is set).</p>
<h2>CMS Modules</h2>
<h1></h1>
<p>If you need authors to be able to manage the redirects or if you don’t have easy access to the config files, then you’ll need to expose the redirect functionality through Sitecore itself. And there are several modules available to handle your redirects inside Sitecore too.</p>
<p>One benefit some of the CMS modules have over the administrator modules is that you’re dealing with Sitecore items now, referencing them by ID rather than simple URLs in strings. This means that if the target item name changes, or if it’s path changes, the redirect doesn’t break and doesn’t need to be updated.</p>
<h3></h3>
<h3>301 Redirect Module</h3>
<p>The <a href="http://trac.sitecore.net/301RedirectModule" target="_blank">301 Redirect Module</a> allows creating both 1 to 1 mappings from old URLs to items as well as creating regular expression based redirects allowing a single rule to map multiple URLs onto multiple items.</p>
<p>The 1 to 1 mappings allow selecting a target item using a droptree field. The value of this field is an ID, so the rule will be resilient to name and path changes of the target item.</p>
<p>The regular expression rules (redirect-pattern rule) uses a regular expression to match the incoming URL and makes use of capture groups to perform a regular expression replacement to a Sitecore path.</p>
<p>The redirect rules are created inside the Sitecore content tree so they are easy to backup (serialise via the Developer tab in the content editor), put into source control through <a href="http://www.hhogdev.com/Products/Team-Development-for-Sitecore/Overview.aspx" target="_blank">TDS</a> or package and deploy via the Sitecore package manager.</p>
<h3></h3>
<h3>Redirect Manager Module</h3>
<p>The <a href="http://redirectmanager.codeplex.com/" target="_blank">Redirect Manager Module</a> allows creating 1 to 1 URL to item mappings. It includes UI integration with the content editor to easily display what redirects are pointing at the current item.</p>
<p>This module also supports “automatic redirects”, detecting when an item is moved or renamed and adding a redirect rule to ensure requests for the previous path still resolve to the item.</p>
<p>Unlike the other CMS modules the rules are stored in a SQL DB. This makes it a little harder to backup the rules (you can always use SQL tools to backup the DB), put them in source control or move the rules between servers.</p>
<h3></h3>
<h3>Sitecore Redirect Manager Module</h3>
<p>The <a href="http://trac.sitecore.net/SitecoreRedirectManager/" target="_blank">Sitecore Redirect Manager Module</a> is very similar to the 301 Redirect Module in that it allows creating rules to map between URLs and items.</p>
<h3></h3>
<h3></h3>
<h2>Conclusion</h2>
<p>The above gives a few options for implementing redirects on your Sitecore site and the reasons to use each.</p>
<p>I generally prefer to handle the redirects using the IIS URL Rewrite module as I normally find that most content authors don’t want to think about redirects and don’t need to manage them themselves. To be honest, I’ve never received a request from any content author to be able to create redirects themselves, this is normally an administrator task.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/345/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/345/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=345&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/07/22/redirect-options/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>
	</item>
		<item>
		<title>Custom WFM Action Settings UI</title>
		<link>http://adeneys.wordpress.com/2012/06/29/custom-wfm-action-settings-ui/</link>
		<comments>http://adeneys.wordpress.com/2012/06/29/custom-wfm-action-settings-ui/#comments</comments>
		<pubDate>Fri, 29 Jun 2012 09:27:58 +0000</pubDate>
		<dc:creator>Alistair Deneys</dc:creator>
				<category><![CDATA[Sitecore]]></category>

		<guid isPermaLink="false">https://adeneys.wordpress.com/?p=343</guid>
		<description><![CDATA[The Sitecore WebForms for Marketers (WFM) module is a great module providing content authors the ability to create and edit ... <br /><a class="more-link" href="http://adeneys.wordpress.com/2012/06/29/custom-wfm-action-settings-ui/">Continue reading</a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=343&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>The Sitecore <a href="http://sdn.sitecore.net/Products/Web%20Forms%20for%20Marketers.aspx" target="_blank">WebForms for Marketers</a> (WFM) module is a great module providing content authors the ability to create and edit their own simple data collection forms without having to tap a developer. It comes with a range of prebuilt “actions” which act on the data being submitted through the form. The most common actions would probably be the “save to database” action which saves the submitted form data to the WFM database for retrieval through the WFM form reports application and the “email” action which emails the submitted form data to a specified email address.</p>
<p>So what happens when you want to do something different with the data which the out-of-the-box actions can’t handle? Let’s say we have an internal legacy system exposing a web service which we need to submit the data into. One way to achieve that would be to create a custom sublayout which statically defines the fields to collect and ties them to the integration to the legacy system. But this will mean any changes required by the content authors will need to be done by a developer. No, we want to leverage WFM so the content author can make those updates themselves.</p>
<p>Like most things in Sitecore, WFM is quite extensible, and we can create our own actions to be used in forms and configured by content authors. To create a custom WFM action:</p>
<ol>
<li>Install the latest WFM module </li>
<li>Create a new class implementing the <code>Sitecore.Form.Submit.ISaveAction</code> interface </li>
<li>Register the action for use with the WFM module by creating a new item based on the <code>/sitecore/templates/Web Forms for Marketers/Actions/Submit Action</code> template under <code>/sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions</code> </li>
</ol>
<p>So, let’s start with creating an action class which will submit data to that aforementioned legacy web service.</p>
<pre><code>using System.Collections.Specialized; 
using Sitecore; 
using Sitecore.Data; 
using Sitecore.Form.Core.Client.Data.Submit; 
using Sitecore.Form.Core.Controls.Data; 
using Sitecore.Form.Submit;

namespace CustomWFMAction 
{ 
  public class SendToWebService : ISaveAction 
  { 
    public void Execute(ID formid, AdaptedResultList fields,
      params object[] data) 
    {
      // Extract the email field
      var email = fields.GetEntryByName(&quot;Email&quot;).Value;

      // Get list of additional fields to send
      var submitFields = new NameValueCollection(); 

      foreach(AdaptedControlResult field in fields) 
      {
        if(field.FieldName != &quot;Email&quot;)
          submitFields.Add(field.FieldName, field.Value); 
      }

      // Submit data to web service
      var client = new TestService.ServiceSoapClient(); 
      client.SubmitData(email, StringUtil.NameValuesToString(submitFields,
        &quot;&amp;&quot;)); 
    }
  } 
} </code></pre>
<p>Custom actions should implement the <code>Sitecore.Forms.Submit.ISaveAction</code> interface. This interface exposes a single method, the <code>Execute()</code> method which we’ve implemented above. In the above example we first extract the email field which must be sent in a specific parameter to the web service and then we loop through each of the submitted form fields which is passed in the parameter <code>fields, </code>adding each to a <code>NameValueCollection</code> so we can easily format them in the correct format for the web service being submitted to.</p>
<p>Once we’ve written our custom action we need to register it with Sitecore. Create a new “Submit to test service” item based on the <code>/sitecore/templates/Web Forms for Marketers/Actions/Submit Action</code> template under the <code>/sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions</code> item to register the action with WFM and have it offer the action as an option in the form designer. Now you can create a test form to use the action on.</p>
<p><a href="http://adeneys.files.wordpress.com/2012/06/custom-action-definition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="custom action definition" border="0" alt="custom action definition" src="http://adeneys.files.wordpress.com/2012/06/custom-action-definition_thumb.png?w=560&#038;h=349" width="560" height="349" /></a></p>
<p>Although the above custom action does what it needs to, it’s not an ideal implementation. It’s quite brittle. The action has hard coded the field name containing the email address. If the form author changed the field name the email field wouldn’t be found and the correct data would not be submitted to the web service. It would be better if the action found the email field by ID rather than name so if the name changes the form still works. Also, we may not want to submit all the fields to the web service. It would be good to allow the author to select the fields to submit.</p>
<p>Let’s update the custom action to allow passing the email address field name and fields to send to the web service through the parameters of the action.</p>
<pre><code>using System.Collections.Specialized; 
using System.Linq; 
using Sitecore; 
using Sitecore.Data; 
using Sitecore.Form.Core.Client.Data.Submit; 
using Sitecore.Form.Core.Controls.Data; 
using Sitecore.Form.Submit;

namespace CustomWFMAction 
{ 
  public class SendToWebService : ISaveAction 
  { 
    public string EmailField 
    { 
      get; 
      set; 
    }

    public string FieldsToSend 
    { 
      get; 
      set; 
    }

    public void Execute(ID formid, AdaptedResultList fields,
      params object[] data) 
    {
      // Extract the email field 
      var email = fields.GetEntryByName(EmailField).Value;

      // Get list of additional fields to send 
      var submitFields = new NameValueCollection(); 
      var fieldNamesToSubmit = (FieldsToSend ?? &quot;&quot;).Split(',');

      foreach(AdaptedControlResult field in fields) 
      { 
        if (fieldNamesToSubmit.Contains(field.FieldName)) 
          submitFields.Add(field.FieldName, field.Value); 
      }

      // Submit data to web service
      var client = new TestService.ServiceSoapClient(); 
      client.SubmitData(email, StringUtil.NameValuesToString(submitFields,
        &quot;&amp;&quot;)); 
    }
  } 
}</code></pre>
<p>We can set the properties of the custom action by setting them in the <code>Parameters</code> field of the action definition item. Each property is set in an XML fragment with the element name matching the property name of the class. WFM will handle setting these properties of the class when it instantiates it.</p>
<pre><code>&lt;EmailField&gt;email&lt;/EmailField&gt; 
&lt;FieldsToSend&gt;Category,Query&lt;/FieldsToSend&gt;</code></pre>
<p>Now although the above example let’s us set the properties of the custom action class, it sets the properties for all instances of the action and doesn’t allow changing the value for an individual form. It’s also not a good solution for the authors who may not be up to editing XML directly. To allow the authors to set these properties per form, we’ll need to provide an editor for the action.</p>
<p>The custom editor will be written using Sheer UI. Below is the XML layout file used for the editor.</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt; 
&lt;control xmlns=&quot;http://schemas.sitecore.net/Visual-Studio-Intellisense&quot; 
  xmlns:def=&quot;Definition&quot; 
  xmlns:asp=&quot;http://www.sitecore.net/microsoft/webcontrols&quot;&gt; 
  &lt;SendToWebServiceSettings&gt; 
    &lt;FormDialog ID=&quot;Dialog&quot; Icon=&quot;Applications/32x32/gear.png&quot;
      Header=&quot;Web Service Settings&quot;
      Text=&quot;Enter the settings for the web service submission&quot;&gt; 
      &lt;CodeBeside
        Type=&quot;CustomWFMAction.SendToWebServiceSettings,CustomWFMAction&quot;/&gt; 
      &lt;GridPanel Class=&quot;scfContent&quot; Columns=&quot;2&quot;
        Margin=&quot;20 15 10 15&quot; Width=&quot;100%&quot;&gt; 
        &lt;Literal Text=&quot;Email Field:&quot; GridPanel.Align=&quot;right&quot;/&gt; 
        &lt;Listbox ID=&quot;EmailFieldName&quot; Width=&quot;97%&quot;
          GridPanel.Width=&quot;80%&quot;/&gt; 
        &lt;Literal Text=&quot;Additional fields to submit:&quot;
          GridPanel.Align=&quot;right&quot;/&gt; 
        &lt;Checklist ID=&quot;Fields&quot; Width=&quot;97%&quot;
          GridPanel.Width=&quot;80%&quot; /&gt; 
      &lt;/GridPanel&gt; 
    &lt;/FormDialog&gt; 
  &lt;/SendToWebServiceSettings&gt; 
&lt;/control&gt;</code></pre>
<p>And we’ll also need the code beside class.</p>
<pre><code>using System; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.Linq; 
using System.Web; 
using Sitecore; 
using Sitecore.Configuration; 
using Sitecore.Form.Core.Utility; 
using Sitecore.Forms.Core.Data; 
using Sitecore.Web.UI.HtmlControls; 
using Sitecore.Web.UI.Pages; 
using Sitecore.Web.UI.Sheer;

namespace CustomWFMAction 
{ 
  public class SendToWebServiceSettings : DialogForm 
  { 
    protected Listbox EmailFieldName; 
    protected Checklist Fields;

    protected override void OnLoad(EventArgs e) 
    { 
      base.OnLoad(e); 
      if (!Context.ClientPage.IsEvent) 
      { 
        // Populate WFM fields into settings form fields 
        PopulateFormFields(); 
      } 
    }

    private void PopulateFormFields() 
    { 
      // Read already configured parameters 
      var parametersKey = Sitecore.Web.WebUtil.GetQueryString(&quot;params&quot;); 
      var parameterString = HttpContext.Current.Session[parametersKey] as string; 
      var parameters = ParametersUtil.XmlToNameValueCollection(parameterString);

      // Get the email field 
      var emailField = parameters[&quot;EmailField&quot;] ?? string.Empty;

      // Get the additional fields to send 
      var fieldsToSend = new string[0]; 
      if (!string.IsNullOrEmpty(parameters[&quot;FieldsToSend&quot;])) 
        fieldsToSend = parameters[&quot;FieldsToSend&quot;].Split(',');

      // Populate options from the form definition 
      var db = Factory.GetDatabase(Sitecore.Web.WebUtil.GetQueryString(&quot;db&quot;)); 
      var formId = Sitecore.Web.WebUtil.GetQueryString(&quot;id&quot;); 
      var form = new FormItem(db.GetItem(formId)); 

      if (form != null) 
      { 
        // Iterate WFM form fields 
        foreach (var field in form.Fields) 
        { 
          // Add field to email droplist 
          EmailFieldName.Controls.Add(new ListItem() { 
            Header = field.Name, 
            Selected = field.Name == emailField, 
            ID = Control.GetUniqueID(&quot;efn&quot;), 
            Value = field.ID.ToString() 
          });

          // Add field to additional fields to send 
          Fields.Controls.Add(new ChecklistItem 
          { 
            Header = field.Name, 
            Checked = fieldsToSend.Contains(field.ID.ToString()), 
            Value = field.ID.ToString() 
          }); 
        }
      } 
    }

    protected override void OnOK(object sender, EventArgs args) 
    { 
      // Get list of selected additional fields to send 
      var selectedFields = new List&lt;string&gt;();

      foreach (var item in Fields.Items) 
      { 
        if(item.Checked) 
          selectedFields.Add(item.Value); 
      }

      // Get XML fragment of settings to store 
      SheerResponse.SetDialogValue( 
        ParametersUtil.NameValueCollectionToXml(new NameValueCollection() 
          { 
            {&quot;EmailField&quot;, EmailFieldName.SelectedItem.Value}, 
            {&quot;FieldsToSend&quot;, string.Join(&quot;,&quot;, selectedFields)} 
          }));

      base.OnOK(sender, args); 
    }
  } 
}</code></pre>
<p>Note in the above code example in the <code>OnOK()</code> method that we’re constructing an XML fragment of the settings. By saving the settings in XML they’re already in the format expected by WFM and it will auto populate these properties on the custom action when it’s instantiated by WFM.</p>
<p>To register this control as the editor for the action, add a reference to this Sheer UI control in the <code>editor</code> field of the action definition item. Remember, in order to refer to a control in Sheer UI we reference the name of the child element of the root control element inside the XML layout file, in this case <code>SendToWebServiceSettings</code>.</p>
<p><a href="http://adeneys.files.wordpress.com/2012/06/custom-action-editor-definition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="custom action editor definition" border="0" alt="custom action editor definition" src="http://adeneys.files.wordpress.com/2012/06/custom-action-editor-definition_thumb.png?w=566&#038;h=417" width="566" height="417" /></a></p>
<p>With the editor field populated the edit button will now be enabled when the action is selected in the <code>save actions</code> dialog box.</p>
<p><a href="http://adeneys.files.wordpress.com/2012/06/save-actions.png"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="save actions" border="0" alt="save actions" src="http://adeneys.files.wordpress.com/2012/06/save-actions_thumb.png?w=480&#038;h=441" width="480" height="441" /></a></p>
<p>And clicking the edit button will open the custom settings editor.</p>
<p><a href="http://adeneys.files.wordpress.com/2012/06/custom-editor.png"><img style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;margin-left:auto;margin-right:auto;padding-top:0;border-width:0;" title="custom editor" border="0" alt="custom editor" src="http://adeneys.files.wordpress.com/2012/06/custom-editor_thumb.png?w=474&#038;h=369" width="474" height="369" /></a></p>
<p>And now we have a user friendly editor for the settings of our custom action. But it’s not just about presenting a friendly UI, this editor has made the action more robust, allowing authors to change the names of fields in the WFM and then use this UI to map the required data for the action.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/adeneys.wordpress.com/343/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/adeneys.wordpress.com/343/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=adeneys.wordpress.com&#038;blog=3885947&#038;post=343&#038;subd=adeneys&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://adeneys.wordpress.com/2012/06/29/custom-wfm-action-settings-ui/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/b4591048ba49c1111162c1db646f4147?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Alistair Deneys</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/06/custom-action-definition_thumb.png" medium="image">
			<media:title type="html">custom action definition</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/06/custom-action-editor-definition_thumb.png" medium="image">
			<media:title type="html">custom action editor definition</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/06/save-actions_thumb.png" medium="image">
			<media:title type="html">save actions</media:title>
		</media:content>

		<media:content url="http://adeneys.files.wordpress.com/2012/06/custom-editor_thumb.png" medium="image">
			<media:title type="html">custom editor</media:title>
		</media:content>
	</item>
	</channel>
</rss>
