<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEUBQXYzeCp7ImA9WhdXGE0.&quot;"><id>tag:blogger.com,1999:blog-8582166</id><updated>2011-08-31T16:57:30.880+01:00</updated><category term="mvc" /><category term="C#" /><category term="EpiServer" /><category term="css" /><category term="General" /><category term="python" /><category term="Factory Pattern" /><category term="Book review" /><category term="Patterns" /><category term="gae" /><category term="FriendlyUrlRewriteProvider" /><category term=".NET" /><category term="ASP.NET" /><category term="extension methods" /><category term="Web" /><category term="memcache" /><title>Code Peace</title><subtitle type="html">Write code not war</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://codepeace.blogspot.com/" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/CodePeace" /><feedburner:info uri="codepeace" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CEQASX0-fSp7ImA9Wx5TF0s.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-8413926561018128635</id><published>2010-01-14T14:51:00.005Z</published><updated>2010-08-02T16:19:08.355+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-02T16:19:08.355+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Declaritively show content in EpiServer</title><content type="html">Not sure if this is a new idea (I doubt it - very few things ever are).
    
    I'm a big fan of reducing the amount of display logic in code-behind, especially
    showing and hiding regions of the page dependant on content stored in the CMS. What
    I wanted was a custom control in which you could declare a list of EpiServer properties
    which would need to be not empty for the control to render. I bet you've done this
    kind of thing a thousand times with a standard
    &lt;var&gt;
        &amp;lt;asp:placeholder ... /&gt;&lt;/var&gt;
    and code-behind.
    
    Here's a self-contained custom control which takes away all your code-behind pain
    and mess and allows you to just write markup in your .aspx/.ascx:
    
    &lt;pre class="brush: csharp"&gt;public class EpiPlaceHolder : PlaceHolder
{
    protected override void OnInit(EventArgs e)
    {
        this.Load += new EventHandler(EpiPlaceHolder_Load);
        base.OnInit(e);
    }

    public string Property
    {
        get;
        set;
    }

    public bool ShowOnFalse
    {
        get;
        set;
    }

    public PageData CurrentPage
    {
        get;
        set;
    }

    void EpiPlaceHolder_Load(object sender, EventArgs e)
    {
        bool isVisible = false;

        if (CurrentPage == null)
        {
            CurrentPage = ((EPiServer.TemplatePage)Page).CurrentPage;
        }

        if (Property != null)
        {
            string propertyName = Property;

            if (propertyName.Contains(","))
            {
                string[] props = propertyName.Split(new char[] { ',' });

                foreach (string prop in props)
                {
                    isVisible = IsVisibleForProperty(prop);

                    if (!isVisible)
                    {
                        break;
                    }
                }
            }
            else
            {
                isVisible = IsVisibleForProperty(propertyName);
            }
        }

        Visible = (ShowOnFalse) ? !isVisible: isVisible;
    }

    private bool IsVisibleForProperty(string propertyName)
    {
        object currentProperty = CurrentPage[propertyName];

        bool isVis = false;
        if (currentProperty != null)
        {
            bool tryParseProperty = false;
            if (bool.TryParse(currentProperty.ToString(), out tryParseProperty))
            {
                isVis = tryParseProperty;
            }
            else
            {
                isVis = true;
            }
        }

        return isVis;
    }
}
&lt;/pre&gt;
    
    
    Here's how to use it:
    
    &lt;pre class="brush: xml"&gt;&amp;lt;pdp:EpiPlaceHolder ID="EpiPlaceHolder1" runat="server" Property="LeadImage"&gt;
    &amp;lt;EPiServer:Property ID="Property2" runat="server" PropertyName="LeadImage" /&gt;
