<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>ViNull, Off the Record : asp.net</title><link>http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx</link><description>Tags: asp.net</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>ASP.NET: Cannot use a leading .. to exit above the top directory</title><link>http://devlicio.us/blogs/vinull/archive/2010/03/12/asp-net-cannot-use-a-leading-to-exit-above-the-top-directory.aspx</link><pubDate>Fri, 12 Mar 2010 20:09:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:55902</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=55902</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2010/03/12/asp-net-cannot-use-a-leading-to-exit-above-the-top-directory.aspx#comments</comments><description>&lt;p&gt;&lt;a title="Caen como moscas by Eduardo!" href="http://www.flickr.com/photos/eduardox/2315932412/"&gt;&lt;img style="border-right-width:0px;margin:0px 10px 10px 0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" align="left" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vinull/image_5F00_28F0EF6F.png" width="244" height="184" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This is a really quick post, mostly for myself so the next time I have this issue I can find the answer (yes, I often search my blog before google).&lt;/p&gt;  &lt;p&gt;The error “Cannot use a leading .. to exit above the top directory” can be thrown by ASP.NET when you use relative paths incorrectly.&amp;#160; If you generate a url with too many “../../../” levels in it that would take the user above the root directory, you can generate the exception.&lt;/p&gt;  &lt;p&gt;Why the exception?&amp;#160; Security I guess, but it’s a client URL and the server should know better than let the internet walk the C drive, but at one time a company in Redmond had servers with just such issues.&amp;#160; My problem isn’t with the unneeded exception (after all, it would just be a 404 link worst case), but with the bug in ASP.NET that causes it.&lt;/p&gt;  &lt;p&gt;If you are using Server.Transfer or HttpContext.RewritePath to redirect a request (say map it to a template page) and have a HyperLink control with the ImageUrl property set, you win an extra “../” by the framework.&amp;#160; The fix is to wrap the HyperLink control around an Image control.&amp;#160; &lt;/p&gt;  &lt;p&gt;In code, if you have:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;HyperLink&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;runat&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;NavigateUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;~/FlyPage.aspx&amp;quot;&lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#ff0000;"&gt;ImageUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;~/Images/DeadFly.png&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Height&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change it to:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;HyperLink&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;runat&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;NavigateUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;~/FlyPage.aspx&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Image&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;runat&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;ImageUrl&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;~/Images/DeadFly.png&amp;quot;&lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Height&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;HyperLink&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;(I said it was a quick post… now go register for &lt;a href="http://codestock.org"&gt;CodeStock&lt;/a&gt;!)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=55902" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category></item><item><title>ASP.NET: Creating a UserControl with Child Content</title><link>http://devlicio.us/blogs/vinull/archive/2009/12/07/asp-net-creating-a-usercontrol-with-child-content.aspx</link><pubDate>Tue, 08 Dec 2009 02:10:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:54344</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=54344</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2009/12/07/asp-net-creating-a-usercontrol-with-child-content.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://www.flickr.com/photos/epublicist/3546059144/"&gt;&lt;img style="border-right-width:0px;margin:0px 10px 10px 0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="square-peg-round-hole-21 by Yoel Ben-Avraham" alt="square-peg-round-hole-21 by Yoel Ben-Avraham" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/vinull/image_5F00_3.png" width="244" align="left" border="0" height="184" /&gt;&lt;/a&gt;I love ASP.NET &lt;a href="http://msdn.microsoft.com/en-us/library/y6wb1a0e.aspx"&gt;User Controls&lt;/a&gt;, aka &amp;ldquo;ascx&amp;rdquo; files.&amp;nbsp; These little guys are great for reusable content and dividing up the components of a website.&amp;nbsp; The little brother of the more powerful &lt;a href="http://msdn.microsoft.com/en-us/library/zt27tfhy.aspx"&gt;Custom Server Control&lt;/a&gt;, they have some limitations, but I&amp;rsquo;ve found they are often sold short.&amp;nbsp; Once falsehood is that a User Control cannot contain content between the opening and closing tags, like such:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color:red;"&gt;Title&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;The Control has Content!&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. &lt;br /&gt;    Donec ut nisi sed elit aliquam vulputate eu et lacus&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;HyperLink &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color:red;"&gt;NavigateUrl&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;~/&amp;quot;&amp;gt;&lt;/span&gt;Home&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;HyperLink&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;If you attempt something like this with a stock User Control you&amp;rsquo;ll get &amp;ldquo;&lt;b&gt;&lt;/b&gt;Type &amp;#39;ASP.mycontent_contentblock_ascx&amp;#39; does not have a public property named &amp;#39;p&amp;#39;.&amp;rdquo;&amp;nbsp; If we just want to have a simple control that formats the content, then we only need a few tweaks and we can keep the User Control (if you have more advanced needs, then it&amp;rsquo;s time to step up to a Custom Server Control).&lt;/p&gt;
&lt;p&gt;The first tweak is to wrap the ascx template in a single control:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#ffee62;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;@ &lt;/span&gt;&lt;span style="color:#a31515;"&gt;Control &lt;/span&gt;&lt;span style="color:red;"&gt;Language&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;C#&amp;quot; &lt;/span&gt;&lt;span style="color:red;"&gt;AutoEventWireup&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;true&amp;quot; &lt;br /&gt;    &lt;/span&gt;&lt;span style="color:red;"&gt;CodeFile&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;ContentBlock.ascx.cs&amp;quot; &lt;/span&gt;&lt;span style="color:red;"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;MyControl_ContentBlock&amp;quot; &lt;/span&gt;&lt;span style="background:#ffee62;"&gt;%&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;PlaceHolder &lt;/span&gt;&lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;phContent&amp;quot; &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;Title &lt;span style="background:#ffee62;"&gt;%&amp;gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div &lt;/span&gt;&lt;span style="color:red;"&gt;class&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;body&amp;quot;&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;Text &lt;span style="background:#ffee62;"&gt;%&amp;gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;PlaceHolder&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I choose a PlaceHolder control because it won&amp;rsquo;t emit any HTML.&amp;nbsp; Then in code-behind we need to make a few tweaks:&lt;/p&gt;
&lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;ParseChildren&lt;/span&gt;(&lt;span style="color:blue;"&gt;false&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:blue;"&gt;public partial class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MyContent_ContentBlock &lt;/span&gt;: System.Web.UI.&lt;span style="color:#2b91af;"&gt;UserControl&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;String &lt;/span&gt;Title { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;    &lt;span style="color:blue;"&gt;protected &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;String &lt;/span&gt;Text { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;protected override void &lt;/span&gt;AddParsedSubObject(&lt;span style="color:blue;"&gt;object &lt;/span&gt;obj) {&lt;br /&gt;        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(obj &lt;span style="color:blue;"&gt;is &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;LiteralControl&lt;/span&gt;) &lt;br /&gt;            &lt;span style="color:blue;"&gt;this&lt;/span&gt;.Text += ((&lt;span style="color:#2b91af;"&gt;LiteralControl&lt;/span&gt;)obj).Text;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;else if &lt;/span&gt;(obj &lt;span style="color:blue;"&gt;is &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;PlaceHolder &lt;/span&gt;&amp;amp;&amp;amp; !&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.IsNullOrEmpty(((&lt;span style="color:#2b91af;"&gt;PlaceHolder&lt;/span&gt;)obj).ID) &lt;br /&gt;            &amp;amp;&amp;amp; ((&lt;span style="color:#2b91af;"&gt;PlaceHolder&lt;/span&gt;)obj).ID.Equals(&lt;span style="color:#a31515;"&gt;&amp;quot;phContent&amp;quot;&lt;/span&gt;)) &lt;br /&gt;            &lt;span style="color:blue;"&gt;base&lt;/span&gt;.AddParsedSubObject(obj);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:blue;"&gt;else &lt;/span&gt;{&lt;br /&gt;            &lt;span style="color:#2b91af;"&gt;StringBuilder &lt;/span&gt;sb = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringBuilder&lt;/span&gt;();&lt;br /&gt;            &lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;StringWriter &lt;/span&gt;sw = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringWriter&lt;/span&gt;(sb)) {&lt;br /&gt;                &lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;HtmlTextWriter &lt;/span&gt;w = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlTextWriter&lt;/span&gt;(sw)) {&lt;br /&gt;                    ((&lt;span style="color:#2b91af;"&gt;Control&lt;/span&gt;)obj).RenderControl(w);&lt;br /&gt;                    &lt;span style="color:blue;"&gt;this&lt;/span&gt;.Text += sb.ToString();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;The class gets a new attribute, &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.parsechildrenattribute.aspx"&gt;ParseChildren&lt;/a&gt;, set to false.&amp;nbsp; I&amp;rsquo;m stealing this attribute from the Custom Server Control which normally would use this attribute to map the child content to a property.&amp;nbsp; Setting it to false however on a User Control will stop the framework from throwing an error on the User Control.&amp;nbsp; If you stop here, the output of the control would look something like:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;    &lt;/span&gt;The Control has Content!&lt;br /&gt;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div &lt;/span&gt;&lt;span style="color:red;"&gt;class&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;body&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. &lt;br /&gt;Donec ut nisi sed elit aliquam vulputate eu et lacus&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;a &lt;/span&gt;&lt;span style="color:red;"&gt;href&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;/Default.aspx&amp;quot;&amp;gt;&lt;/span&gt;Home&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;a&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The content was appended to the User Control template.&amp;nbsp; This can be fixed by overriding the &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.control.addparsedsubobject.aspx"&gt;AddParsedSubObject&lt;/a&gt; method.&amp;nbsp; This method is called for every control in the User Control &amp;ndash; including the PlaceHolder that acts as our template.&amp;nbsp; Any HTML content is converted into a LiteralControl.&amp;nbsp; The logic checks the control being passed in, and if it&amp;rsquo;s a LiteralControl the text is added to the control&amp;rsquo;s Text property.&amp;nbsp; If the control is the PlaceHolder it is passed to the base method to let normal processing takeover.&amp;nbsp; The remaining controls are rendered, and the text appended to the control&amp;rsquo;s Text property.&amp;nbsp; Technically I don&amp;rsquo;t need the special case for LiteralControls, since the last case will handle it, but it&amp;rsquo;s the common case and worth saving the additional CPU cycles required to use the RenderControl method.&lt;/p&gt;
&lt;p&gt;We now have the proper output:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;    &lt;/span&gt;The Control has Content!&lt;br /&gt;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;h1&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div &lt;/span&gt;&lt;span style="color:red;"&gt;class&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;body&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. &lt;br /&gt;    Donec ut nisi sed elit aliquam vulputate eu et lacus&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;p&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;a &lt;/span&gt;&lt;span style="color:red;"&gt;href&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;/Default.aspx&amp;quot;&amp;gt;&lt;/span&gt;Home&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;a&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;div&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;There is a gotcha with this approach (beyond advanced data binding and postback issues you may encounter) &amp;ndash; the following code will botch the output:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DateTime&lt;/span&gt;.Now &lt;span style="background:#ffee62;"&gt;%&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Simply put, Code Blocks change the way controls get processed.&amp;nbsp; Wrapping Code Blocks in another server control will work around this problem:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;PlaceHolder &lt;/span&gt;&lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background:#ffee62;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DateTime&lt;/span&gt;.Now &lt;span style="background:#ffee62;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;PlaceHolder&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;MyControls&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ContentBlock&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now that you have this new power, promise me you&amp;rsquo;ll only use it where proper and create a Custom Server Control when needed.&lt;/p&gt;
&lt;p&gt;Promise?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=54344" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category></item><item><title>ASP.NET SEO Interview on Polymorphic Podcast</title><link>http://devlicio.us/blogs/vinull/archive/2008/10/13/asp-net-seo-interview-on-polymorphic-podcast.aspx</link><pubDate>Tue, 14 Oct 2008 01:05:37 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:42663</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=42663</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2008/10/13/asp-net-seo-interview-on-polymorphic-podcast.aspx#comments</comments><description>&lt;p&gt;&lt;a title="phone_book by How can I recycle this" href="http://flickr.com/photos/recyclethis/186838960/"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;margin:0px 10px 10px 0px;border-right-width:0px;" height="244" alt="image" src="http://devlicio.us/blogs/vinull/WindowsLiveWriter/ASP.NETSEOInterviewonPolymorphicPodcast_120EA/image_3.png" width="194" align="left" border="0" /&gt;&lt;/a&gt; &lt;a href="http://weblogs.asp.net/craigshoemaker"&gt;Craig Shoemaker&lt;/a&gt; just posted the latest episode of the Polymorphic Podcast: &lt;a href="http://polymorphicpodcast.com/shows/aspnetseo/"&gt;ASP.NET SEO - Interview with Michael Neel&lt;/a&gt;.&amp;#160; Yes, I&amp;#39;ve now appeared in a podcast that I didn&amp;#39;t have a hand in recording!&lt;/p&gt;  &lt;p&gt;Even if you don&amp;#39;t listen to the show (and you should, Craig does an awesome job) check out the show notes.&amp;#160; SEO - or Search Engine Optimization - is one of those areas developers tend to overlook or outright ignore.&amp;#160; I think this is partly because it&amp;#39;s not something we think about when knee deep in site code, but also because there is a stigma attached to SEO that it is dirty marketing stuff.&amp;#160; Truth is, a good design for SEO is also a good design for users and helps more people find what they need (I was glad to see &lt;a href="http://www.codinghorror.com/blog/archives/001174.html"&gt;StackOverflow realize the sitemap protocol&lt;/a&gt; is very helpful). &lt;/p&gt;  &lt;p&gt;One thing I mention at the end of the podcast (at least I think it&amp;#39;s the end - I haven&amp;#39;t listened to it yet!) was the new support from System.Web.Routing to handle some of the code I have written myself in mapping urls to content.&amp;#160; &lt;a href="http://morewally.com/cs/Default.aspx"&gt;Wally McClure&lt;/a&gt; has just recently posted an &lt;a href="http://aspnetpodcast.com/CS11/blogs/asp.net_podcast/archive/2008/10/07/asp-net-podcast-show-125-routing-with-webforms.aspx"&gt;ASP.NET Podcast on Routing with WebForms&lt;/a&gt; that explains the new API.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=42663" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/sitemap/default.aspx">sitemap</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/seo/default.aspx">seo</category></item><item><title>Using LINQ to generate HTML</title><link>http://devlicio.us/blogs/vinull/archive/2008/08/03/using-linq-to-generate-html.aspx</link><pubDate>Sun, 03 Aug 2008 17:55:20 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:41644</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=41644</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2008/08/03/using-linq-to-generate-html.aspx#comments</comments><description>&lt;p&gt;&lt;a title="Balancing on the Invisible by Drew Brayshaw" href="http://flickr.com/photos/druclimb/325661568/"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;margin:0px 10px 10px 0px;border-right-width:0px;" height="244" alt="image" src="http://devlicio.us/blogs/vinull/WindowsLiveWriter/UsingLINQtogenerateHTML_B00E/image_3.png" width="165" align="left" border="0" /&gt;&lt;/a&gt; I hate seeing code mixed with markup.&lt;/p&gt;  &lt;p&gt;Seeing a template page with &lt;code&gt;&amp;lt;% if(show) { %&amp;gt;&lt;/code&gt; makes me want to claw my eyes out.&amp;#160; Seeing &lt;code&gt;String htmlTitle = &amp;quot;&amp;lt;h1&amp;gt;&amp;quot; + title + &amp;quot;&amp;lt;/h1&amp;gt;&amp;quot;&lt;/code&gt; causes me to vomit up a little something in my throat.&lt;/p&gt;  &lt;p&gt;Mixing code with markup is not a magic chocolate and peanut butter combination - it&amp;#39;s a volatile cocktail of vinegar and baking soda waiting to explode your application to tiny Server 500 Error giblets.&lt;/p&gt;  &lt;p&gt;The time comes however when we find ourselves needing to generate some well formed HTML in code, and I found myself in just such a position last night adding the agenda to the &lt;a href="http://CodeStock.org"&gt;CodeStock&lt;/a&gt; website. (Less than one week away now!)&lt;/p&gt;  &lt;p&gt;Background: On the CodeStock site, the speakers and sessions list lives in an XML file.&amp;#160; The agenda page has a grid of session times and my task was to fill in each session &amp;quot;cell&amp;quot; with the session planned for that room and time.&amp;#160; I wanted to link to the full session and also list the speaker&amp;#39;s name in the cell.&amp;#160; In the XML I have created Key elements that are used as HTML anchors in a link to a session.&amp;#160; It&amp;#39;s all very low tech, simplistic goodness.&amp;#160; An example of the XML for a speaker:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Speaker&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Brownell&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Name&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Steve Brownell&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Name&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Website&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;http://enthusiasticprogramming.blogspot.com&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Website&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Photo&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;~/Speakers/SteveBrownell.png&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Photo&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Bio&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &lt;/span&gt;Steve is the manager for research and development at AllMeds in Oak Ridge, TN.  Steve
        has been programming one thing or another for over twenty years.  AllMeds makes and
        sells a commercial software product which is an electronic medical record system.  We&amp;#39;ve
        been .NET based since 2000.  AllMeds is a VB.NET shop at heart, but the AllMeds system spans
        many areas of Windows development.
    &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Bio&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Session&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Hobbled&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Title&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
            &lt;/span&gt;The Hobbled:  There And Back Again, or Code Automation:  how I made it from the
            presentation layer to the database and back.
        &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Title&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Abstract&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
            &lt;/span&gt;Stop writing code, and start writing code that writes code.  There&amp;#39;s never been more
            choices to help you automate the creation of the data object layers immediately above
            the database.  Writing class factories and data access classes is boring, time consuming
            and wastes valuable time with expensive developer resources.  This course will examine
            two current approaches:  using a template engine and programming with the CODEDOM.  We&amp;#39;ll
            also briefly discuss other ORM techniques like LINQ to SQL Classes.
        &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Abstract&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Level&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;200&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Level&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Technology&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;VB.NET, C#, LINQ, SQL&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Technology&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Session&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Speaker&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;(Steve was our CodeStock Speaker Idol winner, and I enjoyed seeing System.Codedom in action; something I&amp;#39;ll be playing with and posting on in the future thanks to Steve!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;LINQ to XML, and the new &amp;quot;X&amp;quot; classes that come with it make working with XML as easy as it should have always been.&amp;#160; Armed with LINQ, I decided that putting &amp;lt;%= SessionInfo(&amp;quot;Hobbled&amp;quot;) %&amp;gt; was something I could live with (had this been a larger site that needed to live longer than August 9th, I would have opted for a user control &amp;lt;CodeStock:SessionInfo Key=&amp;quot;Hobbled&amp;quot;/&amp;gt;).&amp;#160; My first LINQ expression looked something like the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;info = (&lt;span style="color:blue;"&gt;from &lt;/span&gt;s &lt;span style="color:blue;"&gt;in &lt;/span&gt;speakers.Descendants(&lt;span style="color:#a31515;"&gt;&amp;quot;Session&amp;quot;&lt;/span&gt;)
            &lt;span style="color:blue;"&gt;where &lt;/span&gt;s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value.Equals(SessionKey)
            &lt;span style="color:blue;"&gt;select new &lt;/span&gt;{
                key = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value,
                title = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;).Value.Trim(),
                speaker = s.Parent.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;).Value
            }).First();&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This yields a very useful info object with just the information I need.&amp;#160; *If* I was in a hurry, and didn&amp;#39;t mind a little vomit, I would follow on with the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;String &lt;/span&gt;hmtl = &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.Format(&lt;span style="color:#a31515;"&gt;&amp;quot;&amp;lt;a href=&amp;#39;{0:s}&amp;#39; title=&amp;#39;{1:s}&amp;#39;&amp;gt;{2:s}&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;{3:s}&amp;quot;&lt;/span&gt;,
    &lt;span style="color:blue;"&gt;new object&lt;/span&gt;[] { ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, info.key),
                   info.title,
                   info.title.Length &amp;gt; 30 ? info.title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: info.title,
                   info.speaker });&lt;/pre&gt;

&lt;p&gt;Why do I despise this so much?&amp;#160; It&amp;#39;s not easy to read, and it can become cumbersome to change.&amp;#160; ASP.NET has a collection of server controls just for generating HTML, intended for use in user controls but they are not limited to user controls alone.&amp;#160; To generate the html above would look something like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;HtmlAnchor &lt;/span&gt;aHref = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlAnchor&lt;/span&gt;() {
    HRef = ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, info.key),
    InnerText = info.title.Length &amp;gt; 30 ? info.title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: info.title,
    Title = Title
};
&lt;span style="color:#2b91af;"&gt;HtmlGenericControl &lt;/span&gt;div = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlGenericControl&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;) {
    InnerText = info.speaker
};

&lt;span style="color:#2b91af;"&gt;StringBuilder &lt;/span&gt;html = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringBuilder&lt;/span&gt;();
&lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;StringWriter &lt;/span&gt;sw = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringWriter&lt;/span&gt;(html)) {
    &lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;HtmlTextWriter &lt;/span&gt;hw = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlTextWriter&lt;/span&gt;(sw)) {
        aHref.RenderControl(hw);
        div.RenderControl(hw);
        hw.Close();
    }
    sw.Close();
}&lt;/pre&gt;

&lt;p&gt;There are times when working with parts of the .Net framework I have wonder if some Java types didn&amp;#39;t design the class.&amp;#160; The mess here to render the HTML is one of those times.&amp;#160; The lack of a RenderControl that returns a String is the problem - thankfully we now have extension methods to fix the framework, but that&amp;#39;s another post.&amp;#160; No matter how much I hate markup in the code, I cannot endorse this version over the vomit inducing first solution.&lt;/p&gt;

