Copied to clipboard

Flag this post as spam?

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

  • Peter Cort Larsen 365 posts 848 karma points
    Sep 18, 2019 @ 10:16
    Peter Cort Larsen


    I have a site where nodes of type 'Course' that are placed under a parent of type 'Courses'.

    Each Course has a category.

    But at the moment the url of a course works in both these situation:

    1. DOMAIN/courses/course
    2. DOMAIN/courses/category/course

    I want only option 2 to be valid. I have a IContentFinder and a IUrlProvider. But i can figure out how to change these to only allow option 2.

    Can anyone help?


    namespace Website.UrlProviders
        public class CoursesWithCategoryUrlProvider : IUrlProvider
            public string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode)
                var content = umbracoContext.ContentCache.GetById(id);
                if (content != null && content.DocumentTypeAlias == Course.ModelTypeAlias)
                    if (content is Course course)
                        var category = course?.Categories?.Last();
                        if (category == null) return null;
                        return $"/{CourseContants.UrlSegmentName}/{category.UrlName}/{course.UrlName}";
                return null;
            public IEnumerable<string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
                return Enumerable.Empty<string>();


    namespace Website.ContentFinders
        public class CoursesWithCategoryContentFinder : IContentFinder
            public bool TryFindContent(PublishedContentRequest contentRequest)
                if (contentRequest == null) return false;
                var pathValues = contentRequest.Uri
                    .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                if(pathValues.Length == 3 && pathValues.First().Equals(CourseContants.UrlSegmentName))
                    var course = UmbracoContext.Current.ContentCache?
                        .Where(x => x.UrlName.Equals(pathValues.Last()))?
                    if (course != null)
                        contentRequest.PublishedContent = course;
                return contentRequest.PublishedContent != null;
  • Marc Goodson 1154 posts 7698 karma points MVP 5x c-trib
    Sep 18, 2019 @ 11:17
    Marc Goodson

    HI Peter

    If your CoursesWithCategoryContentFinder IContentFinder is registered in the ContentFinderCollection 'before' the core's default ContentFinderByUrl IContentFinder, then you have the chance to handle the shorter version of the Url too

    What's happening at the moment is your


    request isn't being handled by your CoursesWithCategoryContentFinder... either because it's being handled first by ContentFinderByUrl or it is falling through your CoursesWithCategoryContentFinder (because it's path length when split will be less than 3) and then it is being handled by the ContentFinderByUrl.

    So if you ensure your CoursesWithCategoryContentFinder is ahead of the ContentFinderByUrl

    and then add a further check to see if the length of the paths is 2, and that the last item is a course, you can then issue a 301 redirect to the desired category version of the Url, (or return a 404) ... but if you do nothing and return false, the pesky default ContentFinderByUrl will find it...!

    ... I'm guessing a course can be in more than one category? otherwise you could structure your content tree /courses/category/course ?



Please Sign in or register to post replies

Write your reply to: