Simple C# Email Template 'System'

Posted at 02:04 a.m. on 02/12/2010 by Daniel

As part of the new email system in Kustom Page, I decided to build a quick little template system, based off models, that could populate email fields, instead of doing a string.Format.

You pass it in a model (C# object), it runs through each of the properties, and applies them to the template file. Simple? Yes.

using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;

namespace KustomPage.Emailer.Client.TemplateEngine
{
    public class TemplateEngine<T>
    {
        private readonly T _templateModel;
        private readonly string _templateFilePath;

        public TemplateEngine(T templateModel, string templateFilePath)
        {
            _templateModel = templateModel;
            _templateFilePath = templateFilePath;
        }

        /// <summary>
        /// Renders the template.
        /// </summary>
        /// <returns></returns>
        public string Render()
        {
            IEnumerable<KeyValuePair<string, object>> modelProperties = GatherModelPropertiesAndValues();
            var output = LoadTemplate();

            foreach (var modelProperty in modelProperties)
            {
                output = output.Replace("<<" + modelProperty.Key + ">>", ObjectToString(modelProperty.Value));
            }

            return output;
        }

        /// <summary>
        /// Loads the template.
        /// </summary>
        /// <returns></returns>
        private string LoadTemplate()
        {
            return File.ReadAllText(_templateFilePath);
        }

        /// <summary>
        /// Converts the objects to a string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        private static string ObjectToString(object value)
        {
            if (value == null)
                return string.Empty;

            if (value.GetType() == typeof(string))
                return (string)value;

            if(value.GetType() == typeof(DateTime))
            {
				// Add formatting here at some point
                DateTime dateTime = (DateTime)value;
                return dateTime.ToString();
            }

            return value.ToString();
        }

        /// <summary>
        /// Gathers the model properties and values into a dictionary
        /// </summary>
        /// <returns></returns>
        private IEnumerable<KeyValuePair<string, object>> GatherModelPropertiesAndValues()
        {
            IDictionary<string, object> properties = new Dictionary<string, object>();
            foreach (PropertyInfo propertyInfo in _templateModel.GetType().GetProperties())
            {
                string name = propertyInfo.Name;
                object value = propertyInfo.GetValue(_templateModel, null);

                properties.Add(name, value);
            }

            return properties;
        }
    }
}

Sample usage

Model

using System;
namespace KustomPage.Emailer.Client.Tests.TemplateEngine
{
    public class TemplateModel
    {
        public string Name { get { return "Daniel"; } }
        public string URL { get { return "http://www.kustompage.com/"; } }
        public DateTime Date { get; set; }
    }
}

And using it...

var model = new TemplateModel { Date = DateTime.Now };
TemplateEngine<TemplateModel> templateEngine = new TemplateEngine<TemplateModel>(model, "EmailTemplates/Test.txt");
var output = templateEngine.Render();

Sample template

Hello <<Name>>,


Pelase verify your account by clicking on the link below:

<<URL>>

This message was generated at <<Date>>

.Net 4.0 with MVC 2.0 on IIS 7.5

Posted at 12:38 p.m. on 06/06/2010 by Daniel

This one has had me stumped for a while – ASP.NET MVC 2 sites refused to run on IIS 7.5 (Windows 7). It would either complain and break. Or show me the files in the directory. After a bit of Googling around – I found a solution (that works for me at least):

Step 1:

Install the .Net Framework 4 into IIS using:

C:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis.exe –i

You will need to run it as Administrator if you have UAC turned on.

Step 2:

Install the correct IIS component’s (Control Panel > Add/Remove Windows features > Internet Information Services > World Wide Web Services)

  • Common HTTP features
    • HTTP Errors
    • HTTP Redirection
  • Health and Diagnostics
    • Request Monitoring
    • Tracing

Step 3:

Set the app pool to use ASP.NET 4.0

Screen shot 2010-06-07 at 12.32.35 AM

 

Screen shot 2010-06-07 at 12.33.01 AM

You show now be able to browse to your sites. Not sure why it doesn’t install into IIS by default though…

C# Convert XML to an object or list of an object

Posted at 10:52 p.m. on 26/04/2010 by Daniel

Instead of doing my normal “write up an object and then parse the xml into it’s properties”, I decided to have a look at the XML deserialiser (well, deserializer in C# itself) – which has worked, and has saved me a lot of time.

Obviously you will need to create your object first, so here’s a person one:

[XmlRoot(ElementName = "person")] 
public class Person 
{
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
}

Note the XmlRoot attribute – you will need to set this to the XML node that contains your properties.

Next you will need an XML document, here’s my sample one:

	<people>
		<person>
			<FirstName>Daniel</FirstName>
			<LastName>Wylie</LastName>
		</person>
		<person>
			<FirstName>Jhon</FirstName>
			<LastName>Smith</LastName>
		</person>
			<person>
			<FirstName>Sam</FirstName>
			<LastName>Brown</LastName>
		</person>
	</people>

And of course, the XML Deserialiser class

using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace SampleApplication.Common 
{ 
    public class Convertors 
    { 
        /// <summary> 
        /// Converts a single XML tree to the type of T 
        /// </summary> 
        /// <typeparam name="T">Type to return</typeparam> 
        /// <param name="xml">XML string to convert</param> 
        /// <returns></returns> 
        public static T XmlToObject<T>(string xml) 
        { 
            using (var xmlStream = new StringReader(xml)) 
            { 
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(XmlReader.Create(xmlStream)); 
            } 
        }

       /// <summary> 
       /// Converts the XML to a list of T
       /// </summary> 
       /// <typeparam name="T">Type to return</typeparam> 
       /// <param name="xml">XML string to convert</param> 
       /// <param name="nodePath">XML Node path to select <example>//People/Person</example></param> 
        /// <returns></returns> 
        public static List<T> XmlToObjectList<T>(string xml, string nodePath) 
        { 
            var xmlDocument = new XmlDocument(); 
            xmlDocument.LoadXml(xml);

            var returnItemsList = new List<T>();

            foreach (XmlNode xmlNode in xmlDocument.SelectNodes(nodePath)) 
            { 
                returnItemsList.Add(XmlToObject<T>(xmlNode.OuterXml)); 
            }

            return returnItemsList; 
        } 
    } 
}

Usage:

var List<Person> = Convertors.XmlToObjectList<Person>(PeopleXML (Load how you wish), "//People/Person");

Simple C# BlogML Parser

Posted at 03:38 a.m. on 10/02/2010 by Daniel

I promised that I would be releasing some code from Kustom Page – And here it is, straight from the guts of Kustom Page!

This little class read in an XML document, formatted to the BlogML standard, and give you an object back. The library is very very simple. You will need to do validation etc yourself (And I highly recommend you do).

Sample Usage

var blogMLImport = BlogMLObject.Parse("BlogML.xml");

            var blogMLImport = BlogMLObject.Parse("BlogML.xml");

            foreach (var post in blogMLImport.Posts)
            {
                Console.WriteLine(string.Format("Post: {0} Written by: {1} on: {2}", post.Title, post.Authors.First().Title, post.DateCreated));
            }

Download Library (8 kb)

Converting UTC Dates to a user specified time zone in C#/ASP.NET

Posted at 03:43 a.m. on 01/12/2009 by Daniel

I have been pissing around with this one for months – when someone posts anything on Kustom Page, the date gets stored in UTC, which is all good for storing date. But, of course, when they want to display a date on their site, say a blog post date, it comes up with that UTC date, which, if you live in New Zealand like I do, is 12 hours behind when you actually posted it. And who posts blogs at 3am in the morning?

My aim was always to allow users to set their own time zone, and then pass the dates through a convertor wherever it will be displayed on the screen. Sounds easy right? Actually it is. After reading this post at least.

So I wrote up a quick little class that takes care of that conversion, and can also return you a list of time zones

 public class TimezoneConvertor
    {
        public static DateTime Convert(DateTime UTCDate, string TimezoneID)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(UTCDate,
                                                   TimeZoneInfo.FindSystemTimeZoneById(TimezoneID));
        }

        public static string Convert(DateTime UTCDate, string TimezoneID, string Format)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(UTCDate,
                                                   TimeZoneInfo.FindSystemTimeZoneById(TimezoneID)).ToString(Format);
        }

        public static ReadOnlyCollection GetTimeZones()
        {
            return TimeZoneInfo.GetSystemTimeZones();
        }
    }

Obviously you’ll need to know the users time zone, which you could store in the database, or wherever you normally store your users settings.

For those of you using ASP.NET MVC, here’s a quick little conversion method to a list of SelectItems

   public static List TimeZoneSelectList(string SelectedName)
        {
            var timeZones = TimezoneConvertor.GetTimeZones();
            var listOfTimeZones = new List();
            foreach (var zone in timeZones)
            {
                var item = new SelectListItem();
                item.Text = zone.DisplayName;
                item.Value = zone.Id;

                if(item.Text == SelectedName)
                    item.Selected = true;

                listOfTimeZones.Add(item);
            }

            return listOfTimeZones;
        }

File Sorter

Posted at 03:03 p.m. on 28/10/2009 by Daniel

I got sick of sorting out files... So I wrote a quick little C# app that does all the work for me. Reads in filenames setup as ProgramNameS01E10.avi etc

 

using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace TorrentSorter
{
class Program
{
   public static string FileInfoRegex = @"(.+)S(\d+)E(\d+)(.+)";
   public static string PathToScan = "";
   public static string OutputDirectory = "";
   static void Main(string[] args)
   {
      // If there aren't any arguments passed in at start, we need to ask the user for the info
      if (args.Length == 0)
      {
         Console.Write("Directory to scan: ");
         PathToScan = Console.ReadLine();
         Console.Write(string.Format("{0}Directory to move too: ", Environment.NewLine));
         OutputDirectory = Console.ReadLine();
      }
      else
      {
         PathToScan = args[0];
         OutputDirectory = args[1];
         // Allow people to pass in a custom regex pattern if run with arguments
         if (args.Length == 3)
            FileInfoRegex = args[2];
      }
      // Start processing the files
      ProcessDirectory(PathToScan, true);
      Console.WriteLine("Done!");
      Console.ReadKey();
   }
   static void ProcessDirectory(string filePath, bool recursive)
   {
      // If recursive is true, then we'll go through all the directories we can find and process them
      if (recursive)
      {
         foreach (var directory in Directory.GetDirectories(filePath))
         {
            ProcessDirectory(directory, recursive);
         }
}
      // Gets a list of files from given directory
      var listOfFiles = Directory.GetFiles(filePath).ToList();
      foreach (var file in listOfFiles)
      {
         var info = new FileInfo(file);
         var reg = new Regex(FileInfoRegex);
         var match = reg.Match(info.Name);
         // If theres a match, and the extention is not .torrent (for people who store the .torrent files in the directory they're using), start sorting
         if (match.Success && info.Extension.ToLowerInvariant() != ".torrent")
         {
            Console.Write(string.Format("{1}Moving file {0}...", info.Name, Environment.NewLine));
            // Get the program name and season number from the Regex matches
            string programName = FixFileName(match.Groups[1].Value);
            string seasonNumber = match.Groups[2].Value;
            // Work out the program and season folder. Append the word season in front of the number
            string programFolder = Path.Combine(OutputDirectory, programName);
            string seasonFolder = Path.Combine(programFolder, string.Format("Season {0}", seasonNumber));
            // Create the program folder if it doesn't already exist
            if (!Directory.Exists(programFolder))
               Directory.CreateDirectory(programFolder);
            // Create the season folder if it doesn't already exist
            if (!Directory.Exists(seasonFolder))
               Directory.CreateDirectory(seasonFolder);
            // Check that the file doesn't already exist, and copy it
            if (!File.Exists(Path.Combine(seasonFolder, info.Name)))
            {
               File.Copy(file, Path.Combine(seasonFolder, info.Name));
               Console.Write("done.");
            }
            else
            {
               Console.Write("already done.");
            }
         }
      }
   }
   /// 
   /// Removes the crap out of file names
   /// 
   /// 
   /// 
   protected static string FixFileName(string fileName)
   {
      fileName = fileName.Replace(".", " ");
      fileName = fileName.Replace("_", " ");
      fileName = fileName.Replace("-", " ");
      fileName = fileName.Replace("+", " ");
      fileName = fileName.Trim();
      return fileName;
   }
}
}

Don't have a c# complier? Download exe:

FileSorter.exe (6.50 kb)

Xero API Wrapper

Posted at 09:20 p.m. on 27/11/2008 by Daniel

Over the last few days I have been writing a small Xero API Wrapper for the new API. It pretty much takes care of requesting the XML from the API, parsing it, and returning populated objects – Saving you from doing it all manually. You can even save objects back to Xero!

The API hasn’t been fully released yet, but if you are busting to try it out, you can email network@xero.com to request an API Key.

Download Here

Setup

Before you can make any request, you will need to setup a new XeroAuth object. You will need to provide it with your API Key, Customer Key, and URL you wish to you. You only have to set this up once as you can reuse the object.

Xero.API.Communication.XeroAuth Auth = new Xero.API.Communication.XeroAuth();

Auth.CustomerKey = "Customer Key";
Auth.ProviderKey = "Your Provider Key";
Auth.URL = "https://networktest.xero.com/";

Each new object you use will need to have the its Auth property setup like the following

Xero.API.Object.Auth = Auth;

Using

Hopefully everything is fairly self explanatory. Use the Get() method to get objects from Xero, use the Save() method to save them back. All properties in each class match up to the Xero API XML.

Sample Code

public static Xero.API.Communication.XeroAuth Auth = new Xero.API.Communication.XeroAuth();
public void PrintContactName() {
     Auth.CustomerKey = "Customer Key";
     Auth.ProviderKey = "Provider Key";
     Auth.URL = "https://networktest.xero.com/";

     Xero.API.ContactCollection.Auth = Auth;
     Xero.API.ContactCollection Collection = Xero.API.ContactCollection.GetContacts();
     
     foreach (var contact in Collection.Records) {
           Console.WriteLine("Contact Name: " + contact.Name);
     }
     Console.ReadKey();
}

Sign Out of BlogEngine.Net

Posted at 06:33 p.m. on 21/07/2008 by Daniel

As much as I love BlogEngine.net, one thing annoyed me, you can't sign out, which is useful when you want to check that your post has published correctly (And because the admin menu is huge) - So I created a quick fix for it

Step 1:

Create a page called Signout.aspx in your Admin/Pages directory and add the following code to the Page_Load event

FormsAuthentication.SignOut();
Session.Abandon();
Response.Redirect("../../");

Step 2:

Add the following line to your Web.sitemap file

<siteMapNode url="~/admin/Pages/Signout.aspx" title="Log out"  description=""  roles="administrators, editors"/>

Done! You should now see a Logout link in your admin menu

Last.fm Widget

Posted at 01:33 a.m. on 09/07/2008 by Daniel

Here is my first widget for Blogengine.net - It shows the list of your 10 recently listened songs from Last.fm.lastfmwidget

To install, simply extract the zip file into your widgets folder, then set your Last.fm username in the options window.

 

Download - Updated found out that it didn't like different timezones very much, so I added an option to add/remove hours from the displayed times

  Next Page