MVC Custom Extension Methods

I've been toying around with MVC for quite some time now. Initially, I couldn't imagine breaking away from the safety-net that is ASP.NET Web Forms. What many developers are not aware of when moving over to the ASP.NET MVC framework is that you have to write everything from scratch. You will not have the comfort of dragging and dropping event driven controls in a GUI-centric way.

But nowadays, I am itching to build new sites in MVC. I like to be in control of the whole page lifecycle and the mark-up that is generated.

Since there are no pre-built resusable controls, I decided start developing my own library of extensions that I could use in future MVC projects I work on. Ranging from pagination to tag clouds.

Creating custom extensions is really easy. I started off by creating a Category Navigation that returns a IHtmlString (HTML-encoded string that should not be encoded again).

public static IHtmlString CategoryNavigation(this WebViewPage wvp)
{
    StringBuilder navBuilder = new StringBuilder();

    List<CustomCategory> categories = CustomCategoryLogic.GetCategories();

    if (categories.Count > 0)
    {
        navBuilder.Append("<ul class=\"nav\">");
        navBuilder.Append("<li><a href=\"/\">Home</a></li>");

        foreach (CustomCategory cc in categories)
            navBuilder.AppendFormat("<li><a href=\"/{0}\">{1}</a></li>", cc.Slug, cc.Name);

        navBuilder.Append("</ul>");
    }

    return MvcHtmlString.Create(navBuilder.ToString());
}

To display my category navigation in one of my Views, I just need to write:

@this.CategoryNavigation()

How easy is that!?

Some New Custom Form Controls I've Been Working On In Kentico...

Over the last few projects I've been working on, I started to notice that clients are requiring increased integration with social platforms that give them the ability to display key elements from well known social platforms, such as YouTube, Twitter and Instagram. Hence the reason why in the past I created a YouTube Form Control that would easily retrieve all information information about a video along with their screen caps by simply entering the YouTube URL.

Recently, I've been working on two more form controls involving Twitter and Instagram to further enhance social platform integration within Kentico from a user standpoint, which (I think) is quite neat!

Twitter

Using a combination of OAuth and Twitter's GET statuses/show/:id API endpoint, I was able to store within Kentico all JSON data relating to a tweet by just entering the ID. One major advantage to storing JSON data is that we can display the tweet as many times as we want throughout the site without worrying about breaching API limits.

In addition, individual elements of a tweet, such as the embedded image, hash tags and author information can be used when required.

Tweet Custom Form Control

As you can see (above), I am using Twitter's Embedded Tweet plugin to display the tweet in a nice graphical representation so that the site administrator is able to view contents of the tweet prior to publishing live.

Instagram

Like the Twitter control above, details of an Instagram image is retrieved in a similar fashion, whereby I'm storing all the details in JSON format.  In this case, I'm using a combination of two Instagram API endpoint's:

  • /oembed - to get the core information of an image by passing in the full URL of where the image resides. This will return important piece of information: the true ID of the image.
  • /media/media-id - to get all information about the media or video object. This information will be stored in Kentico.

Unlike Twitter, Instagram's API is a breeze to implement. There are no API limits (at time of writing) and all you need to access the endpoints is to generate a one time only access token.

Instagram Custom Form Control

By copying and pasting the link of an Instagram image will return all object information and display the image/video within CMS Desk.

I will at some point write a blog post on how I created these two controls once I have refactored all the code into one single control. At the moment, some key functionality is segregated into separate class libraries.

Kentico Certified Developer

A couple days ago I passed my Kentico exam. If anything, I think I've learnt more about Kentico and just how much the platform has to offer. The exam is filled with a wide range of questions from the very simple and straight-forward to the ones that require a more time for deep thought.

In fact, I found the first few set of questions so simple, it got me second guessing myself. I'll admit, I found the exam a little tricky and there are some questions you have to read very carefully, especially ones around K# syntax.

I dedicate this certification to all the awesome guys at Syndicut. I seriously couldn't have done it without them.

I guess I can now display this:

