The When, What and Why of auditing


One of the things I’ve come across in most systems is the requirement for auditing.

As i see it there are 3 approaches to auditing

  1. When - Keeping track of when something changed. e.g Product A was changed by Bob on 1st April 2009.
  2. What - Keeping track of what changed - e.g Product A's price was changed from £15 to £20 by bob on 1st April 2009
  3. Why - Keeping track of why something changed - e.g Product A's price changed from £15 to £20 by bob on 1st April 2009 because it was wrongly priced originally.

Number 3, why, provides the most value. Not only does it allow the users of the system to be able to see the intent of changes (providing an extra dimension to reports) but it also provides some valuable information to any developer tasked with fixing an issue in the system. If a developer can see what the users intent was then it can help in providing a possible diagnoses.

As a more detailed example imagine you own an online shop that allows users to be able to cancel orders before they are actually shipped from the warehouse. You could provide a big button that says "cancel order". Simple, but this would not give a reason behind the user cancelling their order.

A better option would be to give the customer a set of options as to why they want to cancel, is it because they’ve since found it cheaper elsewhere, decided they don’t want it anymore, have heard "the next big thing" is due out in a week and are waiting for that or that it is taking too long to dispatch? Capturing this information allows audit reports to be run in the future about why customers are cancelling their orders.

Once you know the intent behind the customer cancelling the order you can then initiate different business processes, if it is because they've found it cheaper elsewhere then this could invoke a process for the sales team to contact them to match the offer. If its because its taking too long to dispatch then send them a voucher for free delivery on their next order. Keeping the customer happy is more likely to make them return.

Without catching the intent (whether for auditing or not) this would not be possible.

author: Luke Smith | posted @ Thursday, February 04, 2010 11:43 PM | Feedback (0)

Write today, wrong tomorrow


My blogs been without a subtitle for as long as I can remember, I just couldn’t think of anything “catchy”. But now I have come up with something that I think fits “Write today. Wrong tomorrow”.

This refers to the constant learning that occurs in the development world. I’m a huge believer that if you look back at code written 6 months ago and think “wow, that was amazing – I wouldn’t do anything differently” then you haven’t learnt anything new since.

So take whatever I say on this blog with a pinch of salt, I might not necessarily agree with it in 6 months time – that includes the subtitle ;)

author: Luke Smith | posted @ Monday, January 18, 2010 4:47 PM | Feedback (0)

Creating website installer using WiX


I’m currently working on a new project and one of the things I want is an easy deployment process. Rather than wait till I actually want to deploy the site to production to put something in place I’ve decided to build it early and use the same process as part of my CI process. Testing the process early and often will mean any issues will be solved sooner rather than on the day of the release.

I decided to go with an msi installer, so had 2 choices. Either using a Setup Project, that’s included in Visual Studio, or WiX. WiX is far more powerful, and also doesn’t require Visual Studio being installed on the build machine (Setup Projects aren’t supported by MSBuild and so you have to use devenv.exe to build them…urgh).

WiX is a Windows Installer toolset and you write your installation packages using XML. It’s a Microsoft project and hosted on sourceforge.

The following uses wix3.0.5419 and requires Visual Studio 2008.

Step 1: Download WiX

Download WiX from sourceforge. Make sure you also install Votive (included in the WiX installer) which will give you support for creating WiX projects inside Visual Studio with full intellisense.

Step 2: Create a new WiX project

Simple, just as you would any other Visual Studio project.

image 

Step 3: Adding the WixIIsExtension

WiX provides a template to work with when creating a new project, which is useful. The first thing we need to do is reference to WiXIIsExtension, which provides us with the tasks needed to create websites and virtual directories from the installer. References are added in the same way as any other project reference, via the Solution Explorer.

image

You then need to add a new xml namespace to the Wix root element in your Product.wxs file. If you don’t do this then I’ve found you cannot make use of the tasks provided by the extension library and will get the error “The Component element contains an unexpected child element 'WebSite'.”

Add the namespace xmlns:iis=”http://schemas.microsoft.com/wix/IIsExtension”.

image 

Step 4: Creating the website

In the Product.wxs file you can now add a task to create a website in IIS within a Component.

image

Update the ComponentRef under the Feature Id=”ProductFeature” to point to the Website component, Ctrl+Shift+B and you’ve created an installer that creates a website under IIS.

Step 5: Run the installer and view the result

Find the installer that is produced in the bin directory and run it. There is no UI for the user to interact with, and a new website is created pointing to C:\Project Files (x86)\WixSampleProject

 

 

 

 

 

image

We’ve not included any files in our installer, for that I use heat which I’ll blog about in a future post.

 

Hope you’ve found this helpful

 

Technorati Tags: ,,,

