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