<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
  <channel>
    <title>eWorld.UI - Matt Hawley</title>
    <description>Ramblings of Matt</description>
    <link>http://www.eworldui.net/blog/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.6.0.3</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://www.eworldui.net/blog/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://blog.eworldui.net/syndication.axd</blogChannel:blink>
    <dc:creator>Matt Hawley</dc:creator>
    <dc:title>eWorld.UI - Matt Hawley</dc:title>
    <geo:lat>0.000000</geo:lat>
    <geo:long>0.000000</geo:long>
    <item>
      <title>Using Razor Pages with WebForms Master Pages</title>
      <description>&lt;p&gt;There's been some recent chatter about mixing ASP.NET MVC with WebForms, which is &lt;a href="http://www.eworldui.net/blog/post/2008/05/09/ASPNET-MVC-Living-in-a-Web-Forms-World.aspx"&gt;something I'm all too familiar with&lt;/a&gt;. This setup works just fine, but what if you wanted to use the new Razor view engine within ASP.NET MVC? A bit of backstory.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;On a secondary project that I work on within Microsoft, we were given the ability to rewrite the entire UI of the application in ASP.NET MVC. At that time, the first beta of MVC3 was rolling out and we decided to take our first plunge and use the Razor view engine. Unfortunately, the common UI layout that is shared across multiple properties that we had to use was WebForms based. Our attempts to convince the developers of the common UI components to support more of a modularized infrastructure failed for any foreseeable future, so we were left with the conundrum of figuring out an intermediary solution.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;After discussions with the ASP.NET team to see if using a Razor view where it's layout was a WebForms master page was or could be a supported scenario - the general consensus being "No". The primary reason is that WebForms and Razor pages have a completely different architecture and runtime execution model (renders from a control tree vs. mostly-single pass template, respectively). However, what ASP.NET MVC does allow is context switching between view engines based on partials that are rendered. With that in mind, I decided to see if a partial based implementation could be achieved.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The solution is fairly simple, and provides an easy upgrade path if and when you could ditch the WebForms master page. We'll start by creating a few extensions to the controller for rendering Razor based views. The reason we're doing this, is so that a WebForms based view can be rendered, while you think you're rendering a Razor based view.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ViewResult RazorView(&lt;span class="kwrd"&gt;this&lt;/span&gt; Controller controller)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; RazorView(controller, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ViewResult RazorView(&lt;span class="kwrd"&gt;this&lt;/span&gt; Controller controller, &lt;span class="kwrd"&gt;object&lt;/span&gt; model)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; RazorView(controller, &lt;span class="kwrd"&gt;null&lt;/span&gt;, model);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ViewResult RazorView(&lt;span class="kwrd"&gt;this&lt;/span&gt; Controller controller, &lt;span class="kwrd"&gt;string&lt;/span&gt; viewName)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; RazorView(controller, viewName, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ViewResult RazorView(&lt;span class="kwrd"&gt;this&lt;/span&gt; Controller controller, &lt;span class="kwrd"&gt;string&lt;/span&gt; viewName, &lt;span class="kwrd"&gt;object&lt;/span&gt; model)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (model != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        controller.ViewData.Model = model;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    controller.ViewBag._ViewName = GetViewName(controller, viewName);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewResult&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    {&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        ViewName = &lt;span class="str"&gt;&amp;quot;RazorView&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        ViewData = controller.ViewData,&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;        TempData = controller.TempData&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;    };&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetViewName(Controller controller, &lt;span class="kwrd"&gt;string&lt;/span&gt; viewName)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; !&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(viewName)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;        ? viewName&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;        : controller.RouteData.GetRequiredString(&lt;span class="str"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The thing to note from above, is that we're actually rendering a view called "RazorView" specifying the actual view to be rendered on ViewBag._ViewName. This value will later be used to render the appropriate RazorView. &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Side note: This is a naive implementation of GetViewName assuming that if you do not specify the view name, you're rendering a view with the same action name from the route data. This may not be correct in all places, but seems to work reasonably well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll also need to create a "RazorView" WebForms view in the Shared directory which inherits from your master page. This view will ultimately render the Razor view as a partial defined by your action result. I've also created a Razor layout page that all Razor views will use to alleviate the issue of having to touch each view if and when a conversion to only the Razor view engine takes place. You'll find each of the view files below.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared/Site.Master:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%@ Master Language=&amp;quot;C#&amp;quot; Inherits=&amp;quot;System.Web.Mvc.ViewMasterPage&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="html"&gt;DOCTYPE&lt;/span&gt; &lt;span class="attr"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;TitleContent&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ContentPlaceHolder&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MainContent&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Shared/_SiteLayout.cshtml:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;@RenderBody()&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Shared/RazorView.aspx:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%@ Page Title=&amp;quot;&amp;quot; Language=&amp;quot;C#&amp;quot; MasterPageFile=&amp;quot;~/Views/Shared/Site.Master&amp;quot;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    Inherits=&amp;quot;System.Web.Mvc.ViewPage&amp;lt;dynamic&amp;gt;&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Content&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Content2&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ContentPlaceHolderID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MainContent&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; Html.RenderPartial((&lt;span class="kwrd"&gt;string&lt;/span&gt;) ViewBag._ViewName); &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:Content&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Home/Index.cshtml:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;@{&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    Layout = &amp;quot;~/Views/Shared/_SiteLayout.cshtml&amp;quot;;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h2&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;This is the index page&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h2&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;What you'll notice, is that it's not possible to utilize Razor content sections to render different parts from the WebForms master page. However, you are able to use Razor content sections from the Razor layout file since you're in that model. If you do have to render multiple WebForm content sections, you may need to make things a bit more elaborate by specifying specific content areas manually. Ultimately, I wouldn't recommend that, and just try to limit your output to a main content panel.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Within your controller, your action result is simply:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Index()&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.RazorView();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;While this solution isn't optimal, it does allow you to utilize Razor views while still adhering to a common WebForms master page. If possible, I recommend not doing this, but sometimes (like in our solution) you have to do what is necessary. If your master pages are simple enough (and primarily just layout), I fully recommend having a WebForms master page and a Razor layout page. Regardless, the way this has been setup, migration to a Razor only architecture is fairly trivial - just simply change all this.RazorView() calls to View() calls and copy over your layout to _SiteLayout.cshtml.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/files/mvcdemos/mvc-mixworld.zip"&gt;Click here to download the source for this solution.&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2011/01/07/Using-Razor-Pages-with-WebForms-Master-Pages.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2011/01/07/Using-Razor-Pages-with-WebForms-Master-Pages.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=e4722db9-b711-46b0-8c10-69b84dcdbd46</guid>
      <pubDate>Fri, 07 Jan 2011 14:56:17 +0100</pubDate>
      <category>ASP.NET</category>
      <category>.NET</category>
      <category>MVC</category>
      <category>Programming</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=e4722db9-b711-46b0-8c10-69b84dcdbd46</pingback:target>
      <slash:comments>21</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=e4722db9-b711-46b0-8c10-69b84dcdbd46</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2011/01/07/Using-Razor-Pages-with-WebForms-Master-Pages.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=e4722db9-b711-46b0-8c10-69b84dcdbd46</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex 2.0 Released</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt;&lt;/div&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; has hit another major milestone with this release. Since releasing version 1.4, I really started off by adding several new features preparing for what would be a 1.5 release. However, as I took a look at the implementation of WikiPlex, I realized that it needed a bit of love to make the API more consistent for both it's own consumption, but also for the end-user developer. So, with that - upgrading to version 2.0 from 1.x is not a simple xcopy deployment of the new DLL as the entry point has slightly changed, as well as a bit of namespace restructuring (more on both later). Because of these breaking changes, it was time for WikiPlex to turn 2.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;&lt;span style="text-decoration: underline"&gt;Breaking Changes from v1.x&lt;/span&gt;&lt;/strong&gt;       &lt;ol&gt;       &lt;li&gt;All renderers have been moved into the namespace &lt;span style="font-family: consolas"&gt;WikiPlex.Formatting.Renderers&lt;/span&gt; from &lt;span style="font-family: consolas"&gt;WikiPlex.Formatting&lt;/span&gt;. This also includes the &lt;span style="font-family: consolas"&gt;IRenderer&lt;/span&gt; interface. &lt;/li&gt;        &lt;li&gt;The following interfaces have been removed: &lt;span style="font-family: consolas"&gt;IMacroCompiler&lt;/span&gt;, &lt;span style="font-family: consolas"&gt;IMacroParser&lt;/span&gt;, and &lt;span style="font-family: consolas"&gt;IFormatter&lt;/span&gt;. Ultimately, there was no reason to have interfaces for these other than for unit testing purposes. &lt;/li&gt;        &lt;li&gt;The classes &lt;span style="font-family: consolas"&gt;MacroParser&lt;/span&gt; and &lt;span style="font-family: consolas"&gt;MacroFormatter&lt;/span&gt; have been renamed to &lt;span style="font-family: consolas"&gt;Parser&lt;/span&gt; and &lt;span style="font-family: consolas"&gt;Formatter&lt;/span&gt;, respectively. &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;span style="text-decoration: underline"&gt;New Features&lt;/span&gt;&lt;/strong&gt;       &lt;ol&gt;       &lt;li&gt;There is a new base &lt;span style="font-family: consolas"&gt;Renderer&lt;/span&gt; class that encapsulates and simplifies common implementations. See the &lt;a href="http://wikiplex.codeplex.com/wikipage?title=Custom%20Renderers&amp;amp;referringTitle=Documentation"&gt;updated documentation&lt;/a&gt; for more information about this new implementation. Additionally, you can &lt;a href="http://wikiplex.codeplex.com/SourceControl/BrowseLatest"&gt;browse the WikiPlex source&lt;/a&gt; for more concrete examples. &lt;/li&gt;        &lt;li&gt;Ordered and Unordered lists can now be interleaved.          &lt;ul&gt;           &lt;li&gt;For example: level one can be Ordered items while level two can be Unordered items, etc. &lt;/li&gt;            &lt;li&gt;The macros &lt;span style="font-family: consolas"&gt;OrderedListMacro&lt;/span&gt; and &lt;span style="font-family: consolas"&gt;UnorderedListMacro&lt;/span&gt; have been merged into a single &lt;span style="font-family: consolas"&gt;ListMacro&lt;/span&gt;. &lt;/li&gt;            &lt;li&gt;Intermixing of different list types on the same level is unsupported. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;Images can now contain height and width parameters on the image resource.          &lt;ul&gt;           &lt;li&gt;Similarly to other macros, they're specified as &amp;quot;http://foo.com/image.gif,height=220,width=380&amp;quot;. &lt;/li&gt;            &lt;li&gt;You can use any unit type - ie Pixel, Percent, etc. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;A new multi-line indentation macro was added with the syntax of :{ . :} so that content that normally spanned multiple lines (tables, lists, etc) can be indented.          &lt;ul&gt;           &lt;li&gt;The :{ and :} need to be placed on separate lines encapsulating the content. &lt;/li&gt;            &lt;li&gt;You can have N number of colons to indicate level of indentation. &lt;/li&gt;            &lt;li&gt;The number of starting and ending colons must match in order for the macro to be valid. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;        &lt;li&gt;Headings can now be indented on a single line by simply specifying the indentation macro, ie &amp;quot;: ! Heading&amp;quot; &lt;/li&gt;        &lt;li&gt;Two new overloads were added to &lt;span style="font-family: consolas"&gt;IWikiEngine&lt;/span&gt; that accept an &lt;span style="font-family: consolas"&gt;IEnumerable&amp;lt;IRenderer&amp;gt;&lt;/span&gt;. This is an exclusive list the engine will use to format, similarly to overload that takes macros. &lt;/li&gt;        &lt;li&gt;The &lt;span style="font-family: consolas"&gt;ScopeRendered&lt;/span&gt; event on &lt;span style="font-family: consolas"&gt;Formatter&lt;/span&gt; now also includes &lt;span style="font-family: consolas"&gt;RendredContent&lt;/span&gt;. &lt;/li&gt;        &lt;li&gt;The sample application now supports unicode characters as internal wiki page links. &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You can find more information about this release by visiting the project homepage. Go and get it now either by &lt;a href="http://nuget.codeplex.com"&gt;NuGet&lt;/a&gt; or via &lt;a href="http://wikiplex.codeplex.com/releases/view/51732"&gt;CodePlex&lt;/a&gt;!&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/11/09/WikiPlex-20-Released.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/11/09/WikiPlex-20-Released.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=d3c17e7e-ba70-4b9e-992f-0964a0b6cd0d</guid>
      <pubDate>Tue, 09 Nov 2010 12:28:00 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Development</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=d3c17e7e-ba70-4b9e-992f-0964a0b6cd0d</pingback:target>
      <slash:comments>35</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=d3c17e7e-ba70-4b9e-992f-0964a0b6cd0d</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/11/09/WikiPlex-20-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=d3c17e7e-ba70-4b9e-992f-0964a0b6cd0d</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex 1.4 Released</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I’ve finally decided that it was time to do another &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; release. It’s been awhile since the last release (March of this year), but a lot of things have changed over time that I finally officially package a new version up. The &lt;a href="http://wikiplex.codeplex.com/"&gt;CodePlex&lt;/a&gt; website continues to use WikiPlex, and I’m very excited to see the success of this project over time.&lt;/p&gt;  &lt;p&gt;Here’s what you’ll find in WikiPlex 1.4:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;u&gt;&lt;b&gt;Infrastructure Changes&lt;/b&gt;&lt;/u&gt;       &lt;ol&gt;       &lt;li&gt;.NET 4 and .NET 3.5 support (separate downloads) &lt;/li&gt;        &lt;li&gt;Sample website updated to ASP.NET MVC 2 &lt;/li&gt;        &lt;li&gt;Added support to install via Nu / RubyGems (nu install wikiplex) &lt;/li&gt;        &lt;li&gt;&lt;font size="2" face="Consolas"&gt;void IFormatter.Format(string, StringBuilder)&lt;/font&gt; is marked as obsolete. Should utilize &lt;font size="2" face="Consolas"&gt;string IFormatter.Format(string)&lt;/font&gt; instead &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;u&gt;&lt;b&gt;New Features&lt;/b&gt;&lt;/u&gt;       &lt;ol&gt;       &lt;li&gt;Added support for Silverlight 4, as the default version &lt;/li&gt;        &lt;li&gt;Added support for &lt;font size="2" face="Consolas"&gt;gpuAcceleration&lt;/font&gt; for Silverlight 3/4 &lt;/li&gt;        &lt;li&gt;Added support for Vimeo videos &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;u&gt;&lt;b&gt;Bug Fixes&lt;/b&gt;&lt;/u&gt;       &lt;ol&gt;       &lt;li&gt;Runaway syntax highlighting will be killed after 5 seconds resulting in no syntax highlighting. &lt;/li&gt;        &lt;li&gt;Multi-line comments are properly syntax highlighted for Powershell code &lt;/li&gt;        &lt;li&gt;Fixed table rendering bug when a cell contains links with alternate text &lt;/li&gt;        &lt;li&gt;Encoded new line characters are now properly interpreted and replaced with line breaks. &lt;/li&gt;        &lt;li&gt;&amp;quot;Cleared&amp;quot; elements after aligned content are now properly rendering appropriate spacing. &lt;/li&gt;        &lt;li&gt;Fixed &amp;quot;++&amp;quot; not being rendered as plain-text (ie, C++) &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You can find more information about this release by visiting the project homepage. Go and get it now either by &lt;a href="http://nu.wikispot.org/"&gt;Nu&lt;/a&gt; or via &lt;a href="http://wikiplex.codeplex.com/releases/view/51122"&gt;CodePlex&lt;/a&gt;!&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/08/24/WikiPlex-14-Released.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/08/24/WikiPlex-14-Released.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=131555ef-2cf2-4034-8a11-bbc59a2f0a5e</guid>
      <pubDate>Tue, 24 Aug 2010 18:26:42 +0100</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>CodePlex</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=131555ef-2cf2-4034-8a11-bbc59a2f0a5e</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=131555ef-2cf2-4034-8a11-bbc59a2f0a5e</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/08/24/WikiPlex-14-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=131555ef-2cf2-4034-8a11-bbc59a2f0a5e</wfw:commentRss>
    </item>
    <item>
      <title>Setting up Mercurial server in IIS7 using a ISAPI module</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Previously, Jeremy Skinner &lt;a href="http://www.jeremyskinner.co.uk/mercurial-on-iis7/"&gt;posted a very thorough guide on setting up Mercurial in IIS&lt;/a&gt;. The difference between his guide, and what I'll be walking you through, is how Mercurial is hosted in IIS. Where he shows you using a CGI script that executes python.exe, my guide will show you how to use isapi-wsgi to host Mercurial. The biggest benefits of using isapi-wsgi over executing python.exe, is the raw processing speed and the overall throughput your server can handle.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post uses Mercurial 1.5.1, Python 2.6.5 although it should work for all older/future versions released.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Packages Installation&lt;/h3&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Install Python&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The reason you need to install Python first, is that all subsequent installations will install directly into the Python installation (in the Lib\site-packages folder), including Mercurial. It is important to note that you will need to install the version of Python that Mercurial was built against, as well as installing the x86 version (yes, even if you're on a x64 platform). &lt;a href="http://www.python.org/download/"&gt;Download&lt;/a&gt; and install Python 2.6.5.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Install PyWin32&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This component is needed to run certain win32 functions (specifically for ISAPI) that isapi-wsgi needs. &lt;a href="http://sourceforge.net/projects/pywin32/"&gt;Download&lt;/a&gt; and install this package, letting it determine the default installation path for you.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Install Mercurial Source&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Normally, you would download the binary package for Mercurial, but for this process to work, you will need to utilize the source code package. &lt;a href="http://bitbucket.org/tortoisehg/thg-winbuild/downloads/"&gt;Download&lt;/a&gt; the &lt;strong&gt;mercurial-1.5.1.win32-py2.6.exe&lt;/strong&gt; package and install it. Just as PyWin32, let it determine the default installation path for you.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Install isapi-wsgi&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This is the glue that binds everything together. It's used to build a shim based on a python script that you setup (later). &lt;a href="http://code.google.com/p/isapi-wsgi/"&gt;Download&lt;/a&gt; and install this package, also letting it determine the default installation path for you.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Get hgwebdir_wsgi&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;You will now need to download the python script hgwebdir_wsgi.py. This is the script that you will configure to and execute to build the ISAPI shim DLL. This script is apart of the Mercurial source code, and is not distributed with the binaries or the earlier installation. To get it, you can &lt;a href="http://mercurial.selenic.com/wiki/Download"&gt;download the source code&lt;/a&gt; from the Mercurial site, or clone their repository by executing the following command &lt;/p&gt;  &lt;pre class="csharpcode"&gt;hg clone http://selenic.com/repo/hg#stable&lt;/pre&gt;

&lt;p&gt;Once you have the source, you can find the script in the contrib/win32 directory.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="left" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb.png" width="230" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Configuration&lt;/h3&gt;

&lt;p&gt;
  &lt;br /&gt;&lt;strong&gt;Note:&lt;/strong&gt; The following steps assume that you already have IIS installed. If you do not, please refer to Jeremy's guide for these steps.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;1. Create a folder that will be used by the IIS website for hosting your Mercurial installation. For example, C:\inetpub\hg &lt;/p&gt;

&lt;p&gt;2. Copy hgwebdir_wsgi.py to the location created in step 1 &lt;/p&gt;

&lt;p&gt;3. Open hgwebdir_wsgi.py in a text editor, and configure the following settings &lt;/p&gt;

&lt;pre class="csharpcode"&gt;hgweb_config = r'c:\inetpub\hg\hgweb.config' 
path_prefix = 0&lt;/pre&gt;

&lt;p&gt;4. Open a command prompt changing your directory to c:\inetpub\hg&lt;/p&gt;

&lt;p&gt;5. Execute &lt;font face="Courier New"&gt;python hgwebdir_wsgi.py&lt;/font&gt; which will generate a DLL shim called _hgwebdir_wsgi.dll&lt;/p&gt;

&lt;p&gt;6. Create your hgweb.config file with the following content&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[paths]
/ = c:\repos\*&lt;/pre&gt;

&lt;p&gt;7. In IIS Manager, create a new application pool called "Mercurial" and ensure that the "Enable 32-bit Applications" is set to true.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_1.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_1.png" width="600" height="71" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;8. Create a new website pointing it to the location in step 1.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_2.png" width="377" height="366" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;9. Open up the Handler Mappings for your new web site.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_3.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_3.png" width="379" height="309" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;10. Add a new "Wildcard Script Map" with the Executable location pointing to the Shim DLL created in step 5. Give it the name Mercurial-ISAPI.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_4.png" width="377" height="309" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;11. Click the OK button, and when it prompts you to allow this ISAPI extension, click "Yes".&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_5.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_5.png" width="381" height="157" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;12. Now, browse to your newly created website, and you should see hgwebdir being served.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_6.png" width="381" height="165" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;13. Now, run the following command to create a new empty repository, and then refresh your browser.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;hg init c:\repos\test&lt;/pre&gt;
&lt;a href="http://www.eworldui.net/blog/image.axd?picture=image_7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.eworldui.net/blog/image.axd?picture=image_thumb_7.png" width="378" height="163" /&gt;&lt;/a&gt; 

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;All Setup!&lt;/h3&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;At this point, your Mercurial server is setup. You'll also notice that there's no need for URL rewriting unlike the the CGI approach. You can start pulling / pushing changes to your repository. While this setup requires more steps and dependencies, the benefit is that you are running completely within IIS gaining it's benefits of application isolation, memory management, and improved performance.&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/04/08/Setting-up-Mercurial-server-in-IIS7-using-a-ISAPI-module.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/04/08/Setting-up-Mercurial-server-in-IIS7-using-a-ISAPI-module.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=e94a547a-337b-4d0d-bf51-87ef247ed647</guid>
      <pubDate>Thu, 08 Apr 2010 18:10:07 +0100</pubDate>
      <category>Mercurial</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=e94a547a-337b-4d0d-bf51-87ef247ed647</pingback:target>
      <slash:comments>39</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=e94a547a-337b-4d0d-bf51-87ef247ed647</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/04/08/Setting-up-Mercurial-server-in-IIS7-using-a-ISAPI-module.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=e94a547a-337b-4d0d-bf51-87ef247ed647</wfw:commentRss>
    </item>
    <item>
      <title>Mercurial Conversion from Team Foundation Server</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;One of my many (almost) daily tasks when working on the &lt;a href="http://www.codeplex.com/"&gt;CodePlex&lt;/a&gt; platform since releasing Mercurial as a supported version control system, is converting projects from Team Foundation Server (TFS) to Mercurial. I'm happy to say that of all the conversions I have done since mid-January, the success rate of migrating full source history is about 95%. To get to this success point, I have had to learn and refine several techniques utilizing a few different tools to get the job done. Before I jump into the meat of the post, there are several setup tasks that need to be done first.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Configuring Mercurial&lt;/h4&gt;  &lt;p&gt;Mercurial comes with a pre-packaged extension, &lt;em&gt;convert,&lt;/em&gt; which supports nearly all major version control systems (Subversion, CVS, git, Darcs, Bazaar, Monotone, GNU Arch, and yes - even itself). Because this is an extension, you need to enable it in the Mercurial configuration. Open the Mercurial.ini file located at &lt;em&gt;C:\Users\&amp;lt;UserName&amp;gt;&lt;/em&gt; and add the following lines&lt;/p&gt;  &lt;pre class="csharpcode"&gt;[extensions]
convert =&lt;/pre&gt;

&lt;p&gt;Once this is saved, you can test if this extension is working by typing the command &lt;em&gt;hg help convert &lt;/em&gt;If things are configured correctly, it should display the help information regarding the &lt;em&gt;convert &lt;/em&gt;extension.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Conversion Setup&lt;/h4&gt;

&lt;p&gt;Mercurial's &lt;em&gt;convert &lt;/em&gt;extension allows you to have somewhat full control when performing the conversion. These options include mapping usernames, including/excluding certain paths, and renaming branches. These configuration options are to our advantage since TFS requires Active Directory and stores all commits in the format of &lt;em&gt;DOMAIN\User &lt;/em&gt;(though this format is perfectly acceptable, it's not ideal). Utilizing the ability to map usernames, create a new text file named &lt;em&gt;auths.txt &lt;/em&gt;and start adding your mappings:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;CONTOSO\Joe = Joe
CONTOSO\Mark = Mark&lt;/pre&gt;

&lt;p&gt;It is only necessary to add username mappings that appear in the TFS source history. Later, you will see how this username mapping file is used.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Utilizing SvnBridge&lt;/h4&gt;

&lt;p&gt;The first approach I take for doing project conversion for CodePlex, which has a success rate of 85%, is using the hosted &lt;a href="http://svnbridge.codeplex.com"&gt;SvnBridge&lt;/a&gt;. From the command line type the following&lt;/p&gt;

&lt;pre class="csharpcode"&gt;hg convert --authors auth.txt https://xunitcontrib.svn.codeplex.com/svn xunitcontrib&lt;/pre&gt;

&lt;p&gt;If the conversion works, your project will be successfully converted to Mercurial. It is recommended that you view the log history to ensure everything is in order. Should anyone continue to check in sources, just re-run the conversion on the already-converted Mercurial repository, and it will convert anything new.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Utilizing A Suite of Tools&lt;/h4&gt;

&lt;p&gt;Should the hosted SvnBridge not work, or you have TFS hosted elsewhere, the process is not nearly as straight forward and requires the use of several tools. Download and install the following&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://sourceforge.net/projects/tfs2svn/"&gt;tfs2svn&lt;/a&gt; - This converts TFS history into Subversion history &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.visualsvn.com/server/download/"&gt;VisualSVN Server&lt;/a&gt; - Used as the intermediary Subversion repository store &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://tortoisesvn.net/downloads"&gt;TortoiseSVN&lt;/a&gt; - Used for storing the Subversion credentials as well as admin tasks &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you have installed all of these tools (and probably rebooted your machine), follow these steps. &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Create an empty repository in VisualSVN Server. This is where the history from TFS will be migrated to as an intermediary step. Make sure that you do not select &lt;em&gt;Create default structure (trunk, branches, tags)&lt;/em&gt;. If you accidently check this option your import via tfs2svn will fail because it is expecting an empty repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; On the newly created repository open the Manage Hooks dialog by &lt;em&gt;Right Clicking Repository -&amp;gt; All Tasks -&amp;gt; Manage Hooks... &lt;/em&gt;Edit the &lt;em&gt;Pre-revision property change hook&lt;/em&gt; by entering a single carriage return. This is necessary for enabling hook which allows tfs2svn to rewrite the history in Subversion. If the hook is enabled correctly, it will become bolded in the list of available hooks. Click &lt;em&gt;OK&lt;/em&gt; to discard the dialog, and restart the VisualSVN server by &lt;em&gt;Right Clicking VisualSVN Server -&amp;gt; Restart&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: &lt;/strong&gt;You now need to add a user account to VisualSVN server so that tfs2svn can authenticate and import the history. In VisualSVN, right click &lt;em&gt;Users&lt;/em&gt; and select &lt;em&gt;Create User. &lt;/em&gt;Type in a easy-to-remember username and password and click &lt;em&gt;OK&lt;/em&gt;. How tfs2svn operates, is that it uses cached Subversion credentials for the import. The easiest way of caching your credentials, is checking out your new Subversion repository. When prompted for credentials, ensure the checkbox &lt;em&gt;Save Authentication&lt;/em&gt; is checked.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Launch tfs2svn and start filling in the connection information to your TFS and Subversion servers. Once the information is correctly filled out, click the &lt;em&gt;Convert&lt;/em&gt; button and wait while it starts extracting the history from TFS and importing it into your Subversion repository.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_8.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_thumb_8.png" width="434" height="239" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: &lt;/strong&gt;Once the tfs2svn process has been completed, you can view the history of the Subversion repository. One thing you'll notice, is that tfs2svn prefixes all commit messages with "[TFS Changeset #12345]". There are also some instances where tfs2svn will add "tfs2svn: " as a commit message as well. If you don't care if your Mercurial repository will have these messages, skip to step 6 - otherwise continue on.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_9.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_thumb_9.png" width="440" height="278" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;

&lt;p&gt;To remove the erroneous commit messages, you will need to rewrite the Subversion log using administrative tools. The process follows&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Get an XML log of the repository history &lt;/li&gt;

  &lt;li&gt;For each &lt;em&gt;logentry&lt;/em&gt; in the XML log get the &lt;em&gt;msg&lt;/em&gt; content and remove the messages &lt;/li&gt;

  &lt;li&gt;Create a temporary file writing the updated log message to it &lt;/li&gt;

  &lt;li&gt;Call the &lt;em&gt;setlog&lt;/em&gt; command on the executable &lt;em&gt;svnadmin&lt;/em&gt; passing in the path to the temporary file in step 3. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, this is a tedious process - so I automated it with a Powershell script (&lt;a href="http://www.eworldui.net/files/rewrite-log.zip"&gt;downloadable here&lt;/a&gt;). The script assumes that your VisualSVN server can be accessed at &lt;em&gt;https://localhost/svn/&amp;lt;RepositoryName&amp;gt; &lt;/em&gt;as well as the physical path of your VisualSVN repositories are located at &lt;em&gt;C:\Repositories. &lt;/em&gt;Once you have updated the script, place it in &lt;em&gt;%My Documents%\WindowsPowerShell, o&lt;/em&gt;pen a Powershell command prompt and type &lt;em&gt;rewrite-log RepositoryName&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you view the Subversion log again, you may notice that the message for each revision still contains the content we were trying to strip off. If this is the case, don't worry - the history has been rewritten, and you may be viewing a cached version of the repository.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Now that you have your repository migrated to Subversion and you have rewritten the log , you can now convert it into a Mercurial repository. Using the same syntax as SvnBridge conversion earlier, type the following on you command line&lt;/p&gt;

&lt;pre class="csharpcode"&gt;hg convert --authors auth.txt https://localhost/svn/xunitcontrib xunitcontrib&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_10.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://www.eworldui.net/images/blog/MercurialConversionfromTeamFoundationSer_ECE3/image_thumb_10.png" width="438" height="306" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Once completed, you will have a full history of your TFS repository converted to Mercurial! You can now start using your local repository immediately or push the history to a central repository for others to start using.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2010%2f03%2f16%2fMercurial-Conversion-from-Team-Foundation-Server.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2010%2f03%2f16%2fMercurial-Conversion-from-Team-Foundation-Server.aspx" /&gt;&lt;/a&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/03/16/Mercurial-Conversion-from-Team-Foundation-Server.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/03/16/Mercurial-Conversion-from-Team-Foundation-Server.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=89cce6b5-adb9-4cb3-bd1b-ad0959d285f4</guid>
      <pubDate>Tue, 16 Mar 2010 09:12:22 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Programming</category>
      <category>Mercurial</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=89cce6b5-adb9-4cb3-bd1b-ad0959d285f4</pingback:target>
      <slash:comments>8</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=89cce6b5-adb9-4cb3-bd1b-ad0959d285f4</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/03/16/Mercurial-Conversion-from-Team-Foundation-Server.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=89cce6b5-adb9-4cb3-bd1b-ad0959d285f4</wfw:commentRss>
    </item>
    <item>
      <title>VisualHG: A Mercurial Plugin for Visual Studio</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eworldui.net/images/blog/VisualHGAMercurialPluginforVisualStudio_F707/image.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="right" src="http://www.eworldui.net/images/blog/VisualHGAMercurialPluginforVisualStudio_F707/image_thumb.png" width="155" height="155" /&gt;&lt;/a&gt;&lt;a href="http://mercurial.selenic.com"&gt;Mercurial&lt;/a&gt; is quickly gaining momentum in the open source world, and the need for great tooling to make developers lives easier is always essential.&amp;#160; Most developers using Mercurial know of the the explorer shell plugin, &lt;a href="http://tortoisehg.bitbucket.org/"&gt;TortoiseHg&lt;/a&gt;, but what many don't know about is &lt;a href="http://visualhg.codeplex.com/"&gt;VisualHG&lt;/a&gt;. In summary, VisualHG is&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;A source control plugin for Visual Studio (works with 2005, 2008 and 2010) &lt;/li&gt;    &lt;li&gt;It sits on top TortoiseHg exposing common commands in Visual Studio &lt;/li&gt;    &lt;li&gt;It tracks file status changes automatically indicating the state in Visual Studio &lt;/li&gt;    &lt;li&gt;There's absolutely no SCC bindings! &lt;/li&gt;    &lt;li&gt;It's absolutely free! &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;An occasional gripe we hear from &lt;a href="http://www.codeplex.com"&gt;CodePlex&lt;/a&gt; users, is that when they download and open a project from CodePlex that contains SCC bindings, they quickly get annoyed by the Visual Studio warnings of working temporarily uncontrolled. This is why the second to last bullet point is even listed, it's that important! The mere fact that it's free is just a bonus :)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;To get started working with VisualHG is very simple. &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Download and install TortoiseHg and VisualHG. &lt;/li&gt;    &lt;li&gt;Open Visual Studio and go to &lt;em&gt;Tools -&amp;gt; Options&lt;/em&gt;. &lt;/li&gt;    &lt;li&gt;In the options tree view, select &lt;em&gt;Source Control&lt;/em&gt;. (You may need to click the &lt;em&gt;Show all Settings&lt;/em&gt; checkbox) &lt;/li&gt;    &lt;li&gt;Select VisualHG from the drop down list, and click OK. &lt;/li&gt;    &lt;li&gt;Open your Mercurial based solution to see the plugin installed and determining your files' statuses. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So, why am I writing this post? Well, I wanted to highlight and recommend a great Mercurial based project hosted on CodePlex that we, the CodePlex team, use every day. Don't get me wrong, a few of us still use Mercurial from the command line (myself included), but I wouldn't even go without having VisualHG installed for simply tracking file status changes (necessary when doing lots of refactoring).&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2010%2f03%2f15%2fVisualHG-A-Mercurial-Plugin-for-Visual-Studio.aspx%23comment"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2010%2f03%2f15%2fVisualHG-A-Mercurial-Plugin-for-Visual-Studio.aspx%23comment" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/03/15/VisualHG-A-Mercurial-Plugin-for-Visual-Studio.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/03/15/VisualHG-A-Mercurial-Plugin-for-Visual-Studio.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=6f7d37a5-b906-4644-bdad-7f1443e1b80a</guid>
      <pubDate>Mon, 15 Mar 2010 12:03:05 +0100</pubDate>
      <category>CodePlex</category>
      <category>Programming</category>
      <category>Tool Reviews</category>
      <category>Mercurial</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=6f7d37a5-b906-4644-bdad-7f1443e1b80a</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=6f7d37a5-b906-4644-bdad-7f1443e1b80a</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/03/15/VisualHG-A-Mercurial-Plugin-for-Visual-Studio.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=6f7d37a5-b906-4644-bdad-7f1443e1b80a</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex v1.3 Released</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;It's been a many months since the last release of &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;, but its only because there hasn't been a lot of churn recently.&amp;#160; I've very happy where WikiPlex is at, and it continues to be a very integral part of the CodePlex website! &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Here's what you'll find in WikiPlex v1.3:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;b&gt;&lt;u&gt;Documentation&lt;/u&gt;&lt;/b&gt; - This new documentation includes       &lt;ol&gt;       &lt;li&gt;Full Markup Guide with Examples &lt;/li&gt;        &lt;li&gt;Articles on Extending WikiPlex &lt;/li&gt;        &lt;li&gt;API Documentation &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Video Macro&lt;/u&gt;&lt;/b&gt; - This macro was updated to support Channel9 Videos. &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Syntax Highlight Support&lt;/u&gt;&lt;/b&gt; - One more language has been included:       &lt;ol&gt;       &lt;li&gt;{code:powershell} ... Your Powershell Code ... {code:powershell &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;This time I did what I promised two releases ago, provided some good documentation. I even went so far as creating another open-source project called &lt;a href="http://wikimaml.codeplex.com/"&gt;WikiMaml&lt;/a&gt; which will take wiki syntax and convert it to Sandcastle MAML output. The project isn't full proof, and not where I want it to end up, but it is working great within WikiPlex to generate all of the non-API documentation. As always, if you have any ideas for new macros or extensibility points, please post them in the issue tracker and I'll make sure to look at them!&lt;/p&gt;  &lt;p&gt;Now, go and &lt;a href="http://wikiplex.codeplex.com/releases/view/41788"&gt;download WikiPlex v1.3!&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/03/11/WikiPlex-v13-Released.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/03/11/WikiPlex-v13-Released.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=e0b11429-a15e-40a0-9637-aca7f0b31a78</guid>
      <pubDate>Thu, 11 Mar 2010 17:53:48 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Development</category>
      <category>WikiPlex</category>
      <category>Programming</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=e0b11429-a15e-40a0-9637-aca7f0b31a78</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=e0b11429-a15e-40a0-9637-aca7f0b31a78</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/03/11/WikiPlex-v13-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=e0b11429-a15e-40a0-9637-aca7f0b31a78</wfw:commentRss>
    </item>
    <item>
      <title>Extending WikiPlex with Scope Augmenters</title>
      <description>&lt;div style="background-image: url(http://www.eworldui.net/images/blog/twitter.png); padding-bottom: 0px; padding-left: 35px; width: 95%; background-repeat: no-repeat; background-position: left center; height: 32px; padding-top: 5px"&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0.25em; padding-right: 0px; height: 22px; padding-top: 0.25em" class="info"&gt;&lt;em&gt;In addition to blogging, I'm also using Twitter. Follow me &lt;a href="http://www.twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/em&gt; &lt;/div&gt; &lt;/div&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;This post is long overdue, but as I'm preparing the v1.3 release of &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; and working on documentation (yes, I did say documentation) I realized that another extension point with &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; was not covered. This last, important (but rarely used) part is extending with Scope Augmenters. Scope Augmenters allow you to post process the collection of scopes to further augment, or insert/remove, new scopes prior to being rendered. WikiPlex comes with 3 out-of-the-box Scope Augmenters that it uses for indentation, tables, and lists. For reference, I'll be explaining how and why the IndentationScopeAugmenter was created.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Why Its Needed&lt;/h4&gt;  &lt;p&gt;The IndentationMacro allows for an arbitrary indentation level indicated by the number of colons that are placed a the beginning of the line. Let's take a look at the primary macro rule:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;new&lt;/span&gt; MacroRule(&lt;span class="str"&gt;@&amp;quot;(^:+\s)[^\r\n]+((?:\r\n)?)$&amp;quot;&lt;/span&gt;,
              &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;
              {
                 {1, ScopeName.IndentationBegin},
                 {2, ScopeName.IndentationEnd}
              });&lt;/pre&gt;

&lt;p&gt;As you can see, we're capturing any number of colons at the beginning, but our ending scope knows nothing of the how many defined levels there are. If you can imagine, knowing nothing about your the beginning scope when rendering to correctly render the ending is not a trivial task without context. This is the exact reason a Scope Augmenter is used, it has that context.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Ultimately, we would like the input &lt;/p&gt;

&lt;pre class="csharpcode"&gt;:: I am content&lt;/pre&gt;

&lt;p&gt;to be rendered as &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;blockquote&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;blockquote&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;I am content&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;blockquote&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;blockquote&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Create a Scope Augmenter&lt;/h4&gt;

&lt;p&gt;Scope Augmenters can be as easy as you need to make it, but can also be fairly difficult - point of example, the supplied ListScopeAugmenter requires a complex algorithm to correctly identify levels, nested levels, and determining when to start new lists. When creating a Scope Augmenter, it will take in the associated macro, the current list of scopes, and the current content returning a new list of scopes to be rendered. In your solution, create a class called IndentationScopeAugmenter and extend it from WikIPlex.Parsing.IScopeAugmenter. You'll then implement the Augment method.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;Scope&amp;gt; Augment(IMacro macro, IList&amp;lt;Scope&amp;gt; capturedScopes, &lt;span class="kwrd"&gt;string&lt;/span&gt; content)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    var augmentedScopes = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Scope&amp;gt;(capturedScopes.Count);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; insertAt = 0;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; capturedScopes.Count; i = i + 2)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        Scope begin = capturedScopes[i];&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        Scope end = capturedScopes[i + 1];&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; beginContent = content.Substring(begin.Index, begin.Length);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; depth = Utility.CountChars(&lt;span class="str"&gt;':'&lt;/span&gt;, beginContent);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = 0; j &amp;lt; depth; j++)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            augmentedScopes.Insert(insertAt, begin);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            augmentedScopes.Add(end);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        insertAt = augmentedScopes.Count;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; augmentedScopes;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The Indentation begin / end scopes always come in a sequential pair, which is why I'm able to grab the begin and end scope in lines 8 and 9. Next, you'll see that we need to determine the depth to indent, so we grab the beginning content (which ultimately will be a string containing only colons). In line 12, we count the number of colons there are, which gives us our depth count. Lines 14 - 18 are adding the N-1 listing of IndentationBegin and IndentationEnd scopes. The method then returns this, newly augmented, list of scopes. Basically the augmentation goes from&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ScopeName.IndentationBegin,
ScopeName.IndentationEnd&lt;/pre&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ScopeName.IndentationBegin,
ScopeName.IndentationBegin,
ScopeName.IndentationEnd,
ScopeName.IndentationEnd&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Registering a Scope Augmenter&lt;/h4&gt;

&lt;p&gt;Just as registering macros and renderers, there is (only) a static endpoint. Since augmenters should not rely on runtime dependencies, there is no runtime equivalent of using scope augmenters. When you register a Scope Augmenter, it is always associated with a single macro type, and during parsing, the WikiPlex parser will query for the Scope Augmenter that is associated with the current macro being used. To register your Scope Augmenter, have the following code in your application startup method&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ScopeAugmenters.Register&amp;lt;IndentationMacro, IndentationScopeMacro&amp;gt;();&lt;/pre&gt;

&lt;p&gt;When you call the WikiEngine.Render("content"), it will automatically pick up all registered Scope Augmenters and use them during parsing. &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Summary&lt;/h4&gt;

&lt;p&gt;You now have a fully functioning macro / augmenter / renderer that will take an arbitrary depth and have it render correctly. As previously stated, WikiPlex also ships two other Scope Augmenters, ListScopeAugmenter and TableScopeAugmenter, which have a bit more logic associated with them. While Scope Augmenters allow you to manipulate the list of scopes prior to rendering, they should only be used in certain situations in which you cannot capture the correct set of conditions or are unable to contextually determine rendering based on separate scopes.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Download &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; now!&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2010/03/10/Extending-WikiPlex-with-Scope-Augmenters.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2010/03/10/Extending-WikiPlex-with-Scope-Augmenters.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=ea71e045-faf0-4c80-997e-df3ae368b56b</guid>
      <pubDate>Wed, 10 Mar 2010 10:40:04 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Programming</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=ea71e045-faf0-4c80-997e-df3ae368b56b</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=ea71e045-faf0-4c80-997e-df3ae368b56b</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2010/03/10/Extending-WikiPlex-with-Scope-Augmenters.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=ea71e045-faf0-4c80-997e-df3ae368b56b</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex v1.2 Released</title>
      <description>&lt;p&gt;It's been a few months since the last release of &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;, but I honestly have good reasons - paternity leave! This updated version has taken in a lot of user feedback and put it into action - so thank you for contributing ideas. Since the &lt;a href="http://blog.eworldui.net/post/2009/08/WikiPlex-v11-Released.aspx"&gt;last release&lt;/a&gt;, there's been a steady download of the binaries/source code on a day-to-day basis, and am very happy where it is in the ecosystem. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Here's what you'll find in WikiPlex v1.2:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;b&gt;&lt;u&gt;Indentation Macro&lt;/u&gt;&lt;/b&gt; - This new macro adds support for blockquote indentation. Utilize it similar to the ordered/unordered list macros with the colon character. See this &lt;a href="http://wikiplex.codeplex.com/Wiki/View.aspx?title=Text%20Alignment"&gt;documentation&lt;/a&gt; for an example on how to use it. &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Silverlight Macro&lt;/u&gt;&lt;/b&gt; - This macro was updated to support:       &lt;ol&gt;       &lt;li&gt;Any type of height/width unit (px, pc, pt, em, %, etc). &lt;/li&gt;        &lt;li&gt;Require Silverlight 3 as the default. You can optionally revert back to Silverlight 2 with the version=2 parameter. &lt;/li&gt;        &lt;li&gt;Support for initialization parameters by supplying any additional key/value parameters in the macro &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Video Macro&lt;/u&gt;&lt;/b&gt; - This macro was updated to support:       &lt;ol&gt;       &lt;li&gt;A height/width supporting any type (px, pc, pt, em %, etc) &lt;/li&gt;        &lt;li&gt;Videos will not auto-start by default. &lt;/li&gt;        &lt;li&gt;Soapbox support has been removed &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Syntax Highlight Support&lt;/u&gt;&lt;/b&gt; - Two more languages have been included:       &lt;ol&gt;       &lt;li&gt;{code:c++} ...Your C++ Code... {code:c++} &lt;/li&gt;        &lt;li&gt;{code:java} ...Your Java Code... {code:java} &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;&lt;u&gt;Updated Sample Application&lt;/u&gt;&lt;/b&gt; - A WebForms variant was added to the sample application. It can be found under the /WebForms directory. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Unfortunately, I didn't get around to documenting the API, but I've not heard of anyone commenting they can't figure it out - so maybe it'll still happen sometime in the future. As always, if you have any ideas for new macros or extensibility points, please post them in the issue tracker and I'll make sure to look at them!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Now, go and &lt;a href="http://wikiplex.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34162"&gt;download WikiPlex v1.2!&lt;/a&gt; Also, don't forget to follow me on Twitter &lt;a href="http://twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f10%2fWikiPlex-v12-Released.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f10%2fWikiPlex-v12-Released.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2009/10/08/WikiPlex-v12-Released.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2009/10/08/WikiPlex-v12-Released.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=acca4c32-f050-48fe-b8b9-1d37046a4368</guid>
      <pubDate>Thu, 08 Oct 2009 13:46:43 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Development</category>
      <category>Programming</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=acca4c32-f050-48fe-b8b9-1d37046a4368</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=acca4c32-f050-48fe-b8b9-1d37046a4368</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2009/10/08/WikiPlex-v12-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=acca4c32-f050-48fe-b8b9-1d37046a4368</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex v1.1 Released</title>
      <description>&lt;p&gt;It's only been a few weeks since the v1.0 release, but a lot of work has gone into a new release of &lt;a href="http://www.codeplex.com"&gt;CodePlex's&lt;/a&gt; embeddable wiki engine, &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;. The time in between has not been without a few highlights, including (&lt;a href="http://wikiplex.codeplex.com/stats"&gt;detailed stats&lt;/a&gt;):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Over &lt;strong&gt;&lt;u&gt;500 combined downloads&lt;/u&gt;&lt;/strong&gt; of the v1.0 engine and sample application &lt;/li&gt;    &lt;li&gt;Roughly &lt;strong&gt;&lt;u&gt;175 downloads&lt;/u&gt;&lt;/strong&gt; of the source code (not including SVN enlistments) &lt;/li&gt;    &lt;li&gt;Over &lt;strong&gt;&lt;u&gt;8000 page views / 2200 visits&lt;/u&gt;&lt;/strong&gt; of the project site &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;SoftPedia&lt;/u&gt;&lt;/strong&gt; picking up WikiPlex (&lt;a href="http://news.softpedia.com/news/Download-WikiPlex-Free-Open-Source-Wiki-Engine-from-Microsoft-117936.shtml"&gt;Download WikiPlex Free Open Source Wiki Engine from Microsoft&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;WikiPlex being already integrated in several projects (&lt;a href="http://swiki.codeplex.com"&gt;SWiki&lt;/a&gt; / &lt;a href="http://www.dijksterhuis.nu/blog/2009/8/2/wikiplex-for-umbraco.aspx"&gt;Umbraco&lt;/a&gt;) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I didn't have a long-term plan for revamping the wiki engine (I actually still don't!), but I did have several focuses for the short term that I wanted to achieve, including Mono compatibility, refactoring the macro parsing to enable more extensibility into the engine, and general &amp;quot;clean-up&amp;quot; tasks that I've been wanting to do. So, what's new in v1.1?&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;&lt;u&gt;Mono Compatibility&lt;/u&gt;&lt;/strong&gt; - The WikiPlex source has been tested against the 2.4.2.1 release of &lt;a href="http://www.mono-project.com/"&gt;Mono&lt;/a&gt; running on Linux. The source cleanly compiles and runs the sample application (note: you do still have to setup your own database for this). The only remaining issues running the sample application on Mono are ASP.NET MVC / Mono bugs. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;Scope Augmenters&lt;/u&gt;&lt;/strong&gt; - Scope Augmenters allow changing the resulting scopes prior to rendering based on a macro mapping. Previously - the Table, Ordered List, and Unordered List scope augmentation were hard-coded into the MacroParser. With this release, you can now add your own augmenters to fully control the rendering of WikiPlex. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;Syndicated Feeds&lt;/u&gt;&lt;/strong&gt; - The entire WCF syndication API was removed in lieu of utilizing a simpler, customized syndication framework. The main reasons for this change included: Mono currently not supporting this API and supporting the odd Google Atom specification. Aside from these internal changes, the macro was expanded so that it now supports {rss:url=...}, {feed:url=...}, and {atom:url=...} matching. No matter which format you use, the renderer will still choose the appropriate syndication reader (ie, you can specify rss for an atom feed, and vice versa). &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;Sample Download&lt;/u&gt;&lt;/strong&gt; - To be honest, I never opened the sample project from the .zip file, and so I never realized the state that it was in. Be it missing files, incorrect references, whatever - everything is fixed now! Along with that, several people have indicated that they didn't have SQL 2008 Express installed, so within the App_Data directory, there's a Wiki.sql file that you can execute on your local SQL server to create the sample tables/data (oh, and don't forget to change your connection string). &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;Invalid Syntax Highlight Code Blocks&lt;/u&gt;&lt;/strong&gt; - Previously, if someone supplied a {code:xxx} block that didn't match any of the supported languages, their source code would not be formatted as code. In v1.1 this has been changed, as it'll fall back to the non-syntax highlighted display of the code if it cannot find the language. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;u&gt;Namespace Cleanup&lt;/u&gt;&lt;/strong&gt; - This should only affect advanced users of the wiki engine. Below is a list of the changes:       &lt;ol&gt;       &lt;li&gt;ScopeName was moved from WikiPlex.Common to WikiPlex &lt;/li&gt;        &lt;li&gt;IXmlDocumentReader and XmlDocumentReader were moved from WikiPlex.Common to WikiPlex.Syndication &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;One item that is still on my plate, is actually spending some time documenting the API and producing a help file. Hopefully, the API isn't too difficult to understand, but I realize that it's somewhat necessary when it comes to implementing the engine within your application. Regardless, I feel that the engine is pretty close to where it needs to be regarding usability and extensibility. If you have any ideas for new macros or extensibility points, please post them in the &lt;a href="http://wikiplex.codeplex.com/WorkItem/List.aspx"&gt;issue tracker&lt;/a&gt; and I'll make sure to look at them!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;With that said, I give you &lt;a href="http://wikiplex.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=31144"&gt;WikiPlex v1.1&lt;/a&gt; (&lt;a href="http://wikiplex.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=31144"&gt;go and download it now!&lt;/a&gt;) Also, follow me on Twitter &lt;a href="http://twitter.com/matthawley"&gt;@matthawley&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f08%2fWikiPlex-v11-Released.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f08%2fWikiPlex-v11-Released.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2009/08/04/WikiPlex-v11-Released.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2009/08/04/WikiPlex-v11-Released.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=349d28cc-d1e9-442c-ad98-659ab1db1968</guid>
      <pubDate>Tue, 04 Aug 2009 18:31:59 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Development</category>
      <category>Programming</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=349d28cc-d1e9-442c-ad98-659ab1db1968</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=349d28cc-d1e9-442c-ad98-659ab1db1968</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2009/08/04/WikiPlex-v11-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=349d28cc-d1e9-442c-ad98-659ab1db1968</wfw:commentRss>
    </item>
    <item>
      <title>Extending WikiPlex with Custom Renderers</title>
      <description>&lt;p&gt;Following up from my prior post on &lt;a href="http://blog.eworldui.net/post/2009/07/Extending-WikiPlex-with-Custom-Macros.aspx"&gt;Extending WikiPlex with Custom Macros&lt;/a&gt; it's now time to talk about creating custom renderers. When we left off, we had created our title link macro and registered it with &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;. If you had attempted to utilize the new macro in wiki content, you'd get the message "Cannot resolve macro, as no renderers were found." instead of a hyperlink. This was the expected behavior, because while you had identified your new scope via parsing, you were missing that critical link of turning the scope into actual content. Let's take a look at our scenario again to refresh what we're trying to achieve:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;We would like to integrate WikiPlex into an existing application. The idea is to allow a user contributed area specifically for wiki content. The user should be allowed to use all out-of-the-box macros provided, but also have the ability to have inter-wiki links with the format of [Title of Page]. As you probably realized, there is currently no macro/renderer that will take that content and turn it into a inter-wiki link, so we'll have to extend WikiPlex adding this functionality.&lt;/p&gt; &lt;/blockquote&gt;  &lt;h5&gt;Create a Renderer&lt;/h5&gt;  &lt;p&gt;Creating a renderer is actually the easiest portion of defining new wiki syntaxes, as it's as complicated as you need to make it. Again, a renderer simply takes in a scope (which is a contextual identifier), processes the content, and returns new content. Let's get started - so in your solution, create a class called TitleLinkRenderer and extend it from WikiPlex.Formatting.IRenderer. You'll then implement the members it requires (Id, CanExpand and Expand). The Id value is simply a string that is used as a key for static renderer registration, so it should be unique (follow the same rule of thumb for naming as the macros).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Next, you'll implement the CanExpand method. This method simply takes in a scope name and returns a boolean value indicating if this renderer can expand (or render) the scope successfully. As the formatter is processing all scopes, it goes through the list of renderers in the formatter and finds the first match that can expand that particular scope. There is no guarantee of the order of checking renderers, so always unregister a renderer you're overriding its implementation for. As you'll see below, the CanExpand method is fairly trivial, however should your renderer support a number of scopes, you'll need to change this code to include all of them.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; CanExpand(&lt;span class="kwrd"&gt;string&lt;/span&gt; scopeName)
{
   &lt;span class="kwrd"&gt;return&lt;/span&gt; scopeName == WikiScopeName.WikiLink;
}&lt;/pre&gt;

&lt;p&gt;Next, you'll implement the Expand method. This method will take in a scope name, the related input from the wiki source, and html / attribute encoding functions. The reason we're passing in html / attribute encoding functions, is so that you can utilize a consistent encoding scheme across all of the renderers. Out of the box, WikiPlex uses HttpUtility.HtmlEncode and HttpUtility.HtmlAttributeEncode, but by creating &amp;amp; supplying your own formatter, you can change these to use another library (like AntiXss). As previously stated, rendering is as hard as you need it to be. In the sample application example, we're just rendering a link utilizing the ASP.NET MVC UrlHelper (which is supplied via the constructor).&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; LinkFormat = &lt;span class="str"&gt;&amp;quot;&amp;lt;a href=\&amp;quot;{0}\&amp;quot;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;quot;&lt;/span&gt;;

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Expand(&lt;span class="kwrd"&gt;string&lt;/span&gt; scopeName, &lt;span class="kwrd"&gt;string&lt;/span&gt; input,
                     Func&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; htmlEncode, 
                     Func&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; attributeEncode)
{
   &lt;span class="kwrd"&gt;string&lt;/span&gt; url = urlHelper.RouteUrl(&lt;span class="str"&gt;&amp;quot;Default&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; { slug = SlugHelper.Generate(input) });
   &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(LinkFormat, attributeEncode(url), htmlEncode(input));
}&lt;/pre&gt;

&lt;p&gt;And now you have created your renderer, however it will still not be picked up when rendering your wiki content as you need to register the renderer with WikiPlex.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h5&gt;Registering a Renderer&lt;/h5&gt;

&lt;p&gt;Just as registering a macro, you have a static and a dynamic way to register your renderers. If your renderer requires only static dependencies (or no external runtime dependencies), you should opt for statically registering your renderer. To do this, have the following code in your application startup method&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Renderers.Register&amp;lt;TitleLinkRenderer&amp;gt;();&lt;/pre&gt;

&lt;p&gt;When you call the WikiEngine.Render("content"), it will automatically pick up all statically defined renderers and use them when formatting your scopes. As previously stated, if you have external runtime dependencies (like in our example), a little bit of extra work is required when calling WikiEngine.Render - as you'll need to pass in a MacroFormatter instead. However, if you utilize the overload to only take in a formatter, you'll need to union the statically defined renderers with yours.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; MacroFormatter GetFormatter()
{
   var siteRenderers = &lt;span class="kwrd"&gt;new&lt;/span&gt; IRenderer[] {&lt;span class="kwrd"&gt;new&lt;/span&gt; TitleLinkRenderer(Url)};
   IEnumerable&amp;lt;IRenderer&amp;gt; allRenderers = Renderers.All.Union(siteRenderers);
   &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MacroFormatter(allRenderers);
}&lt;/pre&gt;

&lt;p&gt;Now, when you call WikiEngine.Render, you'll utilize the overload that takes in an IFormatter as a parameter. After you've set all of this up, try re-loading your page and you should see your syntax of [Title Link] be converted into the html &amp;lt;a href="http://www.eworldui.net/title-link"&amp;gt;Title Link&amp;lt;/a&amp;gt;.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h5&gt;Summary&lt;/h5&gt;

&lt;p&gt;You now have a new fully functioning macro syntax. Obviously, this example is trivial - but I guarantee if you embed WikiPlex into your application and need any cross-page linking, you'll utilize this macro &amp;amp; renderer. Again, the possibilities are endless with what you can do, so long as you have a syntax, regex, and rendering code - you can allow your users to simply include expansive macros.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Download &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; now!&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fExtending-WikiPlex-with-Custom-Renderers.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fExtending-WikiPlex-with-Custom-Renderers.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2009/07/30/Extending-WikiPlex-with-Custom-Renderers.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2009/07/30/Extending-WikiPlex-with-Custom-Renderers.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=96e8007d-b46e-44a5-aa20-7e4f26066b88</guid>
      <pubDate>Thu, 30 Jul 2009 13:22:27 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>WikiPlex</category>
      <category>Programming</category>
      <category>Development</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=96e8007d-b46e-44a5-aa20-7e4f26066b88</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=96e8007d-b46e-44a5-aa20-7e4f26066b88</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2009/07/30/Extending-WikiPlex-with-Custom-Renderers.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=96e8007d-b46e-44a5-aa20-7e4f26066b88</wfw:commentRss>
    </item>
    <item>
      <title>Extending WikiPlex with Custom Macros</title>
      <description>&lt;p&gt;One of the very nice features of &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; is the ability to extend it to your hearts desire. The API is completely open, and the entry points off of WikiEngine are merely wrappers. This means that, if you really wanted to, you could create your own parser and formatter - but the majority of extending WikiPlex will be done via macros and renderers. A summary of the extension points include: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Macros encapsulate rules for matching segments of content. &lt;/li&gt;    &lt;li&gt;Macro rules are regular expressions that map matches to scopes. &lt;/li&gt;    &lt;li&gt;Scopes are contextual identifiers. &lt;/li&gt;    &lt;li&gt;Renderers take scopes and expand them into a HTML formatted representation of the macro. &lt;/li&gt; &lt;/ol&gt;  &lt;h5&gt;Scenario&lt;/h5&gt;  &lt;p&gt;We would like to integrate WikiPlex into an existing application. The idea is to allow a user contributed area specifically for wiki content. The user should be allowed to use all out-of-the-box macros provided, but also have the ability to have inter-wiki links with the format of [Title of Page]. As you probably realized, there is currently no macro/renderer that will take that content and turn it into a inter-wiki link, so we'll have to extend WikiPlex adding this functionality.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h5&gt;Create a Macro&lt;/h5&gt;  &lt;p&gt;When creating a macro, you're going to have to dust off that copy of RegexBuddy you probably don't have installed anymore. Why? Well, as previously stated, macro rules are regular expressions - and unless you're a regex guru, you won't be able to do this ad-hoc without a great tool. Let's get started - so in your solution, create a class called TitleLinkMacro, and extend it from WikiPlex.Compilation.Macros.IMacro. You'll then implement the members it requires (Id and Rules). The Id value is simply a string that is used as a key for static macro registration and macro compilation, so it should be unique (rule of thumb, give it the name of your class but with spaces). Now, it's time to define your macro rules.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;As you may have noticed, I kept &amp;quot;rule&amp;quot; plural. The reason, is that the majority of macros you will create need to have an initial &amp;quot;escaped&amp;quot; rule. This rule basically stops the regex from matching within code blocks, between curly braces, and possibly between square brackets. Since our macro utilizes square brackets, we'll use the escape rule of CurlyBraceEscape.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Next, you'll define your regex (with extreme caution!) utilizing capturing groups to identify scopes. If you take a look at the code, you may not think that the scope identification is zero based - don't be fooled, it really is! Identifying an index 0 scope indicates the full match for that rule. When creating your capturing groups, you can have any number, allowing for fine granularity when rendering. So, let's take a look at the sample project's macro's rules.&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;MacroRule&amp;gt; {&lt;/pre&gt;

  &lt;pre&gt;   get {&lt;/pre&gt;

  &lt;pre class="alt"&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;MacroRule&amp;gt; {&lt;/pre&gt;

  &lt;pre&gt;         &lt;span class="kwrd"&gt;new&lt;/span&gt; MacroRule(EscapeRegexPatterns.CurlyBraceEscape),&lt;/pre&gt;

  &lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;new&lt;/span&gt; MacroRule(&lt;span class="str"&gt;@&amp;quot;(?i)(\[)(?!\#|[a-z]+:)((?&amp;gt;[^\]]+))(\])&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

  &lt;pre&gt;                 &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; {&lt;/pre&gt;

  &lt;pre class="alt"&gt;                    { 1, ScopeName.Remove },&lt;/pre&gt;

  &lt;pre&gt;                    { 2, WikiScopeName.WikiLink },&lt;/pre&gt;

  &lt;pre class="alt"&gt;                    { 3, ScopeName.Remove }&lt;/pre&gt;

  &lt;pre&gt;                 })&lt;/pre&gt;

  &lt;pre class="alt"&gt;      };&lt;/pre&gt;

  &lt;pre&gt;   }&lt;/pre&gt;

  &lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, the regular expression is indicating that I should match 3 scopes per overall match. The scope &amp;quot;Remove&amp;quot; does just that. It removes the captured content when rendering. The WikiLink scope name is one that was created specifically for the sample. For the non-regex savvy developer, the regex reads:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Use case insensitive matching from this point on &lt;/li&gt;

  &lt;li&gt;Match the character &amp;quot;[&amp;quot; &lt;/li&gt;

  &lt;li&gt;Match any character until &amp;quot;]&amp;quot; is found 
    &lt;ol&gt;
      &lt;li&gt;But do not match if the character is preceded 
        &lt;ol&gt;
          &lt;li&gt;by the &amp;quot;#&amp;quot; character &lt;/li&gt;

          &lt;li&gt;or by any character between a-z, one or more times, followed by a &amp;quot;:&amp;quot; character &lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;li&gt;Match the character &amp;quot;]&amp;quot; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our scope to step matching then is&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Remove &amp;quot;[&amp;quot; &lt;/li&gt;

  &lt;li&gt;WikiLink any content &lt;/li&gt;

  &lt;li&gt;Remove &amp;quot;]&amp;quot; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Defining macro rules is a fairly straight forward process, just keep in mind that the order of the macro rules is &lt;strong&gt;&lt;u&gt;important&lt;/u&gt;&lt;/strong&gt;! You should also realize that if you wish to allow nesting of rules (for example, italicize bolded text) the italics and bold macro rules cannot be apart of the same macro. This, again, is because the macro rules are combined to build a large regular expression - and each rule is treated as an &amp;quot;or&amp;quot; statement.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h5&gt;Registering a Macro&lt;/h5&gt;

&lt;p&gt;After you have created your macro, you need to register it with WikiPlex. You have two ways of doing this - statically and dynamically. When statically registering macros, you simply need to have the following code in your application startup method&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Macros.Register&amp;lt;TitleLinkMacro&amp;gt;();&lt;/pre&gt;

&lt;p&gt;When you call the WikiEngine.Render(&amp;quot;content&amp;quot;), it will automatically pick up your macro, compile it, and use it when parsing the wiki content. Dynamically loading your macros is useful when you require a different set of macros to be executed than what is normally registered. For example, in CodePlex - we have a different set of allowed macros between editing a project's wiki content and editing your personal statement. Dynamically loading is achieved by utilizing one of the WikiEngine.Render overloads:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;WikiEngine.Render(&lt;span class="str"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; IMacro[] { &lt;span class="kwrd"&gt;new&lt;/span&gt; WikiTitleLinkMacro() });&lt;/pre&gt;

&lt;p&gt;The only caveat of this approach, is that it will &lt;strong&gt;&lt;u&gt;only&lt;/u&gt;&lt;/strong&gt; use that macro when parsing your wiki content.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h5&gt;Summary&lt;/h5&gt;

&lt;p&gt;This is just the tip of the extensibility for WikiPlex. Creating your own macro is a great. Simply be cautious of your regular expression as it could have negative side effects (catastrophic backtracking) that will bring your site to a screeching halt! In the next installment, we'll take this scenario to the next step by creating a renderer for your macro.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Download &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; now!&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fExtending-WikiPlex-with-Custom-Macros.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fExtending-WikiPlex-with-Custom-Macros.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2009/07/24/Extending-WikiPlex-with-Custom-Macros.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2009/07/24/Extending-WikiPlex-with-Custom-Macros.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=18702841-321f-40e7-873e-ff44eb1fefdb</guid>
      <pubDate>Fri, 24 Jul 2009 18:47:58 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=18702841-321f-40e7-873e-ff44eb1fefdb</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=18702841-321f-40e7-873e-ff44eb1fefdb</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2009/07/24/Extending-WikiPlex-with-Custom-Macros.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=18702841-321f-40e7-873e-ff44eb1fefdb</wfw:commentRss>
    </item>
    <item>
      <title>WikiPlex &amp;ndash; An Embedded Wiki Engine</title>
      <description>&lt;h4&gt;What and Why?&lt;/h4&gt;  &lt;p&gt;I'd like to introduce you to &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;, which is &lt;a href="http://www.codeplex.com/"&gt;CodePlex's&lt;/a&gt; wiki engine that we have re-written and made open source under the MS-PL license. I'm also happy to announce that our &lt;a href="http://wikiplex.codeplex.com/Release/ProjectReleases.aspx"&gt;first public release is now available&lt;/a&gt;!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;CodePlex previously had a decent wiki engine that was written eon's ago. On the average, that wiki engine worked relatively well, but had a very problematic performance bug that would cause rendering slowness occasionally. So, instead of attempting to fix the bug, we decided to re-write the entire thing with the intensions of making it available to everyone! This time, we chose a different approach for parsing the wiki markup (utilizing regular expressions) which has proven to give us a performance boost as well as a relatively simpler architecture!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The main question you may be asking yourself is - Why use &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; over a different solution? Here's the simple answer: WikiPlex is great if you already have a .NET application you'd like to embed a wiki interface into. Be it as simple as allowing users to host their own homepage content, item descriptions, or comments - the possibilities are endless! &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Usage&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt; was built in a way that it can easily be added into your infrastructure. Whether your using dependency injection or not, the code is as simple as the following:&lt;/p&gt;  &lt;div style="color: black"&gt;   &lt;pre&gt;&lt;span style="color: blue"&gt;var&lt;/span&gt; engine = &lt;span style="color: blue"&gt;new&lt;/span&gt; WikiPlex.WikiEngine();
&lt;span style="color: blue"&gt;string&lt;/span&gt; output = engine.Render(&lt;span style="color: #a31515"&gt;&amp;quot;This is my wiki source!&amp;quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If you take a look at the overloads for Render, you'll see that you have a lot of flexibility as far as rendering various wiki segments differently at runtime. (I'll describe the extensibility in the future)&lt;/p&gt;

&lt;div style="color: black"&gt;
  &lt;pre&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;interface&lt;/span&gt;&lt;span style="color: mediumturquoise"&gt; IWikiEngine
&lt;/span&gt;{
   &lt;span style="color: blue"&gt;string&lt;/span&gt; Render(&lt;span style="color: blue"&gt;string&lt;/span&gt; wikiContent);
   &lt;span style="color: blue"&gt;string&lt;/span&gt; Render(&lt;span style="color: blue"&gt;string&lt;/span&gt; wikiContent, IFormatter formatter);
   &lt;span style="color: blue"&gt;string&lt;/span&gt; Render(&lt;span style="color: blue"&gt;string&lt;/span&gt; wikiContent, IEnumerable&amp;lt;IMacro&amp;gt; macros);
   &lt;span style="color: blue"&gt;string&lt;/span&gt; Render(&lt;span style="color: blue"&gt;string&lt;/span&gt; wikiContent, IEnumerable&amp;lt;IMacro&amp;gt; macros, IFormatter formatter);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;h4&gt;Supported Macros&lt;/h4&gt;

&lt;p&gt;The following are the macros supported out of the box for &lt;a href="http://wikiplex.codeplex.com/"&gt;WikiPlex&lt;/a&gt;. If you'd like to see the description and usage, please visit the &lt;a href="http://wikiplex.codeplex.com/Wiki/View.aspx?title=Markup%20Guide"&gt;markup guide&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Text Formatting 
    &lt;ul&gt;
      &lt;li&gt;Bold &lt;/li&gt;

      &lt;li&gt;Italics &lt;/li&gt;

      &lt;li&gt;Underline &lt;/li&gt;

      &lt;li&gt;Strikethrough &lt;/li&gt;

      &lt;li&gt;Superscript &lt;/li&gt;

      &lt;li&gt;Subscript &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Headings &lt;/li&gt;

  &lt;li&gt;Images &lt;/li&gt;

  &lt;li&gt;Links &lt;/li&gt;

  &lt;li&gt;Tables &lt;/li&gt;

  &lt;li&gt;Left and Right Aligned Text &lt;/li&gt;

  &lt;li&gt;Ordered and Unordered Lists &lt;/li&gt;

  &lt;li&gt;RSS / Atom Feeds &lt;/li&gt;

  &lt;li&gt;Source Code Blocks (both syntax highlighted and not) &lt;/li&gt;

  &lt;li&gt;Silverlight &lt;/li&gt;

  &lt;li&gt;Videos (Flash, Quicktime, Real, Soapbox, Windows Media, and YouTube) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy! And don't forget to &lt;a href="http://wikiplex.codeplex.com/Release/ProjectReleases.aspx"&gt;download WikiPlex now&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fWikiPlex-ndash3b-An-Embedded-Wiki-Engine.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2009%2f07%2fWikiPlex-ndash3b-An-Embedded-Wiki-Engine.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2009/07/16/WikiPlex-ndash3b-An-Embedded-Wiki-Engine.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2009/07/16/WikiPlex-ndash3b-An-Embedded-Wiki-Engine.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=58264690-ea26-468f-848b-b8f7001e8332</guid>
      <pubDate>Thu, 16 Jul 2009 11:04:57 +0100</pubDate>
      <category>.NET</category>
      <category>CodePlex</category>
      <category>Programming</category>
      <category>WikiPlex</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=58264690-ea26-468f-848b-b8f7001e8332</pingback:target>
      <slash:comments>12</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=58264690-ea26-468f-848b-b8f7001e8332</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2009/07/16/WikiPlex-ndash3b-An-Embedded-Wiki-Engine.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=58264690-ea26-468f-848b-b8f7001e8332</wfw:commentRss>
    </item>
    <item>
      <title>MEF + Factories Using an Export Provider</title>
      <description>&lt;p&gt;After my last post about &lt;a href="http://blog.eworldui.net/post/2008/11/MEF-2b-Factories.aspx"&gt;MEF + Factories&lt;/a&gt;, I was chatting with &lt;a href="http://blogs.msdn.com/gblock/"&gt;Glenn Block&lt;/a&gt; (PM for MEF) about my approach. One of the first things he mentioned is why I hadn't used an ExportProvider. As you know, ExportProvider's are new in the latest drop, and provide an interception point for resolving an import to an export. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Taking a look back at the &lt;a href="http://www.codeplex.com/MEF/Wiki/View.aspx?title=Overview&amp;amp;referringTitle=Home"&gt;documentation&lt;/a&gt; on ComposablePart, I can see why Glenn mentioned this. In it, it states that a ComposoblePart must adhere to to Import/Export contracts. If you've looked at the prior example, you'll see that I'm explicitly violating that rule as I'm finding interfaces based on a base interface, not by Export! At this point, my mind started churning - mainly because there's not a lot of examples or descriptions of what an ExportProvider actually is - but because I wanted to do things "correctly" according to the framework provided. (As an aside, Glenn stated that a "What is an Export Provider" post or documentation is coming, maybe this'll boost that necessity!) What I ultimately came up with was a much cleaner solution than using a FactoryPartCatalog. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Introducing FactoryExportProvider:&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FactoryExportProvider&amp;lt;T&amp;gt; : ExportProvider {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryExportProvider(Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryExportProvider(Assembly assembly, Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryExportProvider(IEnumerable&amp;lt;Type&amp;gt; types, Func&amp;lt;Type, T&amp;gt; resolutionMethod { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;What you'll see is again, it's very straight forward and provides a clean implementation in usage, just as the part catalog example did. Each constructor does just as it had done in the part catalog, so I'll not explain that again. One thing that I discussed with Glenn about was, is it appropriate to look for certain types within an Export Provider? His response was "absolutely you can do that". good, I think I've found the correct implementation, both from less code/object graph standpoint, but also from an intention standpoint.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Internally, the code is very simplistic. Since I'm finding these interfaces on-the-fly, and need more information than just the contract name, I needed to use a FactoryExportDefinition to store this information. I've you've looked at the prior example, you'll see this came back out of necessity.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FactoryExportDefinition&amp;lt;T&amp;gt; : ExportDefinition {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryExportDefinition(&lt;span class="kwrd"&gt;string&lt;/span&gt; contractName, Type type, Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ContractName { get { ... } }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; Type ServiceType { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; Func&amp;lt;Type, T&amp;gt; ResolutionMethod { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When finding all of the interfaces that implement the base interface specified in the FactoryExportProvider, I convert those into a list of FactoryExportDefinition objects. Reason being, is that the export provider compares an ImportDefinition to an ExportDefinition when finding all available exports. This comparison is done by implementing the GetExportsCore method. The idea of export providers, is that when resolving all dependencies, MEF will call into all of the registered ExportProviders to determine if they can supply the Export and will do a bunch of cardinality matching for you. Out of the box, MEF provides an export provider for it's registered part catalogs. Here's the FactoryExportProvider's implementation of GetExportsCore.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Export&amp;gt; GetExportsCore(ImportDefinition importDefinition) {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;   IList&amp;lt;Export&amp;gt; exports = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Export&amp;gt;();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;   var constraint = importDefinition.Constraint.Compile();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;   var foundExports = from d &lt;span class="kwrd"&gt;in&lt;/span&gt; definitions&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                      &lt;span class="kwrd"&gt;where&lt;/span&gt; constraint(d)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;                      select &lt;span class="kwrd"&gt;new&lt;/span&gt; Export(d, () =&amp;gt; d.ResolutionMethod(d.ServiceType));&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; (importDefinition.Cardinality == ImportCardinality.ZeroOrMore)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;      exports = foundExports.ToList();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;   &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (foundExports.Count() == 1)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;      exports.Add(foundExports.First());&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;   &lt;span class="kwrd"&gt;return&lt;/span&gt; exports;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It's that simple. The Export's that are returned will have the resolution method called when the actual object is needed. When it comes down to including this within your application, it's just as easy as it was for the part catalog, you just register things a bit differently.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IService { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUserService : IService { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[Export]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserController {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;   [ImportingConstructor]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; UserController(IUserService userService) { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="rem"&gt;// in your application&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Compose() {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;   var catalog = &lt;span class="kwrd"&gt;new&lt;/span&gt; AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;   var factoryProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; FactoryExportProvider&amp;lt;IService&amp;gt;(GetService);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;   var container = &lt;span class="kwrd"&gt;new&lt;/span&gt; CompositionContainer(catalog, factoryProvider);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;   container.AddPart(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;   container.Compose();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IService GetService(Type type) { &lt;span class="kwrd"&gt;return&lt;/span&gt; ... }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And that's it. Ultimately, this leads to a cleaner implementation that uses less types that you have to manage, and, adheres to the correct intentions of the framework. Much thanks to Glenn who I chatted with for several hours last night! You can get the &lt;a href="http://www.eworldui.net/files/mefdemos/meffactoryexportprovider.zip" target="_blank"&gt;downloadable source here&lt;/a&gt;. Enjoy!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2008%2f11%2fMEF-2b-Factories-Using-an-Export-Provider.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost%2f2008%2f11%2fMEF-2b-Factories-Using-an-Export-Provider.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2008/11/29/MEF-2b-Factories-Using-an-Export-Provider.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2008/11/29/MEF-2b-Factories-Using-an-Export-Provider.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=c305eabc-d5b7-4ae5-a17c-1e71a07819f8</guid>
      <pubDate>Sat, 29 Nov 2008 10:25:52 +0100</pubDate>
      <category>.NET</category>
      <category>MEF</category>
      <category>Programming</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=c305eabc-d5b7-4ae5-a17c-1e71a07819f8</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=c305eabc-d5b7-4ae5-a17c-1e71a07819f8</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2008/11/29/MEF-2b-Factories-Using-an-Export-Provider.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=c305eabc-d5b7-4ae5-a17c-1e71a07819f8</wfw:commentRss>
    </item>
    <item>
      <title>MEF + Factories</title>
      <description>&lt;p&gt;Lately I've been really digging into &lt;a href="http://www.codeplex.com/mef"&gt;MEF&lt;/a&gt; and have been looking at it's pros &amp;amp; cons, ease of use, extensibility, and the simple DI container that it can provide. I'm not going to give an overview of MEF, as others have done so already. What I am here to show off is a concept that may prove useful for some applications. Many of us use a DI container in very simplistic ways, as well as registering injection strategies during type resolution. If you have no needs of this latter, MEF is very simple and easily fits into your current architecture by not having to change anything but decorating things. For example: &lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUserService { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;[Export(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IUserService))]&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[CompositionOptions(CreationPolicy = CreationPolicy.Factory)]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserService : IUserService { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;[Export]&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserController {&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;   [ImportingConstructor]&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; UserController(IUserService userService) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;At MEF's simplistic nature, you see that during construction, our exported services are being imported for us, but only because we don't care about it's construction and assume that generic construction will work. So when we call resolve UserController using MEF, it'll create and inject a new instance of UserService for us.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Now, say we have a need where the construction of IUserService needs to go through a factory. For instance, maybe IUserService is a WCF endpoint, and you have custom logic built into properly constructing the proxy endpoint. Well, MEF can solve this issue for you by exporting methods, but what you have to do is ultimately change your code and have 2 constructors.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUserService { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;// in your application&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[Export(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IUserService))]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IUserService ConstructUserService() { &lt;span class="kwrd"&gt;return&lt;/span&gt; ... }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;[Export]&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserController {&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;   [ImportingConstructor]&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; UserController([Import(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IUserService))] Func&amp;lt;IUserService&amp;gt; serviceMethod)&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;       : &lt;span class="kwrd"&gt;this&lt;/span&gt;(serviceMethod())&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;   { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; UserController(IUserService userService) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, it's not that nice. We need both constructors because one is used in production and one is used for testability. It ultimately leads to a lot of confusion as to why we need it. So, with that in mind, I set out to determine how this pattern could be achieved using MEF, but also provide a seamless transition from a DI world to MEF. Enter, FactoryPartCatalog:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FactoryPartCatalog&amp;lt;T&amp;gt; : ComposablePartCatalog {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryPartCatalog(Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryPartCatalog(Assembly assembly, Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; FactoryPartCatalog(IEnumerable&amp;lt;Type&amp;gt; types, Func&amp;lt;Type, T&amp;gt; resolutionMethod) { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; IQueryable&amp;lt;ComposableDefinition&amp;gt; Parts { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; ... } }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When we use this in our application, it brings back the simplicity of MEF. What it's doing during construction is looking through the assembly (first two constructors) to find all interfaces that implement type T. The interfaces that it finds will be created into ComposablePart's for MEF's container to utilize. Ultimately, when GetExportedObject&amp;lt;T&amp;gt; is called, it'll execute the resolution method you specified passing in the Type that was requested.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;As you can see below, we're using a AggregatingComposablePartCatalog adding our new FactoryPartCatalog and AttributedAssemblyPartCatalog. We've told FactoryPartCatalog to look through the current assembly for all interfaces that derive from IService. Upon construction injection by MEF, it'll find that it's requesting an export of IUserService, find it in the FactoryPartCatalog, and call GetService(Type) to get it's instance.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IService { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUserService : IService { }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[Export]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserController {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;   [ImportingConstructor]&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; UserController(IUserService userService) { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="rem"&gt;// in your application&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Compose() {&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;   var catalog = AggregatingComposablePartCatalog();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;   catalog.Catalogs.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;   catalog.Catalogs.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; FactoryPartCatalog&amp;lt;IService&amp;gt;(GetService);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;   var container = &lt;span class="kwrd"&gt;new&lt;/span&gt; CompositionContainer(catalog);&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;   container.AddPart(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;   container.Compose();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;}&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IService GetService(Type type) { &lt;span class="kwrd"&gt;return&lt;/span&gt; ... }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now, there's a lot more code behind the scenes that is required to get a new Part Catalog up and running, but I'll leave that for you to check out in the &lt;a href="http://www.eworldui.net/files/mefdemos/meffactorypartcatalog.zip"&gt;downloadable source&lt;/a&gt;. As this is purely a proof of concept, I'm sure there's more simplifications or additions that can be added, but for getting this running out of the box in this manner, it works great!&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.eworldui.net%2fpost.aspx%3fid%3dbcdae64d-f1b7-40f6-8a96-076cc5767fa0"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.eworldui.net%2fpost.aspx%3fid%3dbcdae64d-f1b7-40f6-8a96-076cc5767fa0" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.eworldui.net/blog/post/2008/11/27/MEF-2b-Factories.aspx</link>
      <author>matthaw</author>
      <comments>http://www.eworldui.net/blog/post/2008/11/27/MEF-2b-Factories.aspx#comment</comments>
      <guid>http://www.eworldui.net/blog/post.aspx?id=bcdae64d-f1b7-40f6-8a96-076cc5767fa0</guid>
      <pubDate>Thu, 27 Nov 2008 13:47:31 +0100</pubDate>
      <category>.NET</category>
      <category>Development</category>
      <category>MEF</category>
      <dc:publisher>matthaw</dc:publisher>
      <pingback:server>http://www.eworldui.net/blog/pingback.axd</pingback:server>
      <pingback:target>http://www.eworldui.net/blog/post.aspx?id=bcdae64d-f1b7-40f6-8a96-076cc5767fa0</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.eworldui.net/blog/trackback.axd?id=bcdae64d-f1b7-40f6-8a96-076cc5767fa0</trackback:ping>
      <wfw:comment>http://www.eworldui.net/blog/post/2008/11/27/MEF-2b-Factories.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.eworldui.net/blog/syndication.axd?post=bcdae64d-f1b7-40f6-8a96-076cc5767fa0</wfw:commentRss>
    </item>
  </channel>
</rss>