Left Navigation Site Links Not Appearing In MOSS 2003

If any of you have come across a problem in SharePoint 2003 whereby some users are not able to see a link to an area within the main portal page, the solution couldn't be even easier. Ensure all users required to access the area are setup with access rights for that area. I always thought that even if a user does not have access to an area the link will always be shown in the navigation within the main portal site. Obviously I was wrong. Silly me!

What's The Difference Between NULL and DBNull

I always used NULL and DBNULL interchangeably in my coding around my database results without ever considering what were the differences. Fortunately, I stumbled upon a great blog written by Bilal Haidar, "Difference between NULL and DBNull"

If I understand correctly, you use DBNULL to check if a certain field in a database is null and you would use NULL to check if a whole record is not found in the database.

The Google Chrome Comic Strip

I have to say that I am quite impressed with the way Google markets its own applications and services. Who would ever had thought of using a comic string to introduce the key workings of a specific application? Its a lengthy comic to say the least, consisting of 38 “fun filled” pages, which actually makes learning about the Chrome browser an interesting read.

Google Chrome Comic 1

Google Chrome Comic 2

But this does ask the question on why Google is releasing their own browser? I thought they had extended their search deal with Mozilla Firefox in return for setting Google as the default search engine. I guess this may cause an awkward relationship between the two in the future. But I suppose any attack against the dreaded Microsoft Internet Explorer browser can only be a benefit!

I have to say that the guy wearing the glasses on the left bares a striking (less cool) resemblance to me. :-)

You can view the full comic strip here.

Outputting Custom Made Charts To An ASP.NET Page

A few weeks ago I was trying to implement a Bar and Pie Chart for a report in a web application. I found that most of the charting solutions on the web cost an arm and a leg. So I decided to have a bash at creating my own one.

I have been reading through the MCTS Application Development Foundation book and found a couple of chapters on using System.Drawing namespace to output graphics and create Pie Charts in a C# application. Great stuff! However, I encountered a problem when my Chart was rendered within a web page that contains other HTML content. For some reason there was no HTML in my page and all that was displayed was my Chart.

This is how I wanted my chart to be inserted into my page:

ChartScreenshot1

However, when my charting code was added, my page looked like this:

ChartScreenshot2

After investigating this problem further it seems that when you output the chart image to a stream the whole page is rendered as an image which removes all the HTML. For example:

Response.ContentTye = "image/gif"; //MIME type
Bitmap.Save(Response.OutputStream, ImageFormat.Gif);

In order to get around this problem required quite a strange work around:

  1. In the page where you need to the chart to be displayed (we will call Report.aspx) add an ASP Image control that will link to an .aspx page that will contain your chart. Things will become more clearer in the next step.
<asp:Image ID="imgSelfAverageBarChart" ImageUrl="/Charts/BarChart.aspx" runat="server" />
  1. Create a new ASP.NET page that will contain all the code for your chart (we will call BarChart.aspx). Now you might be thinking how can I send the figures to the chart? Well this can be done be using Session variables or parameters within the web page link that you used in your ImageUrl in the Report.aspx page.
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public partial class BarChart : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            List<string> Questions = new List<string>();
            List<float> Values = new List<float>();
    
            //Check the session values have values
            if (Session["Sections"] != null && Session["SelfAverageValue"] != null)
            {
                Questions = (List<string>)Session["Sections"];
                Values = (List<float>)Session["SelfAverageValue"];
            }
    
            Bitmap imageBitmap = new Bitmap(600, 285);
            Graphics g = Graphics.FromImage(imageBitmap);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.Clear(Color.White);
    
            Brush[] brushes = new Brush[5];
            brushes[0] = new SolidBrush(Color.FromArgb(255, 216, 0));
            brushes[1] = new SolidBrush(Color.FromArgb(210, 219, 252));
            brushes[2] = new SolidBrush(Color.FromArgb(0, 127, 70));
            brushes[3] = new SolidBrush(Color.FromArgb(0, 148, 255));
            brushes[4] = new SolidBrush(Color.FromArgb(190, 99, 255));
    
            int xInterval = 70;
            int width = 60;
            float height = 0;
    
            //Draw the Pie Chart
            for (int i = 0; i < Values.Count; i++)
            {
                height = (Values[i] * 40);        // adjust barchart to height of Bitmap
                //Draws the bar chart using specific colours
                g.FillRectangle(brushes[i], xInterval * i + 50, 260 - height, width, height);
                //Draw legend
                g.FillRectangle(brushes[i], 420, 25 + (i * 50), 25, 25);
                g.DrawString(Questions[i], new Font("Arial", 8, FontStyle.Bold), Brushes.Black, 450, 31 + (i * 50));
                // Draw the scale
                g.DrawString(Convert.ToString(Math.Round(Convert.ToDecimal(Values[i]), 2)), 
                new Font("Arial", 10, FontStyle.Bold), Brushes.Black, xInterval * i + 45 + (width / 3), 300 - height);
                // Draw the axes
                g.DrawLine(Pens.Black, 40, 10, 40, 260);        //   y-axis
                g.DrawLine(Pens.Black, 20, 260, 400, 260);       //  x-axis
            }
    
            Response.ContentType = "image/gif";
            imageBitmap.Save(Response.OutputStream, ImageFormat.Gif);
            imageBitmap.Dispose();
            g.Dispose();
        }
        catch
        {
        }
    }
}
  1. Go back to Report.aspx page and add the code to parse your values in a Session.
//Some code that carried out calculations
//Calculated the averages
float selfAverageTotal = selfAssessValue / numberOfSections;
float otherAverageTotal = otherAssessValue / numberOfSections;
//Add generic list
List<string> questions = new List<string>(); //To store the names of x and y axis
List<float> averages = new List<float>();    //To store the values
questions.Add("Self Average Total");
averages.Add(selfAverageTotal);
questions.Add("Other Average Total");
averages.Add(otherAverageTotal);
//Parse lists to session variables
Session["Questions"] = questions;
Session["AverageValue"] = averages;

So the idea of this is that the Chart.aspx will just the render our chart and we don't care if the HTML gets wiped in this web page since we only want the image.

You might be thinking: Why didn't you use a User Control? Well this is one of the first things I tried when trying to resolve this issue which I believe would have been a nicer implementation. Unfortunately, my report page HTML still got rendered as an image.

If anyone knows a better way to output a chart to a webpage, then please leave a comment! Thanks!

Oh yeah, and here is what my Bar Chart looked liked by using the above code: Sample Chart Output

Creating A Comma Delimited String

A little while back I needed to create a comma-delimited string to parse into my SQL Query. My first attempt in creating my comma-delimited string involved using a StringBuilder class and appending a comma at the end of each of my values via a loop. However, I found that my application would error when parsing my comma-delimited string into my SQL query due to the fact a comma was added to the end of my string.

After some research on the MSDN website to solve my problem I found a solution and it was simpler than I thought. The .NET Framework already has a class called CommaDelimitedStringCollection and it is pretty simple to use as the following example shows:

using System.Configuration;
public partial class CommaPage : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Create a collection to parse to CommaDelimitedStringCollection class
        List<string> cars = new List<string>();
        cars.Add("Volvo");
        cars.Add("VW");
        cars.Add("BMW");
        cars.Add("Ford");
        
        //Create instance of CommaDelimitedStringCollection
        CommaDelimitedStringCollection commaCollection 
        = new CommaDelimitedStringCollection() ;
        
        //Iterate through cars collection and add to commaCollection
        foreach (string item in cars)
        {
            commaCollection.Add(item);
        }
        
        //Read out list of values
        Response.Write(commaCollection.ToString());     
    }
}

The output of the example above would be: "Volvo, VW, BMW, Ford".

So pretty much the .NET Framework's CommaDelimitedStringCollection class did all the work for me.

Nice one!

Adding An XML Sitemap to a Website

In 2005, the search engine Google launched the Sitemap 0.84 Protocol, which would be using the XML format. A sitemap is a way of organizing a website, identifying the URLs and the data under each section. Previously, the sitemaps were primarily geared for the users of the website. However, Google's XML format was designed for the search engines, allowing them to find the data faster and more efficiently.

Even the most simple sitemap to a website is quite important in order to allow search engines such as Google and Microsoft Live Search to crawl your website for any changes. The following example shows what a basic XML sitemap contains:

<?xml version="1.0" encoding="UTF-8" ?> 
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>/blog/</loc> 
<priority>0.5</priority> 
<changefreq>weekly</changefreq> 
</url>
</urlset>


As you can see the sitemap contain the following:

  • <loc> = Location of the page
  • <priority> = The priority of a particular URL relative to other pages on the same site. The value for this tag is a number between 0.0 and 1.0, where 0.0 identifies the lowest priority page(s) on your site and 1.0 identifies the highest priority page(s) on your site. The default priority of a page is 0.5.
  • <changefreq> = This value indicates how frequently the content at a particular URL is likely to change.

Thankfully, there is a site that will automatically generate an XML sitemap for you: http://www.sitemapspal.com/

I have written a blog post a little while back on how to manually submit your sitemap to search engines which proves to be quite useful if you find that your site has not been crawled for a long time. You can find that blog post here.

Making my way through an MCTS book