&lt;p&gt;It occurs to me that HTML is (or was once) fundamentally XML, and I can return XML from my LINQ expression.&amp;#160; In fact, this is what LINQ is about - not just getting the data you want, but getting it in the format you need.&amp;#160; Here is the new LINQ query:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;XElement &lt;/span&gt;info = (&lt;span style="color:blue;"&gt;from &lt;/span&gt;s &lt;span style="color:blue;"&gt;in &lt;/span&gt;speakers.Descendants(&lt;span style="color:#a31515;"&gt;&amp;quot;Session&amp;quot;&lt;/span&gt;)
                 &lt;span style="color:blue;"&gt;where &lt;/span&gt;s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value.Equals(SessionKey)
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;key = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;title = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;).Value.Trim()
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;shortTitle = title.Length &amp;gt; 30 ? 
                    title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: title
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;session = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;,
                              &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XAttribute&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;,
                                  ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, key)),
                              &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XAttribute&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;, title),
                              shortTitle)
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;speaker = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;, s.Parent.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;).Value)
                 &lt;span style="color:blue;"&gt;select new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;span&amp;quot;&lt;/span&gt;, session, speaker)).First();&lt;/pre&gt;

&lt;p&gt;This may not seem to some as better.&amp;#160; I myself have trouble looking at most LINQ expressions, but as I&amp;#39;m learning to &lt;a href="http://www.thinqlinq.com/"&gt;Thinq Linq&lt;/a&gt; I&amp;#39;m seeing that writing the LINQ expression is where the power lies, not in the syntax.&amp;#160; The mental dialog goes something like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;quot;Okay, from my list of speakers I want a session where the session&amp;#39;s key matches SessionKey.&amp;#160; Now, let me grab some fields I need, first the key, then the title which I need to trim off excess whitespace, then let&amp;#39;s make a short version of that title since Steve&amp;#39;s title is so long - love that title though.&amp;#160; I&amp;#39;ll need an link tag for the session; set the href and title attributes, and then add the speaker&amp;#39;s name in a div tag so I get a cheap line break.&amp;#160; I&amp;#39;m really in XML not HTML, so I&amp;#39;ll need a root node and a span tag will work without affecting layout, and I&amp;#39;ll add the link and div tags as children.&amp;quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Writing LINQ like this I feel much closer to the problem I&amp;#39;m trying to solve, and not bogged down by syntax.&amp;#160; There is still some moments I&amp;#39;m thrust back to code, such as the use of First() to select only one result.&amp;#160; I&amp;#39;d like to have a &amp;quot;select first&amp;quot; option in LINQ expressions instead of just the extension methods.&amp;#160; &lt;/p&gt;

