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 1100 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 1100 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");
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft