Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Nick Bennett 11 posts 81 karma points
    1 week ago
    Nick Bennett
    0

    Registering Custom Routes in Umbraco 8

    In the documentation I see that the way to register a custom route is to create a class inheriting from Umbraco.Web.Mvc.UmbracoVirtualNodeRouteHandler and override its ApplicationStarted method.

    There are three issues:

    1. Where do I create this class? Anywhere?
    2. I need to override the FindContent method of the base class - but I'm not dealing with content, just trying to register a route: content doesn't come into it.
    3. The base class doesn't have an ApplicationStarted virtual method I can override.

    It looks as if this is no longer the correct base class to use for registering routes.

    How do I go about registering a custom route?

  • seanrock 95 posts 127 karma points
    5 days ago
    seanrock
    0

    Just FYI, i started down this path also and i'm not sure it's the correct way.

    Seems you have to implement IComponent, then using composition (implement IUserComposer) add the component to the list of components. I created a folder Compositions and put the classes there.

    The IComponent has an Initialize() method you can use to setup the UmbracoApplication_ApplicationInit. Within that event handler you can specify your custom route and specify your custom UmbracoVirtualNodeRouteHandler (it doesn't have an ApplicationStarted method to override btw).

    In the route handler's FindContent i did use a node id for the umbracoContent.ContentCache.GetById() method. I just used a random node (home) but it did hit my custom controller and it did pass in my query parameters that i was expecting.

    hth

  • seanrock 95 posts 127 karma points
    5 days ago
    seanrock
    0

    Correction, i used the node Id of a node that used a document type with the same name as the controller. Anything else and it doesn't hit the controller.

  • Marc Goodson 781 posts 5137 karma points MVP 3x c-trib
    5 days ago
    Marc Goodson
    0

    Hi Nick

    You need to create a component, and register the route in the Initialize() method using the new MapUmbracoRoute RouteCollection extension method, then use a composer to add the component to the Umbraco composition.

    An Example:

    Add a c# class file in your project as per below, this example would map the custom route /products/details/123 to a custom controller called SuperProductController (that would need to inherit from RenderMvcController). The IPublishedContent model associated with the route comes from the UmbracoVirtualNodeRouteHandler (you can create your own logic as to what this should be based upon your request, but here I'm just hardcoding it to be the Id, of the products node in the starter kit!

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using Umbraco.Core.Composing;
    using Umbraco.Web;
    using Umbraco.Web.Mvc;
    
        namespace Umbraco8.Components
        {
    
                public class RegisterCustomRouteComposer : ComponentComposer<RegisterCustomRouteComponent>
                {
    
                }
    
                public class RegisterCustomRouteComponent : IComponent
                {
                    public void Initialize()
                    {
                        RouteTable.Routes.MapUmbracoRoute("Product Details", "product/details/{id}", new
                        {
                            controller = "SuperProduct",
                            action = "Details",
                            id = UrlParameter.Optional
                        }, new UmbracoVirtualNodeByIdRouteHandler(1105));
                    }
    
                    public void Terminate()
                    {
                        throw new NotImplementedException();
                    }
                }
            }
    

    Anyway hope that make sense!

    regards

    Marc

  • Nick Bennett 11 posts 81 karma points
    5 days ago
    Nick Bennett
    0

    Yes, this seems to work. I am able to use a custom controller for front end functionality, but what I about backoffice functions? What I am trying to do is to create/edit some complicated data structures (railway timetables, which I am storing in the database as JSON) in the back office. I haven't yet managed to get a controller derived from UmbracoAuthorizedController to be instantiated and executed.

  • Marc Goodson 781 posts 5137 karma points MVP 3x c-trib
    5 days ago
    Marc Goodson
    0

    Hi Nick

    Sorry I thought your question was regarding the changes in V8 for mapping a custom route through Umbraco using a VirtualNodeRoute handler...

    Yes, creating an api controller for use in the backoffice is different to this, but I don't think it has changed from V7, you would create an API controller that inherits from UmbracoAuthorizedApiController, with a PluginController attribute, and then this would be automatically routed via /umbraco/backoffice/{pluginname}/{controllername}/{action} etc

    For example:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using Umbraco.Web.Mvc;
    using Umbraco.Web.WebApi;
    
    namespace Umbraco8.Controllers
    {
        ///umbraco/backoffice/SuperTimeTables/TimeTableApi/GetTimeTableDetails
        [PluginController("SuperTimeTables")]
        public class TimeTableApiController : UmbracoAuthorizedApiController
        {
            [HttpGet]
            public TimeTable GetTimeTableDetails()
            {
                return new TimeTable() { Name = "test", Times = "9:00am" };
            }
            [HttpPost]
            public IHttpActionResult SaveTimetableInfo(TimeTable timetable)
            {
                if (timetable == null)
                {
                    return BadRequest("Timetable is null etc");
                }
                // do something to persist timetable
                return Ok();
            }
    
        }
        public class TimeTable
        {
            public string Name { get; set; }
            public string Times { get; set; }
    
        }
    }
    

    in this example the autorouting would be set up to the following url:

    /umbraco/backoffice/SuperTimeTables/TimeTableApi/GetTimeTableDetails

    regards

    Marc

  • Nick Bennett 11 posts 81 karma points
    1 day ago
    Nick Bennett
    0

    It wasn't an API controller I had in mind. I was thinking in terms of a user interface allowing users to create and edit timetables.

    A timetable is a complicated thing with a grid of cells, with a variable number of columns (the UI should allow the user to insert columns). Not only are there times in the cells, but there are references to notes, and there is a cell at the top of each column just for references to notes. Actually, two grid - one for each direction. And then there's the notes themselves!

    Really struggling to see how to incorporate this sort of data into Umbraco! At the moment I've got it in tables in a separate database, but I've had to create the data programatically in a console app.

    What's the usual pattern for this sort of thing?

  • Marc Goodson 781 posts 5137 karma points MVP 3x c-trib
    24 hours ago
    Marc Goodson
    0

    Hi Nick

    Yes I sort of worked out what you meant after posting the API example ... :-(

    It's an unusual way to extend the backoffice functionality, general recommended way is AngularJS + APIControllers, but it is possible in V7! - I have a site that does just this, as long as controller inherits from UmbracoAuthorizedController, and you supply the route to work with it, then it's all ok.

    However I tried to replicate in V8 to provide you a further example and hit an error! (probably the same as you are seeing) so I've raised an issue on the Umbraco Issue Tracker:

    https://github.com/umbraco/Umbraco-CMS/issues/5005

    So hopefully we'll get an answer there, as it's one on my list to update the docs for - and of course you are trying to actually make it work!

    If you've got any further info to add, be ace if you could stick it on the issue.

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft