<?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/"
	>

<channel>
	<title>Codality &#187; Internet Information Services</title>
	<atom:link href="http://blog.najmanowicz.com/category/software-development/internet-information-services/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.najmanowicz.com</link>
	<description>Code and Effect - solving problem with just enough amount of code - by Adam Najmanowicz</description>
	<lastBuildDate>Mon, 08 Feb 2010 12:01:38 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Get out of my way! &#8230; or the story of file metadata for VirtualPathProvider in EPiServer</title>
		<link>http://blog.najmanowicz.com/2009/03/17/get-out-of-my-way-or-the-story-of-file-metadata-for-virtualpathprovider-in-episerver/</link>
		<comments>http://blog.najmanowicz.com/2009/03/17/get-out-of-my-way-or-the-story-of-file-metadata-for-virtualpathprovider-in-episerver/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 00:18:00 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Code Samples]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Solution]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2009/03/17/get-out-of-my-way-or-the-story-of-file-metadata-for-virtualpathprovider-in-episerver/</guid>
		<description><![CDATA[Immediately after you implement the VirtualPathProvider proxy from my previous post you will notice a one fairly serious lack in it. Namely all the files within that provider will be hiding behind the registration form. That is not cool for a couple of reasons…

You may want to keep all of the files in one store [...]]]></description>
			<content:encoded><![CDATA[<p>Immediately after you implement the VirtualPathProvider proxy from my previous post you will notice a one fairly serious lack in it. Namely all the files within that provider will be hiding behind the registration form. That is not cool for a couple of reasons…</p>
<ul>
<li>You may want to keep all of the files in one store – being forced to put them into a designated folder is not desired. </li>
<li>You may want to make some file freely available for some time and lock it after a while, or the other way around (e.g. to allow the robots to crawl it initially). having to move them is just silly and defeats the purpose. </li>
</ul>
<p>So how do you discriminate the files that you want locked from those that you want to be publically available, and potentially from those that you want only the logged in users to be able to get?</p>
<h2></h2>
<h2>Specifying the EPiServer File Metadata sweetness</h2>
<p>One of the potential solutions would be to define a special rights group and check for that group for the people that have your “registered” magic-cookie. That however introduces a bogus group, and I would rather like to avoid that. However if you look into the <strong><em>FileSummary.config</em></strong> file that’s located in your web application folder you will find a slightly mysterious content. A bit of hacking reveals that you can actually add your own metadata to the file. For example adding the access rights based on what I’ve established above would look as follows (the content you can already find in the file that comes with the public templates that-we-all-oh-so-love is skipped):</p>
<p><span id="more-120"></span></p>
<pre>
<div style="font-family: courier new; background: white; color: black; font-size: 8pt">
<span style="color: blue">&lt;</span><span style="color: #a31515">root</span><span style="color: blue"> </span><span style="color: red">xmlns:xforms</span><span style="color: blue">=</span>&quot;<span style="color: blue">http://www.w3.org/2002/xforms</span>&quot;<span style="color: blue"> </span>
<span style="color: blue">      </span><span style="color: red">xmlns:xsi</span><span style="color: blue">=</span>&quot;<span style="color: blue">http://www.w3.org/2001/XMLSchema-instance</span>&quot;<span style="color: blue">&gt;</span>

<span style="color: blue">  &lt;</span><span style="color: #a31515">model</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;</span><span style="color: #a31515">instance</span><span style="color: blue">&gt;</span>
      ...
<span style="color: blue">      &lt;</span><span style="color: #a31515">AccessLevel</span><span style="color: blue"> /&gt;</span>
<span style="color: blue">    &lt;/</span><span style="color: #a31515">instance</span><span style="color: blue">&gt;</span>
<span style="color: blue">  &lt;/</span><span style="color: #a31515">model</span><span style="color: blue">&gt;</span>

  ...
<span style="color: blue">  &lt;</span><span style="color: #a31515">xforms:select1</span><span style="color: blue"> </span><span style="color: red">appearance</span><span style="color: blue">=</span>&quot;<span style="color: blue">full</span>&quot;<span style="color: blue"> </span>
<span style="color: blue">                  </span><span style="color: red">ref</span><span style="color: blue">=</span>&quot;<span style="color: blue">AccessLevel</span>&quot;<span style="color: blue"> </span><span style="color: red">id</span><span style="color: blue">=</span>&quot;<span style="color: blue">id_field51</span>&quot;<span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>Unrestricted<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>Unrestricted<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;/</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>Requires Registration<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>RequireRegistration<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;/</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>Requires CMS Login<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:label</span><span style="color: blue">&gt;</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>LoggedUserAccess<span style="color: blue">&lt;/</span><span style="color: #a31515">xforms:value</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;/</span><span style="color: #a31515">xforms:item</span><span style="color: blue">&gt;</span>
<span style="color: blue">  &lt;/</span><span style="color: #a31515">xforms:select1</span><span style="color: blue">&gt;</span>
  ...

<span style="color: blue">&lt;/</span><span style="color: #a31515">root</span><span style="color: blue">&gt;</span></div>
</pre>
<p>Great. So what does it look in the file manager now?</p>
<p align="center"><a href="http://blog.najmanowicz.com/wp-content/uploads/2009/03/metadataeditor.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="metadata-editor" border="0" alt="metadata-editor" src="http://blog.najmanowicz.com/wp-content/uploads/2009/03/metadataeditor-thumb.png" width="518" height="355" /></a> </p>
<p>Splendid!</p>
<h2>Accessing the metadata</h2>
<p>Now that we gave the user to specify the metadata, we need the VPP to act upon them. For the benefit of automation of parsing I’ve specified the enum defining the access levels as follows:</p>
<pre>
<div style="font-family: courier new; background: white; color: black; font-size: 8pt">
<span style="color: blue">enum</span> <span style="color: #2b91af">FileAccessLevel</span>
{
    Unrestricted,
    RequireRegistration,
    LoggedUserAccess
}
</div>
</pre>
<p>Now we need to update the GetFile method to discriminate the access levels (I have decorated the core lines with <font color="#ff0000">&#8211;<strong>&gt;</strong></font>) those are the lines that access the meta data based on their format specified in the <strong><em>FileSummary.config</em></strong>.</p>
<pre class="brush: csharp; highlight: [11, 12, 13]">
public override VirtualFile GetFile(string virtualPath)
{
    string handledPath;

    if (TryGetHandledAbsolutePath(virtualPath, out handledPath))
    {
        UnifiedFile file = base.GetFile(virtualPath) as UnifiedFile;

        if (file != null)
        {
            string strAccessLevel = (string) file.Summary.Dictionary["AccessLevel"] ??
                                    FileAccessLevel.RequireRegistration.ToString();
            FileAccessLevel accessLevel = (FileAccessLevel) Enum.Parse(typeof (FileAccessLevel), strAccessLevel);

            bool isLoggedIn = HttpContext.Current.Profile != null &#038;&#038; !HttpContext.Current.Profile.IsAnonymous;
            bool isRegistered = HttpContext.Current.Request.Cookies.AllKeys.Contains(PASS_COOKIE_NAME);
            string email = isRegistered ? HttpContext.Current.Request.Cookies[PASS_COOKIE_NAME].Value :
                (isLoggedIn ? HttpContext.Current.Profile.UserName : "unregistered");

            switch (accessLevel)
            {
                case (FileAccessLevel.Unrestricted):
                    return file;
                    break;
                case(FileAccessLevel.RequireRegistration):
                    if (!isRegistered &#038;&#038; ! isLoggedIn)
                    {
                        HttpContext.Current.Response.Redirect(
                            string.Format(registrationFormUrl,
                                          HttpContext.Current.Server.HtmlEncode(virtualPath)));
                        return null;
                    }
                    return file;
                    break;
                case(FileAccessLevel.LoggedUserAccess):
                    if (isLoggedIn)
                    {
                        return file;
                    }
                    return null;
                    break;
                default:
                    return file;
            }
        }
    }
    return Previous.GetFile(virtualPath);
}
</pre>
<p>Now the user is really in control of what is published to the general public and robots, what is protected with the registration form and what is only available to logged in users. (now you may add more granularity with file rights naturally, this is just a basic setting that an editor without administrative rights can add.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=120&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2009/03/17/get-out-of-my-way-or-the-story-of-file-metadata-for-virtualpathprovider-in-episerver/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WebParts based Sidebar for EPiServer &#8211; how to use it?</title>
		<link>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-how-to-use-it/</link>
		<comments>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-how-to-use-it/#comments</comments>
		<pubDate>Thu, 08 Jan 2009 17:06:47 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Downloadable]]></category>
		<category><![CDATA[EPiCode]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>
		<category><![CDATA[WebParts]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-how-to-use-it/</guid>
		<description><![CDATA[Once you’ll update the framework to the extended one, you will immediately notice that… nothing has changed. Hmm… did something go wrong? 
Well, not really. By default the framework will be run in the “legacy mode”. Thanks to an old article by our own Marek Blotny, I’ve learned how to build Plugin settings which are [...]]]></description>
			<content:encoded><![CDATA[<p>Once you’ll update the framework to the extended one, you will immediately notice that… nothing has changed. Hmm… did something go wrong? </p>
<p>Well, not really. By default the framework will be run in the “legacy mode”. Thanks to <a href="http://marekblotny.blogspot.com/2008/07/plugins-and-datafactory-event-handlers.html">an old article by our own Marek Blotny</a>, I’ve learned how to build Plugin settings which are just perfect for the purpose!</p>
<p align="left">So to configure and enable the new features you need to open your admin UI and in the “Config” click on the “Plugin Manager” item and select our framework plugin as shown in the picture</p>
<p align="center"><a href="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings1.png"><img title="WebPartFrameworkPluginSettings1" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="164" alt="WebPartFrameworkPluginSettings1" src="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings1-thumb.png" width="244" border="0" /></a></p>
<p>The available options are:</p>
<p><span id="more-110"></span><br />
<table cellspacing="0" cellpadding="2" border="0">
<tbody>
<tr>
<td><b>Setting Name</b></td>
<td><b>Meaning</b></td>
<td><b>Sample</b></td>
</tr>
<tr>
<td><b><i>Default WebParts Path Pattern</i></b></td>
<td>The pattern to be used when no pattern is defined for a page.</td>
<td>%inherit%</td>
</tr>
<tr>
<td><b><i>WebParts Path Patterns</i></b></td>
<td>The semicolon separated pairs of pattern;pattern name;          <br />This is the part you will want to customize most.</td>
<td>%template%|%pageid%%legacyregion%;Legacy regionalized;%template%|%pageid%;Legacy globalized;page|%pageid%|%region%;Page/region;pagetype|%pagetypeid%;Page Type</td>
</tr>
<tr>
<td><b><i>Cache WebParts in Memory</i></b></td>
<td>Determines whether the WebParts are to be cached&#160; between usages (this is useful for a small set of WebParts (like a number of sidebars) but rather discouraged if you use the legacy mode as there can be a lot of those in such case.</td>
<td>unchecked by default (check to improve performance in sidebar mode)</td>
</tr>
<tr>
<td><b><i>Legacy WebParts Support (per-page only)</i></b></td>
<td>If checked, disables the extensions described by this blog.</td>
<td>checked by default (uncheck to enable the sidebar extensions)</td>
</tr>
</tbody>
</table>
<p>&#160;</p>
<p>As shown here:</p>
<p><a href="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings2.png"><img title="WebPartFrameworkPluginSettings2" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="179" alt="WebPartFrameworkPluginSettings2" src="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings2-thumb.png" width="244" border="0" /></a> </p>
<p>&#160;</p>
<p>Once you fill in the settings as they are suggested in the above table the context menu (or adjust to your needs) will show you the new options:</p>
<p align="center"><a href="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings3.png"><img title="WebPartFrameworkPluginSettings3" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="173" alt="WebPartFrameworkPluginSettings3" src="http://blog.najmanowicz.com/wp-content/uploads/2009/01/webpartframeworkpluginsettings3-thumb.png" width="244" border="0" /></a> </p>
</p>
<p>The new sub menu will allow you to change the pattern by which the WebParts are selected, while “Edit Web Parts” option will enable you to edit the WebParts for the current effective WebPart set.</p>
<p><font color="#ff0000"><strong>First of all – if you want to select a pattern on a page you need a means of storing it. At this moment The framework does it in a property. Which means &#8211; for every page type that wants to redefine the web parts rather than using the default pattern (in our case %inherited%) you need to add String property with a “WebPartsPath” name (I may actually add some routines to add the property definition automatically if there will be enough demand for that).</strong></font></p>
<h1>What does “Effective WebPart Set” mean?</h1>
<p>Assuming (which is the most interesting scenario) that %inherit% is the default pattern the following is true: </p>
<p>&#160;</p>
<table border="1">
<tbody>
<tr>
<td><b>Page</b></td>
<td><b>WebPartsPath</b></td>
<td><b>Effective path</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>Start</td>
<td>&#160;</td>
<td>%root%</td>
<td>Since it&#8217;s a start page and it does not define path %root% is used.</td>
</tr>
<tr>
<td>+ News</td>
<td>&#160;</td>
<td>%root%</td>
<td>inherits from start page which does not define path but inherits from %root%.</td>
</tr>
<tr>
<td>+ Events</td>
<td>page|%pageid%</td>
<td>page|5</td>
<td>directly implements its own pattern.</td>
</tr>
<tr>
<td>| + Partner Day</td>
<td>%inherit%</td>
<td>page|5</td>
<td>Inherits after its parent page.</td>
</tr>
<tr>
<td>+ International</td>
<td>page|%pageid%|%region%</td>
<td>page|6|en, page|6|se</td>
<td>Defines separate WebParts for every language that the page is created for.</td>
</tr>
<tr>
<td>| + Sweden</td>
<td>%inherit%</td>
<td>page|6|se</td>
<td>Inherits after its parent page in its own language.</td>
</tr>
<tr>
<td>| + England</td>
<td>%inherit%</td>
<td>page|6|en</td>
<td>Inherits after its parent page in its own language.</td>
</tr>
</tbody>
</table>
<p>Once you select the effective web parts for the page or just agree with the WebParts pre-selected for you based on the default path you can edit them just like previously. Mind that when you edit WebParts on a page all the pages that have the same “effective path” are going to change as well. (which was our intention in the first place).</p>
<p>&#160;</p>
<p>The library extension is going to be posted on Epicode as soon as I get a hold of Steve to approve the changes :)</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=110&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-how-to-use-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebParts based Sidebar for EPiServer &#8211; the motivation and specification</title>
		<link>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-the-motivation-and-specification/</link>
		<comments>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-the-motivation-and-specification/#comments</comments>
		<pubDate>Thu, 08 Jan 2009 14:04:12 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Downloadable]]></category>
		<category><![CDATA[EPiCode]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>
		<category><![CDATA[WebParts]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-the-motivation-and-specification/</guid>
		<description><![CDATA[Back in the day when we started designing our last project we’ve been presented with a following problem – a big number of templates with slightly different sidebars.
Hmm… 
Is sidebar a part of content? No, rather not. We don’t want the editors to have to setup the sidebar for every article they write (and the [...]]]></description>
			<content:encoded><![CDATA[<p>Back in the day when we started designing our last project we’ve been presented with a following problem – a big number of templates with slightly different sidebars.</p>
<p>Hmm… </p>
<p>Is sidebar a part of content? No, rather not. We don’t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).</p>
<p>Is sidebar more of a template thing? Well… more like it, but still… we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). <strong>But wait! There’s more!</strong> The sidebar will be different for every language (region). Now we’re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn’t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.</p>
<p>To a degree this is an academic discussion as we’ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won’t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it’s not a work a programmer will enjoy, and we all want to do new and more exciting things, don’t we?</p>
<p>We have an internally developed&#160; module to make something like that, that is fully home-grown by another internal team (we now have 3 “squads” capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It’s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but… frankly… about that time <a href="http://labs.episerver.com/en/Blogs/Ted-Nyberg/Dates/112276/8/Using-web-parts-in-EPiServer/">an article by Ted Nyberg</a> reminded me about a technology I have read about quite a while ago in <a href="http://labs.episerver.com/en/Blogs/Stein-Viggo-Grenersen/Dates/112262/2/EPiServer-on-steroids/">an article by Stein-Viggo Grenersen</a> and ooohhhhhh… I got seduced. I really wanted to try if for a long time and Ted’s article made it a snap to try and get convinced, and more important… convince Stu ;) that it’s the right way to explore.</p>
<h2>So I started to dig.</h2>
<p><span id="more-103"></span></p>
<h2></h2>
<p><a href="http://labs.episerver.com/en/Blogs/Stein-Viggo-Grenersen/Dates/112262/2/EPiServer-on-steroids/"><img style="display: inline; margin: 0px 10px 0px 0px" src="http://www.najmanowicz.com/blog_images/DragDropWebPartsmaller.gif" align="left" /></a>Talked with <a href="http://stevecelius.spaces.live.com/">Steve</a> (the original creator of the Framework) a bit and learned that I can “customize a path rewriter” to suit my needs. Great! I just hoped I won’t have to deal with some nasty GUID’s matching, but no! Turns out, all it takes to identify a WebPart set is to have any unique string naming it.</p>
<p>So basically what we needed was a manager to deal with the naming templates and a way to determine the WebParts set to be used per page.</p>
<p>Till now the framework used template file name followed by the page ID, followed by an eventual language/region if a page was not the master branch, for example:</p>
<blockquote><p>~/templates/Demo/WebPartPage.aspx|26    <br />~/templates/Demo/WebPartPage.aspx|26|en-us </p></blockquote>
<p>which makes them unique per page, which is not as appealing when you use EPiServer as it for a big part duplicates its functionality. Also a bit of a caveat here for agile programming methodology which promotes an often and early refactoring – if you move your page around or change its name – you lose the WebParts for all pages using it.</p>
<p>What we needed is a flexible and extensible scheme for reusing “WebParts sets” and that’s what our extension allows for.</p>
<p>Also since we’re very performance sensitive, and we operate in a multi server scenarios a lot we’ve added web parts blobs caching. Meaning that the site does not have to reach to the database every time a page is rendered.</p>
<p>The very appealing side of the framework is that it can be extended form the bottom (persistence) from the top (editors, controls, webparts), as well as being pluggable with custom plumbing.</p>
<h2>The Sidebar Extensions for WebParts Framework</h2>
<p>So to put all the requirements together, we needed the sidebars to be:</p>
<ul>
<li>customizable (out of the box) </li>
<li>easy to use for both developers and editors (out of the box) Wow Steve, I can’t really appreciate enough how cool it is to code for it and how nice it is for the users! </li>
<li>localizable </li>
<li>reusable </li>
<li>inheritable for site branches </li>
</ul>
<h2>WebParts path patterns</h2>
<p>The main idea was to free the path names from the restriction they had – being hardcoded for a page. So to do it without hard-coding them I’ve introduced path patterns. </p>
<h3>What is a pattern?</h3>
<p>Basically a pattern is a way the framework is supposed to encode the WebParts&#160; id for the system to identify. Your site can have any number of “named patterns” and the framework gives you means of switching between them. Pattern allow for almost any string to be a part of it although some tokens have special meaning:</p>
<table cellspacing="0" cellpadding="2" width="680" border="0">
<tbody>
<tr>
<td valign="top" width="200"><strong>Token</strong></td>
<td valign="top" width="478"><strong>Replacemnt Value</strong></td>
</tr>
<tr>
<td valign="top" width="200">%pageid%</td>
<td valign="top" width="478">id of the page the path is formed for</td>
</tr>
<tr>
<td valign="top" width="200">%region%</td>
<td valign="top" width="478">language/region of the WebParts</td>
</tr>
<tr>
<td valign="top" width="200">%pagetypeid%</td>
<td valign="top" width="478">type of the page</td>
</tr>
<tr>
<td valign="top" width="200">%template%</td>
<td valign="top" width="478">legacy token to make it possible to use template names as part of path.          <br />This is just for compatibility so you can have some of the pages using an old scheme.</td>
</tr>
<tr>
<td valign="top" width="200">%legacyregion%</td>
<td valign="top" width="478">legacy token for regionalizable pages (usage described later)</td>
</tr>
<tr>
<td valign="top" width="200">%inherited%</td>
<td valign="top" width="478">states that a page shoud inherit its WebParts from its parent in the page hierarchy (this can only be used as a complete pattern – cannot be a part of a larger pattern)</td>
</tr>
<tr>
<td valign="top" width="200">%root%</td>
<td valign="top" width="478">(again whole pattern) the %root% token is used when the inheritance based on hierarchy does not resolve into another token while reaching the root page.</td>
</tr>
</tbody>
</table>
<h3>Some sample patterns</h3>
<table cellspacing="0" cellpadding="2" width="600" border="1">
<tbody>
<tr>
<td valign="top" width="100"><strong>Name</strong></td>
<td valign="top" width="100"><strong>Pattern</strong></td>
<td valign="top" width="150"><strong>Sample Instance</strong> <strong>of the Pattern</strong></td>
<td valign="top" width="200"><strong>Description</strong></td>
</tr>
<tr>
<td valign="top" width="100">Root pattern</td>
<td valign="top" width="100">%root%</td>
<td valign="top" width="150">%root%</td>
<td valign="top" width="200">The pattern that all inheritance automatically falls back to</td>
</tr>
<tr>
<td valign="top" width="100">Inherited</td>
<td valign="top" width="100">%inherit%</td>
<td valign="top" width="150">anything parent defines</td>
<td valign="top" width="200">Tells the page to use the web parts its parent is using – the inheritance is possible all the way up in the hierarchy to the %root% pattern, meaning – if my parent inherits its WebParts from its parent, so will I.</td>
</tr>
<tr>
<td valign="top" width="100">Legacy regionalized</td>
<td valign="top" width="100">%template%|%pageid%%legacyregion%</td>
<td valign="top" width="150">~/templates/Demo/​​WebPartPage.aspx|26|en-us</td>
<td valign="top" width="200">Creates legacy “non language independent path”</td>
</tr>
<tr>
<td valign="top" width="100">Legacy global </td>
<td valign="top" width="100">%template%|%pageid%</td>
<td valign="top" width="150">~/templates/Demo/​​WebPartPage.aspx|26</td>
<td valign="top" width="200">Creates legacy “language independent path”</td>
</tr>
<tr>
<td valign="top" width="100">Page/region specific</td>
<td valign="top" width="100">page|%pageid%|%region%</td>
<td valign="top" width="150">page|26|en-us</td>
<td valign="top" width="200">template independent per-page/per-language pattern</td>
</tr>
<tr>
<td valign="top" width="100">PageType specific</td>
<td valign="top" width="100">pagetype|%pagetypeid%</td>
<td valign="top" width="150">pagetype|5</td>
<td valign="top" width="200">page type specific path (notice how the previous pattern has “page” and this one has “pagetype” in it) – this is done to avoid conflicts in numbers between pages and page types of the same id</td>
</tr>
<tr>
<td valign="top" width="100">My Sidebar</td>
<td valign="top" width="100">my-sidebar</td>
<td valign="top" width="150">my-sidebar</td>
<td valign="top" width="200">You can create “named sets” that will stay the same across all pages using it</td>
</tr>
<tr>
<td valign="top" width="100">My Localizable Sidebar</td>
<td valign="top" width="100">my-sidebar|%region%</td>
<td valign="top" width="150">my-sidebar|en-us</td>
<td valign="top" width="200">A localized version of the previous “named set”</td>
</tr>
</tbody>
</table>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=103&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2009/01/08/webparts-based-sidebar-for-episerver-the-motivation-and-specification/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Text-Image generation &#8211; VirtualPathProvider for EPiServer (and ASP.NET in general) &#8211; Part 2 (configuration)</title>
		<link>http://blog.najmanowicz.com/2008/06/24/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-2-configuration/</link>
		<comments>http://blog.najmanowicz.com/2008/06/24/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-2-configuration/#comments</comments>
		<pubDate>Tue, 24 Jun 2008 18:36:00 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Downloadable]]></category>
		<category><![CDATA[EPiCode]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2008/06/24/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-2-configuration/</guid>
		<description><![CDATA[
The configuration of the module is a descendant of any EPiServer Virtual Path Provider configuration. This aspect is fairly well described on EPiServer pages. 
A sample configuration for the TextImageVirtualPathProvider can look as follows

&#60;configuration&#62;
  &#60;episerver&#62;
    &#60;virtualPath
      &#60;providers&#62;
        &#60;add showInFileManager="false"
 [...]]]></description>
			<content:encoded><![CDATA[</p>
<p>The configuration of the module is a descendant of any EPiServer Virtual Path Provider configuration. This aspect is fairly well <a href="http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-SP2/Virtual-Path-Providers-in-EPiServer-CMS-5/">described on EPiServer pages</a>. </p>
<p>A sample configuration for the TextImageVirtualPathProvider can look as follows</p>
<pre>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: blue">&lt;</span><span style="color: #a31515">configuration</span><span style="color: blue">&gt;</span>
<span style="color: blue">  &lt;</span><span style="color: #a31515">episerver</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;</span><span style="color: #a31515">virtualPath</span>
<span style="color: blue">      &lt;</span><span style="color: #a31515">providers</span><span style="color: blue">&gt;</span>
<span style="color: blue">        &lt;</span><span style="color: #a31515">add</span><span style="color: blue"> </span><span style="color: red">showInFileManager</span><span style="color: blue">=</span>"<span style="color: blue">false</span>"
<span style="color: blue">             </span><span style="color: red">virtualName</span><span style="color: blue">=</span>"<span style="color: blue">Text Images</span>"
<span style="color: blue">             </span><span style="color: red">virtualPath</span><span style="color: blue">=</span>"<span style="color: blue">~/TextImages/</span>"
<span style="color: blue">             </span><span style="color: red">bypassAccessCheck</span><span style="color: blue">=</span>"<span style="color: blue">false</span>"
<span style="color: blue">             </span><span style="color: red">name</span><span style="color: blue">=</span>"<span style="color: blue">TextImages</span>"
<span style="color: blue">             </span><span style="color: red">type</span><span style="color: blue">=</span>"<span style="color: blue">Cognifide.ImageVirtualPathProvider.TextImageVirtualPathProvider,Cognifide.ImageVirtualPathProvider</span>"
<span style="color: blue">             </span><span style="color: red">physicalPath</span><span style="color: blue">=</span>"<span style="color: blue">C:\temp\TextImages</span>"
<span style="color: blue">             </span><span style="color: red">allowedReferers</span><span style="color: blue">=</span>"<span style="color: blue">(localhost)</span>"
<span style="color: blue">             </span><span style="color: red">allowNullReferrer</span><span style="color: blue">=</span>"<span style="color: blue">false</span>"
<span style="color: blue">             </span><span style="color: red">replacementStrings</span><span style="color: blue">=</span>"<span style="color: blue">$colon$,:,$gt$,&gt;,$dot$,.,$quot$,</span><span style="color: red">&amp;quot;</span><span style="color: blue">,$amp$,</span><span style="color: red">&amp;amp;</span><span style="color: blue">,$star$,*,$eol$,</span><span style="color: red">&amp;#10;</span><span style="color: blue">,</span>"<span style="color: blue">/&gt;</span>
<span style="color: blue">      &lt;/</span><span style="color: #a31515">providers</span><span style="color: blue">&gt;</span>
<span style="color: blue">    &lt;/</span><span style="color: #a31515">virtualPath</span><span style="color: blue">&gt;</span>
<span style="color: blue">  &lt;/</span><span style="color: #a31515">episerver</span><span style="color: blue">&gt;</span>
<span style="color: blue">&lt;/</span><span style="color: #a31515">configuration</span><span style="color: blue">&gt;</span>
</div>
</pre>
<p>&nbsp;</p>
<p>where:</p>
<ul>
<li>physicalPath is where the cached version of images will be stored
</li>
<li>shownInFileManager is “false” as there is nothing to present for the user in the file manager.
</li>
<li>allowedReferrers is the regular expression containing the filter for sites that are allowed to access the path provider and get images. This has been added so that your server does not turn into the internet’s text-image open service :)
</li>
<li>allowNullReferrer should be set to false in production environment but allows for testing by directly creating URL’s without using a page to fill in the referrer.
</li>
<li>replacementStrings – this one actually turned out to be very useful since some characters are invalid and not even reaching the VPP if EPiServer or ASP detects them. so to allow for characters like colon or &lt; or even a dot (which would make it hard to form regular expression if it was explicitly available) or * you need to create an escape token for them. The string is a coma separated list of token,value,token,value,…
</li>
<li>virtualPath is something you need to change if you want your VPP to serve images under a different root level folder. (e.g. if you have a page with that name already)</li>
</ul>
<p>&nbsp;</p>
<p>Additionally for IIS6 (most common scenario) you need to add &lt;location&gt; node to configuration for the VPP to work. </p>
<p><span style="color: blue">&lt;</span><span style="color: #a31515">configuration</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp; &lt;</span><span style="color: #a31515">location</span><span style="color: blue"> </span><span style="color: red">path</span><span style="color: blue">=</span>&#8220;<span style="color: blue">TextImages</span>&#8220;<span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!&#8211;</span><span style="color: green"> Setup the StaticFileHandler for the wildcard mapping to work in IIS6</span><span style="color: blue">&#8211;&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: #a31515">httpHandlers</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: #a31515">add</span><span style="color: blue"> </span><span style="color: red">path</span><span style="color: blue">=</span>&#8220;<span style="color: blue">*</span>&#8220;<span style="color: blue"> </span><span style="color: red">verb</span><span style="color: blue">=</span>&#8220;<span style="color: blue">GET,HEAD</span>&#8220;<span style="color: blue"> </span><span style="color: red">type</span><span style="color: blue">=</span>&#8220;<span style="color: blue">System.Web.StaticFileHandler</span>&#8220;<span style="color: blue"> </span><span style="color: red">validate</span><span style="color: blue">=</span>&#8220;<span style="color: blue">true</span>&#8220;<span style="color: blue"> /&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color: #a31515">httpHandlers</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color: #a31515">staticFile</span><span style="color: blue"> </span><span style="color: red">expirationTime</span><span style="color: blue">=</span>&#8220;<span style="color: blue">-1.0:0:0</span>&#8220;<span style="color: blue"> /&gt;</span><br /><span style="color: blue">&nbsp; &lt;/</span><span style="color: #a31515">location</span><span style="color: blue">&gt;</span><br /><span style="color: blue">&lt;/</span><span style="color: #a31515">configuration</span><span style="color: blue">&gt;</span></p>
<pre>
</pre>
<p>Unless you want to change the location of the virtual path provider can be found under, there is nothing you need to change here.</p>
<p>The <a href="https://www.coderesort.com/p/epicode/browser/Cognifide.ImageVirtualPathProvider/5.x">code is accessible on EPiCode</a>, but you can also <a href="http://www.najmanowicz.com/blog_bin/Cognifide.ImageVirtualPathProvider.zip">download a compiled binary here</a>. All you need to do then is to unzip the archive to the “bin” folder within your site and set the web.config values to your preference.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=101&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2008/06/24/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-2-configuration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Text-Image generation &#8211; VirtualPathProvider for EPiServer (and ASP.NET in general) &#8211; Part 1</title>
		<link>http://blog.najmanowicz.com/2008/06/23/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-1/</link>
		<comments>http://blog.najmanowicz.com/2008/06/23/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-1/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 18:00:00 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[EPiCode]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2008/06/23/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-1/</guid>
		<description><![CDATA[The module code is already available on Epicode SVN, the relevant wiki pages will be following as soon as documentation is complete.
The use case is as follows:

The client wants the site to look exactly as in a template provided as a image, 
the text is using a non standard font that is not available on [...]]]></description>
			<content:encoded><![CDATA[<p>The module code is already available on Epicode SVN, the relevant wiki pages will be following as soon as documentation is complete.</p>
<p>The use case is as follows:</p>
<ul>
<li>The client wants the site to look exactly as in a template provided as a image, </li>
<li>the text is using a non standard font that is not available on 60% of Windows machines, </li>
<li>the site does not use flash. </li>
<li>the site needs to be equally good looking in IE6 (more about it later) </li>
</ul>
<p>The solution was to generate images, but how to do it the right way? This has presented us with a once-in-a-lifetime :) opportunity to create a virtual path provider, do something good and learn something new &amp; cool in the process.</p>
<h2>Creating a new virtual path provider.</h2>
<p>this functionality in itself is fairly well <a href="http://msdn.microsoft.com/en-us/library/system.web.hosting.virtualpathprovider.aspx">documented on MSDN</a> one thing to pay attention to is to remember to pass the control to the next provider in the provider queue if your provider does not want to serve the request, so in my case:</p>
<pre>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new">        <span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: #2b91af">VirtualFile</span> GetFile(<span style="color: blue">string</span> virtualPath)
        {
            <span style="color: blue">if</span> (IsPathVirtual(virtualPath))
                <span style="color: #2b91af">VirtualFile</span> file = <span style="color: blue">new</span> <span style="color: #2b91af">TextImageVirtualFile</span>(<span style="color: blue">this</span>, virtualPath);
                <span style="color: blue">return</span> file;
            <span style="color: blue">else</span>
                <span style="color: red"><strong>return Previous.GetFile(virtualPath);</strong></span>
        }</div>
</pre>
<p>this is necessary so you don’t have to have all-or nothing solution (your provider either serving everything the user requests or not being accessible at all) and honestly I’ve spent quite a while before I found out that… I was just being silly – thinking the technology by itself will resolve that ;)</p>
<p>If your Virtual path provider does not actually implement directories you don’t have to make the very provider to do a lot of complicated things. you are perfectly fine to limit the implementation to providing a custom constructor so that EPiServer passes you the configuration data and a couple of methods to tell whether a file is what you want to handle or not</p>
<pre>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: green">// this one is actually really cool - whatever values you set in your web.config </span>
<span style="color: green">// will be passed to you in the collection so you can really make your VPP </span></div>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: green">// as configurable as necessary</span>
<span style="color: blue">public</span> TextImageVirtualPathProvider(<span style="color: blue">string</span> name, <span style="color: #2b91af">NameValueCollection</span> configAttributes)</div>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new">
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: green">// This one resolves if the file can be generated</span>
<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">bool</span> FileExists(<span style="color: blue">string</span> virtualPath) { <span style="color: green">/* ... */</span> }

<span style="color: green">// Pretty much only passes the info that directory was not found </span>
<span style="color: green">// found if the virtual path matches a path that we should handle</span>
<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">bool</span> DirectoryExists(<span style="color: blue">string</span> virtualDir) {  <span style="color: green">/* ... */</span>  }

<span style="color: green">// Retrieves the virtual file that generates the image if the</span>
<span style="color: green">// Virtual path matches our pattern or disregards the request if it doesn't</span>
<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: #2b91af">VirtualFile</span> GetFile(<span style="color: blue">string</span> virtualPath) {  <span style="color: green">/* ... */</span>  }

<span style="color: green">// Again this is only a pass through method as we don't support directories</span>
<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: #2b91af">VirtualDirectory</span> GetDirectory(<span style="color: blue">string</span> virtualDir) {  <span style="color: green">/* ... */</span> }</div>
</div>
</pre>
<p>Now that we have ASP passing the request to us we need to wonder how to format the request in a way that is intuitive to the user, I wanted the URL to be straightforward and follow the path of EPiServer’s friendly URL-S so that they are easily formed by editors. So how about:</p>
<p><a href="http://my.server.com/color/font-name/font-size/The%20text%20i%20want%20toprint.gif">http://my.server.com/color/font-name/font-size/The%20text%20i%20want%20to%20print.gif</a></p>
<p>Ok.. well…, that won’t fly for GIFs &#8211; the font will be plain ugly if I don’t use antialiasing and if I do I will have an ugly black background underneath it. The solution to that would be using translucent PNG (which the VPP supports) but IE6 does not support those with transparency without ugly hacks. So I need to replace the blacks with a hint so that it generates a background colour when it merges the background with the font for antialiasing. For the sake of this article let’s assume it was an easy switch (IT WASN’T!) and let’s extend the URL to:</p>
<p><a href="http://my.server.com/color/antialias-hint-color/font-name/font-size/the-text-i-want-to-print.gif">http://my.server.com/color/antialias-hint-color/font-name/font-size/The%20text%20i%20want%20to%20print.gif</a></p>
<p>But I need the font to be bold! Ok… ok…</p>
<p><a href="http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting/The%20text%20i%20want%20to%20print.gif">http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting/The%20text%20i%20want%20to%20print.gif</a></p>
</p>
<p>Can I have the image rotated too? Sigh….</p>
</p>
<p><a href="http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting(optional)/transformatio(optional)/The%20text%20i%20want%20to%20print.gif">http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting(optional)/transformatio(optional)/The%20text%20i%20want%20to%20print.gif</a></p>
<p>The image rotation follows the <a href="http://msdn.microsoft.com/en-us/library/system.drawing.rotatefliptype(VS.71).aspx">RotateFlipType enumeration</a> so you can specify any string that is defined in the <a href="http://msdn.microsoft.com/en-us/library/system.drawing.rotatefliptype(VS.71).aspx">MSDN documentation for the enumeration</a>.</p>
</p>
<p>A sample result for the URL:</p>
<p><a title="http://cms5.cognifide.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif" href="http://my.server.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif">http://my.server.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif</a></p>
<p>Will look as follows</p>
<p align="center"><a href="http://blog.najmanowicz.com/wp-content/uploads/2008/06/helloeolfromeolcognifide.png"><img title="Hello$eol$from$eol$Cognifide!" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="Hello$eol$from$eol$Cognifide!" src="http://blog.najmanowicz.com/wp-content/uploads/2008/06/helloeolfromeolcognifide-thumb.png" width="124" border="0" /></a>&#160;</p>
<h2></h2>
<h2>For the curious</h2>
<p>The final string format matching regular expression looks as follows: </p>
<pre>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: #2b91af">Regex</span> regex = <span style="color: blue">new</span> <span style="color: #2b91af">Regex</span>(
<span style="color: #a31515">    @&quot;^(?&lt;colour&gt;                  # The first match - starting form the beginning of the string</span></div>
<div style="font-size: 8pt; background: white; color: black; font-family: courier new"><span style="color: #a31515">    ([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*))   # match either a 6 hex digit string or a name of a known color - this is for text color</span>
<span style="color: #a31515">    /                             # now we expect the first separating slash</span>
<span style="color: #a31515">    (?&lt;hint&gt;                      # next match group is about background hint for antialiasing</span>
<span style="color: #a31515">    ([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*))   # match either a 3 or 6 hex digit string or a name of a known color - this is for antialiasing color hint</span>
<span style="color: #a31515">    /                             # again separating slash</span>
<span style="color: #a31515">    (?&lt;font&gt;[\w\s]*)              # font family name - accept white spaces</span>
<span style="color: #a31515">    /                             # yet another separating slash</span>
<span style="color: #a31515">    (?&lt;size&gt;[\d]{0,3})            # font size </span>
<span style="color: #a31515">    /                             # oh noes! another slash!</span>
<span style="color: #a31515">    ((?&lt;style&gt;[BIUSRN\s]*)        # font style Bold, Italic, Underline, Strikethrough</span>
<span style="color: #a31515">    /){0,1}                       # this group is optional.</span>
<span style="color: #a31515">    ((?&lt;transform&gt;[\w]*)          # transformation name as specified with System.Drawing.RotateFlipType - this group is optional</span>
<span style="color: #a31515">    /){0,1}                       # this group is optional too.</span>
<span style="color: #a31515">    (?&lt;text&gt;[\s\S]*[^\.])         # the text to render - basically anything but a dot - use relacement strings for dots</span>
<span style="color: #a31515">    [\.]                          # separating dot - now that's a nice change!</span>
<span style="color: #a31515">    (?&lt;extension&gt;(png|gif))       # the file extension - so that we know whether to generate png or gif</span>
<span style="color: #a31515">    $                             # everything comes to an end  </span>
<span style="color: #a31515">    &quot;</span>,
    <span style="color: #2b91af">RegexOptions</span>.Compiled | <span style="color: #2b91af">RegexOptions</span>.IgnoreCase | <span style="color: #2b91af">RegexOptions</span>.IgnorePatternWhitespace | <span style="color: #2b91af">RegexOptions</span>.CultureInvariant);</div>
</pre>
<p>&#160;</p>
<h2>Usability concerns</h2>
<p>The Colours can be provided as both named Colours (red, green, etc..) or html hex formatted colours (e.g. ff00bb, fob, fff, badfoo) both 6 and 3 hex digits strings are accepted.</p>
<p>The URL accepts spaces, and whatever text string that cannot be passed as a part of the url or is invalidated by EPiServer can be escaped by defining a token for it in web.config so for example as you can see in the above url the end of line “\n” character has been escaped into $eol$.</p>
<p>Obviously the font selection is limited to what is installed on your server.</p>
<h2>Performance concerns</h2>
<p>The basic concern that comes to mind is – how does this impact the server performance if the image is generated every time? Even though the performance impact seemed to be negligible I’ve decided to cache content. These things simply pile up if you have a high load site so why take the chance? Once an URL is called it is saved on first generation asserting the uniqueness of each parameter. Colours like black and 000 will be treated as same colour and cached only once. </p>
<h2>Security concerns</h2>
<p>So what was done to prevent our server to be an open server for generating images for everyone on the Internet? The VPP only allows for the images to be generated if the request referrer is in a domain or a host that is specified in the web.config. Additionally for testing you can enable the referrer to be null (direct call to images, as opposed to referring to them from a page). </p>
<p>Also as a seconds line of defence, it’s wise to define the cache folder on a share with a quota so we don’t get our server filled up with images should the referrer limiting measure fail for some reason.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=100&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2008/06/23/text-image-generation-virtualpathprovider-for-episerver-and-aspnet-in-general-part-1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>CogniScale &#8211; virtual hosting made easy</title>
		<link>http://blog.najmanowicz.com/2008/06/02/cogniscale-virtual-hosting-made-easy/</link>
		<comments>http://blog.najmanowicz.com/2008/06/02/cogniscale-virtual-hosting-made-easy/#comments</comments>
		<pubDate>Mon, 02 Jun 2008 21:10:03 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Downloadable]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Microsoft SqlServer]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2008/06/02/cogniscale-virtual-hosting-made-easy/</guid>
		<description><![CDATA[We&#8217;ve not been talking much about it and that&#8217;s partially my fault as well (busy with other projects), but Cognifide has a really cool initiative called Cognifide Labs that we intend to grow over time. The plan is to devote up to 10% company time into side projects that help us grow expertise and allow [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve not been talking much about it and that&#8217;s partially my fault as well (busy with other projects), but <a href="http://www.cognifide.com/">Cognifide</a> has a really cool initiative called <a href="http://labs.cognifide.com/">Cognifide Labs</a> that we intend to grow over time. The plan is to devote up to 10% company time into side projects that help us grow expertise and allow our devs to dwell into interesting technologies, methodologies and languages and develop their skills.</p>
<p>One of the first projects (that I took part in) is <a href="http://cogniscale.cognifide.com/">CogniScale</a> &#8211; an app that allows <a href="http://www.flexiscale.com/">FlexiScale</a> users to manage their servers. Here&#8217;s the story&#8230; </p>
<p>Being the agile company taking part in many <a href="http://www.episerver.com/">EPiServer</a> projects we never seem to have enough environments to test our web-apps and software in general in various scenarios. We find ourselves constantly reinstalling and trying to keep our servers in a state that can can at least remotely be called as stable. After all how many deployments and tearing down of various <a href="http://www.episerver.com/">EPiServer</a>, <a href="http://ccnet.thoughtworks.com/">CruiseControl</a>, <a href="http://www.jetbrains.com/teamcity/">TeamCity</a>, SQL Server and other &quot;I need to have&quot; apps can a server take before slowing down to a crawl or collapsing all together (that said I bow before our faithful THOTH for taking all the abuse it does). We definitely needed more servers! And we needed them now! </p>
<p>Early this year we&#8217;ve started to talk to the guys at XCalibre that came up with a great idea. What if you could have an unlimited amount of servers available for you at any given time? I mean really what if you could have 0 servers one day and the next day have a rich farm of servers for literally no cost, paying only when you power them up and not paying a bit if you take them down.&#160; This turned out to be quite a project for them that turned to materialize as FlexiScale. (<a href="http://flexiscale.com/about_us.html">you can read more about it here</a>). Looking at all that I&#8217;ve mentioned before while eliminating the cost of maintaining the servers locally we decided to give FlexiScale a spin. </p>
<p><span id="more-97"></span></p>
<p>Early this year FlexiScale published a set of API&#8217;s that we looked at and (being the geeks we are) tried to utilize it in a desktop application with a limited success. It turned out that the initial API was perfectly accessible from dynamically typed languages while statically typed languages like C# didn&#8217;t really get their love in the initial release :) So we started opening the support tickets and shortly after that establishing a lively dialogue with the great folks there. Let me tell you, the guys in the FlexiScale support are really an amazing and responsive bunch. Not only did we get the support and the fixes we needed for the language we chose but we also pretty much got all our suggestions implemented and added to the API&#8217;s.</p>
<p>Thus <a href="http://cogniscale.cognifide.com/">CogniScale</a> was born:</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="470" alt="cogniscale" src="http://blog.najmanowicz.com/wp-content/uploads/2008/06/cogniscale_main_form.jpg" width="644" border="0" />&#160; </p>
<p>The app allows for easy powering up and down the servers (allowing you to describe the reason for the action) from a nice and shiny GUI as well as scheduling it with windows task scheduler through its command line interface. it allows you to connect using FTP or Remote Desktop as well as any other app you can run from command line (it features a custom command editor that allows you to configure any app to work with it) with a single click. The app also allows you to quickly go through the history of servers&#8217; maintenance to determine how often and for what reason were they taken on and off-line.</p>
<p>Should you decide that FlexiScale is your thing, please give <a href="http://cogniscale.cognifide.com/">CogniScale</a> a whirl and let us know what you think.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=97&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2008/06/02/cogniscale-virtual-hosting-made-easy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Common Language Runtime, now even more common</title>
		<link>http://blog.najmanowicz.com/2007/05/07/common-language-runtime-now-even-more-common/</link>
		<comments>http://blog.najmanowicz.com/2007/05/07/common-language-runtime-now-even-more-common/#comments</comments>
		<pubDate>Mon, 07 May 2007 18:05:26 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[.Net Framework]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2007/05/07/common-language-runtime-now-even-more-common/</guid>
		<description><![CDATA[There seems to be a storm over at over at the Internet about Microsoft going Cross platform and &#8220;opening the common language runtime to a multitude of platforms&#8221;. What seems to be a false perception that even such respectable podcasts as Buzz Out Loud or even TWIT fail to realize and mislead people on is [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://developers.slashdot.org/article.pl?sid=07/05/01/200226">There</a> <a href="http://blogs.zdnet.com/microsoft/?p=414">seems</a> to be a <a href="http://www.itwriting.com/blog/?postid=387">storm</a> over at <a href="http://codebetter.com/blogs/sam.gentile/archive/2007/04/30/cross-platform-clr.aspx">over</a> at the <a href="http://www.knowing.Net/CommentView,guid,36df9349-f62c-41c2-b833-def7f0c65dcf.aspx#commentstart">Internet</a> about Microsoft going Cross platform and &#8220;opening the common language runtime to a multitude of platforms&#8221;. What seems to be a false perception that even such respectable podcasts as <a href="http://bol.cnet.com">Buzz Out Loud</a> or even <a href="http://twit.tv">TWIT</a> fail to realize and mislead people on is that this has NOTHING to do with portable .Net desktop applications. Someone even suggested at one of the BOL podcasts that it&#8217;s Microsoft&#8217;s attempt to put .Net Framework on Linux servers.&nbsp;(Huh? Beg your pardon?) You may have not noticed it but when they say about cross-platform capability of Silverlight it always says Windows, Mac.. and then on a single breath they start enumerating browsers. A casual listener just measures the quantity and the list has an impressive 5-6 bullets. heh&#8230; wait&#8230; erm&#8230; not really&#8230; it&#8217;s actually only 2 platforms. You cannot enumerate browsers as platforms! You share 99% implementation between them, the only cross-browser thing is the interaction between the plugin and the host browser!</p>
<p>As a .Net developer this pretty much makes me laugh through tears. What an excellent publicity stunt. First of all, Microsoft does not plan to release a Linux version. It&#8217;s cross-platformedness (is that a word?) refers strictly to the fact that there has been a runtime engine port made for a Mac. What was ported? The CLR and the DLR. Big deal! This has been there in a form of Mono years ago! And the CLR is available for Linux for a few years now. How is that suddenly an exciting thing?</p>
<p>If you&#8217;re interested in what exactly was done you may want to look at the <a href="http://channel9.msdn.com/showpost.aspx?postid=304508">interview with Scott Guthrie, GM of the Silverlight team</a>. <a href="http://en.wikipedia.org/wiki/Global_Assembly_Cache">GAC</a> was not ported. Wait! GAC WAS NOT PORTED?! Only a subset of classes that are needed inside a browser. Basic GC, no ASP.Net. It&#8217;s nothing like a cross platform version of a full .Net framework. this is also nothing really that new from the cross platform point of view &#8211; this kind of stunt was already pulled by Microsoft in form of the Compact version of the .Net framework. Something similar has already been done in terms of XNA &#8211; which is a form of .Net framework for XBox. In fact Silverlight is much more like <a href="http://en.wikipedia.org/wiki/Microsoft_XNA">XNA</a> than it is like the full .Net framework.</p>
<p>Second of all the only open part is the DLR which is actually developed in an &#8220;embrace and devour&#8221; fashion. Ruby, Python and the likes developers &#8211; we love you! come join us under our Common Language runtime! Of course Microsoft will open it. Those developers are all about open and free this makes a lot of sense doing it this way. Give something, get a lot in return. Don&#8217;t get me wrong, I love the dynamic extensions, and I really like what&#8217;s being developed in the <a href="http://blogs.zdnet.com/microsoft/?p=404">DLR</a>, but make no mistake, the motives haven&#8217;t changed.</p>
<p>In the end CLR has been open for a long time and it&#8217;s not where the most exciting part of the development is. It&#8217;s the framework. I&#8217;ve not seen a word about Windows forms being ported. Or any of the ASP.Net namespaces on that mater. Heck even Mono has big ASP.Net 1.0 and chunks of 2.0. If you look at the image where do you see the CLR?</p>
<p align="center"><a href="http://www.najmanowicz.com/blog_images/SL_Map_FinalNET.png"><img src="http://www.najmanowicz.com/blog_images/SL_Map_FinalNET_small.jpg"/></a></p>
<p>It&#8217;s the small middle circle inside the big one. That&#8217;s a far cry from releasing .Net as a standalone portable framework. And if you think about it, it does not make any sense from Microsoft&#8217;s point of view to go the whole way. What for? for it to make Windows expendable? Ridiculous!</p>
<p>My feeling is that (other than making another bucket of money), partially the motives behind is is to kick Adobe&#8217;s butt. If it did not occur to you yet, Microsoft and Adobe are full-out at war at this point. PDF is combated with <a href="http://en.wikipedia.org/wiki/XML_Paper_Specification">XML Digital Paper</a>, Flash has its Silverlight, Shockwave (&amp; Macromedia Director) has Blend and XAML now and so on&#8230; </p>
<p>Adobe already takes shots <a href="http://www.cfif.org/htdocs/legislative_issues/federal_issues/hot_issues_in_congress/technology/Adobe-vs-Microsoft-Paradigm.htm">back at Microsoft</a></p>
<blockquote><p>While Adobe made PDF readily-available to other software companies such as Apple, Sun, Corel, and OpenOffice, when it came to deep-pocketed Microsoft, Adobe took a different stance, demanding that it remove the feature and charge a separate fee.</p>
<p>In response, Microsoft agreed to remove the feature, but refused to charge consumers separately for it. Adobe consequently sought negotiating leverage by threatening to sue before the EC, despite the fact that neither Adobe nor Microsoft are based in Europe, neither operates major production facilities there, and neither maintains primary business locations there. </p></blockquote>
<p>Now that we have a few myths busted, I don&#8217;t want you to think that I am not excited by Silverlight.</p>
<h2>The coolness ensues</h2>
<p>It is still <strong>incredibly cool</strong> that they are doing it and not for the cross platform reasons (although it&#8217;s nice), and not for the multi browser compatibility (even nicer), but for it&#8217;s roots in the full framework. For us .Net developers it&#8217;s like one day we woke up and we knew how to write <a href="http://en.wikipedia.org/wiki/Action_Script">Action Script (Flash) applications</a>. The Silverlight download is only 5 meg, so in the broadband world it&#8217;s going to be on almost every computer fairly quick. We will have a robust development environment for developing those applets in less than a year. It&#8217;s root in the .Net framework roots will make it talk seamlessly to our IIS embedded apps and services. You wanted web applications? </p>
<p>You asked for web applications? We will deliver&#8230; <br /><font color="#c0c0c0">&#8230; only they will be desktop</font> applications running inside a browser <font color="#c0c0c0"></font><font color="#c0c0c0">we&nbsp;approve..</font>..<br />&#8230; and on any platform <font color="#c0c0c0">we choose for you&#8230;<br />&#8230; </font>the best of both worlds &#8211; no matter if you want to run them in Windows OR in Internet Explorer. :)</p>
<p>But honestly &#8211; should you use some artificial and clunky surrogates of instantly-responsive-interactivity in forms of AJAX when you can have the real thing running faster and delivering much wider functionality? Developing a browser apps was possible before, but .Net was never perceived as a platform specifically designed for that kind of activity, the quasi multi-platform/browser compatibility has a chance to change that perception. Perfect crime :)</p>
<p>I can&#8217;t wait for Silverlight to turn gold. It&#8217;s a brave new world.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=70&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2007/05/07/common-language-runtime-now-even-more-common/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EPiServer’s ObjectStore (Part 2)</title>
		<link>http://blog.najmanowicz.com/2007/04/04/episerver%e2%80%99s-objectstore-part-2/</link>
		<comments>http://blog.najmanowicz.com/2007/04/04/episerver%e2%80%99s-objectstore-part-2/#comments</comments>
		<pubDate>Wed, 04 Apr 2007 17:39:48 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web applications]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2007/04/04/episerver%e2%80%99s-objectstore-part-2/</guid>
		<description><![CDATA[I think we&#8217;re mostly finished investigating ObjectStore for now. In this article I&#8217;ll try to finish up on the apsects of using the Object store in a real life solution that is a basic Page comments. In my previous article concerning ObjectStore I have described a way of storing and retrieving an object from the [...]]]></description>
			<content:encoded><![CDATA[<p>I think we&#8217;re mostly finished investigating ObjectStore for now. In this article I&#8217;ll try to finish up on the apsects of using the Object store in a real life solution that is a basic Page comments. In my <a href="http://blog.najmanowicz.com/2007/03/30/episervers-objectstore/">previous article concerning ObjectStore</a> I have described a way of storing and retrieving an object from the Store, which is fine and dandy if we know exactly the object&#8217;s OD, for example if we reference it from a page. But what good is a store like that if we cannot search it for content? The problem we were trying to solve using ObjectStore was storing comments for ANY Episerver page without having to do anything to the page type. We might need that for the upcoming project so the discovery may prove useful since this is a really neat way of storing objects.</p>
<p>So the class that we are going to store needs to persists the following values:</p>
<pre style="font-size: 8pt; background: white; color: black; font-family: courier new">
<span style="color: blue">namespace</span> Cognifide.EPiServerTest.ObjectStore
{
    [<span style="color: #2b91af">Serializable</span>, <span style="color: #2b91af">XmlInclude</span>(<span style="color: blue">typeof</span> (<span style="color: #2b91af">PageCommentDO</span>))]
    <span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">PageCommentDO</span> : <span style="color: #2b91af">IItem</span>, <span style="color: #2b91af">IPageComment</span>
    {
        <span style="color: blue">private</span> <span style="color: blue">object</span> id;
        <span style="color: blue">private</span> <span style="color: blue">string</span> name;
        [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)]
        <span style="color: blue">private</span> <span style="color: blue">int</span> pageId;
        <span style="color: blue">private</span> <span style="color: blue">string</span> title;
        <span style="color: blue">private</span> <span style="color: blue">string</span> content;
        [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)]
        <span style="color: blue">private</span> <span style="color: #2b91af">DateTime</span> submitDate;
        [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)]
        <span style="color: blue">private</span> <span style="color: blue">bool</span> moderated;
        [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)]
        <span style="color: blue">private</span> <span style="color: blue">bool</span> published = <span style="color: blue">true</span>;
        [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)]
        <span style="color: blue">private</span> <span style="color: blue">bool</span> reported;

    }
}</pre>
<p>&nbsp;You might have noticed that contrary to what I did before this class has some of its fields tagged with [<span style="color: #2b91af">Indexed</span>(<span style="color: blue">true</span>)] attribute. This is required by the store object if we ever want to query the store for the class using those fields as a filtering criteria. The page also implements&nbsp;the required <span style="color: #2b91af">IItem </span>interface (although the properties required by the interface are not shown in the excerpt) as well as our internal <span style="color: #2b91af">IPageComment</span> which is added there for the purpose of easy switching of implementations. We intend to implement it on both ObjectStore and using NHibernate to make sure we get the best performance possible out of our solution. This interface is to allow us to easily switch between the 2 implementations.</p>
<h2>Back to the ObjectStore</h2>
<p>&nbsp;First we need to introduce a few new classes EPiServer uses for querying the Store.&nbsp;The namespace that&nbsp;scopes the querying consists of the following entities:&nbsp;</p>
<pre style="font-size: 8pt; background: white; color: black; font-family: courier new">
<span style="color: blue">namespace</span> EPiServer.BaseLibrary.Search
{
    <span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">BetweenExpression</span> : <span style="color: #2b91af">IExpression</span>;
    <span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">EqualExpression</span> : <span style="color: #2b91af">IExpression</span>;
    <span style="color: blue">public</span> <span style="color: blue">sealed</span> <span style="color: blue">class</span> <span style="color: #2b91af">Expression</span>;
    <span style="color: blue">public</span> <span style="color: blue">interface</span> <span style="color: #2b91af">IExpression</span>;
    <span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">Order</span>;
    <span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">Query</span> : <span style="color: #2b91af">IEnumerable</span>;
}</pre>
<p>The Query class is at the center of any search in the Store, let&#8217;s start with the samples right away. The saving is almost identical to the sample that I&#8217;ve shown in my previous article:</p>
<pre style="font-size: 8pt; background: white; color: black; font-family: courier new">
<span style="color: blue">public</span> <span style="color: blue">void</span> Save()
{
    <span style="color: #2b91af">ISession</span> session = <span style="color: blue">null</span>;
    <span style="color: blue">try</span>
    {
        <span style="color: green">// check if there is a schema for the type, if not create it.</span>
        <span style="color: blue">if</span> (<span style="color: #2b91af">Context</span>.Repository.SchemaForType(GetType()) == <span style="color: blue">null</span>)
        {
            <span style="color: #2b91af">TypeSchemaBuilder</span>.RegisterSchemaAndType(<span style="color: #a31515">"CognifidePageCommentsStorage"</span>, GetType());
        }

        <span style="color: green">// get a new session from the current context.</span>
        session = <span style="color: #2b91af">Context</span>.Repository.CreateSession();

        <span style="color: green">// wrap it in a transaction </span>
        session.BeginTransaction();

        <span style="color: green">// make sure the id has been defined.</span>
        <span style="color: blue">if</span> (Id.Equals(<span style="color: #2b91af">Guid</span>.Empty))
        {
            Id = <span style="color: #2b91af">Guid</span>.NewGuid();
        }

        <span style="color: green">//persist</span>
        session.Save(<span style="color: blue">this</span>);
        session.CommitTransaction();
    }
    <span style="color: blue">catch</span> (<span style="color: #2b91af">ElektroPostException</span> exception)
    {
        <span style="color: green">// ... rollback the transaction and do some reporting</span>
        <span style="color: blue">if</span> (session != <span style="color: blue">null</span>)
        {
            session.RollbackTransaction();
        }
        <span style="color: blue">throw</span>;
    }
    <span style="color: blue">finally</span>
    {
        <span style="color: blue">if</span> (session != <span style="color: blue">null</span>)
        {
            session.Close();
        }
    }
}</pre>
<p>Really there is not much meat there. The interesting part comes in the object retrieval. Even though the Search namespace does not look like it offers much, you can still build a fairly fophisticated filter with it. following code retrieves comments for a specific PageLinkID. The comments can be filtered by date and since the call is used to retrieve the page for viewing, we probably only want the ones that are public (meaning they have not been removed by the comment moderator).</p>
<p>&nbsp;</p>
<pre style="font-size: 8pt; background: white; color: black; font-family: courier new">
<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">PageCommentDO</span>&gt; GetCommentsForPage(<span style="color: blue">int</span> pageId,
    <span style="color: #2b91af">DateTime</span> beforeDate, <span style="color: #2b91af">DateTime</span> afterDate, <span style="color: blue">bool</span> includeOnlyPublished)
{
    <span style="color: #2b91af">ISession</span> session = <span style="color: blue">null</span>;

    <span style="color: blue">try</span>
    {
        <span style="color: green">// make sure there is a schema to read from, otherwise there is no point</span>
        <span style="color: blue">if</span> (<span style="color: #2b91af">Context</span>.Repository.SchemaForType( <span style="color: blue">typeof</span> (<span style="color: #2b91af">PageCommentDO</span>)) == <span style="color: blue">null</span>)
        {
            <span style="color: blue">return</span> <span style="color: blue">null</span>;
        }

        <span style="color: green">//acquire a session</span>
        session = <span style="color: #2b91af">Context</span>.Repository.CreateSession();

        <span style="color: green">//create the query </span>
        <span style="color: #2b91af">Query</span> query = <span style="color: blue">new</span> <span style="color: #2b91af">Query</span>(<span style="color: blue">typeof</span> (<span style="color: #2b91af">PageCommentDO</span>));

        <span style="color: green">// we only want comments for a singler page </span>
        query.Add(<span style="color: #2b91af">Expression</span>.Equal(<span style="color: #a31515">"pageId"</span>, pageId));

        <span style="color: green">// should we filter to only wshow comments from some set time period?</span>
        <span style="color: green">// the following demonstrate how to request a value from within a range</span>
        <span style="color: blue">if</span> ((beforeDate != <span style="color: #2b91af">DateTime</span>.MinValue) ||
            ((afterDate != <span style="color: #2b91af">DateTime</span>.MaxValue) &amp;&amp; (afterDate != <span style="color: #2b91af">DateTime</span>.MinValue)))
        {
            query.Add(
                <span style="color: #2b91af">Expression</span>.Between(<span style="color: #a31515">"submitDate"</span>,
                                   (beforeDate != <span style="color: #2b91af">DateTime</span>.MinValue) ? beforeDate : <span style="color: blue">new</span> <span style="color: #2b91af">DateTime</span>(0x76c, 1, 1),
                                   ((afterDate != <span style="color: #2b91af">DateTime</span>.MinValue) &amp;&amp; (afterDate != <span style="color: #2b91af">DateTime</span>.MaxValue))
                                       ? afterDate
                                       : <span style="color: blue">new</span> <span style="color: #2b91af">DateTime</span>(0x834, 1, 1)));
        }

        <span style="color: green">// probably for a displayed page we will only want to show published comments</span>
        <span style="color: blue">if</span> (includeOnlyPublished)
        {
            query.Add(<span style="color: #2b91af">Expression</span>.Equal(<span style="color: #a31515">"published"</span>, <span style="color: blue">true</span>));
        }

        <span style="color: green">// order the comments by date/time so that we get the most recent first</span>
        query.AddOrder(<span style="color: blue">new</span> <span style="color: #2b91af">Order</span>(<span style="color: #a31515">"submitDate"</span>, <span style="color: blue">true</span>));

        <span style="color: #2b91af">IList</span> list = session.ExecuteQueryObject(query);
        <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">PageCommentDO</span>&gt; result = <span style="color: blue">new</span> <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">PageCommentDO</span>&gt;(list.Count);
        <span style="color: blue">foreach</span> (<span style="color: blue">object</span> item <span style="color: blue">in</span> list)
        {
            result.Add((<span style="color: #2b91af">PageCommentDO</span>) item);
        }
        <span style="color: blue">return</span> result;
    }
    <span style="color: blue">catch</span> (<span style="color: #2b91af">ElektroPostException</span> ex)
    {
        <span style="color: green">// ... do some reporting</span>
        <span style="color: blue">throw</span>;
    }
    <span style="color: blue">finally</span>
    {
        <span style="color: blue">if</span> (session != <span style="color: blue">null</span>)
        {
            session.Close();
        }
    }
}</pre>
<p>You nahe to agree, this really IS neat. All you need to do now to place the comments on a page is a few lines of code to bind the data&nbsp;from the Store with a repeated of a kind, and&nbsp;a set of edit boxes with a submit button :)</p>
<p>This is basically how much code the submission and retrieval the comments comment take:</p>
<pre style="font-size: 8pt; background: white; color: black; font-family: courier new">
<span style="color: green">// Load the comments to a repeater</span>
<span style="color: blue">protected</span> <span style="color: blue">void</span> Page_Load(<span style="color: blue">object</span> sender, <span style="color: #2b91af">EventArgs</span> e)
{
        <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">PageCommentDO</span>&gt; comments =
            <span style="color: #2b91af">PageCommentDO</span>.GetCommentsForPage(CurrentPage.PageLink.ID, <span style="color: #2b91af">DateTime</span>.MinValue, <span style="color: #2b91af">DateTime</span>.MaxValue);
        CurrentComments.DataSource = comments;
        CurrentComments.DataBind();
}

<span style="color: green">// Comment submission</span>
<span style="color: blue">protected</span> <span style="color: blue">void</span> SubmitComment(<span style="color: blue">object</span> sender, System.<span style="color: #2b91af">EventArgs</span> e)
{
    <span style="color: #2b91af">PageCommentDO</span> newComment = <span style="color: blue">new</span>
        <span style="color: #2b91af">PageCommentDO</span>(<span style="color: #2b91af">Guid</span>.Empty,
        <span style="color: blue">string</span>.Format(<span style="color: #a31515">"CommentForPage{0}"</span>, CurrentPage.PageLink.ID),
        CurrentPage.PageLink.ID,
        SubjectTextBox.Text, ContentTextBox.Text, <span style="color: #2b91af">DateTime</span>.Now, <span style="color: blue">false</span>, <span style="color: blue">true</span>, <span style="color: blue">false</span>);
    newComment.Save();
}

<span style="color: green">// the data binding for the labels</span>
<span style="color: blue">protected</span> <span style="color: blue">void</span> CurrentComments_ItemDataBound(<span style="color: blue">object</span> sender, <span style="color: #2b91af">RepeaterItemEventArgs</span> e)
{
    <span style="color: #2b91af">PageCommentDO</span> comment = (e.Item.DataItem <span style="color: blue">as</span> <span style="color: #2b91af">PageCommentDO</span>);

    <span style="color: #2b91af">Label</span> commentSubjectLabel = (<span style="color: #2b91af">Label</span>)e.Item.FindControl(<span style="color: #a31515">"CommentSubjectLabel"</span>);
    <span style="color: blue">if</span> (comment != <span style="color: blue">null</span>)
    {
        commentSubjectLabel.Text = comment.Title;
    }

    <span style="color: #2b91af">Label</span> commentContentLabel = (<span style="color: #2b91af">Label</span>)e.Item.FindControl(<span style="color: #a31515">"CommentContentLabel"</span>);
    <span style="color: blue">if</span> (comment != <span style="color: blue">null</span>)
    {
        commentContentLabel.Text = comment.Content;
    }
}</pre>
<p>Short of having a control pre=built for you I cannot think of it being able to make it easier.</p>
<p>I will&nbsp;look into packing it into a nice control that we would be looking into contributing some time in the future and of course if there is actually a demand for it.</p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=61&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2007/04/04/episerver%e2%80%99s-objectstore-part-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Working with multiple IIS/EPiServers on XP (switching-speed-em-uppers)</title>
		<link>http://blog.najmanowicz.com/2007/03/28/working-with-multiple-iisepiservers-on-xp-switching-speed-em-uppers/</link>
		<comments>http://blog.najmanowicz.com/2007/03/28/working-with-multiple-iisepiservers-on-xp-switching-speed-em-uppers/#comments</comments>
		<pubDate>Wed, 28 Mar 2007 16:15:11 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/2007/03/28/working-with-multiple-iisepiservers-on-xp-switching-speed-em-uppers/</guid>
		<description><![CDATA[Since IIS on XP seems to be handling only one site at a time and I have multiple installations of EpiServer for different purposes on my machine I needed a fast way of switching between them.
Sure I could go to the administration console and do it manually, but hey, why waste 30 seconds every time [...]]]></description>
			<content:encoded><![CDATA[<p>Since IIS on XP seems to be handling only one site at a time and I have multiple installations of EpiServer for different purposes on my machine I needed a fast way of switching between them.</p>
<p>Sure I could go to the administration console and do it manually, but hey, why waste 30 seconds every time you do it when you can actually batch waste them in a chunk of half an hour to automate it.</p>
<p>so here&#8217;s my findings.</p>
<p>The adsutil.vbs is the script you want to get intalled on your system somewhere in the search path. %systemroot% will do.<br />
You will find the script on your XP CD in the <strong>\i386</strong> folder. Unpack with the following command:</p>
<blockquote><p>expand E:\i386\adsutil.vb_ %SystemRoot%\adsutil.vbs</p></blockquote>
<p>Assuming that E: is your CR-ROM drive.</p>
<p>You can find the <a href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/d3df4bc9-0954-459a-b5e6-7a8bc462960c.mspx?mfr=true">user&#8217;s reference for the script on the Microsoft page</a></p>
<p>You may want to make sure that your Episerver is running in the default location by using the following call:</p>
<blockquote><p>Cscript.exe %SystemRoot%\adsutil.vbs SET /W3SVC/1/ROOT</p></blockquote>
<p>But since you&#8217;re probably having only one web server running on your machine anyway (why would you read it otherwise) probably the only thing you really need to do is:</p>
<blockquote><p>Cscript.exe %SystemRoot%\adsutil.vbs SET /W3SVC/1/ROOT &#8220;C:\Inetpub\MyEPiServer###&#8221;</p></blockquote>
<p>Another great tool I use that&#8217;s actually built into windows is reg.exe. this tool actually allows you to modify registry from command line. this was actually my initial approach to changing the path. It didn&#8217;t succeed to actually change the IIS root &#8211; but still it did the modification to the registry (that IIS just merrily ignored).</p>
<blockquote><p>reg.exe ADD &#8220;HKLM\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters\Virtual Roots&#8221; /v &#8220;/&#8221; /d &#8220;C:\Inetpub\MyEPiServer###,,201&#8243; /t REG_SZ /f</p></blockquote>
<p>This is however good for changing some database settings if anything is stored in the registry before restarting the IIS, which is can be scripted as:</p>
<blockquote><p>net stop W3svc<br />
net start W3svc</p></blockquote>
<p>So to summarize&#8230; my script for switching sites ends as:</p>
<blockquote><p>@echo off</p>
<p>set root_folder=C:\Inetpub\MyEPiServer2\<br />
set adscript_location=%SystemRoot%\adsutil.vbs</p>
<p>echo Switching IIS to %root_folder%<br />
Cscript.exe %adscript_location% SET /W3SVC/1/ROOT &#8220;%root_folder%&#8221;<br />
net stop W3svc<br />
net start W3svc</p></blockquote>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=57&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2007/03/28/working-with-multiple-iisepiservers-on-xp-switching-speed-em-uppers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>My first meaningful EPiServer control&#8230; z Biedronki* :)</title>
		<link>http://blog.najmanowicz.com/2006/12/19/my-first-meaningful-episerver-control-z-biedronki/</link>
		<comments>http://blog.najmanowicz.com/2006/12/19/my-first-meaningful-episerver-control-z-biedronki/#comments</comments>
		<pubDate>Tue, 19 Dec 2006 18:20:50 +0000</pubDate>
		<dc:creator>Adam Najmanowicz</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[EPiServer]]></category>
		<category><![CDATA[Internet Information Services]]></category>

		<guid isPermaLink="false">http://blog.najmanowicz.com/archives/49</guid>
		<description><![CDATA[The challenge &#8211; The site that we will be coding will have its pages tagged with episerver categories. Implement a control that will list all the pages tagged with a specific category.
The control aspx code seems looks pretty straightforward and is derivative of some other controls that are defined in the EPiServer sample site:

&#60;%@ Control [...]]]></description>
			<content:encoded><![CDATA[<p>The challenge &#8211; The site that we will be coding will have its pages tagged with episerver categories. Implement a control that will list all the pages tagged with a specific category.<br />
The control aspx code seems looks pretty straightforward and is derivative of some other controls that are defined in the EPiServer sample site:</p>
<blockquote><div style="font-family: Courier New; font-size: 8pt; color: black;">
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Control</span> <span style="color: red;">Language</span><span style="color: blue;">=&#8221;C#&#8221;</span> <span style="color: red;">AutoEventWireup</span><span style="color: blue;">=&#8221;false&#8221;</span> <span style="color: red;">CodeFile</span><span style="color: blue;">=&#8221;CategoryListing.ascx.cs&#8221;</span> <span style="color: red;">Inherits</span><span style="color: blue;">=&#8221;development.templates.Units.CategoryListing&#8221;</span> <span style="color: red;">TargetSchema</span><span style="color: blue;">=&#8221;http://schemas.microsoft.com/intellisense/ie5&#8243;</span> <span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Register</span> <span style="color: red;">TagPrefix</span><span style="color: blue;">=&#8221;EPiServer&#8221;</span> <span style="color: red;">Namespace</span><span style="color: blue;">=&#8221;EPiServer.WebControls&#8221;</span> <span style="color: red;">Assembly</span><span style="color: blue;">=&#8221;EPiServer&#8221;</span> <span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;"><span style="color: blue;">&lt;</span><span style="color: maroon;">div</span> <span style="color: red;">id</span><span style="color: blue;">=&#8221;rightmenudivStartPage&#8221;&gt;</span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; </p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;listheadingcontainer&#8221;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;listheadingleftcorner&#8221;&gt;&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">a</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;listheading leftfloating&#8221;</span> <span style="color: red;">href</span><span style="color: blue;">=&#8221;</span><span style="background: yellow;">&lt;%</span>=EventRootPage.LinkURL<span style="background: yellow;">%&gt;</span><span style="color: blue;">&#8220;&gt;</span><span style="background: yellow;">&lt;%</span><span style="color: blue;">=</span> EventRootPage.PageName <span style="background: yellow;">%&gt;</span><span style="color: blue;">&lt;/</span><span style="color: maroon;">a</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;listheadingrightcorner&#8221;&gt;&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">EPiServer</span><span style="color: blue;">:</span><span style="color: maroon;">PageList</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;</span> <span style="color: red;">ID</span><span style="color: blue;">=&#8221;PageList1&#8243;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">ItemTemplate</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">div</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;startpagecalendaritem&#8221;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">span</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;datelistingtext&#8221;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">episerver</span><span style="color: blue;">:</span><span style="color: maroon;">property</span> <span style="color: red;">ID</span><span style="color: blue;">=&#8221;Property1&#8243;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;</span> <span style="color: red;">PropertyName</span><span style="color: blue;">=&#8221;PageLink&#8221;</span> <span style="color: red;">CssClass</span><span style="color: blue;">=&#8221;StartCalendar&#8221;</span> <span style="color: blue;">/&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">span</span> <span style="color: red;">class</span><span style="color: blue;">=&#8221;Normal&#8221;&gt;&lt;</span><span style="color: maroon;">episerver</span><span style="color: blue;">:</span><span style="color: maroon;">property</span> <span style="color: red;">ID</span><span style="color: blue;">=&#8221;Property3&#8243;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;</span> <span style="color: red;">PropertyName</span><span style="color: blue;">=&#8221;MainIntro&#8221;</span> <span style="color: blue;">/&gt;&lt;/</span><span style="color: maroon;">span</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">ItemTemplate</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">EPiServer</span><span style="color: blue;">:</span><span style="color: maroon;">PageList</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">br</span><span style="color: blue;">/&gt;&lt;</span><span style="color: maroon;">br</span><span style="color: blue;">/&gt;</span></p>
<p style="margin: 0px;"><span style="color: blue;">&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;</span></p>
</div>
</blockquote>
<p>The wirst thing you will notice after looking at the code is that PageList is pretty much a standard ASP.NET <asp:Repeater> reinvented and rehashed. GREAT! Sounds like we can use the Data binding, right? That&#8217;s also true:</p>
<blockquote><div style="font-family: Courier New; font-size: 8pt; color: black;">
<p style="margin: 0px;"><span style="color: blue;">private</span> <span style="color: blue;">void</span> Page_Load(<span style="color: blue;">object</span> sender, System.<span style="color: teal;">EventArgs</span> e)</p>
<p style="margin: 0px;">{</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (!IsPostBack)</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; PageList1.DataSource = CategoryPages;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DataBind();</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p>
<p style="margin: 0px;">}</p>
</div>
</blockquote>
<p>Does the trick of binding the data to the repeater&#8230; uh&#8230; oh&#8230; sorry&#8230; I mean PageList.</p>
<p>Now comes the hard and non-obvious part. </p>
<p>How does one actually find the pages assigned to a category? Short of calling the database directly to query the tblCategorypage table that comes to mind at first, it looks like EPiServer has a really cool page finding module that allows for simple yet fairly effective discovery of pages conforming to some developer defined criteria. Those criteria are defined by means of forming any necessary number of instances of PropertyCriteria class provided as a PropertyCriteriaCollection to Global.EPDataFactory. The result is handed to us back as a PageDataCollection. The fetching of the pages looks like this:</p>
<blockquote><div style="font-family: Courier New; font-size: 8pt; color: black;">
<p style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: teal;">PageDataCollection</span> GetCategoryPages()</p>
<p style="margin: 0px;">{</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: teal;">PropertyCriteria</span> criteria = <span style="color: blue;">null</span>;</p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: teal;">CategoryList</span> categories = ((<span style="color: teal;">PropertyCategory</span>)(CurrentPage.Property[<span style="color: maroon;">"AggregatedCategory"</span>])).Category;</p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria = <span style="color: blue;">new</span> <span style="color: teal;">PropertyCriteria</span>();</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria.Condition = <span style="color: teal;">CompareCondition</span>.Equal;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria.Type = <span style="color: teal;">PropertyDataType</span>.Category;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria.Value = categories.ToString();</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria.Name = <span style="color: maroon;">&#8220;PageCategory&#8221;</span>;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; criteria.Required = <span style="color: blue;">true</span>;</p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: teal;">PropertyCriteriaCollection</span> col = <span style="color: blue;">new</span> <span style="color: teal;">PropertyCriteriaCollection</span>();</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; col.Add(criteria);</p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: teal;">PageDataCollection</span> pdc = <span style="color: blue;">new</span> <span style="color: teal;">PageDataCollection</span>();</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; pdc = <span style="color: teal;">Global</span>.EPDataFactory.FindPagesWithCriteria(EPiServer.<span style="color: teal;">Global</span>.EPConfig.StartPage, col);</p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> pdc;</p>
<p style="margin: 0px;">}</p>
</div>
</blockquote>
<p>For this to work though, one has to define some more stuff in the web admin part of the site. the usual task is to define the Page Template for the control. In this case when you define the Page Template make sure to put the &#8220;AggregatedCategory&#8221; property in that should be of type Category selection. This property defines what categories you want your control to aggregate, and you can provide one or more of those. the other property that is required for this very control is &#8220;CategoryContainer&#8221; of type Page. This is solely for the purpose of having a master page that you define as the &#8220;main page&#8221; for the chosen category selection. It serves as a clickable header in the control. Unnecessary maybe but one would have to define a caption for the control anyway so why not make it meaningful.</p>
<p>The usage of the said control is trivial. A sample usage on the default EPiServer site looks like this:</p>
<blockquote><div style="font-family: Courier New; font-size: 10pt; color: black;">
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Page</span> <span style="color: red;">language</span><span style="color: blue;">=&#8221;c#&#8221;</span> <span style="color: red;">Codebehind</span><span style="color: blue;">=&#8221;CategorySummary.aspx.cs&#8221;</span> <span style="color: red;">AutoEventWireup</span><span style="color: blue;">=&#8221;false&#8221;</span> <span style="color: red;">Inherits</span><span style="color: blue;">=&#8221;development.Templates.CategorySummary&#8221;</span> <span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Register</span> <span style="color: red;">TagPrefix</span><span style="color: blue;">=&#8221;EPiServer&#8221;</span> <span style="color: red;">Namespace</span><span style="color: blue;">=&#8221;EPiServer.WebControls&#8221;</span> <span style="color: red;">Assembly</span><span style="color: blue;">=&#8221;EPiServer&#8221;</span> <span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Register</span> <span style="color: red;">TagPrefix</span><span style="color: blue;">=&#8221;development&#8221;</span> <span style="color: red;">TagName</span><span style="color: blue;">=&#8221;CategoryListing&#8221;</span>&nbsp; <span style="color: red;">Src</span><span style="color: blue;">=&#8221;~/templates/Units/CategoryListing.ascx&#8221;</span><span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;"><span style="background: yellow;">&lt;%</span><span style="color: blue;">@</span> <span style="color: maroon;">Register</span> <span style="color: red;">TagPrefix</span><span style="color: blue;">=&#8221;development&#8221;</span> <span style="color: red;">TagName</span><span style="color: blue;">=&#8221;DefaultFramework&#8221;</span>&nbsp;&nbsp;&nbsp; <span style="color: red;">Src</span><span style="color: blue;">=&#8221;~/templates/Frameworks/DefaultFramework.ascx&#8221;</span><span style="background: yellow;">%&gt;</span></p>
<p style="margin: 0px;">&nbsp;</p>
<p style="margin: 0px;"><span style="color: blue;">&lt;</span><span style="color: maroon;">development</span><span style="color: blue;">:</span><span style="color: maroon;">DefaultFramework</span> <span style="color: red;">ID</span><span style="color: blue;">=&#8221;DefaultFramework&#8221;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">EPiServer</span><span style="color: blue;">:</span><span style="color: maroon;">Content</span> <span style="color: red;">ID</span><span style="color: blue;">=&#8221;Content1&#8243;</span> <span style="color: red;">Region</span><span style="color: blue;">=&#8221;fullRegion&#8221;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;</span><span style="color: maroon;">development</span><span style="color: blue;">:</span><span style="color: maroon;">CategoryListing</span>&nbsp; <span style="color: red;">ID</span><span style="color: blue;">=&#8221;CategoryContent&#8221;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;/&gt;</span></p>
<p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">&lt;/</span><span style="color: maroon;">EPiServer</span><span style="color: blue;">:</span><span style="color: maroon;">Content</span><span style="color: blue;">&gt;</span></p>
<p style="margin: 0px;"><span style="color: blue;">&lt;/</span><span style="color: maroon;">development</span><span style="color: blue;">:</span><span style="color: maroon;">DefaultFramework</span><span style="color: blue;">&gt;</span></p>
</div>
</blockquote>
<p>Out of which really only the   <span style="color: blue;">&lt;</span><span style="color: maroon;">development</span><span style="color: blue;">:</span><span style="color: maroon;">CategoryListing</span>&nbsp; <span style="color: red;">ID</span><span style="color: blue;">=&#8221;CategoryContent&#8221;</span> <span style="color: red;">runat</span><span style="color: blue;">=&#8221;server&#8221;/&gt;</span>   part is meaningful.</p>
<p>For the record&#8230;  It looks like THE place to go to solve that kind of dilemas fast is the <a href="http://www.episerver.com/devforum/default.aspx?id=746&#038;epslanguage=EN">EpiServer &#8220;Developer to Developer&#8221; forums</a>.</p>
<p><em>*)&#8230; couldn&#8217;t ressist with the title joke :) For those not in subject&#8230; It&#8217;s a reference to a silly commercial of one of the market chain (Biedronka) in Poland that advertises recently with &#8220;My first *something*&#8230; from Biedronka*</em></p>
<p><a href="http://www.cognifide.com"><img src="http://www.cognifide.com/logo.jpg" alt="Cognifide" /></a><br />
The article is based on the knowledge I&#8217;ve gathered and work I&#8217;ve performed for <a href="http://www.cognifide.com">Cognifide</a>. <a href="http://www.cognifide.com">Cognifide</a> is an official partner <a href="http://www.episerver.com">EPiServer</a> and the real contributor of the the control. </p>
<img src="http://blog.najmanowicz.com/?ak_action=api_record_view&id=49&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.najmanowicz.com/2006/12/19/my-first-meaningful-episerver-control-z-biedronki/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