&lt;p&gt;Is this something I&amp;#39;ll be using now every time I have this problem?&amp;#160; Not sure yet, but it&amp;#39;s another &amp;quot;tool in the box&amp;quot; I&amp;#39;ll keep around and use when it feels right.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=41644" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Session, ForEach, and a ShallowCopy walk into a bar...</title><link>http://devlicio.us/blogs/vinull/archive/2008/04/14/session-foreach-and-a-shallowcopy-walk-into-a-bar.aspx</link><pubDate>Mon, 14 Apr 2008 18:12:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:40065</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=40065</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2008/04/14/session-foreach-and-a-shallowcopy-walk-into-a-bar.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://flickr.com/photos/thomashawk/229516213/"&gt;&lt;img src="http://devlicio.us/blogs/vinull/WindowsLiveWriter/SessionForEachandaShallowCopywalkintoab_C792/image_3.png" style="border-width:0px;margin:0px 10px 10px 0px;" alt="image" align="left" border="0" height="164" width="244" /&gt;&lt;/a&gt;Before we get started, let&amp;#39;s play &amp;quot;questions you only hear during an interview.&amp;quot;&amp;nbsp;&amp;nbsp; Are the contestants ready?&amp;nbsp; Good, here is the question:&amp;nbsp; What is the difference between a shallow copy and a deep copy?&amp;nbsp; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/system.object.memberwiseclone.aspx"&gt;MSDN on Object.MemberwiseClone&lt;/a&gt;: &amp;quot;Consider an object called X that references objects A and B. Object B, in turn, references object C. A shallow copy of X creates new object X2 that also references objects A and B. In contrast, a deep copy of X creates a new object X2 that references the new objects A2 and B2, which are copies of A and B. B2, in turn, references the new object C2, which is a copy C.&amp;quot; &lt;/p&gt;  &lt;p&gt;Clear as mud?&amp;nbsp; Okay, think of it this was - if you made a shallow copy of a directory it would copy only the files in the top level of the directory and create shortcut links to the subfolders.&amp;nbsp; A deep copy would copy the files, all subfolders and their file, and the subfolder&amp;#39;s subfolders and files, etc.&amp;nbsp; In C#/.Net world, 99% of the time you are making shallow copies.&lt;/p&gt;  &lt;p&gt;It common for me to have an asp.net app that gets data from a webservice, and then applies filters selected by the user.&amp;nbsp; Since the user will change sorting, filters, etc with the same set of data several times, I cache the call to the webservice in Session.&amp;nbsp; (Note: It&amp;#39;s okay because I expect only 2-4 user&amp;#39;s at a time on these, mostly internal applications - don&amp;#39;t do this if you need to scale beyond a small set of users!).&amp;nbsp; It looks something like:&lt;/p&gt;  &lt;pre class="code"&gt;    &lt;span&gt;public&lt;/span&gt; &lt;span&gt;ShowProduct&lt;/span&gt;[] Products { &lt;br /&gt;        &lt;span&gt;get&lt;/span&gt; {&lt;br /&gt;            &lt;span&gt;return&lt;/span&gt; Session[&lt;span&gt;&amp;quot;Products&amp;quot;&lt;/span&gt;] == &lt;span&gt;null&lt;/span&gt; ? &lt;br /&gt;                &lt;span&gt;new&lt;/span&gt; &lt;span&gt;ShowProduct&lt;/span&gt;[0] : &lt;br /&gt;                (&lt;span&gt;ShowProduct&lt;/span&gt;[])Session[&lt;span&gt;&amp;quot;Products&amp;quot;&lt;/span&gt;];&lt;br /&gt;        }&lt;br /&gt;        &lt;span&gt;set&lt;/span&gt; {&lt;br /&gt;            Session[&lt;span&gt;&amp;quot;Products&amp;quot;&lt;/span&gt;] = &lt;span&gt;value&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span&gt;protected&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; LoadProducts()&lt;br /&gt;    {&lt;br /&gt;        &lt;span&gt;ShowServiceSoap&lt;/span&gt; svc = &lt;span&gt;new&lt;/span&gt; &lt;span&gt;ShowServiceSoap&lt;/span&gt;();&lt;br /&gt;        Products = svc.GetProductsByShowID(&lt;br /&gt;            &lt;span&gt;String&lt;/span&gt;.Empty, &lt;br /&gt;            &lt;span&gt;Convert&lt;/span&gt;.ToDecimal(ddlShows.SelectedValue));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span&gt;protected&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; FilterProducts() {&lt;br /&gt;        &lt;span&gt;ShowProduct&lt;/span&gt;[] products = Products;&lt;br /&gt;&lt;br /&gt;        &lt;span&gt;if&lt;/span&gt; (cbFilterSizeable.Checked) {&lt;br /&gt;            products = (&lt;span&gt;from&lt;/span&gt; p &lt;span&gt;in&lt;/span&gt; products &lt;br /&gt;                        &lt;span&gt;where&lt;/span&gt; p.Sizeable.Equals(&lt;span&gt;true&lt;/span&gt;) &lt;br /&gt;                        &lt;span&gt;select&lt;/span&gt; p).ToArray();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        gvProducts.DataSource = products;&lt;br /&gt;        gvProducts.DataBind();&lt;br /&gt;    }&lt;/pre&gt;

&lt;p&gt;This works just fine.&amp;nbsp; In practice, there are many steps in the FilterProducts method and I add some &lt;a href="http://en.wikipedia.org/wiki/Dependency_injection"&gt;dependency injection&lt;/a&gt; options beyond using a property to access session, but you get the idea.&amp;nbsp; These methods are called from event handlers on the web form.&amp;nbsp; &lt;/p&gt;

&lt;p&gt;Now, I had a request to add an option to filter product videos to only .AVI, which are stored in the ShowProduct.Video list, so I changed FilterProducts like so:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span&gt;protected&lt;/span&gt; &lt;span&gt;void&lt;/span&gt; FilterProducts() {&lt;br /&gt;        &lt;span&gt;ShowProduct&lt;/span&gt;[] products = Products;&lt;br /&gt;&lt;br /&gt;        &lt;span&gt;if&lt;/span&gt; (cbFilterSizeable.Checked) {&lt;br /&gt;            products = (&lt;span&gt;from&lt;/span&gt; p &lt;span&gt;in&lt;/span&gt; products &lt;br /&gt;                        &lt;span&gt;where&lt;/span&gt; p.Sizeable.Equals(&lt;span&gt;true&lt;/span&gt;) &lt;br /&gt;                        &lt;span&gt;select&lt;/span&gt; p).ToArray();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span&gt;if&lt;/span&gt; (cbFilterAviOnly.Checked) {&lt;br /&gt;            &lt;span&gt;foreach&lt;/span&gt; (&lt;span&gt;ShowProduct&lt;/span&gt; p &lt;span&gt;in&lt;/span&gt; products)&lt;br /&gt;                p.Videos = (&lt;span&gt;from&lt;/span&gt; v &lt;span&gt;in&lt;/span&gt; p.Videos&lt;br /&gt;                            &lt;span&gt;where&lt;/span&gt; v.FileType.Equals(&lt;span&gt;&amp;quot;AVI&amp;quot;&lt;/span&gt;, &lt;br /&gt;                                &lt;span&gt;StringComparison&lt;/span&gt;.CurrentCultureIgnoreCase)&lt;br /&gt;                            &lt;span&gt;select&lt;/span&gt; v).ToArray();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        gvProducts.DataSource = products;&lt;br /&gt;        gvProducts.DataBind();&lt;br /&gt;    }&lt;/pre&gt;

&lt;p&gt;If you see the error, and understand why it happens, congratulations!&amp;nbsp; If you are like me you noticed that when this runs, and the user filters AVI only, all works as expected.&amp;nbsp; When they remove the filter however, the non-AVI files do not return.&amp;nbsp; More confusing is that if they filtered Sizeable products only, and the removed the filter, the missing product did return!&amp;nbsp; What&amp;#39;s going on?&lt;/p&gt;

&lt;pre class="code"&gt;        &lt;span&gt;ShowProduct&lt;/span&gt;[] products = Products;&lt;/pre&gt;

&lt;p&gt;This made a shallow copy of the array in Session.&amp;nbsp; Each ShowProduct was copied, &lt;b&gt;but the Videos array was a reference.&lt;/b&gt;&amp;nbsp; When I changed the Videos array in the shallow copy, it changed the object in Session because both Session and my copy pointed at the same location in memory.&lt;/p&gt;

&lt;p&gt;I searched around for a bit to find a way to solve my problem; i.e. how to make a deep copy in C#/.Net.&amp;nbsp; There is a method System.FantasyFramework.DeepCopy that will take any object type and return a deep copy of that object back, but I can&amp;#39;t get my Visual Studio to find the dll for System.FantasyFramework in the GAC.&amp;nbsp; Many people have this issue as well, and resort to implementing &lt;a href="http://msdn2.microsoft.com/en-us/library/system.icloneable.aspx"&gt;ICloneable&lt;/a&gt; on their object so that the object deep copies itself instead of shallow copies or write an extension method to deep copy the Array class.&amp;nbsp; I however opted for the quick fix below:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span&gt;public&lt;/span&gt; &lt;span&gt;ShowProduct&lt;/span&gt;[] Products { &lt;br /&gt;        &lt;span&gt;get&lt;/span&gt; {&lt;br /&gt;            &lt;span&gt;if&lt;/span&gt; (Session[&lt;span&gt;&amp;quot;ShowProducts&amp;quot;&lt;/span&gt;] == &lt;span&gt;null&lt;/span&gt;)&lt;br /&gt;                &lt;span&gt;return&lt;/span&gt; &lt;span&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;            &lt;span&gt;Object&lt;/span&gt; result = &lt;span&gt;null&lt;/span&gt;;&lt;br /&gt;            &lt;span&gt;using&lt;/span&gt; (&lt;span&gt;MemoryStream&lt;/span&gt; ms = &lt;span&gt;new&lt;/span&gt; &lt;span&gt;MemoryStream&lt;/span&gt;()) {&lt;br /&gt;                &lt;span&gt;BinaryFormatter&lt;/span&gt; bf = &lt;span&gt;new&lt;/span&gt; &lt;span&gt;BinaryFormatter&lt;/span&gt;();&lt;br /&gt;                bf.Serialize(ms, Session[&lt;span&gt;&amp;quot;ShowProducts&amp;quot;&lt;/span&gt;]);&lt;br /&gt;                ms.Seek(0, &lt;span&gt;SeekOrigin&lt;/span&gt;.Begin);&lt;br /&gt;                result = bf.Deserialize(ms);&lt;br /&gt;                ms.Close();&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            &lt;span&gt;return&lt;/span&gt; (&lt;span&gt;ShowProduct&lt;/span&gt;[])result;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span&gt;set&lt;/span&gt; {&lt;br /&gt;            Session[&lt;span&gt;&amp;quot;Products&amp;quot;&lt;/span&gt;] = &lt;span&gt;value&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;

&lt;p&gt;When accessed, the property loads the shallow copy from Session, then Serializes it to memory, then load it&amp;#39;s back and returns the result.&amp;nbsp; This &amp;quot;washes&amp;quot; away any references and makes a full deep copy of the array.&amp;nbsp; (You do remember the part about not needing this to scale right?&amp;nbsp; Cool, do don&amp;#39;t this on your public website&amp;#39;s homepage).&amp;nbsp; This is also a case where good TDD practices have benefits beyond making it easier to write unit tests.&lt;/p&gt;

&lt;p&gt;As for the end of the bar joke, I&amp;#39;m afraid I don&amp;#39;t have a punch-line yet.&amp;nbsp; I think it will have something to do with Session drinking only water, while ForEach and ShallowCopy see who can do the most shots of tequila - until Session falls over drunk.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=40065" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/session/default.aspx">session</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category></item></channel></rss>