Kentico Certified Developer Logo

There's Nothing Like a SSD To Breath Life Back Into Your Computer...

Crucial 480GB SSDThe plan originally was to ditch my current laptop, Alienware M11x R3 for something a little more recent with a better build quality. Even though my Alienware is an amazing workhorse for the type of work I do (with a very high spec), I started to get annoyed with the common issue these laptop's have: screen touching the keyboard when closed.

I wanted to get an Apple MacBook Pro Retina. But that got thrown completely out the window when I decided to go on the path of getting a property! Eek! So I had to make do with what I currently have on a very modest budget.

As of late, I started noticing that my laptop was getting very sluggish and kept freezing every so often. This continued even after carrying a full factory format to give my Operating System a fresh install. The only thing I could amount this to was that my hard drive was on its way out.

Luckily for me, at the same time, Amazon had some great offers in their computer components section and managed to get a Crucial 480GB Solid State Drive at a price that was an absolute steal!

I've heard online and from a few friends of mine that once you go SSD, you definitely won't go back...and this truly is the case. I wasn't expecting to see so much of a performance increase. My laptop has never performed this well.

At the same time, I decided to upgrade my current Operating System to Windows 8. I was getting a little bored of Windows 7. Plus, I quite like the new tiles interface. Very pretty! I don't understand the complaints or negativity. Some are obviously scared of change...but that's for a future blog post.

Here are a few things I've noticed since my upgrade:

  • Boot times have minimised substantially.
  • My laptop always used to feel very warm during long-term usage. Now it always feels cool.
  • I'm sure battery times have improved.
  • Virtual Machines load in seconds, rather than minutes.

Upgrading to a SSD is a very cheap and easy way to get more out of your machine. Highly recommended!

Official Google Nexus 7 (2013) Case Review

Nexus 7 Case Google LabelEver since I purchased my Nexus 7 last year. I've been trying to find a nice case for it. Failing, I settled for a cheap and cheerful folio case from eBay, which (still to this day) has served me well. But I was dying to have a case that looked different and oozed some unique design elements.

When I noticed Google selling their own collection of Nexus 5 and 7 cases, I purchased one straight away. The Grey/Blue colour scheme caught my eye. It seemed that Google's offering ticked all the boxes. What could they possibly do wrong? It's an official product designed and manufactured by the very people who made the Nexus 7. If anyone could make a case without fault, it would have to be Google....right?

Sadly no.

For starters, the case lacks magnet technology allowing automatic power on/off feature when opening the case. Secondly, there was no type of latch that would keep the case closed and found that the case opened whilst it was moving around in my backpack. Maybe I just had high expectations since my current offering already had these features.

Yes. These might be small things. But I found myself getting increasingly agitated (maybe an overstatement!) whilst using my Nexus 7, especially for a case that cost four times the price of the case I previously used.

Nexus 7 Case - Outside

Nexus 7 Case - Inside

It wasn't all doom and gloom. There were things I did like about Google's case offering. I loved that the case looked and felt very different to what is available on the market currently. Outside was covered with hard wearing fabric with an inner lining of suede. Definitely high quality stuff! 

Unfortunately, Google just seemed to miss the mark by not including a few key features, mainly being the magnetic sensor.

Back to Google it goes.

Update - 11/02/2014

I was expecting to pay for all postage costs to return the case. But after contacting Google Support regarding the reasons to why I wanted to return the item, they sent me a prepaid shipping package and were very helpful throughout the return process. Quick and easy!

Custom Form Control To Select A Folder In Media Library

I had a need to have the ability to select a folder from within the site's media library. Not a file. A folder. The idea behind this requirement was to allow the site administrator to upload a bunch of images to a single directory in the media library, so that the contents (in this case images) could be output to the page.

Unfortunately, after contacting Kentico support, I was told that such a folder selector control does not exist and I would need to create one myself. So I did exactly that!

Step 1: Create A New User Control

I have created a user control in "/CMSFormControls/Surinder/" of my Kentico installation. I have named the user control: FolderSelector.ascx.