Over the last couple of months I have been reading through the "MCTS .NET Framework 2.0 for Web Applications" book in order to gain the first of what would hopefully be one of many Microsoft certifications. After reading the first couple of chapters, I found it to be a little daunting to say the least due to the fact that there are many coding techniques to get your head around. At the same time I have found it to be very useful in understanding good programming practices. Previously when I coded anything my motto was along the lines of "as long as the website works..." Not a good motto...

I found the first couple of chapters were the most straight-forward and really showed me how much of a crap programmer I am. Even though the "MCTS .NET Framework 2.0 for Web Applications" book is very good I found that it lacked a bit more explanation in the more technical chapters as you carry on reading. So I decided to use a another C# book (unless you are going to read Visual Basic) to fill in the missing gap.

The book I recommend is Murach's C# 2005 book which you can purchase here. It teaches you all the basic C# features that have carried over from earlier editions of C# that you'll use every day and underlying OOP concepts and features like inheritance and interfaces that make you a savvy, confident developer. This way you can use the MCTS book as a guide on what you need to learn and the C# book for further info.The same author has also written a coding book for VB as well which will be worth a read for people attempting the Visual Basic coding format.

I just hope I have the energy to carry on reading...

Could Writing a Blog Post Get Any Easier???

I have just installed Window Live Messenger 8.5. Yes, you might be thinking I have been a little late installing the latest version of Messenger. The reason for this is because I really had no reason to. After all I use Messenger just to talk to my friends. Nothing more, nothing less.

Anyway. Back to this blog post. Windows Live Messenger 8.5 has a really neat tool to manage you own blog. It is called Windows Live Writer (WLW). WLW has to be the most useful application for anyone who is an avid blogger. It features a WYSIWYG authoring, photo-publishing and map-publishing functionality, and is currently compatible with Windows Live Spaces, Blogger, LiveJournal, TypePad, Wordpress, Community_Server, PBlogs.gr, JournalHome, the MetaWeblog API, and the Moveable Type API. Even if your blogging engine is not listed here I am sure WLW will be compatible. For example, my blogging engine is BlogEngine and I was able to connect WLW to it really easily!

There are many extensions available to add extra functionality to WLW which you can find here. I highly recommend downloading "Code Snippet". This extension makes inserting code a breeze!

Code Snippet In Use:

// Hello1.cs
public class Hello1
{
   public static void Main()
   {
      System.Console.WriteLine("Hello, World!");
   }
}


WLW user interface is just as what you'd expect from the Microsoft product family. Very easy and intuitive to use:

WLWScreen

If you have not already tried WLW I highly recommend it. You can download WLW without installing Windows Live Messenger here.

Is an Arraylist still in use?

When I first started using ASP.NET 1.1, I always used an Arraylist to iterate through most of my collections. However, when I started using ASP.NET 2.0 I was introduced to Generic Lists. The List<T> class is the generic equivalent of the ArrayList class. It implements the IList<T> generic interface using an array whose size is dynamically increased as required. This means the List class performs much better in most cases and more importantly it is "type" safe.

So I am not too sure why you would ever need to use an Arraylist since a Generic List class is able to do exactly the same thing with the added benefit of extra perfomance. So is the Arraylist still widely used in todays standards? I guess it still must be in use if Microsoft has not omitted it from their Framework. Maybe Microsoft has something in store for the Arraylist in their grand plan.

Here are a few useful links:

C# Corner - C# Generics Josh Williams MSDN Blog - Arraylist vs. Generic List MSDN Network - List (T) Generic Class

Apply Theme To All Sites In Sharepoint 2007

After I designed a theme to my SharePoint 2007 site I came across a small problem. Well it was not exactly a problem it was more of a hassle I encountered. The current SharePoint Intranet I was working on contained quite a lot of sites and I didn't want to change the site settings within each site in order to change the theme. Thankfully, SharePoint 2007 allows you to apply a Custom CSS from your theme.

In order to change the theme across the whole SharePoint Intranet carry out the following:

  1. View the source of main portal homepage and look for a line which looks something like this:
<link rel="stylesheet" type="text/css" id="onetidThemeCSS" href="/_themes/Intranet/Intr1011-65001.css?rev=12%2E0%2E0%2E4518"/> 
  1. In Site Settings click on Masterpage and scroll down to the bottom of the page.
  2. Select the "Specify a CSS file to be used by this publishing site and all sites that inherit from it" radio button.
  3. Use the link from the CSS HTML tag above excluding anything after the query string. For example: ""/_themes/Intranet/Intr1011-65001.css".

Now the theme should be applied throughout the site. You can change the link for the Custom CSS by changing the directory path.