User experience is key on the web. With that in mind, I went out looking for some good looking validation and tooltip JQuery plugins.

I found a single solution and decided that using the new MVC 2.0 JQuery Validation, I will try and integrate it so that it works seamlessly with the ASP.NET MVC 2.0 Custom Validation.

Validation Engine – Because Validation is a mess.
Kudos to Cedric Dugas, because I really enjoy using this library, it’s clean, easy to use and it’s extremely flexible.

The first step was to determine where the validation was taking place. Inside of jquery.validate.js, go to line number 574. This is where the error message is compiled and added to a list. We will inject our validation engine code in here.

    formatAndAdd: function(element, rule) {
        var message = this.defaultMessage(element, rule.method),
    	theregex = /\$?\{(\d+)\}/g;
        if (typeof message == "function") {
            message = message.call(this, rule.parameters, element);
        } else if (theregex.test(message)) {
            message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
        }
        $.validationEngine.buildPrompt(element, message, "error");
        this.errorList.push({
            message: "",
            element: element
        });
    
        this.errorMap[element.name] = message;
        this.submitted[element.name] = message;
    },
    

Notice that on line 9, I added the buildPrompt from the validation engine. I pass it the element and the message that describes the error.

Step was to determine where the errors are removed if they have passed the validation. On line 259, there is a unhighlight, which removes the background highlighting from the element with the error.

We will inject our closePrompt code here.

unhighlight: function(element, errorClass, validClass) {
    $.validationEngine.closePrompt(element);
    $(element).removeClass(errorClass).addClass(validClass);
}

The final step is to initialize the validation engine.

on line 50, after the submit button was clicked, we will initialize our validation engine.

if (validator.settings.onsubmit) {
    $(validator.currentForm).validationEngine();

prettyaspnetmvcvalidation

Here is the sample code. To utilize this code, all you will need to do is get the latest version of the Validation Engine and replace the jquery.validation.js with this one


ValidationDemo.zip (391.38 kb)

jquery.validate.js (48.89 kb)


What is a bad way to determine whether your software works?

Do you have to click through every single button on every single screen to make sure that something isn’t broken? And if it breaks, do you know what went wrong and where?

unit-test-101_b16b3de3-b37c-41df-b1a9-b9675fb9019e 

If you answered yes and then no, then you probably haven’t written unit tests for your code as most of these issue can be reduced.

Unit tests improve design and and ensures that as a developer, you are thinking about decoupled objects serving a single responsibility and thinking more along the lines of writing testable code.

I am not saying that Unit tests eliminates all bugs or issues. It just reduces them significantly.

What Unit Testing frameworks are there for us to use?

There are quite a couple as we can see from Wikipedia.

I just tend to use the Visual Studio unit tests.

It’s difficult to break away from old traditions, but sometimes it pays to think a differently. NHibernate is an awesome example of what I am talking about. It gives a developer the flexibility of concentrating on writing code instead of having to synchronize the database with the data layer/code.

Currently, what I see happening quite often is the following.

  1. Specification document gets drawn up.
  2. Database is slapped together by the developer or DB “dude”.
  3. Developer starts working on the code, only to realize that a column is missing due to either poor planning or requirements changing, the developer spends time having to change/add a column/s and tracking down all the changes in the stored procedure and hopefully he/she has tracked all of them down, otherwise….

    15154

I have 2 words, Fluent NHibernate…

How to setup Fluent NHibernate

  1. Download Fluent NHibernate from http://fluentnhibernate.org/downloads
  2. Add references to the DLLs
  3. Create your first Entity
    public class Person
    {
    	public virtual int ID { get; private set; }
    	public virtual string Name { get; set; }
    	public virtual string Lastname { get; set; }
    }
    
    public class PersonMap : ClassMap<Person>
    {
    	public PersonMap()
    	{
    		Schema("dbo");
    		Table("Person");
    		Id(x => x.ID);
    		Map(x => x.Name);
    		Map(x => x.Lastname);
    	}
    }
  4. Setup Fluent NHibernate and this is where fluent really shines. No more having to deal with the pain of the XML configuration.
    public static class SessionFactory
    {
    	public static ISessionFactory CreateSessionFactory()
    	{
    		return Fluently.Configure()
    			.Database(MsSqlConfiguration.MsSql2005
    			.ConnectionString(
    				c => c.FromConnectionStringWithKey("AthenaConnectionString")))
    			.Mappings(
    				m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
    			.ExposeConfiguration(BuildSchema)
    			.BuildSessionFactory();
    	}
    
    	private static void BuildSchema(Configuration config)
    	{
    		new SchemaUpdate(config).Execute(true, true);
    	}
    }
    
  5. How to use Fluent NHibernate in a simple example
var sessionFactory = SessionFactory.CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
	using (var transaction = session.BeginTransaction())
	{
		Person person = new Person { Name = "Pieter", Lastname = "Germishuys" };
		session.SaveOrUpdate(person);
		transaction.Commit();
	}
}

3JDQDM2DSFR8

Isn’t symmetry nice? I always have some OCD when it comes to diagrams. So, it’s not surprise when you see this screenshot of the Linq2Sql Contextathena_dbml

Along with this, now we can go ahead and create Athena.DAL which contains the Linq2Sql context.

The solution isn’t that far long, so I won’t put up any code yet.

From this fantastic post on implementing the Repository pattern using Linq2SQL, we quickly put together some code that resembles the following

The Repository Interface

namespace Athena.DAL
{
	/// <summary>
	/// Repository Contract
	/// </summary>
	public interface IRepository<TRow, TEntity>
		where TRow : class
	{
		#region Find
		IList<TEntity> Find(Expression<Func<TRow, bool>> exp);
		TEntity FindSingle(Expression<Func<TRow, bool>> exp);
		#endregion

		#region Save
		void Save(TEntity entity);
		#endregion

		#region Delete
		void Delete(TEntity entity);
		#endregion
	}
}

Our Entry Model, which will describe an Entry fully

namespace Athena.DAL
{
	/// <summary>
	/// Entry Model
	/// </summary>
	public class EntryModel
	{
		public Entry Entry { get; set; }
		public List<Tag> Tags { get; set; }
		public List<Category> Categories { get; set; }
	}
}

and now for our not yet implemented EntryRepository

namespace Athena.DAL
{
	/// <summary>
	/// Entry Repository
	/// </summary>
	public class EntryRepository : IRepository<Entry, EntryModel>
	{
		#region Find
		/// <summary>
		/// Find
		/// </summary>
		/// <param name="exp"></param>
		/// <returns></returns>
		public IList<EntryModel> Find(System.Linq.Expressions.Expression<Func<Entry, bool>> exp)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// Find Single
		/// </summary>
		/// <param name="exp"></param>
		/// <returns></returns>
		public EntryModel FindSingle(System.Linq.Expressions.Expression<Func<Entry, bool>> exp)
		{
			throw new NotImplementedException();
		}
		#endregion

		#region Save
		/// <summary>
		/// Save
		/// </summary>
		/// <param name="entity"></param>
		public void Save(EntryModel entityModel)
		{
			throw new NotImplementedException();
		}
		#endregion

		#region Delete
		/// <summary>
		/// Delete
		/// </summary>
		/// <param name="entity"></param>
		public void Delete(EntryModel entityModel)
		{
			throw new NotImplementedException();
		}

		#endregion
	}
}

So, here is a quick database design of Athena, the blogging engine that I am building as a pet project. Also, my girlfriend recently asked me if I wouldn’t code something for her, so there is some motivation behind it, other than the geek inside of me.athena

Next, we need to create a new ASP.NET MVC 2.0 Project and start working on the model.

This framework is not at all supposed to challenge or replace a blog engine but to merely be an effort from myself to showcase some of the fantastic and cool technologies out there.

I chose Athena because she is the Greek god of wisdom!

athena

I have already blogged about some of technologies that we are going to use, so tonight, we are just going to quickly put the framework together and then start playing.

Caching considerations
Donut hole caching from Phill Haack!
The Repository Pattern
This thread on StackOverflow

The Output cache is a clear winner for fast and effective caching, but like Mr. Haack has mentioned, only use it when it’s the right tool for the job. The Output Cache can give a great bit of flexibility with regards to where the output is stored.

The current locations for the Output Cache are the following
from http://support.microsoft.com/kb/323290

    • Any - This stores the output cache in the client's browser, on the proxy server (or any other server) that participates in the request, or on the server where the request is processed. By default, Any is selected.
    • Client - This stores output cache in the client's browser.
    • Downstream - This stores the output cache in any cache-capable devices (other than the origin server) that participate in the request.
    • Server - This stores the output cache on the Web server.
    • None - This turns off the output cache.

Models
I currently have about 10 tables which are all sitting inside of a Linq2SQL dbml, I then have a Context class that managed the Linq2SQL database context.

For instance, let’s say I want to get entries, the Context class will make sure that the Linq2Sql context is up and retrieve all the entries

The ViewModels
Every View has a “ViewModel” associated with it. Let me give you an example.
For a blog, where you would like to view an Entry, the Entry might contain a title, content, tags and some comments.

The View Model for the View Entry (View) would look something like this

public class EntryViewModel
{
	public Entry Entry { get; set; }
	public List<Comment> Comments { get; set; }
	public List<Tag> Tags { get; set; }
}

The Controllers
They perform pretty mondain tasks, such as begging the ViewModel for some data. i.e. I want to view entry "”Hello World”, go fetch the data for me. Which the ViewModel in turn requests from the Model.

The Views
They are pretty dumb alright, all they do is take the ViewModel they are given and display it the nicest way they can.

The technologies that I am using include the following

Data Layer
Linq2SQL

Logging
Log4NET

Client Technologies
ASP.NET MVC 2.0
JQuery
ValidationEngine (Because validation is a mess :))

Mocking Framework
MOQ

So, I recently had the chance to quickly write some code that gave me the ability to quickly get data from the database.

I didn’t like the naming of the columns so I came up with an Attribute ColumnMapping that has UIName and DBName properties and here is the method to retrieve the data

/// Context Mapper that takes an Attribute and maps it from the stored procedure
///
///
public static class ContextMapper<T> where T : new()
{
    private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    ///
    /// Get Data Maps the data from a Stored Procedure result to a Type
    ///
    ///
    ///
    public static List GetData(StoredProcedure storedProcedure)
    {
        List results = new List();
        DbDataReader dbReader = storedProcedure.ExecuteReader();

        while (dbReader.Read())
        {
            T result = new T();
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            foreach (PropertyInfo propInfo in propertyInfos)
            {
                int? ordinal = null;
                try
                {
                    ordinal = dbReader.GetOrdinal((propInfo.GetCustomAttributes(typeof(ColumnMapping), false)[0] as ColumnMapping).ColumnName);
                }
                catch (IndexOutOfRangeException ex)
                {
                    //Couldn't find ordinal, probably doesn't exist in the collection
                    logger.Warn(ex.Message, ex);
                }
                if (ordinal != null)
                {
                    if (propInfo.GetCustomAttributes(typeof(ColumnMapping), false).Count() && !dbReader.IsDBNull(dbReader.GetOrdinal((propInfo.GetCustomAttributes(typeof(ColumnMapping), false)[0] as ColumnMapping).ColumnName)))
                    {
                        propInfo.SetValue(result, dbReader[(propInfo.GetCustomAttributes(typeof(ColumnMapping), false)[0] as ColumnMapping).ColumnName], null);
                    }
                }
            }
            results.Add(result);
        }
        return results;
    }
}