HTML

<table>
        <tr>
            <td class="EditingFormValueCell">
                <asp:TreeView ID="MediaLibraryTree" SelectedNodeStyle-BackColor="LightGray" ExpandDepth="0" ImageSet="Arrows" runat="server"></asp:TreeView>
            </td>
        </tr>
</table>

Code-behind

using CMS.CMSHelper;
using CMS.FormControls;
using CMS.GlobalHelper;
using CMS.MediaLibrary;
using CMS.SettingsProvider;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class CMSFormControls_iSurinder_FolderSelector : FormEngineUserControl
{
    private string _Value;

    public override Object Value
    {
        get
        {
            return MediaLibraryTree.SelectedValue;
        }
        set
        {
            _Value = System.Convert.ToString(value);
        }
    }

    public string MediaLibraryPath
    {
        get
        {
            //Get filter where condition format or default format
            return DataHelper.GetNotEmpty(GetValue("MediaLibraryPath"), String.Empty);
        }
        set
        {
            SetValue("MediaLibraryPath", value);
        }
    }

    public override bool IsValid()
    {
        bool isControlValid = true;

        if ((FieldInfo != null) && !FieldInfo.AllowEmpty)
        {
            this.ValidationError = "Please select an Image Gallery directory";
            isControlValid = false;
        }

        return isControlValid;
    }

    protected void EnsureItems()
    {
        if (MediaLibraryPath != String.Empty)
        {
            string fullPath = Server.MapPath(String.Format("~/{0}", MediaLibraryPath));

            if (Directory.Exists(fullPath))
            {
                DirectoryInfo rootDir = new DirectoryInfo(fullPath);

                TreeNode treeNodes = OutputDirectories(rootDir, null);

                MediaLibraryTree.Nodes.Add(treeNodes);
            }
            else
            {
                this.ValidationError = "Directory path does not exist.";
            }
        }
        else
        {
            this.ValidationError = "Properties for this control have not been set.";
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
            EnsureItems();
    }
    
    TreeNode OutputDirectories(DirectoryInfo directory, TreeNode parentNode)
    {
        if (directory == null)
            return null;

        //Create a node for directory
        TreeNode dirNode = new TreeNode(directory.Name, directory.FullName);

        //Get subdirectories of the current directory
        DirectoryInfo[] subDirectories = directory.GetDirectories();

        //Mark node as selected
        if (dirNode.Value == _Value.ToString())
            dirNode.Selected = true;

        //Get all subdirectories
        for (int d = 0; d < subDirectories.Length; d++)
            OutputDirectories(subDirectories[d], dirNode);
                
        //If the parent node is null, return this node
        //otherwise add this node to the parent and return the parent
        if (parentNode == null)
        {
            return dirNode;
        }
        else
        {
            parentNode.ChildNodes.Add(dirNode);

            return parentNode;
        }
    }
}

I'm hoping that the code I've shown above is quite self-explanatory. But the only thing you need to be aware of is the "MediaLibraryPath" public property. You will see in the next steps that we will be using this property to contain a link to where our Media Library resides.

Step 2: Add New Control To Kentico

When creating a custom form control in Kentico, ensure we have the following form control settings:

Kentico Folder Selector Settings

Step 3: Add Form Control Property

Remember, from Step 1, we had a property called "MediaLibraryPath". Now we just need to create this property in our custom control settings.

Kentico Folder Selector Settings

Now, when our Folder Selector control is added to a document, we will need enter a map path to the location of our Media Library. For example, "/Surinder/media/Surinder/".

If this custom control has been implemented successfully, you should see something like this when creating a new page based on a document type:

Kentico Folder Selector Tree

Easy Way to Generate Strongly-Typed C# Classes From JSON

In nearly all my previous projects I've worked on required some kind of manipulation with reading some form of JSON data.

To allow better integration into my application, I always create strongly-typed classes that mirror the structure of the incoming data feed. This in turn allows me to serialize the JSON and select specific properties I require. But sometimes, its quite difficult and confusing to the exact class structure right, especially when the JSON contains lots of fields of data.

When I find this is the case, I use json2csharp.com. By simply pasting the contents of your JSON, the site does all the hard work and creates all the strongly-typed classes for you.

Experts Exchange: Does The Pay for An Answer Model Work?

In one word: No.

I've been an Experts Exchange user on and off over the last few years and always re-registered my Experts Exchange account, at times, out of pure desperation in the hope that a complex question of mine could be answered.

If I look back at all the questions I've asked throughout the year whilst being a fully paid member, the responses (or solutions as Experts Exchange call it) are by far not detailed enough for the price you pay. There have been many times when I've been very patiently waiting for some kind of response to my problem for days and even when highlighting to the moderator numerous times to get an expert to look into my issue, they seem to fail at the first hurdle...

If Experts Exchange was truly the forum where all these so called "experts" reside, they should have no problem in resolving or if not at least assisting me to a relevent solution. Majority of the time its hit or miss to whether an answer I could either find an answer from their "vast" knowledge-base.

The major problem I do have with Experts Exchange is that there is no refund policy and the customer support staff don't seem at all bothered by the fact that (in my case) four of my questions were not responded to. They are unable to see that you are paying them a service to do one thing: assist YOU!

Experts Exchange really need to rethink their pricing model considerably for the true service they provide. This has become ever so apparent since the dawn of a widely used and popular StackOverflow Q&A forum where I find the response rate higher.

Of course, I can only speak about my own experience and Experts Exchange is probably a great resource for others who are employed in a different sector of the IT industry. It all comes down to the expert answering your question. Some are really good, some not so good...

Unfortunately, it's unable to fulfil my needs. I've learnt my lesson and will not be renewing my subscription after my last cancellation.

Back in the day, there was a need for a paid service like Experts Exchange. But that's long since passed.

Instagram API: Get Access Token In ASP.NET

I've written some code that outputs images using Instagram's Developer API. The code can either output images based on a user's profile or via search term.

As you may already know, in order to get any form of information from any external API an access token is required. Before we dive into some code, the first thing that we need to do is register ourselves as an Instagram Developer by going to: http://instagram.com/developer/.

Next, we need to register a new client specifically for our intended use. In my case, all I want to do is to get all image information from my own Instagram profile.

Instagram API - Register New Client

Here, you will be supplied with Client ID and Client Secret codes. But most importantly, you will need to set an OAuth Redirect URL (or Callback URL) for user's to authenticate your application.

The strange thing I've noticed about the Instagram API is that a callback page is a compulsory requirement. Even if you are planning on carrying out something as simple as listing some images from your own profile where a public users intervention is not required.

I'm not interested in their images, I'm interested in my own. I hope Instagram changes this soon. If Twitter can allow you to retrieve tweets by simply registering your application, why can't Instagram?

From what I've read on Instagram's Google Group's is that an access token needs to only be generated once and they don't expire. But of course Instagram have stated:

"These tokens are unique to a user and should be stored securely. Access tokens may expire at any time in the future."

Just make sure you have some fail safe's in your code that carries out the re-authentication process within your application on the event access token has expired. In my own implementation, I've kept the callback page secret and new access token requests can be made within an Administration interface.

So lets get to the code.

Step 1: Authentication Request Classes

These strongly-typed classes mirror the exact structure of the JSON returned from our authentication request. Even though we only require the "access_token" property, I've added additional information, such as details on the Instagram user making the request.

public class AuthToken
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }

    [JsonProperty("user")]
    public InstagramUser User { get; set; }
}
public class InstagramUser
{
    [JsonProperty("id")]
    public string ID { get; set; }

