<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1285</guid>
      <link>https://shazwazza.com/post/need-to-remove-an-auto-routed-controller-in-umbraco/</link>
      <category>Umbraco</category>
      <title>Need to remove an auto-routed controller in Umbraco?</title>
      <description>&lt;p&gt;Umbraco will auto-route some controllers automatically. These controllers are any MVC &lt;em&gt;SurfaceControllers&lt;/em&gt; or WebApi &lt;em&gt;UmbracoApiController &lt;/em&gt;types discovered during startup. There might be some cases where you just don’t want these controllers to be routed at all, maybe a package installs a controller that you’d rather not have routable or maybe you want to control if your own plugin controllers are auto-routed based on some configuration.&lt;/p&gt;&lt;p&gt;The good news is that this is quite easy by just removing these routes during startup. There’s various ways you could do this but I’ve shown below one of the ways to interrogate the routes that have been created to remove the ones you don’t want:&lt;/p&gt;&lt;h3&gt;Version 8&lt;/h3&gt;




&lt;pre class="lang-csharp"&gt;&lt;code&gt;
//This is required to ensure this composer runs after
//Umbraco's WebFinalComposer which is the component
//that creates all of the routes during startup    
[ComposeAfter(typeof(WebFinalComposer))]
public class MyComposer : ComponentComposer&amp;lt;MyComponent&amp;gt;{ }

//The component that runs after WebFinalComponent
//during startup to modify the routes
public class MyComponent : IComponent
{
    public void Initialize()
    {
        //list the routes you want removed, in this example
        //this will remove the built in Umbraco UmbRegisterController
        //and the TagsController from being routed.
        var removeRoutes = new[]
        {
            "/surface/umbregister",
            "/api/tags"
        };

        foreach (var route in RouteTable.Routes.OfType&lt;route&gt;().ToList())
        {
            if (removeRoutes.Any(r =&amp;gt; route.Url.InvariantContains(r)))
                RouteTable.Routes.Remove(route);
        }
    }

    public void Terminate() { }
}&lt;/route&gt;&lt;/code&gt;
&lt;/pre&gt;





&lt;h3&gt;Version 7&lt;/h3&gt;

&lt;pre class="lang-csharp"&gt;&lt;code&gt;public class MyStartupHandler : ApplicationEventHandler
{
    protected override void ApplicationStarted(
        UmbracoApplicationBase umbracoApplication,
        ApplicationContext applicationContext)
    {

        //list the routes you want removed, in this example
        //this will remove the built in Umbraco UmbRegisterController
        //and the TagsController from being routed.
        var removeRoutes = new[]
        {
            "/surface/umbregister",
            "/api/tags"
        };

        foreach(var route in RouteTable.Routes.OfType&amp;lt;Route&amp;gt;().ToList())
        {
            if (removeRoutes.Any(r =&amp;gt; route.Url.InvariantContains(r)))
                RouteTable.Routes.Remove(route);
        }
    }
}
&lt;/code&gt;
&lt;/pre&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:21 Z</pubDate>
      <a10:updated>2023-03-23T15:09:21Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1288</guid>
      <link>https://shazwazza.com/post/custom-mvc-routes-within-the-umbraco-pipeline/</link>
      <category>Umbraco</category>
      <category>ASP.Net MVC</category>
      <title>Custom MVC routes within the Umbraco pipeline</title>
      <description>&lt;p&gt;A while ago I wrote a &lt;a href="http://shazwazza.com/post/Custom-MVC-routing-in-Umbraco" target="_blank"&gt;post on how to do custom MVC routing in Umbraco&lt;/a&gt;, though the end result wasn’t quite ideal. There were a few tricks required and It wasn’t perfect since there were problems with rendering macros on the resulting view, etc… This was due to not having a &lt;em&gt;PublishedContentRequest&lt;/em&gt; object assigned to the context. So then we went ahead and created a new attribute to assign to your MVC action to resolve this: [&lt;em&gt;EnsurePublishedContentRequestAttribute&lt;/em&gt;]&lt;/p&gt; &lt;p&gt;Like the last post, you can read a lot about all of this in &lt;a href="http://our.umbraco.org/forum/developers/extending-umbraco/41367-Umbraco-6-MVC-Custom-MVC-Route?p=3" target="_blank"&gt;this Our thread&lt;/a&gt;. With the [&lt;em&gt;EnsurePublishedContentRequestAttribute&lt;/em&gt;] attribute you could now assign any &lt;em&gt;IPublishedContent&lt;/em&gt; instance to a &lt;em&gt;PublishedContentRequest&lt;/em&gt; and be sure that it was assigned to the &lt;em&gt;UmbracoContext&lt;/em&gt;. But this still isn’t the most ideal way to go about specifying MVC routes to work within the Umbraco pipeline… so I’ve created the following implementation which works quite well.&lt;/p&gt; &lt;h2&gt;Background&lt;/h2&gt; &lt;p&gt;A little bit of background in to custom MVC routes and Umbraco… The reason why it is not terribly straight forward to create a custom route and have it assigned to an Umbraco node is because the node doesn’t exist at your custom route’s location.&lt;/p&gt; &lt;p&gt;For example, if we have this route:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//Create a custom route&lt;/span&gt;
