Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sitecore MVC Custom route while still using the Sitecore rendering pipeline

I am using Sitecore 7.5 and Sitecore 8 (2 separate projects with the same need). We have content items stored in buckets, but they are not page items themselves (they have no presentation bound to them, they are data items only and might come from varying sources including item buckets).

So here's a general layout of the problem: The page we want to render items with would be something like /sitecore/content/home/news We need to be able to parse the pathinfo after the item name as the data payload for the controller rendering.

So, what I've tried so far includes creating a custom route along these lines:

            routes.MapRoute(
            "Blog", 
            "blog/{*pathInfo}", 
            new
            {
                scItemPath = "/sitecore/content/Home/Blog",
                controller = "Blog",
                action = "DefaultAction"
            });

I load the routes from the RenderCustomRoutes pipeline, and I have configured this to be called from before and after the Sitecore InitializeRoutes pipeline in different testing attempts.

I referenced this from http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2012/10/using-sitecore-keys-in-mvc-routes-with-the-sitecore-aspnet-cms.aspx and some related articles.

Following a number of additional articles from there where he revises his instructions or goes on to address other problems doesn't solve my scenario. The thing is, none of this works. In this case the controller is called correctly, but while I get the item itself in the rendering context I do not get any of the rest of the page's renderings. Is there a way to launch the rendering pipeline from here, or to assemble the page using the rest of the presentation details of the blog item and do it manually?

The other route I've tried was just trying to pass the pathinfo as data to the existing blog page url, but I end up with a 404.

I don't know if I'm chasing a wild goose here and that there's a better way or if I'm just missing a piece somewhere. In Webforms I'd probably have done url rewriting to achieve this without using querystrings but I was hoping that the routes would be designed to handle things just like this and the articles I was seeing seemed to lead me to think it is possible.

Additional things I've been considering: John West says that there are 4 ways for Sitecore to handle an MVC request

1.Ignore the Request: Allow ASP.NET MVC to handle it as if Sitecore was not installed, without establishing a Sitecore context.

2.Apply a Route: Use the controller and action specified by an MVC route.

3.Apply the Designated Action: Use the controller and action specified in the context item.

4.Apply a View: Use Sitecore’s default controller and action to invoke the view defined in layout details for the context device in the context item.

What I get when I use the custom route seems to fit #2, but what I need is something more like #3 or #4 while still using the custom route.

like image 420
Jon Upchurch Avatar asked Apr 23 '15 16:04

Jon Upchurch


People also ask

What is the routing in MVC?

Routing is responsible for mapping incoming browser requests to particular controller actions (or Razor Pages handlers). This section covers how routing differs between ASP.NET MVC (and Web API) and ASP.NET Core (MVC, Razor Pages, and otherwise).

How do I render a datasource Sitecore?

To add a data source setting to a rendering: First, create the new template. In the Content Editor, navigate to your tenant templates folder (sitecore/Templates/Project/) and insert the new template. This new data source item template must inherit from the existing SXA data source item template.


1 Answers

Since the items in your bucket do not have any Presentation I believe it's going to be tricky to handle this with the routes. It may be possible and hopefully someone else will chime in but...

You could use wildcard Items to achieve what you trying. It's going to depend on the exact setup and structure of your components, but simply create an item called * as a child of /sitecore/content/Home/Blog. You can then set the presentation details etc on this wildcard item.

  • Eliminating query strings with Sitecore’s wildcard nodes
  • Using wildcards and displaynames in urls

Now any url will match this item. You need to resolve the Item at some point, it could be in the Controller itself, you will need to parse the URL and then look up the item for use in your rendering. Note that Context.Item is still the wildcard * item, therefore you'd have to create a new variable in code then populate your model:

Item requestedItem = Sitecore.Context.Database.GetItem("resolved-path");
Model.Name = requestedItem.Name;
Model.MyProperty = requestedItem["My Property"];

However, it will probably be better to resolve the Item after the ItemResolver pipeline and then store the guid in Sitecore.Context.Items dictionary:

Item requestedItem = Sitecore.Context.Database.GetItem("resolved-path");
Sitecore.Context.Items["wildcard-guid"] = requestedItem.ID.ToString();

This way you can use this in several components and set it as the datasource for components (from code), e.g. breadcrumbs, main content etc. This can be beneficial also from a caching perspective since you can enable caching using VaryByData option. You can also throw an appropriate 404 if the Item is not found by setting Sitecore.Context.Item = null if required.

You also need to be able to handle link generation, so you will, need to create a custom LinkProvider to generate some friendly URLs.

Hope that makes sense some what! I have to do something similar soon and this is the best option I have come up with so far...

like image 147
jammykam Avatar answered Oct 16 '22 18:10

jammykam