Copied to clipboard

Flag this post as spam?

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


  • Linx 98 posts 258 karma points
    Aug 16, 2022 @ 16:14
    Linx
    0

    Routing not working in Umbraco 8 (maybe)??

    Im struggling with getting this working the way i need.

    I create a DocumentType called CustomerHome

    This creates a CustomerHome Template

    Create a new template called Customer.

    Adjust the permissions on CustomerHome to allow the template Customer

    Create an Umbraco node under content called Customers assigning the CustomerHome template and CustomerHome Document type.

    Under this node create another page called Customer and assign the Customer template to it.

    Create 2 new Controllers and Models for each page called CustomersController and CustomerController (notice the plural)

    When i visit localhost:12/Customers, it loads my customers from my database which is using RenderMvcController (Can post the code if anyone likes).

    When i visit localhost:12/Customers/customer the default template content is displayed.

    When i visit localhost:12/Customers/customer/1 (Note the parameter 1) it throws an error

    "Object reference not set to an instance of an object."

    Highlighting the model is empty

    My code on the Customer controller is

    public class CustomerController : RenderMvcController
    {
    
        public CustomerController()
        {
    
        }
    
        public new ActionResult Index(ContentModel model)
        {
            var vm = new CustomerContentModel(model.Content);
    
            return View(vm);
        }
    }
    

    I then read around and some suggest adding a route. I add a route and (this is where i think ive done something wrong)

    public class RoutingComponent : IComponent
    {
        public void Initialize()
        {
            RouteTable.Routes.MapRoute("customers/customer/{0}", "customers/customer/{0}", new { controller = "Customer", action = "Index", id = UrlParameter.Optional });
    
        }
    
        public void Terminate()
        {
            //throw new NotImplementedException();
        }
    }
    

    What i would like to happen is if they arrive at

    localhost:12/Customers/customer the default empty template is displayed to say no customer found as no parameter has been passed in.

    When i visit localhost:12/Customers/customer/1 I would like it to load up a customer from my database (which i can do) but i dont seem to be able to get past the error when passing in a customer ID?

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Aug 16, 2022 @ 17:16
    Marc Goodson
    1

    Hi Linx

    I think you are caught between two methodologies...

    I think you could change the ActionResult of your CustomerController to accept a parameter of customerId

    eg

       public ActionResult Index(ContentModel model, string customerId = "")
        {
            var vm = new CustomerContentModel(model.Content);
    
            return View(vm);
        }
    

    and you wouldn't need any custom routing, because /customers/customer would map to your published content in Umbraco and having ?customerId=1

    would automatically bind to your customerId parameter....

    The other approach would be to use 'MapUmbracoRoute' to create a routing pattern such as /customers/customer/1 to map to a controller that imherits from RenderMvcController, and you associate an IPublishedContent context item to associate with the route by implementing a VirtualNodeRouteHandler...

    There is a reasonable example or wiring this up here:

    https://our.umbraco.com/Documentation/Reference/Routing/Custom-Routes/index-v8

    regards

    Marc

  • Linx 98 posts 258 karma points
    Aug 16, 2022 @ 18:23
    Linx
    0

    Thanks Marc, I'll try out your first solution but I'm pretty certain I tried that and got an no constructorless parameter error message or similar (for the model if I recall correctly) but will try again. Please note the Umbraco page (customer) is empty there are no properties other than title.

    As for the second solution, I did read that article but I couldn't find any reference on what the class would look like for the ProductsRouteHandler class. Is there an example I could look at?

    Thanks

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Aug 16, 2022 @ 21:48
    Marc Goodson
    1

    Hi Linx

    There is an example of a Virtual Node Route Handler in the core..

    https://github.com/umbraco/Umbraco-CMS/blob/4be1c3b4c4f26bd0925a3164d32f554b679045da/src/Umbraco.Web/Mvc/UmbracoVirtualNodeByIdRouteHandler.cs

    In fact you could use this to try out the MapUmbracoRoute...

    It takes in the Umbraco Id of the content item that you want to use as your IPublishedContent context for your route.

      RouteTable.Routes.MapUmbracoRoute("CustomersCustomRoute", "customers/customer-info/{id}", new
                {
                    controller = "Customer",
                    action = "Index",
                    id = UrlParameter.Optional
                }, new UmbracoVirtualNodeByIdRouteHandler(1105));
    

    where 1105 is the id of your placeholding customer page...

    Regards

    Marc

  • Linx 98 posts 258 karma points
    Aug 17, 2022 @ 08:37
    Linx
    0

    Thanks will look into that.

    Just to ensure i have this correctly configured. I have one Doc type and two templates.

    I am using the same doctype for both customers and customer but each one has a different template. Is this the correct approach? Or should i have separate doc types for each (Even though the Doctype is likely to be empty)?

    Edit: I created a new separate doctype and all seems to work. So i assume you need a new doctype for all new templates? Just now trying to understand when a new DT is needed and when i can re-use an existing? Cheers

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Aug 17, 2022 @ 16:02
    Marc Goodson
    100

    Hi Linx

    It's all about the convention.

    If you aren't mapping a custom route (eg the VirtualNodeRouteHandler stuff and MapUmbracoRoute)

    Then for each 'DocType' you can hijack the request to it by convention by having the Controller match the name of the DocType

    So what I missed in your original explanation (apologies) is that you had a controller called

    CustomerController

    but a doc type called CustomerHome

    So you would have needed a

    CustomerHomeController to 'hijack' requests to that type of page by the convention

    Now you've created a Customer DocType, your existing named controller has a match!

    Now by default a hijacked request will hit the Action called Index in your named controller, and return the 'Current Template' selected in Umbraco for the page.

    But if a Doctype does have two templates, then you can still hijack the request for the other template in your hijacked controller by creating an ActionResult that has the same name as the template....

    ... so 'you could' have had

        public class CustomerHomeController : RenderMvcController
        {
        public CustomerHomeController()
        {
    
        }
        public ActionResult CustomerHome(ContentModel model) {
    
        return CurrentTemplate(model);
        }
        public ActionResult Customer(ContentModel model, string customerId) {
    //create custom ViewModel that inherits from ContentModel, with properties for the customer
    var vm = GetCustomerViewModel(model, customerId);    
    return CurrentTemplate(model):
        }
    

    If you had wanted to stick with One Document Type and Two Templates, and handle each request differently!

    Not sure if I've made that any clearer :-P!!!

    regards

    marc

Please Sign in or register to post replies

Write your reply to:

Draft