    [JsonProperty("username")]
    public string Username { get; set; }

    [JsonProperty("full_name")]
    public string FullName { get; set; }

    [JsonProperty("profile_picture")]
    public string ProfilePicture { get; set; }
}

It's worth noting at this point that I'm using Newtonsoft.Json framework.

Step 2: Callback Page

protected void Page_Load(object sender, EventArgs e)
{
    if (!String.IsNullOrEmpty(Request["code"]) && !Page.IsPostBack)
    {
        try
        {
            string code = Request["code"].ToString();

            NameValueCollection parameters = new NameValueCollection();
            parameters.Add("client_id", ConfigurationManager.AppSettings["instagram.clientid"].ToString());
            parameters.Add("client_secret", ConfigurationManager.AppSettings["instagram.clientsecret"].ToString());
            parameters.Add("grant_type", "authorization_code");
            parameters.Add("redirect_uri", ConfigurationManager.AppSettings["instagram.redirecturi"].ToString());
            parameters.Add("code", code);

            WebClient client = new WebClient();
            var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "POST", parameters);

            var response = System.Text.Encoding.Default.GetString(result);

            var jsResult = JsonConvert.DeserializeObject(response);

            //Store Access token in database
            InstagramAPI.StoreAccessToken(jsResult.AccessToken);

            Response.Redirect("/CallbackSummary.aspx?status=success", false);
        }
        catch (Exception ex)
        {  
            EventLogProvider.LogException("Instagram - Generate Authentication Key", "INSTAGRAM", ex);

            Response.Redirect("/CallbackSummary.aspx?status=error");
        }
    }
}

