Copied to clipboard

Flag this post as spam?

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


  • Paul 6 posts 75 karma points
    Apr 25, 2020 @ 23:01
    Paul
    0

    SurfaceController Route Attributes?

    After a number of attempts, cannot seem to specify a route attribute for a SurfaceController method. To avoid bashing my head into a wall, can anyone clarify? If you have it working I'd love to see an example.

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Apr 27, 2020 @ 06:24
    Marc Goodson
    0

    Hi Paul

    I haven't used MVC Attribute Routes with Umbraco before (I have for API Routes), so I'm not sure if this will work, or what you are aiming to achieve, if you have some example code for context that would be great.

    SurfaceControllers are 'auto routed',

    /umbraco/surface/{controllername}/{action}/{id}

    when you create a controller that inherits from SurfaceController the route is setup through Umbraco, and they are designed to sit on the surface of the underlying RenderMvcController and handle Postbacks from forms or be used as a Child Action.

    Usually if you want to handle an incoming Umbraco Url in a custom way, you would either create an IContentFinder + UrlProvider to map that custom Url to an Umbraco item (https://our.umbraco.com/documentation/Reference/Routing/Request-Pipeline/) , or use RouteHijacking to map the request to a custom RenderMvcController by Document Type Convention (https://our.umbraco.com/documentation/reference/routing/custom-controllers) - or by Mapping a custom route to the RenderMvcController using a Virtual Node Route Handler.(https://our.umbraco.com/documentation/Reference/Routing/custom-routes)

    That all said there is a type of MVC controller that isn't auto-routed, called a PluginController (Surface Controller inherits from this), so depending on your aims, your custom MVC controller could inherit directly from this...

    ... MVC attribute routing needs to be 'called' to be setup on an MVC site, so the further step would be to call

    routes.MapMvcAttributeRoutes();
    

    During the startup of the Umbraco site, which you would achieve by creating and registering a component to modify this during composition.

           public class RegisterCustomRouteComponent : IComponent
        {
            public void Initialize()
            {
                RouteTable.Routes.MapMvcAttributeRoutes();
            }
        }
    

    There is an example of using a UserComposer to add a Component to Umbraco here: https://our.umbraco.com/documentation/Implementation/Composing/#example---creating-a-component-to-listen-for-contentservicesaving-events

    So in summary... Umbraco is handling routing in a particular way to make requests work through the CMS, yes it's using MVC but it needs to do some additional things to build the context of a PublishedContent request... there are paths for most common scenarios to change Url routing and ways to create custom MVC controllers to process requests... so check if those provide the options you are looking for... but fundamentally it is MVC so if MapMvcAttributeRoutes() is called at application startup, you should be able to make use of attribute routing... as I've done for APIAttribute routing, it will be interesting to see if it works for a plain Controller, or SurfaceController/PluginController or RenderMvcController...

    regards

    Marc

  • Paul 6 posts 75 karma points
    Apr 28, 2020 @ 00:12
    Paul
    0

    Those are great options -- and tried all but the plugin approach (didn't look like it would work there). Having to setup the route using the UserComposer approach means you're not using Route attributes.....which is a bit throw back. If you've spent much time using Razor pages (basically a simplification of traditional MVC -- https://stackify.com/asp-net-razor-pages-vs-mvc/), you get a bit spoiled. You can add a view to the project setup the route, and not even have to compile anything.

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    May 03, 2020 @ 16:44
    Marc Goodson
    0

    Hi Paul

    Can confirm that if you call MapMvcAttributeRoutes() once in a Component at initialization time, then you are free to use attribute routing across your Controllers: PluginController, RenderMvcController or SurfaceController.

    Example would be

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using Umbraco.Core;
    using Umbraco.Core.Composing;
    using Umbraco.Web.Mvc;
    
    namespace UmbracoV8.AttributeRoutingExample
    {
        [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
        public class RegisterAttributeRoutingComposer : ComponentComposer<RegisterAttributeRoutingComponent>
        {
            // nothing needed to be done here!
        }
        public class RegisterAttributeRoutingComponent : IComponent
        {
            public void Initialize()
            {
                RouteTable.Routes.MapMvcAttributeRoutes();
            }
            public void Terminate()
            {
    
            }
        }
    
        public class CustomBooksPluginController : PluginController
        {
            [Route("books/{isbn?}")]
            public ActionResult Index(string isbn)
            {
                return Content("display a book with isbn no: " + isbn);
            }
        }
    }
    

    then a request to /books/1234 is routed to your bespoke MVC Controller...

    ... however if using a SurfaceController, or RenderMVCController Umbraco won't know the context of the published content associated with the request, so CurrentPage will be null... but if you are just running an MVC route alongside Umbraco then the PluginController is the one to use.

    But agree this is different to pure MVC, Umbraco predates MVC and has evolve overtime, they are currently working on .net core version.. https://umbraco.com/blog/the-unicore-team/ so maybe there will be more flexibility over how the routes are defined, or how to associate a published content item with a particular route... (eg another attribute perhaps...) or maybe this is the time to raise the issue on the github tracker.

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft