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

Forums / Developing with Sitefinity / popular news articles

popular news articles

14 posts, 0 answered
  1. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    16 Jun 2009
    Link to this post
    Hey guys!

    I am looking into providing functionality whereby i can track popularity of articles based on some metric (most likely number of views). The reason being so that i can create a control which will display the most popular articles.

    The best solution i can think of to this would be to add a new meta field to news and then on the news view (specifically the control template for displaying the actual article, not the list), this value could be incremented each time the article is viewed.

    Does this seem like the most sensible solution? We have a a rather large amount of articles in total (ever-increasing), with quite a high throughput of users, and thus i must consider the impact of writing to the database every time an article is viewed.

    Thanks for any help or suggestions guys, it's always appreciated :-)
    Nick
  2. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    16 Jun 2009
    Link to this post
    Hi Nick,

    Adding a new metafield is the approach which instantly came to my mind as well. Then the performance issues appear.
    If you are writing something to the database on each request, given the fact you have a lot of visitors and articles, this will most probably cause a performance problem.

    If it is possible, you might use another approach - to write the value to a buffer, and periodically write that buffer in the database. (pst - this is the approach we will use in 4.0 - it will allows us to have exceptional performance on big web sites like yours).

    Another way could be the following:
    You are creating a special HttpModule which can track requests to the Articles URLs. The articles URLs are saved in database table. Once the application is started you load these Urls into the memory (in a dictionary - URL and Visits Count). Each time someone access given URL, you increase the visit count for the URL. On every 15 minutes for example, you write the URLs with changed Visit count back to the database.

    I hope that you might find some of the ideas here helpful.

    Kind regards,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  3. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    16 Jun 2009
    Link to this post
    Thanks for the quick reply Georgi :-)

    Your suggestions are very interesting!

    Whilst i do not have experience of writing HttpModule, I'm sure someone here has knowledge they could impart to me on this matte, if this was the route i went down..

    As for the buffer suggestion, this seems like it may be the easiest and quickest approach. What would you suggest as a buffer? As you mentioned with the HttpModule, a dictionary mapping strings (URL's) to int (view count)? If so, how would i make a unique instance of this buffer across the application? If i was to use a singleton, or a static property on the news view, what would be the lifetime of that object? I ask this as I am unfamiliar with some of the inner workings of ASP.Net..

    Assuming i have implemented the above, i could use a System.Timer.Timer class to periodically call a method to persist any incremented view counts to the DB?

    Would there not be the potential of the buffer getting large (and thus eat up resources) very quickly considering the amount of users and articles?

    As for your mention of v4.0, any ideas when that will be available? i'm very much looking forward to it :-)
  4. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    17 Jun 2009
    Link to this post
    Hi Nick,

    I do not think that the buffer might get that large to compare with the performance bottleneck if you write something to the database on every request. Please take a look at the following example in MSDN about a custom module:
    You will notice the Application_BeginRequest method. You might get the Request URL in this method. I guess the whole logic should be coded here. A dictionary mapping strings (URL's) to int sounds fine as well.

    If you go with this approach, you should register the HttpModule in the Sitefinity's web.config module, before ours. Every request will go through it.

    Greetings,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  5. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    17 Jun 2009
    Link to this post
    Georgi, i musrt once again thank you for your sterling help here :-)

    from the looks of that article, writing a custom HttpModule isn't all that difficult! The most difficult part, i guess, would be to write some logic to determine whether or not the page being viewed contains an article or other type of content (as i only wish to track the popularity of articles, and not other types of content or pages themselves). Any suggestions?

    The only other part of this problem that seems taxing, would be how to grab an instance of the article so that I can write back the newly incremented view count. How woudl you recommend this? We append, on the end of our article URLs, an ID value, as defined in the web.config
    <add name="News" urlRewriteFormat="[Title]-{ID}" ... /> 

    As this ID is supplied by the CMS, rather than generated in some code i have written, i assume this is comparable to a primary key in the DB? If so, could i use the NewsManager with a filter on the ID to retrieve the correct article?

    Thanks again Georgi, your help has been invaluable - especially as one suggestion (by someone else) was to manually manage a list of the most popular articles, which would be an absolute nightmare to oversee!!
  6. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    17 Jun 2009
    Link to this post
    Hi Nick,

    You are right for everything here.

    It will be difficult to get the News articles URLs, since they are dynamic and depend on the NewsView control and its location. If you know that your articles are published all under http://yourdomain.com/news/<article>.aspx then it would be easy - every IContent item (such as the article, returned by the NewsManager.GetContent method) has an Url and UrlWithExtension property. You should concatenate this value with the http://yourdomain.com/news/<article>.aspx and you should have the article url.

    If not, then the task gets really complicated. I can take a look in my spare time though, because it is very interesting to me as well. Basically, what should be done is retrieve all pages, scan for NewsView controls, check what kind of articles they are showing (for example in given category?), remember the path, take the items.UrlWithExtension property and form the full url.

    I will get back to you.

    Sincerely yours,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  7. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    17 Jun 2009
    Link to this post
    I look forward to hearing what you have to say after you have given more thought to the matter Georgi.

    One thing that can be taken into consideration with our system is that we changed the way in which article URLs are formed.

    We use the news control to drive all articles on the site, but needed a way to be able to filter articles at a very fine grained level. We needed to have different types of article other than just news. To achieve this we had to introduce different types of articles (News, Guides etc), for each type of article we have multiple areas, and for each area we have multiple products.

    As i said this is all driven by the News module, so we had to add three new meta fields to represent these values (type, area, product). We also ran into another problem when developing this - we have many many news views throughout our site, which would normally result in the same article being displayed at many different URLs depending on the location of the news view control. This was not desirable for the purposes of SEO. So once again we extended the news view so that it uses the three meta fields previously mentioned to form a static (and predicatable) URL, which will always be the same for the article - wherever the news view control is situated.

    E.G.
    all article URLs will always be of the following format:
    www.ourwebsite.com/type/area/product/title-ID

    So, since any news article always has a predicatable URL, i can use this in the dictionary as a key, but will it help with being able to retrieve an IContent instance of the article so i can call the setMetaData() method with the new view count?

    Thanks again, hope this helps with your considerations :-)
    Nick
  8. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    22 Jun 2009
    Link to this post
    Georgi, did you get any further with ideas about this problem?

    thanks,
    Nick
  9. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    23 Jun 2009
    Link to this post
    Hello Nick,

    I apologize for the bit late reply, but good news - I was able to get the urls all articles that are being shown by the NewsView controls:

    using System; 
    using System.Collections; 
    using System.Configuration; 
    using System.Data; 
    using System.Web; 
    using System.Web.Security; 
    using System.Web.UI; 
    using System.Web.UI.HtmlControls; 
    using System.Web.UI.WebControls; 
    using System.Web.UI.WebControls.WebParts; 
    // 
    using Telerik.News; 
    using Telerik.Cms; 
    using Telerik.News.WebControls; 
    using System.Collections.Generic; 
    using Telerik.Cms.Engine; 
    using Telerik.Cms.Engine.ContentViewFiltering; 
     
    public partial class FindNewsUrls : System.Web.UI.Page 
        protected void Page_Load(object sender, EventArgs e) 
        { 
            CmsManager pageManager = new CmsManager(); 
            IList pages = pageManager.GetPages(); 
            // 
            List<string> newsUrls = new List<string>(); 
            // 
            string path = Request.Url.AbsoluteUri.Replace(Request.Url.LocalPath, ""); 
     
            foreach (IPage page in pages) 
            { 
                IList<ICmsWebControl> controls = page.Controls; 
                foreach (ICmsWebControl control in controls) 
                { 
                    if (control.TypeName.Equals(typeof(Telerik.News.WebControls.NewsView).AssemblyQualifiedName)) 
                    { 
                        NewsManager newsManager = new NewsManager("News"); 
                        IList newsArticles; 
                        NewsView nvCtrl = control.LoadControl() as NewsView; 
                        //load the "filtered" news articles only. Note that a blank FilterExpression is still a FilterExpression 
                        ContentFilterBuilder filterBuilder = new ContentFilterBuilder(nvCtrl); 
                        if (filterBuilder.IsFilterValid) 
                        { 
                            newsArticles = newsManager.Content.GetContent(0, 
                                              int.MaxValue, 
                                              nvCtrl.SortExpression, 
                                              filterBuilder.ParseTagFilter(), 
                                              ContentStatus.Published, 
                                              null
                                              filterBuilder.ParseParentsFilter(), 
                                              filterBuilder.ParseMetaFieldsFilter() 
                                              ); 
                        } 
                        else 
                        { 
                            //filter not valid. Perhaps the NewsView is showing..nothing. 
                            continue
                        } 
                        //We will take the URL from the Master control, so we could skip this NewsView if it is in 
                        //Detail behavior mode. 
                        if (nvCtrl.BehaviorMode == Telerik.Cms.Engine.WebControls.ContentView.BehaviorModes.Detail) 
                        { 
                            continue
                        } 
     
                        string pageUrl; 
                        //the news page could be the NewsView detail page... (e.g. NewsView is in Master/Auto mode) 
                        if (nvCtrl.SingleItemUrl.Length != 0) 
                        { 
                            pageUrl = nvCtrl.SingleItemUrl; 
                        } 
                        else 
                        { 
                            ICmsPage cmsPage = pageManager.GetPage(page.ID) as ICmsPage; 
                            //we could iterate through all additional urls, now taking the default one. 
                            pageUrl = cmsPage.DefaultUrl.Url; 
                        } 
     
                        pageUrl = pageUrl.Replace(".aspx"""); 
                        pageUrl = pageUrl.Replace("~"""); 
                        foreach (IContent article in newsArticles) 
                        { 
                            //this should be url = pageUrl + article.UrlWithExtension in 3.6 
                            string url = path + pageUrl + article.Url + ".aspx"
                            //add the url to the list 
                            if (!newsUrls.Contains(url)) 
                                newsUrls.Add(url); 
                        } 
                    } 
                } 
     
            } 
            //remove the duplicating entries. 
            foreach (string articleUrl in newsUrls) 
            { 
                Response.Write(articleUrl + "<br />"); 
            } 
        } 

    I am definitely sure this can be optimized, but I want to give you the idea. I will also blog about it, since we had a couple of requests already.

    The hard part was the Urls are dynamically generated depending on the page on which the NewsView is placed. There is even an option the NewsView control to show the list of the items, but the full article (and url) to be on separate page.

    I have not completely tested it, but at least it will get you going.

    Greetings,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  10. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    23 Jun 2009
    Link to this post
    Hello Nick,

    Quick follow up. Please replace the following line:

    string
     path = Request.Url.AbsoluteUri.Replace(Request.Url.LocalPath, "");

    With:
      string vd = Request.AppRelativeCurrentExecutionFilePath.Replace("~", String.Empty); 
      string path = Request.Url.AbsoluteUri.Replace(vd, string.Empty); 

    The code was not resolving the server path correctly in the first place.

    Regards,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  11. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    23 Jun 2009
    Link to this post
    thanks for the help georgi, that is certainly a lot of effort you have gone to on my part!!!

    I have had a look through the code, but have some problems, presumably because i am using Sitefinity 3.2 (we are looking to upgrade, but risk analysis first) instead of 3.6 which i assume you are using. Thus the namespace Telerik.Cms.Engine.ContentViewFiltering is not available.

    I'm sure i could adapt the code if need be though..

    One question i have, is it possible to use the NewsManager (or any other class) to retrieve an IContent instance (or List of IContent's) based on a property rather than a piece of meta data? as far as i am aware, you can only filter on metafields and not on properties.

    One further enquiry - as i said in a previous post, our article URLs are formatted as such:
    [Title]-{ID}

    what does the ID part of that refer to, the value that is written isn't a GUID, so i am wondering whether this would be a searchable field at all?


  12. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    24 Jun 2009
    Link to this post
    Hi Nick,

    I was using 3.5, but it will work on 3.6 as well. Unfortunately, the approach on 3.2 will be different because of the ContentFilterBuilder class. I would suggest you an upgrade because of many fixes and optimizations though.


    One question i have, is it possible to use the NewsManager (or any other class) to retrieve an IContent instance (or List of IContent's) based on a property rather than a piece of meta data? as far as i am aware, you can only filter on metafields and not on properties.


    Unfortunately there is no such method, but you might do something like this:
    NewsManager manager = new NewsManager("News"); 
    IList items = manager.Content.GetContent(); 
    foreach (IContent item in items) 
        if (item.GetMetaData("YourField").ToString().Equals("Something")) 
        { 
            //add to another list, or do some additional processing 
        } 

    As for your last question, can you show me how your web.config UrlRewriteFormat for the News provider look like? The ID is a random number with fixed length. This can be used if you have more than one article with the same Title, a IDentifier by which the URL will be resolved by the system. It will be searchable, since the ID is not going in the search index, and only the original Title is taken in mind.

    All the best,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  13. Nick
    Nick avatar
    91 posts
    Registered:
    04 Aug 2008
    25 Jun 2009
    Link to this post
    Yes, an upgrade is definitely planned in the near future, but we have so many customisations in the CMS that we can't risk upgrading without fully testing every aspect before going live with the update.

    That aside, could you tell me how the news view manages to work out which article you wish to view?

    i understand how the list page master part of the news view works - by supplying a number of relevant filters which are then passed to the news manager to retrieve a list of content.

    But how does the list page details part work? How does it calculate which article should be displayed? Is it based off the URL of the Request (primarily, the title section of the URL)? If so, how is this mapping achieved?

    This is the part of the popularity tracking i am struggling with: i need some method of going from a URL to an actual instance of the article (so that i can then update the article's view count meta data).

    If this is not possible, i cannot think how else i would achieve this desired functionality other than to have a database table independent of the CMS, to which i periodically write the number of views against the URL of the page viewed. As i said previously, we have customised the news view so that an article has the same URL, wherever it is viewed from, meaning the URL can be used as a primary key.

    Thanks Georgi!
  14. Georgi
    Georgi avatar
    3583 posts
    Registered:
    28 Oct 2016
    01 Jul 2009
    Link to this post
    Hello Nick,

    I will describe you the process.

    If we have a list of articles, then we can form the URL for the full articles by taking the current page, or the page that holds the article details (specified in the NewsView control). But what happens if we type directly the News Article Url?
    1. We try to determine the page from the URL. If we succeed than -
    2. We look for the an article with this URL in the database. We store the relative articles URLs (the Url produced by the Url rewriting service) in a table.

    Let me know if you have further questions.

    All the best,
    Georgi
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
Register for webinar
14 posts, 0 answered