+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / ContentIndexProvider for a custom content module

ContentIndexProvider for a custom content module

13 posts, 0 answered
  1. David van Geel
    David van Geel avatar
    59 posts
    Registered:
    19 Aug 2009
    26 Aug 2010
    Link to this post

    Hi All,

    I am trying to get a ContentIndexProvider class working correctly for a custom module. By overriding the GetContentToIndex() method I got the reindixing of the entire index working as I want. The trouble is that the same method is not used when add, changing or deleting an item in that module. I need to determine the title and the url of the item in the search result myself. Is there a method to do that?

    Regards,

    David

  2. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    26 Aug 2010
    Link to this post
    Hi David van Geel,

    You can override ContentProvider_Executed and check the e.Command name

    switch (e.CommandName)
     {
        case "UpdateContent":
        case "CreateContent":  
        case "DeleteContent":
        IContent content = (IContent)e.Data;
        break;
     }

    You can do the same in Global.asax file, when you subscribe for Executed event of the ContentManager class.

    Best wishes,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. David van Geel
    David van Geel avatar
    59 posts
    Registered:
    19 Aug 2009
    08 Nov 2010
    Link to this post

    Hi Ivan,

    Ok, this method is executed when an item is updated, created or deleted but it doesn't help me much. Maybe I am asking the wrong question. I'll try to rephrase. The custom module I am trying to index doesn;t have a title field so in the search result that dd element is left empty.

    In the GetContentToIndex method I could tell the system to use the field name instead. Regretfully that only solves the problem when I (re)index the entire index. When I update one item theat method isn't used so my change doesn't work. Is there a wat to determine the content which wille be stored in the index when I updat a single item.

    Regards,

    David

  4. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    08 Nov 2010
    Link to this post
    Hi David,

    You can override GetIndexerInfo and return new instance of ContentIndexerInfo where you can pass the metakeys you want. The GetIndexerInfo give you access to the IContent object and metafields collection.

    Best wishes,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  5. David van Geel
    David van Geel avatar
    59 posts
    Registered:
    19 Aug 2009
    09 Nov 2010
    Link to this post

    Hi Ivan,

    I have been able to override the GetIndexerInfo method and the changed data is going into the index. But the old data is not removed from the index. Do I need to do something in the GetIndexerInfo method for that?

    Regards,


    David

    private LinksIndexerInfo DetermineIndexInformation(IContent item)
    {
        Hashtable metaFields = new Hashtable();
        foreach (string key in this.MetaFields)
        {
            if (key == "Tags")
            {
                metaFields["Tags"] = string.Empty + linksManager.GetTags(item.ID).ToString();
            }
            else if (key == "Name")
            {
                if (item.GetMetaData(key) == null || String.IsNullOrEmpty(item.GetMetaData(key).ToString()))
                {
                    metaFields["Title"] = string.Empty;
                }
                else
                {
                    metaFields["Title"] = item.GetMetaData(key).ToString();
                }
            }
            else
            {
                if (item.GetMetaData(key) == null || String.IsNullOrEmpty(item.GetMetaData(key).ToString()))
                {
                    metaFields[key] = string.Empty;
                }
                else
                {
                    metaFields[key] = item.GetMetaData(key).ToString();
                }
            }
        }
          
        string url = GetItemUrl(item, linksPageUrl, Thread.CurrentThread.CurrentCulture);
        LinksIndexerInfo linkIndexInfo = new LinksIndexerInfo(url,metaFields, item.Content.ToString());
          
        return linkIndexInfo;
    }

    protected override IIndexerInfo GetIndexerInfo(string path, IContent content)
    {
        LinksIndexerInfo linkIndexInfo = DetermineIndexInformation(content);
          
        return linkIndexInfo;
    }

     

  6. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    09 Nov 2010
    Link to this post
    Hello David ,

    The old data will be removed when ContentProvider.Executed static event is called. There is a virtual method OnIndex that you can call and pass the command argument - "DeleteContent" with the ID of the data item you want to remove.

    this.OnIndex(new IndexEventArgs("DeleteIndex", new Guid[] { someid }));

    The same applies for CreateContent or Upadate content.

    Greetings,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  7. David van Geel
    David van Geel avatar
    59 posts
    Registered:
    19 Aug 2009
    09 Nov 2010
    Link to this post
    Hi Ivan,

    I am sorry to keep bugging you with this but I can not get this to work. Wherever I add the last line of code you suggested there is no visible effect. When I change an item the old data of that item is not removed from the index. I have included the custom index provider I am using. Could you take a look to see that I am not doing something else wrong which is causing this?

    Regards,

    David


    using
    System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Telerik.Cms.Engine;
    using System.Globalization;
    using Estate.SitefinityModules.Persons.Resources;
    using Telerik.Framework.Search;
    using Estate.SitefinityModules.Persons.WebControls.Search;
    using System.Collections;
    using System.Threading;
      
    namespace Estate.SitefinityModules.Persons
    {
        public class PersonsIndexProvider : ContentIndexProvider
        {
            /// <summary>
            /// Defines the name of the provider. This name is used to manage providers within Indexing Service.
            /// </summary>
            public override string Name
            {
                get { return Messages.Module_Name + "Index"; }
            }
      
            /// <summary>
            /// Provides detailed description of the provider
            /// </summary>
            public override string Description
            {
                get { return Messages.IndexProviderDescription; }
            }
      
            /// <summary>
            /// Gets the content item key implicitly. This property should be overriden in the
            /// derived classes so that 2 different controls deriving from this one can be used together.
            /// </summary>
            /// <value>The content item key implicitly.</value>
            protected override string ContentItemKeyImpl
            {
                get
                {
                    return "PersonItem";
                }
            }
      
            /// <summary>
            /// Gets the content provider key implicitly. This property should be overriden in the
            /// derived classes so that 2 different controls deriving from this one can be used together.
            /// </summary>
            /// <value>The content provider key implicitly.</value>
            protected override string ContentProviderKeyImpl
            {
                get
                {
                    return "PersonProv";
                }
            }
      
            /// <summary>
            /// Gets the name of the default news data provider. 
            /// </summary>
            /// <returns>The name of the default news data provider.</returns>
            protected override string GetDefaultContentProvider()
            {
                if (!string.IsNullOrEmpty(personsProvider))
                    return personsProvider;
                return new PersonsManager().DefaultProvider;
            }
      
            /// <summary>
            /// Gets the filter expression - specifying the given filter will ignore culture on the
            /// provider level and search will index all content, regardless of localization. You
            /// are of course free to modify the filter expression as you wish.
            /// </summary>
            public override string FilterExpression
            {
                get
                {
                    return "Name='InVariantCulture';";
                }
            }
      
            /// <summary>
            /// Meta fields for this provider
            /// </summary>
            protected override string[] MetaFields
            {
                get
                {
                    personsManager = new ContentManager(GetDefaultContentProvider());
                    ArrayList fields = new ArrayList();
                      
                    foreach (KeyValuePair<string,IMetaInfo> metaKey in personsManager.MetaKeys)
                    {
                        if (personsManager.MetaKeys[metaKey.Key].Searchable)
                        {
                            fields.Add(metaKey.Key);
                        }
                    }
                      
                    return (string[])fields.ToArray(typeof(System.String));
                 }
            }
      
            /// <summary>
            /// Gets the URL to a single content item. This method is invoked for every item that
            /// is binding to the list. By default the item ID is appended to the query string portion
            /// of the URL.
            /// </summary>
            /// <returns>String containing the URL address.</returns>
            /// <param name="contentItem">
            /// <param name="singleItemUrl">Url of the page where single persons are displayed</param>
            /// <param name="culture">Culture of the item</param>
            ///     The <see cref="Telerik.Cms.Engine.IContent">IContent</see> item that is currently
            ///     binding.
            /// </param>
            protected override string GetItemUrl(IContent contentItem, string singleItemUrl, CultureInfo culture)
            {
                if (String.IsNullOrEmpty(singleItemUrl))
                {
                    int idx = personsPageUrl.IndexOf('.');
                    if (idx != -1)
                        personsPageUrl = personsPageUrl.Substring(0, idx);
      
                    singleItemUrl = personsPageUrl;
                }
                return base.GetItemUrl(contentItem, singleItemUrl, culture);
            }
      
            /// <summary>
            /// Initializes this instance with the settings provided.
            /// </summary>
            /// <param name="settings"><c>IDictionary<string, string></c> representing key value collection of settings.</param>
            /// <remarks>
            /// The settings dictionary you see here, will be populated through the PersonsIndexSettings control.
            /// </remarks>
            public override void Initialize(IDictionary<string, string> indexsettings)
            {
                personsPageUrl = indexsettings["PersonPageUrl"];
                indexsettings.TryGetValue("personsProvider", out personsProvider);
      
                if (String.IsNullOrEmpty(personsPageUrl))
                    throw new ArgumentException(String.Format("CannotCreateAbsoluteUri"));
                base.Initialize(indexsettings);
            }
      
            /// <summary>
            /// Gets the content to index when the entire index is (re)build.
            /// </summary>
            /// <returns>The list of index information to add to the index</returns>
            public override Telerik.Framework.Search.IIndexerInfo[] GetContentToIndex()
            {
                personsManager = new ContentManager(GetDefaultContentProvider());
                List<PersonsIndexerInfo> contentItems = new List<PersonsIndexerInfo>();
                IList itemsList;
      
                List<IMetaSearchInfo> publicationFilters = new List<IMetaSearchInfo>();
                publicationFilters.Add(new MetaSearchInfo(MetaValueTypes.DateTime, "Publication_Date", DateTime.Now, SearchCondition.LessOrEqual));
                publicationFilters.Add(new MetaSearchInfo(MetaValueTypes.DateTime, "Expiration_Date", DateTime.Now,SearchCondition.GreaterThen));
                  
                itemsList = personsManager.GetContent("Publication_Date DESC", publicationFilters.ToArray());
                  
                if (itemsList != null && itemsList.Count > 0)
                {
                    foreach (IContent item in itemsList) {
                        PersonsIndexerInfo linkIndexInfo = DetermineIndexInformation(item);
                        contentItems.Add(linkIndexInfo);
                    }
                }
                  
                return contentItems.ToArray();
            }
      
            /// <summary>
            /// Determines the index information for one item.
            /// </summary>
            /// <param name="item">The item to index.</param>
            /// <returns>The information to add to the index</returns>
            private PersonsIndexerInfo DetermineIndexInformation(IContent item)
            {
                Hashtable metaFields = new Hashtable();
                foreach (string key in this.MetaFields)
                {
                    if (key == "Tags")
                    {
                        metaFields["Tags"] = string.Empty + personsManager.GetTags(item.ID).ToString();
                    }
                    else if (key == "Name")
                    {
                        if (item.GetMetaData(key) == null || String.IsNullOrEmpty(item.GetMetaData(key).ToString()))
                        {
                            metaFields["Title"] = string.Empty;
                        }
                        else
                        {
                            metaFields["Title"] = item.GetMetaData(key).ToString();
                        }
                    }
                    else
                    {
                        if (item.GetMetaData(key) == null || String.IsNullOrEmpty(item.GetMetaData(key).ToString()))
                        {
                            metaFields[key] = string.Empty;
                        }
                        else
                        {
                            metaFields[key] = item.GetMetaData(key).ToString();
                        }
                    }
                }
                  
                string url = GetItemUrl(item, personsPageUrl, Thread.CurrentThread.CurrentCulture);
                PersonsIndexerInfo linkIndexInfo = new PersonsIndexerInfo(url,metaFields, item.Content.ToString());
                  
                return linkIndexInfo;
            }
      
            /// <summary>
            /// Gets the indexer info for an item when that item is changed, created or deleted.
            /// </summary>
            /// <param name="path">The path of the item.</param>
            /// <param name="content">The content of the item.</param>
            /// <returns></returns>
            protected override IIndexerInfo GetIndexerInfo(string path, IContent content)
            {
                PersonsIndexerInfo linkIndexInfo = DetermineIndexInformation(content);
                  
                return linkIndexInfo;
            }
              
            private ContentManager personsManager;
            private string personsProvider;
            private string personsPageUrl;
        }
    }

  8. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    09 Nov 2010
    Link to this post
    Hello David,

    I do not see that you use OnIndex method somewhere in your code to manually force items updated which is automatically handled by ContentIndexProvider in cases of Create, Update, Delete.

    Best wishes,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  9. David van Geel
    David van Geel avatar
    59 posts
    Registered:
    19 Aug 2009
    10 Nov 2010
    Link to this post
    Hi Ivan,

    Adding the following method to the PersonIndexProvider class has no effect whatsoever. Creating an item will add data to the index. Deleting the item will leave the item in the index. When I change the name of an item the old name is retained in the index.

    Regards,


    David

    protected override void ContentProvider_Executed(object sender, Telerik.ExecutedEventArgs e)
    {
        if (e.CommandName == "DeleteContent")
        {
            this.OnIndex(new IndexEventArgs("DeleteIndex", new Guid[] { e.ItemID }));
        }
        else
        {
            base.ContentProvider_Executed(sender, e);
        }
    }
  10. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    11 Nov 2010
    Link to this post
    Hi David,

    When you update an item, the old segment is not removed from the index and the data for the renamed file is appended. The old segment is removed when you trigger the entire index. There is a static method of IndexingManager - DeleteDocumentsFromIndex which you can use to force deleting when you update the item, but the same will happen when you pass "DeleteContent" as a command argument to "OnIndex"
    Also you are removing the item from the segments files only in case you delete an item.

    All the best,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  11. Jacques
    Jacques avatar
    427 posts
    Registered:
    28 Jun 2007
    09 Dec 2010
    Link to this post
    Hi David and Ivan,

    We're dealing with a similar situation except that it's not a custom control. For some reason when you update page names in Sitefinity, it automatically updates the index without the need to manually (or using code) re-index the content. But, with the news items, if you change the title of the news item Sitefinity does not remove the old item from the index.

    So we implemented another one of Ivan's suggestions, but that re-indexes the entire site every time a news item is updated.

    Will this solution work if we subscribe to the executed event handler? Will we have a reference to the item being changed so that we can A) Remove the old one from the next and B) have Sitefinity add the new one to the index?

    Regards,
    Jacques
  12. Jacques
    Jacques avatar
    427 posts
    Registered:
    28 Jun 2007
    09 Dec 2010
    Link to this post
    OnIndex is a member of the Telerik.Cms.Engine.ContentIndexProvider class. What is the context to use it in the Global asax file when you're working with the ContentManager_Executed eventhandler?

    I can see that I'll have the ItemId from the event arguments so I'm hoping I'll be able to pass that to either the OnIndex method or DeleteDocumentsFromIndex method, but which is appropriate in the Global asax file in the ContentManager_Executed handler?

    Thanks
    Jacques
  13. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    25 Nov 2016
    10 Dec 2010
    Link to this post
    Hi J.Hoventer,

    ContentIndexProvider does not have a static event for which you can subscribe on Global.asax. You need a custom provider.

    Regards,
    Ivan Dimitrov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Register for webinar
13 posts, 0 answered