&amp;lt;/pdp:EpiPlaceHolder&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-8413926561018128635?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/Zl4m22PkmVQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/8413926561018128635/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=8413926561018128635" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/8413926561018128635?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/8413926561018128635?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/Zl4m22PkmVQ/declaritively-show-content-in-episerver.html" title="Declaritively show content in EpiServer" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2010/01/declaritively-show-content-in-episerver.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8FRXc9fip7ImA9WxBQFEo.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-9178752018188636521</id><published>2010-01-14T14:10:00.006Z</published><updated>2010-01-14T14:20:14.966Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-14T14:20:14.966Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="extension methods" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Randomize a List&lt;T&gt;</title><content type="html">Here's another instalment in a sporadic series of useful C# extension methods. This time we return a List&lt;T&gt; in a random order:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static class ICollectionExtensions&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// Randomizes the specified source.&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    /// &amp;lt;typeparam name="T"&gt;&amp;lt;/typeparam&gt;&lt;br /&gt;    /// &amp;lt;param name="source"&gt;The source.&amp;lt;/param&gt;&lt;br /&gt;    /// &amp;lt;returns&gt;&amp;lt;/returns&gt;&lt;br /&gt;    public static ICollection&amp;lt;T&gt; Randomize&lt;T&gt;(this ICollection&amp;lt;T&gt; source)&lt;br /&gt;    {&lt;br /&gt;        Random rng = new Random();&lt;br /&gt;&lt;br /&gt;        T[] a = new T[source.Count];&lt;br /&gt;        source.CopyTo(a, 0);&lt;br /&gt;&lt;br /&gt;        byte[] b = new byte[a.Length];&lt;br /&gt;        rng.NextBytes(b);&lt;br /&gt;&lt;br /&gt;        Array.Sort(b, a);&lt;br /&gt;&lt;br /&gt;        return new List&amp;lt;T&gt;(a);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-9178752018188636521?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/jushQ3U_Rf0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/9178752018188636521/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=9178752018188636521" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/9178752018188636521?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/9178752018188636521?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/jushQ3U_Rf0/randomize-list.html" title="Randomize a List&amp;lt;T&gt;" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2010/01/randomize-list.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcNQ3Y4cSp7ImA9WxNVEk8.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-7716637518406052629</id><published>2009-10-22T16:06:00.007+01:00</published><updated>2009-10-22T16:58:12.839+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T16:58:12.839+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="extension methods" /><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>More EpiServer extension methods</title><content type="html">Here's another extension method for returning a normal EpiServer Url to a page from a LinkItem (from a &lt;var&gt;PropertyLinkCollection&lt;/var&gt;).&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static class LinkItemExtensions&lt;br /&gt;{&lt;br /&gt;    public static string ToExternal(this LinkItem item)&lt;br /&gt;    {&lt;br /&gt;        string externalUrl = item.Href;&lt;br /&gt;&lt;br /&gt;        PermanentLinkMapStore.TryToMapped(item.Href, out externalUrl);&lt;br /&gt;&lt;br /&gt;        return externalUrl;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'm using the &lt;var&gt;PermanentLinkMapStore&lt;/var&gt; following a read of &lt;a href="http://marekblotny.blogspot.com/2009/02/episerver-5-r2-and-link-collection.html"&gt;this post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I've been using it when binding a LinkItemCollection to a ListView like this:&lt;br /&gt;&lt;pre class="prettyprint"&gt;PropertyLinkCollection linksProperty = CurrentPage.ToProperty&lt;PropertyLinkCollection&gt;("Links");&lt;br /&gt;&lt;br /&gt;var links = from l in linksProperty.Links&lt;br /&gt;    select new&lt;br /&gt;    {&lt;br /&gt;        Href = l.ToExternal(),&lt;br /&gt;        Title = l.Title,&lt;br /&gt;        Text = l.Text,&lt;br /&gt;        Extension = Path.GetExtension(l.Href)&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    lvLinks.DataSource = links;&lt;br /&gt;    lvLinks.DataBind();&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-7716637518406052629?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/MVvH6blMmnA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/7716637518406052629/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=7716637518406052629" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/7716637518406052629?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/7716637518406052629?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/MVvH6blMmnA/more-episerver-extension-methods.html" title="More EpiServer extension methods" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/10/more-episerver-extension-methods.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYGR38_eSp7ImA9WxNVEk8.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-8901533526162867065</id><published>2009-10-14T00:51:00.002+01:00</published><updated>2009-10-22T16:58:46.141+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T16:58:46.141+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="extension methods" /><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>EpiServer Extension methods</title><content type="html">Following on from my &lt;a href="http://codepeace.blogspot.com/2009/10/some-useful-extensions-methods.html"&gt;previous post&lt;/a&gt; I realised that the majority of the Extension methods that I use in everyday coding are EpiServer related.&lt;br /&gt;&lt;br /&gt;Here are some really useful ones:&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Gets the children.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;public static PageDataCollection GetChildren(this PageData page)&lt;br /&gt;{&lt;br /&gt;    PageDataCollection children = new PageDataCollection();&lt;br /&gt;&lt;br /&gt;    if (page.PageLink != null &amp;&amp; page.PageLink.ID &amp;gt; 0)&lt;br /&gt;    {&lt;br /&gt;        children = DataFactory.Instance.GetChildren(page.PageLink);&lt;br /&gt;&lt;br /&gt;        FilterPublished publishedDateFilter = new FilterPublished(PagePublishedStatus.Published);&lt;br /&gt;    FilterSort indexSorter = new EPiServer.Filters.FilterSort(FilterSortOrder.Index);&lt;br /&gt;&lt;br /&gt;        publishedDateFilter.Filter(children);&lt;br /&gt;        indexSorter.Sort(children);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return children;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Gets the external URL.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;public static string GetExternalUrl(this PageData page)&lt;br /&gt;{&lt;br /&gt;    string result = String.Empty;&lt;br /&gt;&lt;br /&gt;    if (page != null)&lt;br /&gt;    {&lt;br /&gt;        UrlBuilder builder = new UrlBuilder(page.LinkURL);&lt;br /&gt;&lt;br /&gt;        EPiServer.Global.UrlRewriteProvider.ConvertToExternal(builder, page, Encoding.UTF8);&lt;br /&gt;&lt;br /&gt;        result = builder.ToString();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return result;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Returns a concrete PropertyData (or child class)&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;&lt;br /&gt;/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="propertyName"&amp;gt;Name of the property.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;public static T ToProperty&amp;lt;T&amp;gt;(this PageData page, string propertyName) where T : PropertyData&lt;br /&gt;{&lt;br /&gt;    return page.Property[propertyName] as T;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Returns a PageData property or string.Empty if null&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="page"&amp;gt;The page.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;param name="propertyName"&amp;gt;Name of the property.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;public static string SafeProperty(this PageData page, string propertyName)&lt;br /&gt;{&lt;br /&gt;    return (page.HasProperty(propertyName)) ? page[propertyName].ToString() : string.Empty;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Gets the page for a Pagereference.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;param name="pageRef"&amp;gt;The Pagereference.&amp;lt;/param&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;public static PageData GetPage(this PageReference pageRef)&lt;br /&gt;{&lt;br /&gt;    return DataFactory.Instance.GetPage(pageRef);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-8901533526162867065?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/lTWxETqTAWc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/8901533526162867065/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=8901533526162867065" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/8901533526162867065?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/8901533526162867065?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/lTWxETqTAWc/episerver-extension-methods.html" title="EpiServer Extension methods" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>1</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/10/episerver-extension-methods.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYHQH49fCp7ImA9WxNVEk8.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-6463096166509406301</id><published>2009-10-14T00:30:00.010+01:00</published><updated>2009-10-22T16:58:51.064+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T16:58:51.064+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="extension methods" /><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Some useful Extensions methods</title><content type="html">Extension methods have been around a while now and I like them more every day. Oh I know they are just aliased static methods, but they are convenient for small common situations where it seems like the framework developers missed something out.&lt;br /&gt;&lt;br /&gt;Here's a few of my that I find useful:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;c&gt;NameValueCollection&lt;/c&gt; Extensions&lt;/span&gt;:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/// &amp;lt;summary&gt;&lt;br /&gt;/// Returns the collectionas a standard URL type QueryString&lt;br /&gt;/// &amp;lt;/summary&gt;&lt;br /&gt;/// &amp;lt;param name="self"&gt;The self.&amp;lt;/param&gt;&lt;br /&gt;/// &amp;lt;returns&gt;&amp;lt;/returns&gt;&lt;br /&gt;public static string ToQueryString(this NameValueCollection self)&lt;br /&gt;{&lt;br /&gt;    string qsString = string.Empty;&lt;br /&gt;    if (self.Count &gt; 0)&lt;br /&gt;    {&lt;br /&gt;        StringBuilder qsBuilder = new StringBuilder("?");&lt;br /&gt;&lt;br /&gt;        for (int i = 0; i &lt; self.Keys.Count; i++)&lt;br /&gt;        {&lt;br /&gt;            if (self.Keys[i] != null &amp;&amp; self.Keys[i].Length &gt; 0)&lt;br /&gt;            {&lt;br /&gt;                qsBuilder.AppendFormat("{0}={1}&amp;", HttpContext.Current.Server.UrlEncode(self.Keys[i]), HttpContext.Current.Server.UrlEncode(self[i]));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        qsString = qsBuilder.ToString();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return qsString;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&gt;&lt;br /&gt;/// Creates a copy the specified NameValueCollection.&lt;br /&gt;/// &amp;lt;/summary&gt;&lt;br /&gt;/// &amp;lt;param name="self"&gt;The NameValueCollection.&amp;lt;/param&gt;&lt;br /&gt;/// &amp;lt;returns&gt;&amp;lt;/returns&gt;&lt;br /&gt;public static NameValueCollection Copy(this NameValueCollection self)&lt;br /&gt;{&lt;br /&gt;    return new NameValueCollection(self);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;c&gt;String&lt;/c&gt; Extensions&lt;/span&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/// &amp;lt;summary&gt;&lt;br /&gt;/// Capitalizes the specified word.&lt;br /&gt;/// &amp;lt;/summary&gt;&lt;br /&gt;/// &amp;lt;param name="word"&gt;The word.&amp;lt;/param&gt;&lt;br /&gt;/// &amp;lt;returns&gt;&amp;lt;/returns&gt;&lt;br /&gt;public static string Capitalize(this string word)&lt;br /&gt;{&lt;br /&gt;    if (word.IsNullOrEmpty())&lt;br /&gt;    {&lt;br /&gt;        return word;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;// The aggregate is because IEnumerable&lt;char&gt;.ToString doesn't return the characters as a string, it returns the type's name as a string.&lt;br /&gt;    return word[0].ToString().ToUpper() + word.Skip(1).Aggregate("", (s, c) =&gt; s + c);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&gt;&lt;br /&gt;/// Splits the specified string into a list of white-space separated word strings.&lt;br /&gt;/// &amp;lt;/summary&gt;&lt;br /&gt;/// &amp;lt;param name="s"&gt;The s.&amp;lt;/param&gt;&lt;br /&gt;/// &amp;lt;returns&gt;&amp;lt;/returns&gt;&lt;br /&gt;public static IEnumerable&lt;string&gt; Wordify(this string s)&lt;br /&gt;{&lt;br /&gt;    return s.Split(new char[]{' ', '\n', '\t', '\r', '.', ',', ';', ':', '-'}, StringSplitOptions.RemoveEmptyEntries);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-6463096166509406301?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/mqEwLY6FplE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/6463096166509406301/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=6463096166509406301" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6463096166509406301?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6463096166509406301?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/mqEwLY6FplE/some-useful-extensions-methods.html" title="Some useful Extensions methods" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/10/some-useful-extensions-methods.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYGR38_eSp7ImA9WxNVEk8.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-6478311651127190943</id><published>2009-09-16T12:36:00.011+01:00</published><updated>2009-10-22T16:58:46.141+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T16:58:46.141+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="css" /><title>Custom styles in EPiServer WYSIWYG</title><content type="html">If you've been using EPiServer for a while you'll know the frustration of the built in WYSIWYG editor for rich text entry. It's IE only and rather clunky.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_Br-rhvDBMR4/SrDfM1SYMoI/AAAAAAAAABA/CPPZ_O7rEA8/s1600-h/2009-09-16_123816.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 57px;" src="http://2.bp.blogspot.com/_Br-rhvDBMR4/SrDfM1SYMoI/AAAAAAAAABA/CPPZ_O7rEA8/s400/2009-09-16_123816.jpg" alt="" id="BLOGGER_PHOTO_ID_5382046966263329410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is a way to add your own custom HTML and CSS classes into the editor which get added to a drop down box.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_Br-rhvDBMR4/SrDfZmYpFpI/AAAAAAAAABI/B2CYd3DN-6Y/s1600-h/2009-09-16_123905.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 253px;" src="http://2.bp.blogspot.com/_Br-rhvDBMR4/SrDfZmYpFpI/AAAAAAAAABI/B2CYd3DN-6Y/s400/2009-09-16_123905.jpg" alt="" id="BLOGGER_PHOTO_ID_5382047185601369746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;By selecting an item from this drop down you can insert both HTML tags and classes into the text.&lt;br /&gt;&lt;br /&gt;To do this you need to set the 'Path to CSS file for Editor' either in the Web.Config&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Br-rhvDBMR4/SrDgw1VeJaI/AAAAAAAAABQ/38bHZLOHbYM/s1600-h/2009-09-16_123939.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 193px;" src="http://4.bp.blogspot.com/_Br-rhvDBMR4/SrDgw1VeJaI/AAAAAAAAABQ/38bHZLOHbYM/s400/2009-09-16_123939.jpg" alt="" id="BLOGGER_PHOTO_ID_5382048684263220642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;sitesettings uieditorcsspaths="/styles/episerver.css" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the CSS file the secret is a custom style attribute called &lt;c&gt;EditMenuName&lt;/c&gt; which gives the name to put in the drop down list in the editor:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;/*&lt;br /&gt;Inserts &amp;lt;h1&amp;gt; &amp;lt;/h1&amp;gt;&lt;br /&gt;*/&lt;br /&gt;h1&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;EditMenuName:Heading1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Inserts &amp;lt;h2&amp;gt; &amp;lt;/h2&amp;gt;&lt;br /&gt;*/&lt;br /&gt;h2&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;EditMenuName:Heading2;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Inserts &amp;lt;p class="intro"&amp;gt; &amp;lt;/p&amp;gt;&lt;br /&gt;*/&lt;br /&gt;p.intro&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;EditMenuName:IntroParagraph;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding-bottom: 1em;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-bottom: 1px solid #E8E8E8;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Inserts &amp;lt;div class="box white"&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;*/&lt;br /&gt;div.box white&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;EditMenuName:Rounded Corner Box;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;border: solid 1px #E8E8E8;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding: 10px;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-6478311651127190943?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/iid64_Momyc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/6478311651127190943/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=6478311651127190943" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6478311651127190943?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6478311651127190943?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/iid64_Momyc/custom-styles-in-episerver-wysiwyg.html" title="Custom styles in EPiServer WYSIWYG" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_Br-rhvDBMR4/SrDfM1SYMoI/AAAAAAAAABA/CPPZ_O7rEA8/s72-c/2009-09-16_123816.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/09/custom-styles-in-episerver-wysiwyg.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8CRHw5fCp7ImA9WxBQFEo.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-7908590270818032781</id><published>2009-06-18T01:00:00.009+01:00</published><updated>2010-01-14T14:21:05.224Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-14T14:21:05.224Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="extension methods" /><category scheme="http://www.blogger.com/atom/ns#" term="EpiServer" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="FriendlyUrlRewriteProvider" /><title>Simple UrlRewriter for EpiServer</title><content type="html">On an EpiServer project that I just finished there was a requirement that all URLs generated by the CMS should be lowercase. I couldn't really see the issue. I know that web servers are allowed to be case sensitive with URLs, but didn't really see the big deal.&lt;br /&gt;&lt;br /&gt;However, looking at EpiServer, I thught that I might re-write a PageData extension method which I wrote previously which generates the external URL of a page:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public static string GetExternalUrl(this PageData page)&lt;br /&gt;{&lt;br /&gt;string result = String.Empty;&lt;br /&gt;&lt;br /&gt;if (page != null)&lt;br /&gt;{&lt;br /&gt;UrlBuilder builder = new UrlBuilder(page.LinkURL);&lt;br /&gt;EPiServer.Global.UrlRewriteProvider.ConvertToExternal&lt;/code&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;(builder, page, Encoding.UTF8);&lt;br /&gt;&lt;br /&gt;result = builder.ToString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This might have worked, but was still a bit of a kludge, so I turned to the undocumented waters of the &lt;var&gt;EPiServer.Web.FriendlyUrlRewriteProvider&lt;/var&gt;&lt;br /&gt;&lt;br /&gt;The &lt;var&gt;FriendlyUrlRewriteProvider&lt;/var&gt; has a virtual method called:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;ConvertToExternalInternal(EPiServer.UrlBuilder url, object internalObject, Encoding toEncoding)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which is called by the &lt;var&gt;EPiServer.Global.UrlRewriteProvider.ConvertToExternal(...)&lt;/var&gt; method I use in the Extension method above. Overriding that mehtod and converting the UrlBuilder's &lt;var&gt;path&lt;/var&gt; property to lowercase seemed to do the trick.&lt;br /&gt;&lt;br /&gt;Here's the final class:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class LowerCaseUrlRewriteProvider : EPiServer.Web.FriendlyUrlRewriteProvider&lt;br /&gt;{&lt;br /&gt;public LowerCaseUrlRewriteProvider()&lt;br /&gt;: base()&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected override bool ConvertToExternalInternal&lt;br /&gt;(EPiServer.UrlBuilder url, object internalObject, Encoding toEncoding)&lt;br /&gt;{&lt;br /&gt;base.ConvertToExternalInternal(url, internalObject, toEncoding);&lt;br /&gt;&lt;br /&gt;url.Path = url.Path.ToLower();&lt;br /&gt;&lt;br /&gt;return true;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Update: Setting it up in the Web.Config&lt;br /&gt;&lt;br /&gt;You now need to add this to the &lt;c&gt;urlRewrite&lt;/c&gt; EpiServer config element in the Web.Config:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;      &amp;lt;urlRewrite defaultProvider="LowerCaseUrlRewriteProvider"&gt;&lt;br /&gt;          &amp;lt;providers&gt;&lt;br /&gt;              &amp;lt;add name="LowerCaseUrlRewriteProvider" type="Shared.EpiServer.Web.LowerCaseUrlRewriteProvider,Shared.EpiServer" /&gt;&lt;br /&gt;              &amp;lt;add name="EPiServerFriendlyUrlRewriteProvider" type="EPiServer.Web.FriendlyUrlRewriteProvider,EPiServer" /&gt;&lt;br /&gt;              &amp;lt;add description="EPiServer identity URL rewriter" name="EPiServerIdentityUrlRewriteProvider"&lt;br /&gt;                  type="EPiServer.Web.IdentityUrlRewriteProvider,EPiServer" /&gt;&lt;br /&gt;              &amp;lt;add description="EPiServer bypass URL rewriter" name="EPiServerNullUrlRewriteProvider"&lt;br /&gt;                  type="EPiServer.Web.NullUrlRewriteProvider,EPiServer" /&gt;&lt;br /&gt;          &amp;lt;/providers&gt;&lt;br /&gt;      &amp;lt;/urlRewrite&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-7908590270818032781?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/OQeFZyM_Zcc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/7908590270818032781/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=7908590270818032781" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/7908590270818032781?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/7908590270818032781?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/OQeFZyM_Zcc/simple-urlrewriter-for-episerver.html" title="Simple UrlRewriter for EpiServer" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>2</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/06/simple-urlrewriter-for-episerver.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUESHs7eCp7ImA9WxNQEU0.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-5371520669709573512</id><published>2009-04-29T22:27:00.005+01:00</published><updated>2009-09-16T14:36:49.500+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-16T14:36:49.500+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mvc" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="gae" /><title>MVC Controller for webapp using Routes</title><content type="html">Foloowing on from my &lt;a href="http://codepeace.blogspot.com/2009/04/session-handling-with-memcache-api-in.html"&gt;previous post&lt;/a&gt; my MVC home brew is coming along slowly. I decided to implement &lt;a href="http://routes.groovie.org/"&gt;Routes&lt;/a&gt; (Rails style routing for Python), basing my wsgi class on &lt;a href="http://appengine-cookbook.appspot.com/recipe/match-webapp-urls-using-routes/"&gt;one I found&lt;/a&gt; on the App Engine Recipe site.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I altered the wsgi class very slightly to use a constructor passing in the &lt;c&gt;request&lt;/c&gt; and &lt;c&gt;response&lt;/c&gt; objects.&lt;/div&gt;&lt;pre class="prettyprint"&gt;# Initialize matched controller from given module.&lt;br /&gt;    __import__(module_name)&lt;br /&gt;    module = sys.modules[module_name]&lt;br /&gt;&lt;br /&gt;    if (module is not None and hasattr(module, class_name)):&lt;br /&gt;        controller = getattr(module, class_name)(request, response)&lt;br /&gt;    else:&lt;br /&gt;        raise ImportError('Controller %s could not be initialized.' % (class_name))&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;The Controller itself acts as a base class for the actual concrete controllers which will be used in the application itself.&lt;/div&gt;&lt;pre class="prettyprint"&gt;import os&lt;br /&gt;import urlparse&lt;br /&gt;import cgi&lt;br /&gt;import logging&lt;br /&gt;import sys&lt;br /&gt;import traceback&lt;br /&gt;from google.appengine.ext.webapp import template&lt;br /&gt;from SessionManager import SessionManager&lt;br /&gt;from routes.util import url_for&lt;br /&gt;&lt;br /&gt;class Controller(object):&lt;br /&gt; def __init__(self, request, response):&lt;br /&gt;     self.request = request&lt;br /&gt;     self.response = response&lt;br /&gt;     self.sessionManager = SessionManager(self.request, self.response)&lt;br /&gt;     self.session = self.sessionManager.current()&lt;br /&gt;     self.initialize()&lt;br /&gt;&lt;br /&gt; def initialize(self):&lt;br /&gt;     pass&lt;br /&gt;&lt;br /&gt; def handle_exception(self, e, debug):&lt;br /&gt;     #self.error(500)&lt;br /&gt;     logging.exception(e)&lt;br /&gt;     if debug:&lt;br /&gt;         lines = ''.join(traceback.format_exception(*sys.exc_info()))&lt;br /&gt;         self.response.clear()&lt;br /&gt;         self.response.out.write('%s' % (cgi.escape(lines, quote=True)))&lt;br /&gt;&lt;br /&gt; def error(self, code):&lt;br /&gt;     """Clears the response output stream and sets the given HTTP error code.&lt;br /&gt;&lt;br /&gt;     Args:&lt;br /&gt;       code: the HTTP status error code (e.g., 501)&lt;br /&gt;     """&lt;br /&gt;     self.response.set_status(code)&lt;br /&gt;     self.response.clear()&lt;br /&gt;&lt;br /&gt; def rendertemplate(self, context, path):&lt;br /&gt;     if (path is None):&lt;br /&gt;         path = __file__ + '.html'&lt;br /&gt;&lt;br /&gt;     if (context is None):&lt;br /&gt;         context = dict()&lt;br /&gt;&lt;br /&gt;     context['session'] = self.session&lt;br /&gt;     context['request'] = self.request&lt;br /&gt;&lt;br /&gt;     path = os.path.join(os.path.dirname(__file__), path)&lt;br /&gt;     logging.warn(path)&lt;br /&gt;     self.response.out.write(template.render(path, context))&lt;br /&gt;&lt;br /&gt; def redirect(self, uri, permanent=False):&lt;br /&gt;     """Issues an HTTP redirect to the given relative URL.&lt;br /&gt;&lt;br /&gt;     Args:&lt;br /&gt;       uri: a relative or absolute URI (e.g., '../flowers.html')&lt;br /&gt;       permanent: if true, we use a 301 redirect instead of a 302 redirect&lt;br /&gt;     """&lt;br /&gt;     if permanent:&lt;br /&gt;         self.response.set_status(301)&lt;br /&gt;     else:&lt;br /&gt;         self.response.set_status(302)&lt;br /&gt;&lt;br /&gt;     absolute_url = urlparse.urljoin(self.request.uri, uri)&lt;br /&gt;     self.response.headers['Location'] = str(absolute_url)&lt;br /&gt;     self.response.clear()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;The Controller class has a couple of methods of note:&lt;c&gt;&lt;/c&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;c&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;def rendertemplate(self, context, path):&lt;/span&gt;&lt;/c&gt; which takes a dictionary (&lt;c&gt;context&lt;/c&gt;) and the relative path to an HTML template. The templates themselves will use the Django template markup tags.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;c&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;def redirect(self, uri, permanent=False):&lt;/span&gt;&lt;/c&gt; which does an HTTP 301 or 302 redirect.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an example concrete Controller class where the &lt;c&gt;view&lt;/c&gt; method is the action as defined using Routes.&lt;/div&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;import twitter as twitter&lt;br /&gt;from controllers.Controller import Controller as controllerBase&lt;br /&gt;&lt;br /&gt;class ConcreteController(controllerBase):&lt;br /&gt;    def view(self, id):&lt;br /&gt;&lt;br /&gt;        data = doSomething(id)&lt;br /&gt;&lt;br /&gt;        template_values['data'] = data&lt;br /&gt;&lt;br /&gt;        self.rendertemplate(template_values, '../views/template.html')&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-5371520669709573512?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/NImpkpCxxkg" height="1" width="1"/&gt;</content><link rel="related" href="http://appengine-cookbook.appspot.com/recipe/match-webapp-urls-using-routes/" title="MVC Controller for webapp using Routes" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/5371520669709573512/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=5371520669709573512" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/5371520669709573512?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/5371520669709573512?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/NImpkpCxxkg/mvc-controller-for-webapp-using-routes.html" title="MVC Controller for webapp using Routes" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/04/mvc-controller-for-webapp-using-routes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUNSHY_cCp7ImA9WxJTFko.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-1580178280605561608</id><published>2009-04-25T16:43:00.000+01:00</published><updated>2009-04-25T16:44:59.848+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-25T16:44:59.848+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="memcache" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="gae" /><title>Session handling with Memcache API in Google AppEngine</title><content type="html">&lt;span class="Apple-style-span" style="font-family: Helvetica; font-size: 14px; "&gt;I've been trying to teach myself Python by witting a basic Twitter client in Google AppEngine. &lt;br /&gt;&lt;br /&gt;One of the things which I found lacking from the Webapp and Django frameworks was anything to manage sessions well. So, realising that the Memcache API has a timeout I figured that I could use that as the basis for session management. &lt;br /&gt;&lt;br /&gt;I ended up creating 2 classes, a SessionManager class to create, retrieve and delete sessions ans a Session object which would act as a simple dictionary to store arbitrary session values in. &lt;br /&gt;&lt;br /&gt;I would then be able to use the Session and SessionManager classes like this in my Controller class: &lt;br /&gt;&lt;div class="source_code_container"&gt;&lt;div class="source_code" style="background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: rgb(248, 248, 248); background-position: initial initial; "&gt;&lt;pre style="font-family: monospace; color: rgb(0, 112, 0); font-size: 9pt; background-color: rgb(250, 250, 250); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(187, 187, 187); border-right-color: rgb(187, 187, 187); border-bottom-color: rgb(187, 187, 187); border-left-color: rgb(187, 187, 187); line-height: 125%; margin-top: 1em; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.99em; padding-right: 0.99em; padding-bottom: 0.99em; padding-left: 0.99em; overflow-x: auto; overflow-y: auto; word-wrap: break-word; "&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;class&lt;/span&gt; &lt;span class="nc" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessionManager&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessionManager&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The SessionManager constructor needs both Request and Response objects because it needs to read and write Cookies. &lt;br /&gt;&lt;br /&gt;Here's the SessionManager class: &lt;br /&gt;&lt;div class="source_code_container"&gt;&lt;div class="source_code" style="background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: rgb(248, 248, 248); background-position: initial initial; "&gt;&lt;pre style="font-family: monospace; color: rgb(0, 112, 0); font-size: 9pt; background-color: rgb(250, 250, 250); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(187, 187, 187); border-right-color: rgb(187, 187, 187); border-bottom-color: rgb(187, 187, 187); border-left-color: rgb(187, 187, 187); line-height: 125%; margin-top: 1em; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.99em; padding-right: 0.99em; padding-bottom: 0.99em; padding-left: 0.99em; overflow-x: auto; overflow-y: auto; word-wrap: break-word; "&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;from&lt;/span&gt; &lt;span class="nn" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;google.appengine.api&lt;/span&gt; &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;import&lt;/span&gt; &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;br /&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;import&lt;/span&gt; &lt;span class="nn" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;datetime&lt;/span&gt;&lt;br /&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;import&lt;/span&gt; &lt;span class="nn" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;random&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;class&lt;/span&gt; &lt;span class="nc" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="mf" style="color: rgb(102, 102, 102); "&gt;1200&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookieName&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'SID'&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;cookievalue&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookieName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;cookievalue&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;is&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;not&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookievalue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;is&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;not&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;None&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;&lt;br /&gt;           &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookievalue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;           &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;newId&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;createNewId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;newId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+=&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookieName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;newId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;destroySession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookieName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;createNewId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;newHash&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'%Y%m&lt;/span&gt;&lt;span class="si" style="color: rgb(187, 102, 136); font-weight: bold; "&gt;%d&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;%H%M%S&lt;/span&gt;&lt;span class="si" style="color: rgb(187, 102, 136); font-weight: bold; "&gt;%f&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt; &lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;while&lt;/span&gt; &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;is&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;not&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;           &lt;span class="n"&gt;newHash&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateNewId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="n"&gt;newHash&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;setCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'Set-Cookie'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'='&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt; &lt;span class="s" style="color: rgb(186, 33, 33); "&gt;' path='&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'; expires '&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'%a, &lt;/span&gt;&lt;span class="si" style="color: rgb(187, 102, 136); font-weight: bold; "&gt;%d&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;-%b-%Y %H:%M:00 %Z'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I'm creating a unique sessionId by concatenating the current date/time with a random number. &lt;br /&gt;&lt;br /&gt;Here's the Session class: &lt;br /&gt;&lt;div class="source_code_container"&gt;&lt;div class="source_code" style="background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: rgb(248, 248, 248); background-position: initial initial; "&gt;&lt;pre style="font-family: monospace; color: rgb(0, 112, 0); font-size: 9pt; background-color: rgb(250, 250, 250); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(187, 187, 187); border-right-color: rgb(187, 187, 187); border-bottom-color: rgb(187, 187, 187); border-left-color: rgb(187, 187, 187); line-height: 125%; margin-top: 1em; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0.99em; padding-right: 0.99em; padding-bottom: 0.99em; padding-left: 0.99em; overflow-x: auto; overflow-y: auto; word-wrap: break-word; "&gt;&lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;class&lt;/span&gt; &lt;span class="nc" style="color: rgb(0, 0, 255); font-weight: bold; "&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isNew&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;id&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNew&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;isNew&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="nb" style="color: rgb(0, 128, 0); "&gt;dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'__keys'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'_'&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;__setitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'_'&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;br /&gt;       &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'__keys'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;def&lt;/span&gt; &lt;span class="nf" style="color: rgb(0, 0, 255); "&gt;hasKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;       &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o" style="color: rgb(102, 102, 102); "&gt;=&lt;/span&gt; &lt;span class="n"&gt;memcache&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;+&lt;/span&gt;&lt;span class="s" style="color: rgb(186, 33, 33); "&gt;'__keys'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;       &lt;span class="k" style="color: rgb(0, 128, 0); font-weight: bold; "&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow" style="color: rgb(170, 34, 255); font-weight: bold; "&gt;in&lt;/span&gt; &lt;span class="bp" style="color: rgb(0, 128, 0); "&gt;self&lt;/span&gt;&lt;span class="o" style="color: rgb(102, 102, 102); "&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;That's kind of it really. It's working well at the moment but I've not used it with very large numbers of concurrent users.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-1580178280605561608?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/9bWfbR7weVo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/1580178280605561608/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=1580178280605561608" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/1580178280605561608?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/1580178280605561608?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/9bWfbR7weVo/session-handling-with-memcache-api-in.html" title="Session handling with Memcache API in Google AppEngine" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/04/session-handling-with-memcache-api-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08BSHg_fyp7ImA9WxVWE0Q.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-1465777583938474462</id><published>2009-02-22T00:49:00.006Z</published><updated>2009-02-23T14:37:39.647Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-23T14:37:39.647Z</app:edited><title>Virtual site handler in .net</title><content type="html">I cam across a situation the other day where I found that my ASP.NET was limited to 1 website and I wanted to be able to host more than one website. Each site wasn't going to be that big or clever so I decided to see if I could come up with an IHttpModule which would be able to make it serve different pages depending on which domain was requested.&lt;br /&gt;&lt;br /&gt;The core of the solution I came up with is the &lt;c&gt;VirtualSiteManager&lt;/c&gt; class which given a request will return a re-written path which an IHttpModule can rewrite to.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; VirtualSiteManager&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; VirtualSiteManager(&lt;span class="kwrd"&gt;string&lt;/span&gt; defaultSiteName)&lt;br /&gt;   {&lt;br /&gt;       _defaultSiteName = defaultSiteName;&lt;br /&gt;       Sites = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, VirtualSite&amp;gt;();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _defaultSiteName;&lt;br /&gt;  &lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; VirtualSiteManager _instance;&lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Type _lock = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(VirtualSiteManager);&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; VirtualSiteManager Instance&lt;br /&gt;   {&lt;br /&gt;       get&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;lock&lt;/span&gt; (_lock)&lt;br /&gt;           {&lt;br /&gt;               &lt;span class="kwrd"&gt;if&lt;/span&gt; (_instance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;               {&lt;br /&gt;                   _instance = (VirtualSiteManager) WebConfigurationManager.GetSection(&lt;span class="str"&gt;"virtualSite"&lt;/span&gt;);&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; _instance;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; VirtualSite DefaultSite&lt;br /&gt;   {&lt;br /&gt;       get&lt;br /&gt;       {&lt;br /&gt;           VirtualSite defaultSite = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;if&lt;/span&gt; (Sites.ContainsKey(_defaultSiteName))&lt;br /&gt;           {&lt;br /&gt;               defaultSite = Sites[_defaultSiteName];&lt;br /&gt;           }&lt;br /&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; defaultSite;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, VirtualSite&amp;gt; Sites&lt;br /&gt;   {&lt;br /&gt;       get;&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; set;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddSite(VirtualSite site)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Sites.ContainsKey(site.Host))&lt;br /&gt;       {&lt;br /&gt;           Sites.Add(site.Host, site);&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;       {&lt;br /&gt;           Sites[site.Host] = site;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddSite(&lt;span class="kwrd"&gt;string&lt;/span&gt; name, &lt;span class="kwrd"&gt;string&lt;/span&gt; host, &lt;span class="kwrd"&gt;string&lt;/span&gt; virtualPath)&lt;br /&gt;   {&lt;br /&gt;       AddSite(&lt;span class="kwrd"&gt;new&lt;/span&gt; VirtualSite(name, host, virtualPath));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; RewritePath(HttpContext context)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;string&lt;/span&gt; host = context.Request.Url.Host;&lt;br /&gt;       VirtualSite handlingSite = (Sites.ContainsKey(host)) ? Sites[host]: DefaultSite;&lt;br /&gt;       &lt;span class="kwrd"&gt;string&lt;/span&gt; currentPath = context.Request.CurrentExecutionFilePath;&lt;br /&gt;&lt;br /&gt;       context.Response.AddHeader(&lt;span class="str"&gt;"X-Debug-currentPath"&lt;/span&gt;, currentPath);&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;string&lt;/span&gt; returnPath = handlingSite.VirtualPath + (currentPath.StartsWith(&lt;span class="str"&gt;"/"&lt;/span&gt;) ? currentPath.Substring(1) : currentPath);&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (returnPath.EndsWith(&lt;span class="str"&gt;"/"&lt;/span&gt;))&lt;br /&gt;       {&lt;br /&gt;           returnPath += &lt;span class="str"&gt;"index.aspx"&lt;/span&gt;;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; returnPath;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;I store the domains and what their virtual path's are in the Web.Config like this:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;section&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="virtualSite"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="RomfordEvan.Web.Components.VirtualSite.VirtualSiteHandler, RomfordEvan.Web.Components"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;virtualSite&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="default"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;site&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="default"&lt;/span&gt; &lt;span class="attr"&gt;host&lt;/span&gt;&lt;span class="kwrd"&gt;="www.domain1.com"&lt;/span&gt; &lt;span class="attr"&gt;virtualPath&lt;/span&gt;&lt;span class="kwrd"&gt;="/"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;site&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="localhost"&lt;/span&gt; &lt;span class="attr"&gt;host&lt;/span&gt;&lt;span class="kwrd"&gt;="localhost"&lt;/span&gt; &lt;span class="attr"&gt;virtualPath&lt;/span&gt;&lt;span class="kwrd"&gt;="/"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;site&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="domain2"&lt;/span&gt; &lt;span class="attr"&gt;host&lt;/span&gt;&lt;span class="kwrd"&gt;="www.domain2.com"&lt;/span&gt; &lt;span class="attr"&gt;virtualPath&lt;/span&gt;&lt;span class="kwrd"&gt;="/domain2/"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;virtualSite&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;c&gt;IConfigurationSectionHandler&lt;/c&gt; to read the Web.Config and create the &lt;c&gt;VirtualSiteManager&lt;/c&gt; looks like this:&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; VirtualSiteHandler : IConfigurationSectionHandler&lt;br /&gt;{&lt;br /&gt;   &lt;span class="preproc"&gt;#region&lt;/span&gt; IConfigurationSectionHandler Members&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; Create(&lt;span class="kwrd"&gt;object&lt;/span&gt; parent, &lt;span class="kwrd"&gt;object&lt;/span&gt; configContext, System.Xml.XmlNode section)&lt;br /&gt;   {           &lt;br /&gt;       XmlAttribute def = section.Attributes[&lt;span class="str"&gt;"default"&lt;/span&gt;];&lt;br /&gt;      &lt;br /&gt;       &lt;span class="kwrd"&gt;string&lt;/span&gt; defaultSiteName = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (def != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; def.InnerText.Length &amp;gt; 0)&lt;br /&gt;       {&lt;br /&gt;           defaultSiteName = def.InnerText;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       VirtualSiteManager manager = &lt;span class="kwrd"&gt;new&lt;/span&gt; VirtualSiteManager(defaultSiteName);&lt;br /&gt;&lt;br /&gt;       XmlNodeList siteNodes = section.SelectNodes(&lt;span class="str"&gt;".//site"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (XmlNode siteNode &lt;span class="kwrd"&gt;in&lt;/span&gt; siteNodes)&lt;br /&gt;       {&lt;br /&gt;           manager.AddSite(siteNode.Attributes[&lt;span class="str"&gt;"name"&lt;/span&gt;].InnerText, siteNode.Attributes[&lt;span class="str"&gt;"host"&lt;/span&gt;].InnerText, siteNode.Attributes[&lt;span class="str"&gt;"virtualPath"&lt;/span&gt;].InnerText);&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; manager;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This works fine with the following caveats:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Under IIS6 it requires wildcard mapping to the ASP.NET ISAPI filter.&lt;/li&gt;&lt;li&gt;You will need to add &lt;c&gt;HttpHandler&lt;/c&gt;s for all the file types which your site will serve (see below)&lt;/li&gt;&lt;/ul&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET,POST"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*/"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.UI.PageHandlerFactory"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.html"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.js"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.gif"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.jpg"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.png"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.css"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.StaticFileHandler"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-1465777583938474462?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/dmpGowhTFCA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/1465777583938474462/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=1465777583938474462" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/1465777583938474462?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/1465777583938474462?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/dmpGowhTFCA/virtual-site-handler-in-net.html" title="Virtual site handler in .net" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/02/virtual-site-handler-in-net.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcCRXc5eCp7ImA9WxVWFE0.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-6598036843743926413</id><published>2009-02-18T18:12:00.016Z</published><updated>2009-02-23T14:41:04.920Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-23T14:41:04.920Z</app:edited><title>Generic, type safe Configuration Manager</title><content type="html">I like to store lots of config data in the Web.Config and I get fed up with having to cast the ConfigSection to the concrete class:&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;MyConfigSectionHandler handler =&lt;br /&gt;(MyConfigSectionHandler)&lt;br /&gt;WebConfigurationManager.GetSection(sectionName);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So I've written a helper class where now you can use:&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;MyConfigSectionHandler config =&lt;br /&gt;ConfigManager.Instance.GetSection&amp;lt;MyConfigSectionHandler&amp;gt;&lt;br /&gt;(sectionName);&lt;/pre&gt;&lt;br /&gt;Here's the code - (I've implemented it as a Singleton for a reason I don't remember now):&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ConfigManager&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ConfigManager _instance;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; _lock = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ConfigManager);&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; ConfigManager()&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// Gets a singleton instance.&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;value&amp;gt;The instance.&amp;lt;/value&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ConfigManager Instance&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;lock&lt;/span&gt; (_lock)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_instance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    _instance = &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigManager();&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; _instance;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// Gets the section.&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;param name="sectionName"&amp;gt;Name of the section.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; T GetSection&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt; sectionName)&lt;br /&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; T : &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; WebConfigurationManager.GetSection(sectionName) &lt;span class="kwrd"&gt;as&lt;/span&gt; T;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-6598036843743926413?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/rIdbAD3OwX4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/6598036843743926413/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=6598036843743926413" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6598036843743926413?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/6598036843743926413?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/rIdbAD3OwX4/generic-configuration-manager.html" title="Generic, type safe Configuration Manager" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2009/02/generic-configuration-manager.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkAMSHs5cCp7ImA9WxVWEE4.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-112420205821607074</id><published>2007-07-13T15:06:00.007+01:00</published><updated>2009-02-19T10:19:49.528Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-19T10:19:49.528Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Factory Pattern" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>The Factory pattern with Attributes</title><content type="html">I've been using the Factory design pattern for some time, it's nice and simple, creating different objects depending on what parameters you pass to a given 'Create' function. The only problem is that for most of the situations that I come across, all the Create function seems to do is contain a &lt;code&gt;switch case&lt;/code&gt; statement, which is rather in-elegant and not really scalable.&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;public Cheese CreateCheese(string cheeseType)&lt;br /&gt;{&lt;br /&gt;    Cheese newCheese = null;&lt;br /&gt;&lt;br /&gt;    switch (cheeseType)&lt;br /&gt;    {&lt;br /&gt;        case "Cheddar":&lt;br /&gt;            newCheese = CheddarCheese();&lt;br /&gt;            break;&lt;br /&gt;        case "Edam":&lt;br /&gt;            newCheese = EdamCheese();&lt;br /&gt;            break;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return newCheese;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The problem obviously is that (in this case) if you now wanted to add a new type of cheese, that you would have to add a new case statement to the list.&lt;br /&gt;&lt;br /&gt;I recently found a few good examples of how to get around this problem using Reflection and custom Attributes, I especially liked the &lt;a href="http://www.codeproject.com/csharp/factorywithattributes.asp"&gt;Implementing the factory pattern using attributes and activation&lt;/a&gt; solution by John Gunnarsson.&lt;br /&gt;&lt;br /&gt;However, what I didn't like about this was that you swapped your switch case statement for a series of statements adding types to a collection:&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;factory.RegisterCheeseType(typeof(CheddarCheese));&lt;br /&gt;factory.RegisterCheeseType(typeof(EdamCheese));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;My alternate solution is to store this list a custom section within the config file. This way you can define the classes that the Factory can create outside the Factory Assembly and reference them in the config file. This is a good thing because it provides an extensible architecture allowing other developers to extend the functionality without recompiling the main assembly&lt;br /&gt;&lt;br /&gt;The Factory class would now look like this:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;CheeseFactory.cs&lt;/h4&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;public class CheeseFactory&lt;br /&gt;{&lt;br /&gt;    private CheeseFactorySettings settings;&lt;br /&gt;&lt;br /&gt;    public CheeseFactory()&lt;br /&gt;    {&lt;br /&gt;        settings = (CheeseFactorySettings)ConfigurationSettings.GetConfig("cheeseFactory");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Cheese CreateCheese(string cheeseType)&lt;br /&gt;    {&lt;br /&gt;        return settings.GetCheese(cheeseType);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;What we're doing here is to pass the actual decision as to which class to make to this &lt;var&gt;CheeseFactorySettings&lt;/var&gt; class. You could argue that we're duplicating the 'Create' Factory method in both the &lt;var&gt;CheeseFactorySettings&lt;/var&gt; class and the &lt;var&gt;CheeseFactory&lt;/var&gt; class, and that that's a bad thing. If you think that smells a bit too much, then just stick the collection traversing logic in the &lt;var&gt;CheeseFactorySettings.GetCheeseFactory()&lt;/var&gt; method into the &lt;var&gt;CheeseFactory.CreateCheese()&lt;/var&gt; method. In any case, the &lt;var&gt;CheeseFactorySettings&lt;/var&gt; class is defined below:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;CheeseFactorySettings.cs&lt;/h4&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;public class CheeseFactorySettings : CollectionBase&lt;br /&gt;{&lt;br /&gt;    public CheeseFactorySettings(XmlNode section)&lt;br /&gt;    {&lt;br /&gt;        foreach (XmlNode node in section.ChildNodes)&lt;br /&gt;        {&lt;br /&gt;            if (node.Name == "formatter")&lt;br /&gt;            {&lt;br /&gt;                List.Add(Type.GetType(node.Attributes["type"].InnerText));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Cheese GetCheeseFactory(string format)&lt;br /&gt;    {&lt;br /&gt;        foreach (Type implementation in List)&lt;br /&gt;        {&lt;br /&gt;            CheeseFactoryAttribute[] attributeList = (CheeseFactoryAttribute[])implementation.GetCustomAttributes(typeof(CheeseFactoryAttribute), true);&lt;br /&gt;&lt;br /&gt;            foreach (object attribute in attributeList)&lt;br /&gt;            {&lt;br /&gt;                if (attribute is CheeseFactoryAttribute)&lt;br /&gt;                {&lt;br /&gt;                    if (((CheeseFactoryAttribute) attribute).Format == format)&lt;br /&gt;                    {&lt;br /&gt;                        return (Cheese) Activator.CreateInstance(implementation);&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        break;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        throw new InvalidCastException("Could not find a Cheese implementation for this format");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;A possible addition you could do to this class is to implement the &lt;var&gt;OnValidate&lt;/var&gt; method of the &lt;var&gt;CollectionBase&lt;/var&gt; class to prevent classes that do not inherit from &lt;var&gt;Cheese&lt;/var&gt; from being added to the collection of types. (The &lt;var&gt;base.OnValidate&lt;/var&gt; call checks to see if the newly added value is not a &lt;var&gt;null&lt;/var&gt; reference).&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;protected override void OnValidate(object value)&lt;br /&gt;{&lt;br /&gt;    base.OnValidate(value);&lt;br /&gt;&lt;br /&gt;    if (!(value as Type).IsSubclassOf(typeof(Cheese)))&lt;br /&gt;    {&lt;br /&gt;        throw new InvalidCastException("Cheese types must inherit from Cheese");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There's a couple more final classes to go before the whole barebones of the solution is complete. Firstly the &lt;var&gt;IConfigurationSectionHandler&lt;/var&gt; implementation to read the values from the config file at runtime. This is pretty standard stuff:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;CheeseFactorySectionHandler.cs&lt;/h4&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;public class CheeseFactorySectionHandler : IConfigurationSectionHandler&lt;br /&gt;{&lt;br /&gt;    public object Create(object parent, object configContext, XmlNode section)&lt;br /&gt;    {&lt;br /&gt;        CheeseFactorySettings settings = new CheeseFactorySettings(section);&lt;br /&gt;&lt;br /&gt;        return settings;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;All we're doing is creating a new &lt;var&gt;CheeseFactorySettings&lt;/var&gt; class and passing through the &lt;var&gt;XmlNode&lt;/var&gt; from the config file to it's constructor.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-112420205821607074?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/WC0dxBcnMF8" height="1" width="1"/&gt;</content><link rel="related" href="http://www.codeproject.com/cs/design/factorywithattributes.asp" title="The Factory pattern with Attributes" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/112420205821607074/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=112420205821607074" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/112420205821607074?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/112420205821607074?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/WC0dxBcnMF8/factory-pattern-with-attributes-config.html" title="The Factory pattern with Attributes" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2005/08/factory-pattern-with-attributes-config.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYDSXs_eip7ImA9WxNQEU0.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-110122292240377364</id><published>2006-11-23T14:43:00.001Z</published><updated>2009-09-16T14:19:38.542+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-16T14:19:38.542+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Web" /><title>Viewing RSS feeds in a browser</title><content type="html">&lt;p&gt;It's an obvious little trick and I don't know why I hadn't thought of it before, but MSDN have updated their RSS feeds with a reference to an XSL so that browsers that support XSL will render the feed as XHTML rather than displaying the source.&lt;/p&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;p&gt;All it does is to force the browser to transform the rss xml to XHTML thus:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml-stylesheet type='text/xsl' href='rsspretty.xsl' version='1.0'?&amp;gt;&lt;br /&gt;&amp;lt;rss xmlns:msdn="http://msdn.microsoft.com/aboutmsdn/rss/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:msdndomain="http://msdn.microsoft.com/aboutmsdn/...&lt;br /&gt;rss/domains" version="2"&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;channel&amp;gt;&lt;br /&gt;&lt;br /&gt;      &amp;lt;title&gt;MSDN: Visual C#&amp;lt;/title&amp;gt;&lt;br /&gt;&lt;br /&gt;      ...&lt;br /&gt;&lt;br /&gt;   &amp;lt;/channel&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/rss&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-110122292240377364?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/Bza8b_9Dw1U" height="1" width="1"/&gt;</content><link rel="related" href="http://msdn.microsoft.com/vcsharp/rss.xml" title="Viewing RSS feeds in a browser" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/110122292240377364/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=110122292240377364" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/110122292240377364?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/110122292240377364?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/Bza8b_9Dw1U/viewing-rss-feeds-in-browser.html" title="Viewing RSS feeds in a browser" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2004/11/viewing-rss-feeds-in-browser.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQBR3s7eip7ImA9WB5XEkU.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-109782828763252891</id><published>2004-10-15T09:18:00.000+01:00</published><updated>2007-07-13T00:35:56.502+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-07-13T00:35:56.502+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Web" /><title>Google Desktop Search</title><content type="html">&lt;div style="margin: 0.5em; padding: 0.25em; float: right;"&gt;&lt;a href="http://www.desktop.google.com/" target="_blank" title="Link will open in new window"&gt;&lt;img src="http://www.desktop.google.com/images/tasktray.gif" title="Google Desktop Search task tray" height="38" width="130" /&gt;&lt;/a&gt;&lt;/div&gt;Have you seen this new Desktop search tool from Google? Essentially it's a search engine/application for use on your local machine, rather than the web.&lt;span class="fullpost"&gt; By default it indexes all files on your machine.&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Google Desktop Search finds:&lt;/strong&gt;&lt;/p&gt;&lt;ul class="gl"&gt;&lt;li id="gl-outlook"&gt;Outlook / Outlook Express&lt;/li&gt;&lt;li id="gl-word"&gt;Word&lt;/li&gt;&lt;li id="gl-aol"&gt;AOL Instant Messenger&lt;/li&gt;&lt;li id="gl-excel"&gt;Excel&lt;/li&gt;&lt;li id="gl-ie"&gt;Internet Explorer&lt;/li&gt;&lt;li id="gl-pp"&gt;PowerPoint&lt;/li&gt;&lt;li id="gl-txt"&gt;Text&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;A neat trick (which I guess it does with cookies for the www.google.com site) is that it puts a link on the existing www.google.com site to search your desktop instead of the web. A nice thing that it does is that it searches your Outlook emails - and returns results in super quick time! From a technical point of view, what it looks like is that it installs some kind of mini-web server - you search through the browser on an address of http://127.0.0.1:xxxx/.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-109782828763252891?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/iOe25HhaaT8" height="1" width="1"/&gt;</content><link rel="related" href="http://www.desktop.google.com/" title="Google Desktop Search" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/109782828763252891/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=109782828763252891" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109782828763252891?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109782828763252891?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/iOe25HhaaT8/google-desktop-search.html" title="Google Desktop Search" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2004/10/google-desktop-search.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQDQH8-fyp7ImA9WB5XEkU.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-109766284402673950</id><published>2004-10-13T10:55:00.000+01:00</published><updated>2007-07-13T00:36:11.157+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-07-13T00:36:11.157+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Book review" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Book Review: Design Patterns in C#</title><content type="html">&lt;div style="float: right; margin-left: 10px; margin-bottom: 10px;"&gt; &lt;a href="http://www.oozinoz.com/dpcs.htm" target="_blank" title="Link will open in new window"&gt;&lt;img src="http://www.oozinoz.com/images/dpcs.jpg" title="Design Patterns in C#" style="border: 1px solid rgb(0, 0, 0);" height="171" width="125" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="margin-top: 0px;font-size:0;" &gt;Design Patterns in C#&lt;/span&gt;&lt;/div&gt;Covering all the classic &lt;em&gt;Gang of Four&lt;/em&gt; software design patterns in one straighforward book, Steven Metsker gives some decent concrete examples of their application with the corresponding UML.&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;Design patterns help developers leverage the wisdom of the entire software community to build more robust higher-quality software. Now, for the first time, there is a complete patterns guide &lt;em&gt;specifically for C# and .NET programmers&lt;/em&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;What's good about the book is the writing style and the exercises. The author obviously has done a good job of applying design patterns to the .NET framework, utilising events, delegates and reflection. On the downside, what would be additionally useful would be more discussion about applying design patterns in non-standard situations.&lt;br /&gt;&lt;br /&gt;All in all, this book would be an excellent addition to the stack of books you keep next to your workstation. My copy is almost always open at the pattern I'm using at the moment.&lt;br /&gt;&lt;div style="border: 1px solid rgb(224, 224, 224); padding: 0.5em; margin: 0.5em; clear: both;"&gt;You can get a sample chapter of the book from the publishers &lt;a href="http://www.awprofessional.com/" title="Link will open in new window" target="_blank"&gt;Addison Wesley&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.awprofessional.com/content/images/0321126971/samplechapter/metskerch03.pdf" title="Link will open in new window" target="_blank" style="padding-left: 55px; background-image: url(http://www.adobe.com/products/images/pdf_logo_trefoil.gif); background-position: left top; background-repeat: no-repeat; height: 40px; display: block; padding-top: 1em;"&gt;Sample chapter&lt;/a&gt;&lt;/div&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-109766284402673950?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/w3Snr7Pj69A" height="1" width="1"/&gt;</content><link rel="related" href="http://www.oozinoz.com/dpcs.htm" title="Book Review: Design Patterns in C#" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/109766284402673950/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=109766284402673950" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109766284402673950?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109766284402673950?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/w3Snr7Pj69A/book-review-design-patterns-in-c.html" title="Book Review: Design Patterns in C#" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2004/10/book-review-design-patterns-in-c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQMQnw-cSp7ImA9WB5XEkU.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-109705735784994551</id><published>2004-10-06T11:09:00.000+01:00</published><updated>2007-07-13T00:36:23.259+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-07-13T00:36:23.259+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="General" /><title>Attack of the Canonicalization-alisers</title><content type="html">&lt;span class="fullpost"&gt;Canonicalization attacks are where malicious users try to gain access to files that they shouldn't by entering file names and paths that the system understands, but that you don't expect.&lt;/span&gt; It's quite possible that the following filepaths could (depending on the context) all point to the same file:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;c:\dir\test.dat&lt;br/&gt;&lt;br /&gt;test.dat&lt;br/&gt;&lt;br /&gt;..\..\test.dat&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When a URL is received by a Web server, the server maps the request to a file system path that determines the response. The canonicalization routine that is used to map the request must correctly parse the URL to avoid serving or processing unexpected content. For more information about canonicalization, visit the following Microsoft Web site: &lt;br /&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh04.asp" title="Link will open in new window" target="_blank"&gt;http://msdn.microsoft.com/library/.../THCMCh04.asp&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Also related to this KB article is somthing that &lt;a href="http://scottwater.com/" title="Link will open in new window" target="_blank"&gt;Scott Watermasysk&lt;/a&gt; highlighted&lt;br /&gt;&lt;a href="http://scottwater.com/blog/archive/2004/10/05/aspnet_security_issue_and_guidance" title="Link will open in new window" target="_blank"&gt;ASP.NET Security Issue and Guidance&lt;/a&gt; about an ASP.NET Forms authentication vulnerability, which can be cured with the appropriate canonical checks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-109705735784994551?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/ysiZQVQq3ns" height="1" width="1"/&gt;</content><link rel="related" href="http://support.microsoft.com/?kbid=887459" title="Attack of the Canonicalization-alisers" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/109705735784994551/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=109705735784994551" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109705735784994551?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109705735784994551?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/ysiZQVQq3ns/attack-of-canonicalization-alisers.html" title="Attack of the Canonicalization-alisers" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>1</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2004/10/attack-of-canonicalization-alisers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMEQn8_eyp7ImA9WB5XEkU.&quot;"><id>tag:blogger.com,1999:blog-8582166.post-109688878815849683</id><published>2004-10-04T13:18:00.000+01:00</published><updated>2007-07-13T00:36:43.143+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-07-13T00:36:43.143+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Web" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Using Reflection to Bind Business Objects to ASP.NET Form Controls</title><content type="html">This looks like a really useful way to simplify databinding ASP.NET controls to a generic business object. I've yet to use this in a fully fledged live project and so I'm not sure how accurate their performance metrics are. &lt;span class="fullpost"&gt;Off the top of my head I think I would implement these two methods 'BindControlsToObject' and 'BindObjectToControls' in a new class derived from the Page object, but whatever takes your fancy really.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8582166-109688878815849683?l=codepeace.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodePeace/~4/M15OoIS65Wo" height="1" width="1"/&gt;</content><link rel="related" href="http://msdn.microsoft.com/asp.net/using/building/web/default.aspx?pull=/library/en-us/dnaspp/html/aspformbinding.asp" title="Using Reflection to Bind Business Objects to ASP.NET Form Controls" /><link rel="replies" type="application/atom+xml" href="http://codepeace.blogspot.com/feeds/109688878815849683/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8582166&amp;postID=109688878815849683" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109688878815849683?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8582166/posts/default/109688878815849683?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodePeace/~3/M15OoIS65Wo/using-reflection-to-bind-business.html" title="Using Reflection to Bind Business Objects to ASP.NET Form Controls" /><author><name>Phil Peace</name><uri>http://www.blogger.com/profile/02235125191645027799</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://www.flickr.com/buddyicons/51035725674@N01.jpg?1095873651" /></author><thr:total>0</thr:total><feedburner:origLink>http://codepeace.blogspot.com/2004/10/using-reflection-to-bind-business.html</feedburner:origLink></entry></feed>