author: Luke Smith | posted @ Sunday, January 17, 2010 3:47 PM | Feedback (0)

Reading Geek Night Presentation slides


I recently gave a 15minute presentation covering the SOLID Principles at the Reading Geek Night, not enough time to go into each principle but hopefully enough that people went away with some understanding of the principles and were encouraged to learn more about them.

I highly recommend watching this video of "UncleBob" at the Norwegian Developers Conference 2009 on SOLID Principles of OO class design

I’ve also uploaded my slides of my presentation to slideshare.

author: Luke Smith | posted @ Wednesday, December 09, 2009 7:51 PM | Feedback (0)

Now using github


I've decided to move my open source projects over to github, rather than hosting them on a private subversion server where they aren’t very accessible.

From what I've seen, and heard, github is a great source control repository, I only hope there is a visual studio addin as good as visualsvn in the pipeline.

Currently my 2 JavaScript libraries have been moved over

  • linq2js is a JavaScript library providing an api similar to that of linq in the .net framework. It features a near complete method for method implementation of those found on the IEnumerable interface as well as lazy evaluation of queries.
  • vegeojson is a helper utility i wrote for drawing shapes on a virtual earth (now bing) map given an object in the geojson format.

author: Luke Smith | posted @ Sunday, November 01, 2009 12:24 PM | Feedback (0)

aspnet RoleProvider woes with StructureMap and NHibernate


I just fixed a bug that has plagued me for the last 2 nights. NHibernate was throwing completely random exceptions, rolling back transactions with no real consistency other than always happening on requests made after the application had started and almost always within my RoleProvider. I couldn’t figure out what the heck was happening.

Some of the exceptions:

“Could not synchronize database state with session”

“Rollback failed - System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable.”

“Commit failed - System.NullReferenceException: Object reference not set to an instance of an object.”

“Could not synchronize database state with session - NHibernate.ADOException: There was a problem converting an IDataReader to NDataReader”

“System.ObjectDisposedException: Session was disposed of or closed Object name: 'ISession'.”

I’m using StructureMap to Dependency Inject an NHibernate.ISession into my NHibernateRepositoryBase class, and inject the repository to my Service class. Because you can’t dependency inject into a AspNet RoleProvider I’m using the StructureMap ObjectFactory.GetInstance<T> to get me an instance of my IUserService. I was placing this in the constructor, setting a private field that was then accessed in all the overridden methods I am implementing.

And this was what got me.

The reason that the exceptions would happen on any requests made after the application had started was because AspNet Providers are created once per application and reused throughout the duration of the application. This meant when the instance was created it would have a reference to the NHibernate.ISession for that request, but since the ISession is closed in application_endrequest subsequent requests the RoleProvider was now referencing an ISession that was closed.

My solution was to remove the ObjectFactory.GetInstance<T> field assignments to within each method that needed the service, that way ensuring that the NHibernate.ISession for the current request would be used.

author: Luke Smith | posted @ Wednesday, June 24, 2009 11:06 PM | Feedback (2)

ASUS Eee PC 1000HE Review


I’ve been on the lookout for a netbook for a few months. I’ve been tempted by the HP Mini-Note 2133, Dell Mini 9 and Dell Mini 10. Each had things I liked about them but none made me part with my cash.

The Dell Mini 9 looks great, but after seeing it in the shops and being able to get my hands on it the keyboard was far too small for me. So when the Dell Mini 10 was announced I thought “great, a larger screen and larger keyboard so it should be OK” but unfortunately you can’t upgrade the RAM, so you’re stuck at 1GB, not enough to comfortably run Windows 7.

In the end I was looking at the Asus Eee PC 1000H which lead my to spot the 1000HE. With a whopping 9.5 hours battery life, 1.66GHz Intel Atom CPU (the 1000H comes with a 1.6GHz), 10” screen, 120GB HDD, built in 1.3MP camera and multi touch trackpad temptation became too much. So I ordered one, along with a new 2GB stick of RAM to replace the standard 1GB.

First impressions were good, it looks great, it’s not too heavy and the screen is nice and bright. I booted up with the default XP installation to check that everything was working and then proceeded to install the Windows 7 Beta released a few months back.

Installing Windows 7 was amazingly quick, taking about 30-40 minutes in total (I installed via hosting the ISO image using the Microsoft Virtual CD-ROM utility under XP).

Windows 7 had no problems finding drivers, except for the LAN driver (you can download the XP driver from the ASUS website that works under Windows 7). Everything “just works”. CPU usage is currently sitting around 20% with Outlook, Live Writer, twhirl and IE8 open.

The keyboard isn’t full size, but is perfectly big enough even for my large hands. The only issue, as with getting any new keyboard, is the placement of some keys, Home/End/PgUp/PgDn are all function keys, which is annoying. It’s nothing that a few days of use won’t solve, so my fingers memorise the locations.