RouteTable.Routes.MapRoute(
    &lt;span class="str"&gt;"test"&lt;/span&gt;,
    &lt;span class="str"&gt;"Products/{action}/{sku}"&lt;/span&gt;,
    &lt;span class="kwrd"&gt;new&lt;/span&gt;
        {
            controller = &lt;span class="str"&gt;"MyProduct"&lt;/span&gt;, 
            action = &lt;span class="str"&gt;"Product"&lt;/span&gt;, 
            sku = UrlParameter.Optional
        });&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
Umbraco by default would have no idea what node (&lt;em&gt;IPublishedContent&lt;/em&gt;) would be assigned to this. The way Umbraco relates a URL to an &lt;em&gt;IPublishedContent&lt;/em&gt; instance is by a list of &lt;em&gt;IContentFinder&lt;/em&gt;’s. A very easy way to relate a custom URL to an &lt;em&gt;IPublishedContent&lt;/em&gt; instance is to create your own &lt;a href="http://our.umbraco.org/documentation/Reference/Request-Pipeline/IContentFinder" target="_blank"&gt;IContentFinder&lt;/a&gt;. Combine that with &lt;a href="http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers" target="_blank"&gt;route hijacking&lt;/a&gt; and in many cases this would probably be enough for your custom routing needs. However, it does not solve how you would wire up custom route parameters to your controller like how MVC normally works. Like in the above routing example, you’d want to have the ‘sku’ parameter value wired up to your Action parameter.&lt;/p&gt;
&lt;p&gt;The above route can work and be integrated into Umbraco by following some aspects of my &lt;a href="http://shazwazza.com/post/Custom-MVC-routing-in-Umbraco" target="_blank"&gt;previous blog post&lt;/a&gt; and use the [&lt;em&gt;EnsurePublishedContentRequestAttribute], &lt;/em&gt;but we can make it easier…&lt;/p&gt;
&lt;h2&gt;Creating routes&lt;/h2&gt;
&lt;p&gt;The simplest way to demonstrate this new way to create MVC routes in Umbraco is to just show you an example, so here it is:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//custom route&lt;/span&gt;
routes.MapUmbracoRoute(
    &lt;span class="str"&gt;"test"&lt;/span&gt;,
    &lt;span class="str"&gt;"Products/{action}/{sku}"&lt;/span&gt;,
    &lt;span class="kwrd"&gt;new&lt;/span&gt;
    {
        controller = &lt;span class="str"&gt;"MyProduct"&lt;/span&gt;,
        sku = UrlParameter.Optional
    },
    &lt;span class="kwrd"&gt;new&lt;/span&gt; ProductsRouteHandler(_productsNodeId));&lt;/pre&gt;
