Home
Atom Feed

My First Umbraco Usercontrol - Part 3: The Real Deal

Today we will create the CSV functionality. Since we have already set up a working usercontrol, the only thing we need to do is to change the code in Visual Studio, and upload the files again.

I will not go into detail about the code and why I chose to code it the way I did.
Let the comments in the code speak for itself.

EyeCatchCSVGenerator.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EyeCatchCSVGenerator.ascx.cs" Inherits="EyeCatchCSVGenerator.EyeCatchCSVGenerator" %>

EyeCatchCSVGenerator.ascx.cs

using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using umbraco.presentation.nodeFactory;

namespace EyeCatchCSVGenerator
{
    public partial class EyeCatchCSVGenerator : System.Web.UI.UserControl
    {
        public int Source { get; set; }
        public Boolean getChildrenOfSource { get; set; }
        public string documentTypeAlias { get; set; }
        public Boolean encodeHtmlTags { get; set; }
        public Boolean stripHtmlTags { get; set; }
        public string Delimiter { get; set; }

        /// 
        /// Handles the Load event of the Page control.
        /// 
        /// The source of the event.
        /// The  instance containing the event data.
        protected void Page_Load(object sender, EventArgs e)
        {
            // By default, set src to current page
            Node src = Node.GetCurrent();

            // Set a value for src if the parameterer was passed
            if(Source!=0)
            {
                src = new Node(Source);
            }

            if(src.Id != 0)
            {
                // Set a value for Delimiter if none exists
                if (string.IsNullOrEmpty(Delimiter))
                {
                    Delimiter = ",";
                }

                // Set a value for documentTypeAlias if none exists
                if (string.IsNullOrEmpty(documentTypeAlias))
                {
                    documentTypeAlias = src.NodeTypeAlias;
                }

                Response.Clear();
                Response.ContentType = "text/csv";
                Response.AddHeader("content-disposition", "attachment; filename=\"" + src.Name + ".csv\"");
                Response.Buffer = true;

                // If getChildrenOfSource and documentTypeAlias is specified
                if (getChildrenOfSource && !documentTypeAlias.Equals(""))
                {
                    // LINQ expression that extracts all nodes that matches the specified documentTypeAlias
                    List nodeCollection = (from Node n in src.Children where n.NodeTypeAlias.Equals(documentTypeAlias) select n).ToList();

                    // Print headers from first node
                    WritePropertyHeaders((Node)nodeCollection[0]);

                    // Print values for all nodes
                    foreach (Node n in nodeCollection)
                    {
                        WritePropertyValues(n);
                    }
                }

                // Default action
                else
                {
                    WritePropertyHeaders(src);
                    WritePropertyValues(src);
                }

                Response.End();
            }
            else
            {
                throw new NullReferenceException("Something went wrong with the Source! \nIs the referenced node published?");
            }
        }

        /// 
        /// Writes the property headers to page.
        /// 
        /// The node.
        public void WritePropertyHeaders(Node elem)
        {
            // Going through every property and lists the title
            foreach (Property p in elem.Properties)
            {
                Response.Write(p.Alias);
                Response.Write(Delimiter);
            }

        }

        /// 
        /// Writes the property values to page.
        /// 
        /// The node.
        public void WritePropertyValues(Node elem)
        {
            Response.Write("\n");

            // Going through every property and lists the value
            foreach (Property p in elem.Properties)
            {
                string result = "";
                // Remove carriage returns (0x0D)
                result = p.Value.Replace("\r", " ");
                // Remove line feeds (0x0A)
                result = result.Replace("\n", string.Empty);

                // If macro is set to encode HTML tags
                if (encodeHtmlTags && !stripHtmlTags)
                {
                    result = HttpUtility.HtmlEncode(result);
                }
                // If macro is set to remove HTML tags. (Ignores the encodeHtmlTags property)
                if (stripHtmlTags)
                {
                    result = StripTagsCharArray(result);
                }

                Response.Write("\"" + result + "\"");
                Response.Write(Delimiter);
            }
        }

        /// 
        /// Remove HTML tags from string using char array.
        /// 
        /// The string containing HTML tags.
        public string StripTagsCharArray(string source)
        {
            char[] array = new char[source.Length];
            int arrayIndex = 0;
            bool inside = false;

            for (int i = 0; i < source.Length; i++)
            {
                char let = source[i];
                if (let == '<')
                {
                    inside = true;
                    continue;
                }
                if (let == '>')
                {
                    inside = false;
                    continue;
                }
                if (!inside)
                {
                    array[arrayIndex] = let;
                    arrayIndex++;
                }
            }
            return new string(array, 0, arrayIndex);
        }
    }
}

Build the project and upload your .dll and .ascx files.

Since we have added some new parameters, we need to update the macro to reflect these changes. Go to your macro and click "Browse properties" again and then "Save properties". You have now added the parameters from the code to your macro.

You also probably need to do some changes to your template. This is because it needs to be empty except for the CSV data this usercontrol produces.

Here is my template (remember to change the parameters to reflect your nodes):
The best way is probably to remove the macro line below and re- add it.

<%@ Master Language="C#" MasterPageFile="/masterpages/default.master" AutoEventWireup="true" %>"><umbraco:Macro Source="1127" getChildrenOfSource="1" documentTypeAlias="Article" stripHtmlTags="0" encodeHtmlTags="1" Delimiter=";" Alias="[EyeCatch]CSVGenerator" runat="server"></umbraco:Macro>

Note: There is no set standard for the delimiter character in CSV, so you can choose which one you want. Microsoft Excel uses the ";" character to delimit cells.

When you have changed your template and added the macro, view the page from Part 2 in your browser. You should get a file download window, with your CSV data in it. Try to open it in Excel or a similar program and see if it can parse the file properly.

Mine looked like this:

If it doesn't work for you, please give me a notification.