The one thing which I wish was present was a nipple. I really hate trackpads to control the mouse cursor. They can’t cost much to include, and theres enough room in the keyboard for one to be put. However I do like the multitouch functionality of the trackpad, especially for vertical scrolling.

Battery life appears excellent, I seem to be getting about 7 hours out of it with the wireless card turned on.

My next task was to install some software, Office 2007 and Visual Studio 2008, which because I don’t have an external DVD drive I had to do via sharing the DVD drive on my desktop over the network. VS2008 took about an hour, which tends to be the usual amount of time. However when installing Visual Studio 2008 SP1 I began getting issues with the graphics drivers, the machine became unusable and unresponsive with the graphics flickering and disappearing every few seconds. I left the install to run and it completed after about 2 hours.

Overall I’m very happy with the device. Netbooks are the perfect device for throwing in your rucksack for use when commuting, which I do alot of, and so the battery life is a real bonus with the Eee PC 1000HE. Windows 7 is perfect for netbooks, hopefully by RTM there will be some more performance boost and the graphics drivers will be improved.

Technorati Tags: ,

author: Luke Smith | posted @ Saturday, March 21, 2009 5:03 PM | Feedback (4)

Generating and enforcing that any link and request is lowercase with ASP.NET MVC


This post is based off 2 other blog posts I found which helped me come up with my solution with some slight modifications on their code. For my new project I’m having my URLs all lowercase, as some search engines interpret ‘/Home’ and ‘/home’ as two different locations. So the problem became “how can I enforce all my URLs get rendered as lowercase, and how do I force a request to a URL with an uppercase letter to redirect to the lowercase equivalent?”. Because I’m using ASP.NET MVC I needed a way to get the Routing engine to render the URL as lowercase when using an ActionLink. Asking the question over on stackoverflow I got a solution that involved creating my own class that inherits from Route, which I’ve called LowercaseRoute, and overrides the GetVirtualPath method. I also created a MapLowercaseRoute extension method on the RouteCollection class that allows me to map a LowercaseRoute easily.
public class LowercaseRoute : Route
{
public LowercaseRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}

public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}

public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var virtualPath = base.GetVirtualPath(requestContext, values);

if (virtualPath != null)
{
virtualPath.VirtualPath = virtualPath.VirtualPath.ToLowerInvariant();
}

return virtualPath;
}
}
Next up is to ensure that any request to the site is enforced to be lowercased, and perform a 301 redirect if not. For this I’ve created a HttpModule, EnforceLowecaseRequestHttpModule, which I then register in the web.config. I could have put this directly into the global.asax file but I wanted to make it easily reusable on future projects.
public class EnforceLowercaseRequestHttpModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}

private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;

// If upper case letters are found in the URL, redirect to lower case URL (keep querystring the same).
string requestedUrl = ((application.Context.Request.Url.Scheme + "://" + application.Context.Request.Url.Authority + application.Context.Request.Url.AbsolutePath));

if (Regex.IsMatch(requestedUrl, @"[A-Z]") == true)
{
string lowercaseUrl = requestedUrl.ToLower();
lowercaseUrl += HttpContext.Current.Request.Url.Query;

application.Context.Response.Clear();
application.Context.Response.Status = "301 Moved Permanently";
application.Context.Response.AddHeader("Location", lowercaseUrl);
application.Context.Response.End();
}
}
}

author: Luke Smith | posted @ Sunday, February 01, 2009 6:02 PM | Feedback (1)

JavaScript variable generation for ASP.NET MVC