&lt;p&gt;This is using a new extension method: &lt;em&gt;MapUmbracoRoute &lt;/em&gt;which takes in the normal routing parameters (you can also include constraints, namespaces, etc….) but also takes in an instance of &lt;em&gt;UmbracoVirtualNodeRouteHandler. &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The instance of UmbracoVirtualNodeRouteHandler is responsible for associating an &lt;em&gt;IPublishedContent &lt;/em&gt;with this route. It has one abstract method which must be implemented:&lt;/p&gt;&lt;pre class="csharpcode"&gt;IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)&lt;/pre&gt;
&lt;p&gt;It has another virtual method that can be overridden which will allow you to manipulate the &lt;em&gt;PublishedContentRequest &lt;/em&gt;however you’d like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;PreparePublishedContentRequest(PublishedContentRequest publishedContentRequest)&lt;/pre&gt;
&lt;p&gt;So how do you find content to associate with the route? Well that’s up to you, one way (as seen above) would be to specify a node Id. In the example my ProductsRouteHandler is inheriting from &lt;em&gt;UmbracoVirtualNodeByIdRouteHandler &lt;/em&gt;which has an abstract method:&lt;/p&gt;&lt;pre class="csharpcode"&gt;IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext, 
    IPublishedContent baseContent);&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
