Copied to clipboard

Flag this post as spam?

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


  • MB 113 posts 422 karma points
    Dec 11, 2023 @ 04:46
    MB
    0

    Creating a Custom Route to Media Library

    I have a requirement from a client to externally access items in the media library, using a virtual 'perma-link'.

    They know the media-item's name and its library folder-path, but don't know the library index or the current URL for the item - as obviously both may be constantly changing with each revision to the media item, depending on the content editor's updates.

    So, the idea is for them to request a 'virtual' perma-link - based on a virtual folder, the item's library folder-path, and the item's name - and have a custom route intercept the request, route to a controller, which then works out the current media-item URL, and rewrites/redirects the request so it resolves to the current version of the requested media item.

    e.g. request: .../docs/<item-path>/<item-name> ==> [controller-search-and-redirect] ==> .../media/<index>/<item-file.ext>

    However, obviously, the library item-path can be a variable level of folders deep so the request might vary:

    eg .../docs/folder-1/some-pdf-document

    or .../docs/folder-1/folder-2/folder-3/another-pdf-document

    If I can create a custom route for all requests starting with the virtual folder /docs to a custom controller, where I can parse the request, then recursively searching for the folder-path/name of an item is something I've done often enough before. It's not high-performant, but fortunately this is a relatively low volume request.

    However, the part I'm a little bit stuck on is how to create a custom route for .../docs/... to a controller that actions it, given that the requesting URL will vary depending on the folder-path location of the item.

    Every example I've seen assumes a fixed structure URL with parameterized segments.

    Any and all help appreciated.

  • Brendan Rice 538 posts 1102 karma points
    Dec 11, 2023 @ 13:53
    Brendan Rice
    0

    I seen another post recently by Lee Kelleher that used this approach (thanks Lee).

    I'd be interested to know if this works for you

    using Umbraco.Cms.Web.Common.Controllers;
    
    public class DocsController : UmbracoApiController
    {
        [HttpGet("docs/{*path}")]
        public IActionResult GetDocument(string path)
        {
            // Put your code here
        }
    }
    
  • MB 113 posts 422 karma points
    Dec 11, 2023 @ 21:06
    MB
    0

    Hi, thanks for the response.

    I'm not sure if an ApiController would be applicable to this situation. I would have thought an ApiController would be expecting to return either JSON, HTML or similar, not redirect/rewrite to another URL. Would you happen to have the thread reference so I can read the full context and see if it might be useful?

    My initial thoughts were to declare and initialize a Custom Route, so that any request that starts with my nominated virtual folder e.g. .../docs/* or whatever I specify - gets routed to a dedicated controller that handles the request.

    However, I'm unsure how to set up such a custom route, given the variable request URL.

  • Brendan Rice 538 posts 1102 karma points
    Dec 11, 2023 @ 21:32
    Brendan Rice
    0

    You're right that approach won't work. Try this:

    1. Alter Startup.cs Configure method, under .WidthEndpoints add something like this (u.EndpointRouteBuilder.MapControllerRoute...):

          app.UseUmbraco()
              .WithMiddleware(u =>
              {
                  u.UseBackOffice();
                  u.UseWebsite();
              })
              .WithEndpoints(u =>
              {
                  u.UseInstallerEndpoints();
                  u.UseBackOfficeEndpoints();
                  u.UseWebsiteEndpoints();
                  u.EndpointRouteBuilder.MapControllerRoute("sitemap", "sitemap.xml", new { controller = "Sitemap", action = "Sitemap" });
              });
      
      1. Add the sitemap controller, which looks like this: { public class SitemapController : UmbracoPageController, IVirtualPageController

        private readonly IUmbracoContextAccessor _umbracoContextAccessor;
        private readonly IPublishedValueFallback _publishedValueFallback;
        
        
        public SitemapController(ILogger<UmbracoPageController> logger,
        

        ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor, IPublishedValueFallback publishedValueFallback) : base(logger, compositeViewEngine) { _umbracoContextAccessor = umbracoContextAccessor; _publishedValueFallback = publishedValueFallback; }

        [HttpGet]
        public IActionResult Sitemap()
        {
            if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext))
            {
                IPublishedContent rootNode = umbracoContext.Content.GetAtRoot().FirstOrDefault();
        
  • MB 113 posts 422 karma points
    Dec 12, 2023 @ 07:52
    MB
    0

    Thanks again for your time and input, but I don't think that's a solution I can use for this Umbraco-8 application.

    I suspect that the requirement is to use this type of construct from the documentation - but the part that confuses me is the {action}/{id} of the path, and what my options for specifying the path are, as I'm basically interested in routing any request for /docs/* to MyDocsController

     RouteTable.Routes.MapRoute("MyDocs", "Docs/{action}/{id}",
                new
                {
                    controller = "MyDocsController",
                    action = "Index",
                    id = UrlParameter.Optional
                });
    
  • MB 113 posts 422 karma points
    Dec 20, 2023 @ 05:41
    MB
    100

    Ok, I got this figured out and working.

    The issue had more to do with knowing the specifics of MVC Routing than Umbraco per-se, even though I'm using MapUmbracoRoute

    Just required configuring the route to use a WildCard, and the trick there is knowing that syntax - something like:

    RouteTable.Routes.MapUmbracoRoute(
        "customRoute1",
        "docs/{*path}",
        new
        {
            controller = "MyDocs",
            action = "Index"
        },
        new MyCustomContentFinder(),
        null,
        new string[] { "My", "Custom", "Controllers" }
    );
    

    That will route requests of the form .../docs/* to MyDocsController, with the option of finding Umbraco content to pass as a model. I also used the namespace array argument to configure that for the controller.

    namespace My.Custom.Controllers
    {
        public class MyDocsController : Umbraco.Web.Mvc.RenderMvcController
        {
            public override ActionResult Index(RenderModel model)
            {
                // do stuff
                return Redirect("somewhere");
            }
        }
    }
    
  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies