Copied to clipboard

Flag this post as spam?

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


  • Michaël Vanbrabandt 863 posts 3348 karma points c-trib
    Oct 31, 2016 @ 14:35
    Michaël Vanbrabandt
    0

    Issue using the IContentFinder

    Hi all,

    I am using the IContentFinder to show the correct template based on the url.

    My content structure:

    Home
        Categories ( no template )
            Categorie-1 ( /categorie-1/ )
                Sub-categorie-1 ( /sub-categorie-1/ )
                Sub-categorie-2 ( /sub-categorie-2/ )
            Categorie-2 ( /categorie-2/ )
                Sub-categorie-3 ( /sub-categorie-3/ )
                Sub-categorie-4 ( /sub-categorie-4/ )
        Companies ( no template )
            Company-1 ( /company-1/ )
    

    As you can see I have setup a url provider so that all of my categories and companies have a custom url, eg no parent segments.

    Now when you go to for example /sub-categorie-1/ it will display companies of that categorie with an url to the company of /sub-categorie-1/company-1/.

    Using a custom ContentFinder I have managed to get the correct template and show the company details.

    I do this by taking the last segment and do a search on the company document type alias and url name.

    But the problem is that if I open url /sub-categorie-2/company-1/, even when its not a category of this company, or a non existing url like /test/company-1/ it also opens the template of the company.

    Would it be hard to lookup the parent segment and do a check to see if it really is a category of that company and do a redirect if this is not the case?

    /Michaël

  • David Peck 690 posts 1896 karma points c-trib
    Nov 01, 2016 @ 08:49
    David Peck
    0

    Hi Michael,

    I'm not sure using an IContentFinder to select the template is possible or the right approach, but if you've got it to work then great. Personally I'd use Published Content Request Preparation or using a controller return View("templateName", model) where templateName is determinded based on the document type alias of the model supplied.

    With regard to your question though, this should be quite achievable. I'm not sure what the complication, you IContentFinder just needs to return a result for genuine results. So if you have a cache of all your company, category and sub-category url names then you can check that they genuinely exist.

    I'd also have three IContentFinders one for categories, one for sub-categories and one for companies (though it might be easiest to combine categories and sub-categories). Each finder just handles urls of it's type and will validate a geniune url. That way it shouldn't get confused by mixing urls.

    Send me some code if you like. Here is some of mine:

     public class NewsCategoryContentFinder : IContentFinder
      {
        public bool TryFindContent(PublishedContentRequest contentRequest)
        {
          try
          {
            var newsService = new NewsService(UmbracoContext.Current);
    
            string nextSegment;
            if (!newsService.GetSegmentAfterListing(contentRequest.Uri, out nextSegment))
              return false;
    
            NewsCategory newsCategory;
            if (newsService.IsCategory(nextSegment, out newsCategory))
            {
              var umbraco = new UmbracoHelper(UmbracoContext.Current);
              //This method returns an IPublishedContent created from the Models Builder that I've extended to add RequestedCategory to avoid the controller having to re-workout which category the url relates to
              var newsHome = umbraco.GetNewsHome();
              newsHome.RequestedCategory = newsCategory;
              contentRequest.PublishedContent = newsHome;
              return true;
            }
          }
          catch (Exception exception)
          {
            LogHelper.Error<NewsCategoryContentFinder>(exception.Message, exception);
          }
          return false;
        }
      }
    
      //IsCategory looks like
      public bool IsCategory(string urlSegment, out NewsCategory newsCategory)
        {
          foreach (var category in Categories)
          {
            var urlAlias = category.GetUrlName();
            if (!urlSegment.Equals(urlAlias.ToUrlSegment(), StringComparison.InvariantCultureIgnoreCase))
              continue;
    
            newsCategory = category;
            return true;
          }
    
          newsCategory = null;
          return false;
        }
    
    //GetSegmentAfterListing looks like
    public bool GetSegmentAfterListing(Uri uri, out string segment)
    {
      var newsHomeUri = new Uri(uri, NewsHomeUrl);
    
      //Jump out early if this isn't a news based URL
      if (!newsHomeUri.IsBaseOf(uri))
      {
        segment = null;
        return false;
      }
    
      //What is right of the news url
      var relativePath = newsHomeUri.MakeRelativeUri(uri);
    
      segment = relativePath.OriginalString.Split('/').FirstOrDefault();
      if (segment == null)
        return false;
    
      if (segment.Contains("?"))
        segment = segment.Split('?').First();
    
      segment = HttpUtility.UrlDecode(segment).ToUrlSegment();
      return true;
    }
    
  • Michaël Vanbrabandt 863 posts 3348 karma points c-trib
    Nov 01, 2016 @ 10:10
    Michaël Vanbrabandt
    1

    Hi David,

    What I mean was using my custom urls I created using the IUrlProvider I needed to lookup and display the correct node. So returning the correct IPublishedContent and Template.

    Below is my code, I have managed to get it working by checking the parent to see if it exists and if the category belongs to the current Company from the given url:

        public bool TryFindContent(PublishedContentRequest contentRequest)
        {
            try
            {
                if (contentRequest != null)
                {
                    var url = contentRequest.Uri.AbsoluteUri;
    
                    var cachedCompanyNodes =
                        (Dictionary<string, ContentFinderItem>)HttpContext.Current.Cache["CachedCompanyNodes"];
    
                    if (cachedCompanyNodes != null)
                    {
                        if (cachedCompanyNodes.ContainsKey(url))
                        {
                            var contentFinderItem = cachedCompanyNodes[url];
                            contentRequest.PublishedContent = contentFinderItem.Content;
                            contentRequest.TrySetTemplate(contentFinderItem.Template);
                            return true;
                        }
                    }
    
                    // Split the url segments.
                    var path = contentRequest.Uri.GetAbsolutePathDecoded();
                    var parts = path.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
    
                    // Company can be called directly like : /company-1/
                    // or it can be called by category like : /category/company-1/
                    if (parts.Length > 0 && parts.Length < 3)
                    {
                        // Get all the root nodes.
                        var rootNodes = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetAtRoot();
    
                        // Find the company item that matches
                        var companyItem = rootNodes.DescendantsOrSelf("companyItem")
                            .Where(x => x.UrlName == parts.Last())
                            .FirstOrDefault();
    
                        if (companyItem != null)
                        {
                            bool valid = true;
    
                            // Company accessed by category
                            if(parts.Length == 2)
                            {
                                var categoryItem = rootNodes.DescendantsOrSelf("subCategory")
                                    .Where(x => x.UrlName == parts.First())
                                    .FirstOrDefault();
    
                                // Category must exists and category must be assigned to the company
                                int[] _categories = Array.ConvertAll(companyItem.GetPropertyValue<string>("categories").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), int.Parse);
                                valid = categoryItem != null && _categories.Contains(categoryItem.Id);
                            }
    
                            if(valid)
                            {
                                // Get the company item template.
                                var template = Services.FileService.GetTemplate(companyItem.TemplateId);
    
                                if (template != null)
                                {
                                    // Store the fields in the ContentFinderItem-object.
                                    var contentFinderItem = new ContentFinderItem()
                                    {
                                        Template = template.Alias,
                                        Content = companyItem
                                    };
    
                                    // If the correct node is found display that node.
                                    contentRequest.PublishedContent = contentFinderItem.Content;
                                    contentRequest.TrySetTemplate(contentFinderItem.Template);
    
                                    if (cachedCompanyNodes != null)
                                    {
                                        // Add the new ContentFinderItem-object to the cache.
                                        cachedCompanyNodes.Add(url, contentFinderItem);
                                    }
                                    else
                                    {
                                        // Create a new dictionary and store it in the cache.
                                        cachedCompanyNodes = new Dictionary<string, ContentFinderItem>()
                                        {
                                            {
                                                url, contentFinderItem
                                            }
                                        };
    
                                        HttpContext.Current.Cache.Add("CachedCompanyNodes",
                                                cachedCompanyNodes,
                                                null,
                                                DateTime.Now.AddDays(1),
                                                System.Web.Caching.Cache.NoSlidingExpiration,
                                                System.Web.Caching.CacheItemPriority.High,
                                                null);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch(Exception e) {
                LogHelper.Error<CompaniesContentFinder>("Error while searching for the company", e);
            }
    
            return contentRequest.PublishedContent != null;
        }
    
Please Sign in or register to post replies

Write your reply to:

Draft