So based on all this information provided in these methods, you can associate whatever IPublishedContent item you want to the request.&lt;/p&gt;
&lt;h2&gt;Virtual content&lt;/h2&gt;
&lt;p&gt;This implementation expects &lt;strong&gt;any&lt;/strong&gt; instance of IPublishedContent, so this means you can create your own virtual nodes with any custom properties you want. Generally speaking you’ll probably have a real Umbraco IPublishedContent instance as a reference point, so you could create your own virtual IPublishedContent item based on &lt;em&gt;PublishedContentWrapped&lt;/em&gt;, pass in this real node and then just override whatever properties you want, like the page Name, etc..&lt;/p&gt;
&lt;p&gt;Whatever instance of IPublishedContent returned here will be converted to a &lt;em&gt;RenderModel&lt;/em&gt; for use in your controllers.&lt;/p&gt;
&lt;h2&gt;Controllers&lt;/h2&gt;
&lt;p&gt;Controllers are straight forward and work like any other routed controller except that the Action will have an instance of RenderModel mapped to it’s parameter. Example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyProductController : RenderMvcController
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Product(RenderModel model, &lt;span class="kwrd"&gt;string&lt;/span&gt; sku)
    {
        &lt;span class="rem"&gt;//in my case, the IPublishedContent attached to this&lt;/span&gt;
        &lt;span class="rem"&gt;// model will be my products node in Umbraco which i &lt;/span&gt;
        &lt;span class="rem"&gt;// can now use to traverse to display the product list&lt;/span&gt;
        &lt;span class="rem"&gt;// or lookup the product by sku&lt;/span&gt;
            
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(sku))
        {
            &lt;span class="rem"&gt;//render the products list if no sku&lt;/span&gt;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; RenderProductsList(model);
        }
        &lt;span class="kwrd"&gt;else&lt;/span&gt;
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; RenderProduct(model, sku);
        }
    }
}&lt;/pre&gt;
&lt;p&gt;I have this all working well in a side project of mine at the moment. This functionality will be exposed in an upcoming Umbraco version near you&amp;nbsp; :)&lt;/p&gt;
&lt;p&gt;It’s also worth noting that all of this was accomplished outside of the Umbraco core with the publicly available APIs that currently exist. I will admit though there were a few hacks involved which of course won’t be hacks when moved into the core ;)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:14 Z</pubDate>
      <a10:updated>2023-03-23T15:08:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1166</guid>
      <link>https://shazwazza.com/post/multiple-webapi-controllers-with-the-same-name-but-different-namespaces/</link>
      <category>ASP.Net</category>
      <title>Multiple WebApi controllers with the same name but different namespaces</title>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/warrenbuckley" target="_blank"&gt;Warren&lt;/a&gt; recently reported &lt;a href="http://issues.umbraco.org/issue/U4-5151" target="_blank"&gt;this issue&lt;/a&gt; on Umbraco which prohibits WebApi from routing to two different paths that specify the same controller name but different namespaces. This type of thing is fully supported in MVC but not in WebApi for some reason.&lt;/p&gt; &lt;p&gt;Here’s a quick example, suppose we have two controllers:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Test1
{
    [PluginController(&lt;span class="str"&gt;"Test1"&lt;/span&gt;)]
    [IsBackOffice]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ConfigController : UmbracoApiController
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetStuff()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; 9876;
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Test2
{
    [PluginController(&lt;span class="str"&gt;"Test2"&lt;/span&gt;)]
    [IsBackOffice]    
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ConfigController : UmbracoApiController
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetStuff()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; 1234;
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;These controller definitions will create routes to the following paths respectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;/umbraco/backoffice/test1/config/getstuff
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;/umbraco/backoffice/test2/config/getstuff &lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;When these routes are created, the “Namespaces” data token is specified on the route, just like what is done in MVC, however in WebApi that needs to be done manually. Example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;var r = routes.MapHttpRoute(
    name: &lt;span class="str"&gt;"DefaultApi"&lt;/span&gt;,
    routeTemplate: &lt;span class="str"&gt;"api/{controller}/{id}"&lt;/span&gt;,
    defaults: &lt;span class="kwrd"&gt;new&lt;/span&gt; { id = RouteParameter.Optional }
);
r.DataTokens[&lt;span class="str"&gt;"Namespaces"&lt;/span&gt;] = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] {&lt;span class="str"&gt;"Foo"&lt;/span&gt;};&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;but if you navigate to either of these paths you’ll end up with a message like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Multiple types were found that match the controller named 'Config'. This can happen if the route that services this request ('umbraco/backoffice/Test2/Config/{action}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported. The request for 'Config' has found the following matching controllers: Test1.ConfigController Test2.ConfigController&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2&gt;Custom IHttpControllerSelector&lt;/h2&gt;
&lt;p&gt;To achieve what we want, we need to create a custom IHttpControllerSelector. I’ve created this in the Umbraco core to solve the issue and the source can be found &lt;a href="https://github.com/umbraco/Umbraco-CMS/blob/7.1.5/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs" target="_blank"&gt;HERE&lt;/a&gt;. The implementation is pretty straight forward – it relies on the default WebApi controller selector for everything unless a “Namespaces” data token is detected in the route and more than one controller type was found for the current controller name in the app domain. &lt;/p&gt;
&lt;p&gt;There’s some posts out there that elude to the possibility of this being supported in WebApi in the future but as of the latest source code for the &lt;a href="http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/Dispatcher/DefaultHttpControllerSelector.cs" target="_blank"&gt;DefaultHttpControllerSelector&lt;/a&gt;, it appears that the functionality is not yet there. &lt;/p&gt;
&lt;p&gt;If you need this functionality though, this implementation is working and pretty simple. To register this selector just use this code on startup:&lt;/p&gt;&lt;pre class="csharpcode"&gt;GlobalConfiguration.Configuration.Services.Replace(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IHttpControllerSelector),
    &lt;span class="kwrd"&gt;new&lt;/span&gt; NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));&lt;/pre&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:14 Z</pubDate>
      <a10:updated>2023-03-23T15:08:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1151</guid>
      <link>https://shazwazza.com/post/custom-mvc-routing-in-umbraco/</link>
      <category>Umbraco</category>
      <title>Custom MVC routing in Umbraco</title>
      <description>&lt;p&gt;This post will describe how you can declare your own custom MVC routes in order to execute your own custom controllers in Umbraco but still be able to render Umbraco views with the same model that Umbraco uses natively. &lt;/p&gt; &lt;p&gt;&lt;em&gt;NOTE: This post is not about trying to execute a particular Umbraco page under a custom URL, that functionality can be accomplished by creating a custom IContentFinder (in v6.1), or by applying the &lt;/em&gt;&lt;a href="http://our.umbraco.org/wiki/reference/umbraco-best-practices/umbracourlalias" target="_blank"&gt;&lt;em&gt;umbracoUrlAlias&lt;/em&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;There’s a &lt;a href="http://our.umbraco.org/forum/developers/extending-umbraco/41367-Umbraco-6-MVC-Custom-MVC-Route" target="_blank"&gt;long (but very useful) thread on Our&lt;/a&gt; describing various needs for custom MVC routing inside of Umbraco, definitely worth a read. Here I’ll try to describe a pretty easy way to accomplish this. I’m using Umbraco v6.0.7 (but I’m pretty sure this will work in v4.10+ as well). &lt;/p&gt; &lt;h2&gt;Create the route&lt;/h2&gt; &lt;p&gt;This example will use an &lt;em&gt;IApplicationEventHandler&lt;/em&gt; (in 6.1 you should use the base class &lt;em&gt;ApplicationEventHandler&lt;/em&gt; instead). Here I’m defining a custom route for handling products on my website. The example URLs that I want handled will be:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;/Products/Product/ProductA&lt;/li&gt; &lt;li&gt;/Products/Category/CategoryA&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyStartupHandler : IApplicationEventHandler
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnApplicationStarted(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
        &lt;span class="rem"&gt;//Create a custom route&lt;/span&gt;
        RouteTable.Routes.MapRoute(
            &lt;span class="str"&gt;"test"&lt;/span&gt;,
            &lt;span class="str"&gt;"Products/{action}/{id}"&lt;/span&gt;,
            &lt;span class="kwrd"&gt;new&lt;/span&gt;
                {
                    controller = &lt;span class="str"&gt;"MyProduct"&lt;/span&gt;, 
                    action = &lt;span class="str"&gt;"Product"&lt;/span&gt;, 
                    id = UrlParameter.Optional
                });           
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnApplicationInitialized(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnApplicationStarting(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
    }
}&lt;/pre&gt;
&lt;h2&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
Create the controller&lt;/h2&gt;
&lt;p&gt;With the above route in place, I need to create a controller called “&lt;em&gt;MyProductController&lt;/em&gt;”. The base class it will inherit from will be “&lt;em&gt;Umbraco.Mvc.PluginController&lt;/em&gt;”. This abstract class exposes many of the underlying Umbraco objects that I might need to work with such as an &lt;em&gt;UmbracoHelper, UmbracoContext, ApplicationContext&lt;/em&gt;, etc… Also note that the &lt;em&gt;PluginController&lt;/em&gt; doesn’t get auto-routed like a &lt;em&gt;SurfaceController&lt;/em&gt; which is good because we only want to route our controller once. In 6.1 you can inherit from a different controller called &lt;em&gt;Umbraco.Mvc.UmbracoController&lt;/em&gt;, which is what the &lt;em&gt;PluginController&lt;/em&gt; will be inheriting from in the next version.&lt;/p&gt;
&lt;h3&gt;Constructor&lt;/h3&gt;
&lt;p&gt;First thing is to define the constructors since the &lt;em&gt;PluginController&lt;/em&gt; doesn’t have an empty constructor but we want ours to (unless you have IoC setup).&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyProductController : PluginController
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; MyProductController()
        : &lt;span class="kwrd"&gt;this&lt;/span&gt;(UmbracoContext.Current)
    {            
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; MyProductController(UmbracoContext umbracoContext) 
        : &lt;span class="kwrd"&gt;base&lt;/span&gt;(umbracoContext)
    {
    }
}&lt;/pre&gt;
&lt;h3&gt;Actions&lt;/h3&gt;
&lt;p&gt;Next we need to create the controller Actions. These actions will need to lookup either a Product or a Category based on the ‘id’ string they get passed. For example, given the following URL: /Products/Category/CategoryA the id would be &lt;strong&gt;CategoryA &lt;/strong&gt;and it would execute on the &lt;strong&gt;Category&lt;/strong&gt; action.&lt;/p&gt;
&lt;p&gt;In my Umbraco installation, I have 2 document types with aliases: “Product” and “ProductCategory”&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate-import/image_35.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://shazwazza.com/media/articulate-import/image_thumb_33.png" width="300" height="96"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To perform the lookup in the controller Actions we’ll use the UmbracoHelper.TypedSearch overload which uses Examine.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Category(&lt;span class="kwrd"&gt;string&lt;/span&gt; id)
{
    var criteria = ExamineManager.Instance.DefaultSearchProvider
        .CreateSearchCriteria(&lt;span class="str"&gt;"content"&lt;/span&gt;);
    var filter = criteria.NodeTypeAlias(&lt;span class="str"&gt;"ProductCategory"&lt;/span&gt;).And().NodeName(id);
    var result = Umbraco.TypedSearch(filter.Compile()).ToArray();
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!result.Any())
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpException(404, &lt;span class="str"&gt;"No category"&lt;/span&gt;);
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; View(&lt;span class="str"&gt;"ProductCategory"&lt;/span&gt;, CreateRenderModel(result.First()));
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Product(&lt;span class="kwrd"&gt;string&lt;/span&gt; id)
{
    var criteria = ExamineManager.Instance.DefaultSearchProvider
        .CreateSearchCriteria(&lt;span class="str"&gt;"content"&lt;/span&gt;);
    var filter = criteria.NodeTypeAlias(&lt;span class="str"&gt;"Product"&lt;/span&gt;).And().NodeName(id);
    var result = Umbraco.TypedSearch(filter.Compile()).ToArray();
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!result.Any())
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpException(404, &lt;span class="str"&gt;"No product"&lt;/span&gt;);
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; View(&lt;span class="str"&gt;"Product"&lt;/span&gt;, CreateRenderModel(result.First()));
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;The Category action lookup uses Examine to lookup any document with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A document type alias of “ProductCategory” &lt;/li&gt;
&lt;li&gt;A name equal to the id parameter passed in&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The Product action lookup uses Examine to lookup any document with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A document type alias of “Product”&lt;/li&gt;
&lt;li&gt;A name equal to the id parameter passed in&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The result from &lt;em&gt;TypedSearch&lt;/em&gt; is &lt;em&gt;IEnumerable&amp;lt;IPublishedContent&amp;gt;&lt;/em&gt; and since we know we only want one result we pass in the first item of the collection in “result.First()”&lt;/p&gt;
&lt;p&gt;If you didn’t want to use Examine to do the lookup, you could use a Linq query based on the result of &lt;em&gt;Umbraco.TypedContentAtRoot()&lt;/em&gt;, but I wouldn’t recommend that since it will be much slower.&lt;/p&gt;
&lt;p&gt;In v6.1 the UmbracoHelper exposes a couple of other methods that you could use to perform your lookup if you didn’t want to use Examine and wanted to use XPath instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TypedContentSingleAtXPath(string xpath, params XPathVariable[] vars)&lt;/li&gt;
&lt;li&gt;TypedContentAtXPath(string xpath, params XPathVariable[] vars)&lt;/li&gt;
&lt;li&gt;TypedContentAtXPath(XPathExpression xpath, params XPathVariable[] vars)&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;CreateRenderModel method&lt;/h3&gt;
&lt;p&gt;You will have noticed that I’m using a method called &lt;em&gt;CreateRenderModel&lt;/em&gt; to create the model that is passed to the View. This method accepts an &lt;em&gt;IPublishedContent&lt;/em&gt; object as an argument and creates a &lt;em&gt;RenderModel&lt;/em&gt; object which is what a normal Umbraco view expects. This method isn’t complex but it does have a couple things worth noting:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; RenderModel CreateRenderModel(IPublishedContent content)
{
    var model = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderModel(content, CultureInfo.CurrentUICulture);

    &lt;span class="rem"&gt;//add an umbraco data token so the umbraco view engine executes&lt;/span&gt;
    RouteData.DataTokens[&lt;span class="str"&gt;"umbraco"&lt;/span&gt;] = model;

    &lt;span class="kwrd"&gt;return&lt;/span&gt; model;
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
The first thing is that you need to construct the &lt;em&gt;RenderModel&lt;/em&gt; with an explicit culture otherwise you’ll get an exception. The next line adds the created &lt;em&gt;RenderModel&lt;/em&gt; to the RouteData.DataTokens… this is because we want to render an Umbraco view which will be stored in either of the following places (based on Umbraco standard practices):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;~/Views/Product.cshtml&lt;/li&gt;
&lt;li&gt;~/Views/ProductCategory.cshtml&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;These locations are not MVC standard practices. Normally MVC will look in a controller specific folder for views. For this custom controller the locations would be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;~/Views/MyProduct/Product.cshtml&lt;/li&gt;
&lt;li&gt;~/Views/MyProduct/ProductCategory.cshtml&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;But we want to use the views that Umbraco has created for us so we need to ensure that the built in Umbraco ViewEngine gets executed. For performance reasons the Umbraco &lt;em&gt;RenderViewEngine&lt;/em&gt; will not execute for a view unless a &lt;em&gt;RenderModel&lt;/em&gt; instance exists in the RouteData.DataTokens with a key of “umbraco”, so we just add it there before we return the view.&lt;/p&gt;
&lt;h2&gt;Views&lt;/h2&gt;
&lt;p&gt;The views are your regular Umbraco views but there’s a few things that might not work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Macros. Sorry, since we’ve bypassed the Umbraco routing pipeline which macros rely upon, any call to Umbraco.RenderMacro will fail. But you should be able to achieve what you want with Partial Views or Child Actions.&lt;/li&gt;
&lt;li&gt;Umbraco.Field. Actually this will work but you’ll need to upgrade to 6.0.7 or 6.1.2 based on this fixed issue: &lt;a href="http://issues.umbraco.org/issue/U4-2324"&gt;http://issues.umbraco.org/issue/U4-2324&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;One cool thing is that you can use the regular MVC &lt;em&gt;UrlHelper&lt;/em&gt; to resolve the URLs of your actions, since this custom controller is actually just a regular old MVC controller after all.&lt;/p&gt;
&lt;p&gt;These view example are nothing extraordinary, just demonstrating that they are the same as Umbraco templates with the same model (but using our custom URLs)&lt;/p&gt;
&lt;h3&gt;ProductCategory&lt;/h3&gt;&lt;pre class="csharpcode"&gt;@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}
&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;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;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Product category&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;hr&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&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;@Model.Content.Name&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;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            @foreach (var product in Model.Content.Children
                .Where(x =&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; x.DocumentTypeAlias == "Product"))
            {
                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="@Url.Action("&lt;/span&gt;&lt;span class="attr"&gt;Product&lt;/span&gt;&lt;span class="kwrd"&gt;", "&lt;/span&gt;&lt;span class="attr"&gt;MyProduct&lt;/span&gt;&lt;span class="kwrd"&gt;", new { id = product.Name })"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                        @product.Name
                    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            }
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&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;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;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;Which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate-import/image_36.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://shazwazza.com/media/articulate-import/image_thumb_34.png" width="244" height="201"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Product&lt;/h3&gt;&lt;pre class="csharpcode"&gt;@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}
&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;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;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Product&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;hr&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&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;@Model.Content.Name&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;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;
            @(Model.Content.GetPropertyValue("Description"))
        &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;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;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;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
Which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate-import/image_37.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://shazwazza.com/media/articulate-import/image_thumb_35.png" width="244" height="187"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Whats next?&lt;/h2&gt;
&lt;p&gt;With the setup above you should be able to achieve most of what you would want with custom routing, controllers, URLs and lookups. However, as I mentioned before things like executing Macros and potentially other internal Umbraco bits that rely on objects like the &lt;em&gt;PublishedContentRequest&lt;/em&gt; will not work. &lt;/p&gt;
&lt;p&gt;Of course if there is a will, there is a way and I have some cool ideas that could make all of those things work seamlessly too with custom MVC routes. Stay tuned!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:08 Z</pubDate>
      <a10:updated>2023-03-23T15:08:08Z</a10:updated>
    </item>
  </channel>
</rss>