RC1 of the ASP.NET MVC framework adds a new ActionResult, JavaScriptResult. This class takes a string and returns a response with the string with the required ContentType. So now theres a built in (very simple) ActionResult for returning JavaScript what about generating the JavaScript string on the server to return? One thing I do alot is to recreate service side enums on the client in JavaScript, so rather than checking values I can use names, which improves the readability of the javascript. However this requires both the server and the client to be kept in sync, which can be a pain. To resolve this issue I’ve created a JavaScriptGenerator class which handles serialization of objects and Enum types as variables and generates the JavaScriptResult, as well as a helper method to take a controller name and action name and insert the required <script .. /> tag into the markup. Note I’ve created my own JavaScriptHelper class, similar to HtmlHelper, that I extend with extension methods the are javascript specific. I’ve also got a bunch of other extension methods for registering variables in the html itself as well as adding the <script /> tag for a specified filename.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace LukeSmith.Web.Mvc.JavaScript
{
    public class JavaScriptGenerator
    {
        private StringBuilder builder;

        /// 
        /// Initializes a new instance of the  class.
        /// 
        public JavaScriptGenerator()
        {
            builder = new StringBuilder();
        }

        /// 
        /// Generates a javascript variable from enum.
        /// 
        /// The name to give the javascript variable.
        /// Type of the enum.
        /// 
        /// Current instance of the .
        /// 
        /// 
        public JavaScriptGenerator GenerateVariableFromEnum(string name, Type enumType)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            if (enumType.IsEnum)
            {
                Array values = Enum.GetValues(enumType);
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                Dictionary dictionary =new Dictionary();

                foreach (var value in values)
                {
                    string enumName = Enum.GetName(enumType, value);

                    dictionary.Add(enumName, value);
                }

                builder.Append(string.Format("var {0} = {1};", name, serializer.Serialize(dictionary)));
            }
            else
            {
                throw new InvalidOperationException("Cannot generate JavaScript code when enumType is not an Enum.");
            }

            return this;
        }

        /// 
        /// Generates a javascript variable from an object.
        /// 
        /// The name to give the javascript variable.
        /// The value.
        /// 
        /// Current instance of the .
        /// 
        public JavaScriptGenerator GenerateVariableFromObject(string name, object value)
        {
            List converters = new List();

            return this.GenerateVariableFromObject(name, value, converters);
        }

        /// 
        /// Generates a javascript variable from an object.
        /// 
        /// The name to give the javascript variable.
        /// The value.
        /// The  to use to convert the .
        /// 
        /// Current instance of the .
        /// 
        public JavaScriptGenerator GenerateVariableFromObject(string name, object value, JavaScriptConverter converter)
        {
            List converters = new List();
            converters.Add(converter);

            return this.GenerateVariableFromObject(name, value, converters);
        }

        /// 
        /// Generates a javascript variable from an object.
        /// 
        /// The name to give the javascript variable.
        /// The value.
        /// An  of  to use to convert the .
        /// 
        /// Current instance of the .
        /// 
        public JavaScriptGenerator GenerateVariableFromObject(string name, object value, IEnumerable converters)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(converters);

            builder.Append(string.Format("var {0} = {1};", name, serializer.Serialize(value)));

            return this;
        }

        /// 
        /// Generates the .
        /// 
        /// 
        public JavaScriptResult Generate()
        {
            return new JavaScriptResult() { Script = this.ToString() };
        }

        /// 
        /// Returns a  that represents the current .
        /// 
        /// 
        /// A  that represents the current .
        /// 
        public override string ToString()
        {
            return builder.ToString();
        }
    }
}
And the code for the helper method  
public static string ScriptInclude(this JavaScriptHelper javaScriptHelper, string actionName, string controllerName)
        {
            UrlHelper helper = new UrlHelper(javaScriptHelper.ViewContext.RequestContext);
            string url = helper.Action(actionName, controllerName);

            return string.Format("{1}", url, Environment.NewLine);
        }

author: Luke Smith | posted @ Saturday, January 31, 2009 2:01 PM | Feedback (0)

ASP.NET MVC


WebForms are the existing technology in ASP.NET for web applications, which have been around since the beginning of ASP.NET. However, despite being mature and having a large developer base they aren’t ‘all that’. It’s been said that WebForms are “web development for VB Developers”, in that the drag ‘n’ drop and double clicking to add an event handler for a button eases the migration from Windows Development to the web. The problem with this is that WebForms brings a state-based system (via ViewState) to the web, that is fundamentally stateless. Added onto this the complex page-life cycle of the WebForms model and the lack of separating of concerns, WebForms isn’t really suitable for building maintainable and testable web applications.

ASP.NET MVC is built on the ASP.NET framework, so existing WebForms developers can make use of the existing classes and framework knowledge they possess (Forms/Windows Authentication, Membership Roles, Session/Profile state, Health Monitoring etc…). ASP.NET MVC projects also have the added benefit that they can include traditional WebForms pages and User Controls (though I wouldn’t recommend mixing the two if you can help it), so the transition can be made without throwing all your existing pages away.

By default ASP.NET ships with the WebForms syntax View Engine, however third party view engines can easily be used with a few additions to the web.config file and global.asax. The best ViewEngine I’ve seen is SparkViewEngine. This engine allows ‘the html to dominate the flow and the code to fit seamlessly’, losing the horrible <% %> tags which can make the default viewengine unreadable.

Overall I’m very impressed with the MVC framework, and how easy it is to pick up. The time its taken to learn has been minimal and hasn’t affected the time it’s taken to use it on my current project. I can see the benefits it will bring in the future, including having greater confidence of releases (due to unit testing) and the maintainability that the MVC pattern enforces via the separation of concerns.

author: Luke Smith | posted @ Saturday, December 13, 2008 12:12 AM | Feedback (1)