Blog

Posts written in 2011.

  • For a news site I am currently working on, I needed to display the last time a news article was last published. I wanted to be able to show the duration based on respective major time format. For example, if an article was displayed a couple hours ago, I would want it to to display “2 hours” not “120 minutes”.

    More importantly, if an article hadn’t been published to the site more than a week, I don’t want the exact time duration to be displayed. I would prefer the following message: “more than a week ago”. This way, if the site administrator gets really lazy the website viewer will not know the exact time period the site was last updated.

    Code:

    public class TimePassed
    {
        public static string GetPassedTime(DateTime since)
        {
            TimeSpan ts = DateTime.Now.Subtract(since);
    
            if (ts.Days <= 7)
            {
                switch (ts.Days)
                {
                    case 0:
                        switch (ts.Hours)
                        {
                            case 0:
                                switch (ts.Minutes)
                                {
                                    case 0:
                                        return String.Format("{0} seconds ago", ts.Seconds);
                                    case 1:
                                        return "1 minute ago";
                                    default:
                                        return String.Format("{0} minutes ago", ts.Minutes);
                                }
                            case 1:
                                return "1 hour ago";
                            default:
                                return String.Format("{0} hours ago", ts.Hours);
                        }
                    case 1:
                        return "yesterday";
                    default:
                        return String.Format("{0} days ago", ts.Days);
                }
            }
            else
            {
                return "more than a week ago";
            }
        }
    }
    
  • Published on
    -
    1 min read

    Get CheckBoxList Values Using jQuery

    To be able to retrieve values from a ASP.NET CheckBoxList control or a group of HTML checkboxes, use the following jQuery:

    $(document).ready(function () {
        var checkboxValues = [];
    
        $('#<%=MyCheckBoxList.ClientID %> input[type=checkbox]').click(function () {
            $('input[type=checkbox]:checked').each(function () {
                checkboxValues.push(this.value);
            });        
        });
        
        var values = checkboxValues.toString(); //Output Format: 1,2,3
    });
    

    If you do use this code snippet on a CheckBoxList, take a look that this article on how to create a custom CheckBoxList control with a value attribute.

  • Published on
    -
    2 min read

    ASP.NET CheckBoxList Control With Value Attribute

    ASP.NET server controls is a great way to quickly build a page with dynamic functionality. Even though we do not have much of direct control over the way these controls are rendered, they do a pretty good job and its not very often I get annoyed with them.

    Until now.

    Generally, I find myself using the .Attributes.Add() method when needing to add additional attributes to certain server controls. No problem! In this case, I wanted to add a “value” attribute that will contain the record ID for that checkbox. I can then use this value within my JavaScript. I would have thought a value attribute would already be there. Its perfectly valid HTML mark-up:

    <form>
        <input type="checkbox" name="vehicle" value="Volvo" />
        <input type="checkbox" name="vehicle" value="Volkswagen" />
    </form> 
    

    For some reason, when I tried to add my custom attributes after my CheckBoxList was databound (as shown below), the attribute was simply ignored.

    NewsCheckList.Items[0].Attributes["value"] = "1";
    NewsCheckList.Items[1].Attributes["value"] = "2";
    NewsCheckList.Items[2].Attributes["value"] = "3";
    

    So I decided the best way forward would be to create a custom CheckBoxList control that would contain a value attribute. I based my code from an old (but very useful) article that can be found here.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.UI.WebControls;
    using System.IO;
    using System.Web.UI;
    using System.Collections;
    using System.ComponentModel;
    
    namespace Site.WebControls
    {
        [DefaultProperty("Text"),
        ToolboxData("<{0}:CheckBoxValueList runat=server></{0}:CheckBoxValueList>")]
        public class CheckBoxValueList : CheckBoxList
        {
            protected override void Render(HtmlTextWriter writer)
            {
                StringBuilder sb = new StringBuilder();
                TextWriter tw = new StringWriter(sb);
                
                HtmlTextWriter originalStream = new HtmlTextWriter(tw);
                base.Render(originalStream);
                string renderedText = sb.ToString();
    
                int start = 0;
                int labelStart = 0;
                int end = renderedText.Length;
    
                for (int i = 0; i < this.Items.Count; i++)
                {
                    StringBuilder itemAttributeBuilder = new StringBuilder();
    
                    end = renderedText.Length;
                    start = renderedText.IndexOf("<input", start, end - start);
                    labelStart = renderedText.IndexOf("<label", start, end - start);
    
                    this.Items[i].Attributes.Render(new HtmlTextWriter(new StringWriter(itemAttributeBuilder)));
    
                    renderedText = renderedText.Insert(labelStart + 7, itemAttributeBuilder.ToString() + " ");
                    renderedText = renderedText.Insert(start + 7, String.Format("{0} value=\"{1}\" ", itemAttributeBuilder.ToString(), this.Items[i].Value));
                    start = renderedText.IndexOf("/>", start, renderedText.Length - start);
                }
                
                writer.Write(renderedText);
            }
        }
    }
    
  • Published on
    -
    2 min read

    Has Facebook Redefined Friendship?

    Definition Of FriendI was a late bloomer when when it came to joining the social networking giant that is Facebook (around late 2007). The only reason I can remember for ever joining the site was just because all people around me were submitting their profiles like crazy. Not wanting to miss out on this new trend, I decided to “pop” my social networking cherry and take the plunge!

    Looking back on my first experience on Facebook I was amazed at how easily I could connect with friends and people I used to know from a past life (school, work etc). Within a few months my Facebook profile spread through the social networking vine in quick haste and found myself receiving friend requests. But it became ever so prevalent that the people who requested me to add them as a friend weren’t people I would necessarily call a friend. I knew of them and that is where my connection ends. So in some ways Facebook has redefined the term “friend”.

    Facebook has broken down the friendship barriers considerably. Its made it really easy. Too easy in fact. It was only a couple days ago when my sister said: “Look! I got more friends than you!”. In all honesty I wasn’t really bothered…ok maybe a little. This is where personal feelings come into play.

    One of the feelings I will call: “Facebook guilt”. Facebook guilt is when you receive a friend request and don’t act on it. You simply ignore it hoping they would just forget or even worse…remove their request altogether. Hoping by not accepting their friend request you haven’t made an enemy or caused emotional discourse.

    Then there is “Facebook rejection”. An example of this is the following conversation I had with with a work mate of mine a few years back:

    Anonymous friend: I’ve sent you a Facebook friend request. Me: Ok cool. Anonymous friend: How come you haven’t approved it yet? Me: Mate, I’ve been on holiday for over a week and haven’t checked Facebook yet. I’ll do it today. Anonymous friend: Thanks Surinder!

    I was surprised that he took not responding to his friend request as a personal hit.

    Social Networking sites have created a trend that makes us more interested in the number of people in our social circles rather than the relationships we have with them.

    So where do I stand in the social networking medium? My Facebook activity has drastically declined over the years. Currently, I have 114 friends with majority of them I know quite well and only a handful of them I haven’t really met. Nowadays, I have become more of a tweeter. I just feel that Twitter has met my social needs over Facebook. Its just more flexible and open. If someone likes you they follow you, if not they don’t.

  • Published on
    -
    1 min read

    EaseUS Todo Backup Disk Clone Tool…It’s Good!

    Earlier today, I decided to upgrade my laptop’s hard drive to a larger capacity disk. As we all know, the most straight-forward method of carrying this out is by cloning the existing drive onto your new disk of choice. Originally, I was planning on purchasing “Acronis True Image” since this is something I’ve used it in the past and makes cloning any disk a cinch!

    I decided to look for some freely available cloning software available online, instead of having to pay £30 for software I won’t be using that often. Yes I am that tight! :-) In all honesty, I wasn’t expecting to find anything substantial but I was surprised to find a great piece of cloning software called “EaseUS Todo Backup” free edition. EaseUS Todo Backup software not only had the ability to clone a disk but also had the following useful features:

    • Backup – on selected files, partitions or your entire computer
    • Recovery
    • Scheduled backup plan

    I am happy to report that I managed to clone the whole of my disk drive successfully within 2.5 hours (based on 126GB of data). Whoever said nothing in life is free!

    You can download EaseUS Todo Backup here.

  • Published on
    -
    3 min read

    BlogEngine Disqus Comment Count Fix

    For those of you that have decided to opt out of using BlogEngine’s default commenting system and instead, use Disqus platform will probably encounter a minor issue. The minor issue being the fact that the comment count displayed in within post view doesn’t actually work.

    I needed to make a few modifications to the way Disqus is used within BlogEngine. I have to say that I wasn’t exactly impressed with the way Disqus was setup within the JavaScript code (maybe over-exaggerating). You’ll see what I mean from the Disqus JavaScript code found in “post.aspx” and “page.aspx”:

    <script type="text/javascript">
        var disqus_url = '<%= Post.PermaLink %>';
        var disqus_developer = '<%= BlogEngine.Core.BlogSettings.Instance.DisqusDevMode ? 1 : 0 %>';
        (function() {
            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
            dsq.src = 'http://<%=BlogEngine.Core.BlogSettings.Instance.DisqusWebsiteName %>.disqus.com/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
        })();
    </script>
    

    I believe that additional Disqus variable’s should be used, such as:

    • disqus_title - Tells the Disqus service the title of the current page.
    • disqus_identifier -  If this variable is undefined, the page's URL will be used. The URL can be unreliable, such as when renaming an article slug or changing domains, so its recommended using your own unique way of identifying a thread.

    After you have made this change, your JavaScript should look like this:

    <script type="text/javascript">
        var disqus_title = '<%=Post.Title %>';
        var disqus_identifier = '<%= Post.Id.ToString() %>';
        var disqus_url = '<%= Post.AbsoluteLink %>';
        var disqus_developer = '<%= BlogEngine.Core.BlogSettings.Instance.DisqusDevMode ? 1 : 0 %>';
        (function() {
            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
            dsq.src = 'http://<%=BlogEngine.Core.BlogSettings.Instance.DisqusWebsiteName %>.disqus.com/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
        })();
    </script>
    

    You may or may not have noticed the “disqus_url” is getting assigned the Post.AbsoluteLink rather than Post.PermaLink. I prefer using the AbsoluteLink since it will output a nice clean friendly URL.

    The next thing we need to do is modify the “PostView.ascx” file found in your themes folder. The line we are looking for is where the Disqus comments link is set.

    <% if (BlogEngine.Core.BlogSettings.Instance.ModerationType == BlogEngine.Core.BlogSettings.Moderation.Disqus)
    { %>
        <a rel="nofollow" href="<%=Post.PermaLink %>#disqus_thread"><%=Resources.labels.comments %></a>
    <%}
        else
    { %>
        <a rel="bookmark" href="<%=Post.PermaLink %>" title="<%=Server.HtmlEncode(Post.Title) %>">Permalink</a> |
        <a rel="nofollow" href="<%=Post.RelativeLink %>#comment"><%=Resources.labels.comments %> (<%=Post.ApprovedComments.Count %>)</a>   
    <%} %>
    

    We need to make two changes to the current comments code. Firstly, we need to add an important missing attribute to the anchor tag. The missing tag is the “data-disqus-identifier”. This is recommended practice by the Disqus Developer guide. Secondly, we need to change the “href” attribute to use an AbsoluteLink instead of a PermaLink. The code should now look like this:

    <% if (BlogEngine.Core.BlogSettings.Instance.ModerationType == BlogEngine.Core.BlogSettings.Moderation.Disqus)
    { %>
        <a rel="nofollow" href="<%=Post.AbsoluteLink %>#disqus_thread" identifier="<%= Post.Id.ToString() %>"><%=Resources.labels.comments %></a>
    <%}
        else
    { %>
        <a rel="nofollow" href="<%=Post.RelativeLink %>#comment"><%=Resources.labels.comments %> (<%=Post.ApprovedComments.Count %>)</a>   
    <%} %>
    

    From personal experience, I believe it is best to carry out the “post.aspx” and “page.aspx” code changes before moving onto the Disqus platform. If you currently have comments that need to be exported to Disqus, I found this exporter tool really useful. Be prepared to carry out a few Disqus imports to get things exactly right.

  • I needed to implement a message board for users to comment on individual articles stored within my Kentico site. To achieve this, I decided to use a message board. Initially, what I found when I implemented the message board web part to my article template was that submitted comments for individual articles were getting displayed on all other articles.

    In my page I am using two Kentico controls: MessageBoardViewer to output the list of comments and MessageBoard for the comments form.

    <%@ Register Src="/CMSWebParts/MessageBoards/MessageBoard.ascx" TagName="MessageBoard" TagPrefix="cms" %>
    <%@ Register Src="/CMSWebParts/MessageBoards/MessageBoardViewer.ascx" TagName="MessageBoardViewer" TagPrefix="cms" %>
    
    <cms:MessageBoardViewer ID="MessageBoardViewer1" runat="server" Enabled="true" HideControlForZeroRows="false" DisplayOnlyApproved="true" DisplayToRoles="Registered;Paid" ShowForDocumentTypes="NewsSite.News" ZeroRowsText="No Messages in viewer" TransformationName="Community.Transformations.MessageBoard" AlternatingItemTransformationName="Community.Transformations.MessageBoard"></cms:MessageBoardViewer>
    <cms:MessageBoard ID="MessageBoard1" BoardModerated="true" runat="server" BoardUseCaptcha="false" BoardAccess="AllUsers" DisplayToRoles="Paid" BoardOpened="true" BoardRequireEmails="false"  BoardEnableSubscriptions="true" ></cms:MessageBoard>
    

    I came across a fix on the (very informative) Kentico forums whereby a user carried out a where condition on the MessageBoardViewer control to retrieve article comments through the “BoardDisplayName” field:

    MessageBoardViewer1.WhereCondition = 
        String.Concat("BoardDisplayName = '", 
                        CMSContext.CurrentDocument.GetValue("Title"), " (", 
                        CMSContext.CurrentDocument.DocumentNamePath, 
                      ")'"); 
    

    Some of you may not know, the Board Display Name field is also used in the Message board section within CMS Desk.

    Kentico Message Board Admin

    Retrieving comments based on the Board Display Name is in my opinion not the best way. As you can see from the title of my document (above) contains single quotes. This would cause an SQL syntax error (which I did experience).

    To get around this, it is best to query the MessageBoardViewer control using the “BoardDocumentID” field. So the code will be as follows:

    MessageBoardViewer1.WhereCondition = 
        String.Concat("BoardDocumentID = ", 
                        CMSContext.CurrentDocument.DocumentID); 
    

    If anyone knows of a better way of achieving the same thing. Please leave a comment. I am relatively new to Kentico and probably missed a trick!

  • Published on
    -
    1 min read

    BlogEngine: There was an error in callback issue

    Whilst carrying out some tests on my blog after upgrading my blog platform from BlogEngine 1.6 to 2.0, I noticed an error occurring when a comment was in process of getting submitted. The error that cropped up was: “There was an error in callback”. The strange thing about this error was that it only occurred for Internet Explorer users. In other mainstream browsers (I do not class Internet Explorer as a mainstream), my comments were successfully submitted.

    There Was Error In Callback

    As it turns out, the issue was due to one of my BlogEngine extensions. When I disabled the “Recaptcha” extension all worked as expected. I still need to investigate what is causing the “Recaptcha” extension to error since this is one of the most important extensions to void all spammers out there.

    Recaptcha Extension

    So if you are also experiencing a similar error, disabling the Recaptcha extension may help.

    I will post further updates if I manage to get the commenting system working using Recaptcha. But since BlogEngine is now supporting the Disqus commenting platform, I may decide to make the move.

  • Published on
    -
    1 min read

    SharePoint Internal Column Names

    I needed to create a web part that simply output all information from an Announcements list. Sounds simple doesn’t it? But I came across a compiler error when using the “Created By” and “Modified By” columns. The error was telling me that the columns I am trying to read in my code do not exist.

    After some Googling, I found out that SharePoint has something called “Internal Field Names”, whereby the display name of a column isn’t the actual column name. The full list of internal field names can be found at Michael Yeager's MSDN Blog.

    If ever in doubt, you can find out the internal field names within SharePoint, by carrying out the following:

    1. Go to your list and select “List Settings” from the ribbon.

    2. Navigate to the where the list of columns are displayed and right click on the column in question. Select “Properties”.

    SP2010 Hidden Field Right Click

    1. When the link property window opens, scroll to the end of the “Address: (URL)” section. You will find a query string parameter called “Field”. This query string parameter contains the real field name.

    SP2010 Hidden Field Properties

    Confusing isn’t it? Well I guess it wouldn’t be SharePoint if the most simplest task failed to confuse a developer.

  • Published on
    -
    2 min read

    Using SPMetal in SharePoint 2010

    One of the best development features in making customisations within a SharePoint environment is the SPMetal tool. The SPMetal tool generates entity classes in order to use LINQ syntax to retrieve items from lists. The SPMetal.exe resides in the 14/bin folder. I will show you a quick demonstration on how I have generated a DataContext class using the SPMetal executable.

    You will need to create two files:

    1. XML file – containing the list or library name we are interested in generating our class from. In the code snippet (below), the list I am interested in is called Quicklinks.
    <?xml version="1.0" encoding="utf-8"?>
    <Web xmlns="http://schemas.microsoft.com/SharePoint/2009/spmetal">
      <List Name="Quicklinks" Member="Quicklinks" />
      <ExcludeOtherLists />
    </Web>
    

    Save the XML file into the 14/bin director and name it “SPMetalConfig.xml”.

    1. Batch File – will contain the SharePoint command prompt needed to fire the SPMetal executable. Creating a batch file is not required. You can run the command as normal through Windows Command Line. I just find it a lot easier to manage and make changes using a batch file.
    SET SPMETALDIR="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\BIN\" 
    
    cd %SPMETALDIR% 
    
    spmetal.exe /web:http://myintranet /code:QuicklinksOMEnitites.cs /parameters:SPMetalConfig.xml
    

    Once this has run, a class called “QuicklinksOMEnitites.cs” will be generated in the 14/bin folder.

    SPMetal.exe

    One thing I did find when using SPMetal for retrieving list data to be output to a custom webpart was that it is only able to retrieve data from a site collection the list resides. But this is probably to be expected. So if the webpart was used in a separate site collection, no data will be shown. In order to get around this, SPMetal will not suffice. You will need to go through the code route and do the following:

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        using (SPWeb intranetSite = new SPSite("http://myintranet/sites/depts/").OpenWeb())
        {
            SPList quickLinks = intranetSite.Lists.TryGetList("Quicklinks");
            
            if (quickLinks != null)
            {
                //Do something with list data.
            }                           
        }
    });