As you can see, I'm redirecting the user to a "CallbackSummary" page to show if the authentication request was either a success or failure. (Remember, the page is secured within my own Administration interface.)

If the request is successful, the access token is stored.

Step 3: Request Callback Page

The last piece of the puzzle is to actually request our callback page by authorizing ourselves via Instagram API. In this case, I just have a simple page with the following mark up:

<p>If Instagram fails to output images to the page, this maybe because a new Authorisation key needs to be generated.</p>
<p>To generate a new key, press the button below and follow the required steps.</p>
<a onclick="window.open('https://api.instagram.com/oauth/authorize/?client_id=<%=ConfigurationManager.AppSettings["instagram.clientid"].ToString() %>&redirect_uri=<%=ConfigurationManager.AppSettings["instagram.redirecturi"].ToString() %>&response_type=code', 'newwindow', config='height=476,width=641,toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no,directories=no, status=no'); return false;" href="#" target="_parent">Generate</a>

If all goes to plan, you should have successfully recieved the access token.

I will post more Instagram code in future posts.

C# In Depth by Jon Skeet Review

C# In Depth Third EditionWhen working as a programmer, it's really easy to continue coding in the same manner you have done since you picked up a language and made your first program.

The saying: "Why fix it if it ain't broken?" comes to mind...

I for one sometimes fail to move with the times (unknowingly to me) and find new and better ways of coding. It's only on the off chance I get introduced to different approaches through my work colleague or whilst Googling for an answer to one of my coding queries.

After reading some rave reviews on C# In Depth, written by the one and only Stackoverflow god: Jon Skeet. I decided to part with my hard earned money and make a purchase.

C# In Depth is different from other programming books I've read on C#. In fact it's really good and don't let the title of the book deter you. The contents is ideal for novice and semi-experienced programmers.

Firstly, you start off by being shown code samples on how C# has evolved through its iterations (v1 - v4). In most cases I gave myself a gratifying pat on the back when I noticed the approaches I've taken in my own projects utilised practises and features of the current language. ;-)

Secondly, unlike some programming books I've read in the past, it's not intimidating to read at all. Jon Skeet really has a great way to talk about some concepts I find difficult to comprehend in a clear a meaningful way, so I could utilise these concepts within my current applications.

The only minor niggle I have is that there were a few places where I would have liked specific chapters to go into more detail. On the other hand, it gave me the opportunity to research the nitty-gritty details for myself.

Since I purchased this book, I found myself referencing it many times and appreciating what C# has to offer along with it misconstrued and underused features.

All in all, the author truly has a gift in clearly demonstrating his understanding on the subject with finesse and if I am able to comprehend even one-tenth of his knowledge, I will be a happy man.