Tuesday, May 17, 2011

Css Resets

I've come across Eric's Reset, but not the Yahoo and MaxDesign ones, so thought it was about time to make a list when I did: (I'll add as I find them)

meyerweb.com | Reset Reloaded
Yahoo! YUI Reset
maxdesign | Css Reset - a simpler option

Html 5 Doctor | Html 5 Reset

Tuesday, April 26, 2011

Javascript Hash Libraries

Today I came across these hash algorithm implementations in Javascript.

SHA-256 : http://anmar.eu.org/projects/jssha2/ (download)
MD5 & SHA1: http://pajhome.org.uk/crypt/md5/ (download)

The download links are to the latest versions as of 2011-04-27.

Monday, April 25, 2011

OleDbException | Exception on Inserting a Date

The exception in question is an OleDbException with the message: "The fractional part of the provided time value overflows the scale of the corresponding SQL Server parameter or column. Increase bScale in DBPARAMBINDINFO or column scale to correct this error."

I was receiving this error when inserting a row that contained a DateTime in Sql Server.

Firstly, Some Context
The context is that I have an application that I'm volunteering some time on that has OleDbConnections/OleDbCommands scattered through many pages. It used to connect to a Microsoft Access database, but I moved it to Sql Server and ended up using a connection string that uses the SQLNCLI10 provider (Originally the SQLNCLI provider, but that wasn't provided on the host that we signed up for) I didn't want to change all the occurrences of OleDbConnection etc obviously.

I received the above mentioned exception and had a quick look, but didn't find anything obvious as to why this might be happening. The exception is somewhat clear, but why this was happening in my case was not so clear.

The Test Code
I made a simple test application that talked to a database to simply insert a date. The code that fails is thus:

string query = "INSERT INTO DateTimeTest ([Date]) VALUES (?)";

var date = DateTime.Now;

OleDbConnection connection = new OleDbConnection(
    connectionString );

OleDbCommand command = new OleDbCommand( query, connection );
command.Parameters.Add(new OleDbParameter( "Date", date));

connection.Open();

command.ExecuteNonQuery();

Fairly simple stuff. Note that the connection string is stored in a variable called connectionString and looks something like this:

string connectionString = "PROVIDER=SQLNCLI10;database=TESTING;Server=localhost\\instance_name; trusted_connection=yes";

The Solution
The solution to my problem was to change the way that I was adding the date as a parameter to the command so that the command knew that it was a DateTime; like this:

command.Parameters.Add( "Date", OleDbType.Date ).Value = date;

I now no longer get the exception and my code works. Yay! :oD

Explanation
I'm not sure exactly why the failing code failed, but I suspect that it might be something along the lines of that the provider doesn't know or try to determine the type that the OleDb type that the parameter should be and therefore might just call .ToString() on the date time and try and insert it in this manner, and thus the error. I've not verified that this is what is happening though.

Friday, April 22, 2011

Extension Methods | Calling Extension Methods on Null References

"Can extension methods be called on a null reference?" That was what I said when I read the following on a post by Marc Gravell's where he says:

(the Step(…) method is implemented as an extension method, so it is perfectly happy operating on a null reference; which is a crude but simple way of short-circuiting the timings for regular users)

To be honest I had never thought about this before... I therefore had to try it out and figure out why!

using System;

namespace ExtensionMethodNullReferenceTest
{
    class Program
    {
        static void Main( string [] args ) {
            ((object)null).SaySomething();
        }
    }

    static class ExtensionMethod
    {
        public static void SaySomething( this object obj ) {
            Console.WriteLine( "Saying something..." );
        }
    }
}

In the example above we have a very simple extension method called SaySomething(). In Main I'm calling that extension method on... well... nothing.

If we remind ourselves that extension methods are not really extending the object, but are simply static methods on a static class, and that they are called as static methods, this makes sense. The object that we appear to be calling the extension method on is just passed as an argument to the static extension method.

The Il produced for the call to the extension method is as follows, the null reference being pushed onto the stack for the first parameter:

call void ExtensionMethodNullReferenceTest.ExtensionMethod::SaySomething(object)

This raises a possibly obvious issue. If we are going to do anything with the object that is passed we need to be careful. The following code will throw a NullReferenceException

using System;

namespace ExtensionMethodNullReferenceTest
{
    class Program
    {
        static void Main( string [] args ) {
            ((object)null).SaySomething();
        }
    }

    static class ExtensionMethod
    {
        public static void SaySomething( this object obj ) {
            Console.WriteLine( obj.ToString() );
        }

    }
}

The error is as follows:

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at ExtensionMethodNullReferenceTest.Program.Main(String[] args) in C:\_Development\Examples\ExtensionMethodNullReferenceTest\ExtensionMethodNullReferenceTest\Program.cs:line 8

Interestingly, in the error I received above, I don't actually get a line number inside the extension method. ( Though when I put another Console.WriteLine() above the first Console.WriteLine() in the extension method I do then get an exception message that tells me the line number within the extension method.)

The main point is that if you are calling an extension method on an object reference that is null and you try and do something with that reference within the extension method, you could get an exception if not careful.

Wednesday, April 20, 2011

microsoft-web-helpers MVC3 | SimpleMembershipProvider Error

I tried to install the microsoft-web-helpers (version 1.1) package via NuGet today and then all of a sudden I could not build because I received an error saying that SimpleMembershipProvider could not be found.

The solution is to add the following references to the project:

  • WebMatrix.Data
  • WebMatrix.WebData

I found the solution here.

Wednesday, March 23, 2011

Max Length of CultureInfo.Name Property

I was looking for the answer to the question: "What is the maximum length of the CultureInfo.Name property?" and came across this question. I've answered the question but thought that I would find the answer easier if it was on my blog (ie. here).

The reason that the maximum is 84 characters is because that is what the CultureAndRegionInfoBuilder class restricts the length to. But you can't just declare a culture called "ThisIsLongerThan8Characters" because you must seperate the culture name with - (or _ it seems) with each part being a maximum of 8 characters long.

The following code creates a culture with a length of 84 characters, registers it, uses it and unregisters it.

string cultureName = "qwertyui-12345678-qwertyui-12345678-qwertyui-12345678-qwertyui-12345678-qwertyui-123";
Console.WriteLine( "MAX LENGTH: " + cultureName.Length );
try {
    CultureAndRegionInfoBuilder.Unregister( cultureName );
} catch {
    Console.WriteLine( "Cannot remove culture" );
}

CultureAndRegionInfoBuilder builder = new CultureAndRegionInfoBuilder( cultureName , CultureAndRegionModifiers.None );
             
CultureInfo ci = new CultureInfo( "en-AU" );
RegionInfo ri = new RegionInfo( "US" );

builder.LoadDataFromCultureInfo( ci );
builder.LoadDataFromRegionInfo( ri );
builder.Register();

CultureInfo info = new CultureInfo( cultureName );
            
Console.WriteLine( DateTime.Now.ToString( info.DateTimeFormat.LongDatePattern ) );
Console.WriteLine( info.Name );
Console.WriteLine( info.DisplayName );

try {
    CultureAndRegionInfoBuilder.Unregister( cultureName );
} catch {
    Console.WriteLine( "Cannot remove culture" );
}

Tuesday, March 22, 2011

Gravatar Helpers | ASP.NET MVC

Update: 2011-04-26 Changed the methods from returning string to returning MvcHtmlString (silly me) and created a few more overloads to assign a title attribute.

Was looking for a helper that I'd seen previously. I still haven't found it, but noticed this post with Gravatar helpers.

I've adjusted it in the following ways:
  • The code didn't trim or lowercase the email address before hashing, so I changed that
  • I added an overload which takes an enum for selecting the default image. 
  • The Url for the default image was not being Url encoded. This is fine if you are using one of the defaults that they provide, but might not work if you pass a Url to an image in.
  • There are several more overloads
  • Generally made more of a mess :oD
Some of these changed just help to ensure that there are no problems when getting the Gravatar, some are just niceties for me which are probably a little clearer to read, but not really necessary considering that you would generally call these a total of maybe 1 or 2 places in an application.

Hope this is useful to someone.
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web.Mvc;

namespace Catechize.Helpers
{
    public enum GravatarDefault
    {
        FileNotFound,
        MysteryMan,
        Identicon,
        MonsterID,
        Wavatar,
        Retro
    }

    // Kudos to Rob Connery http://blog.wekeroad.com/2010/01/20/my-favorite-helpers-for-aspnet-mvc
    public static class GravatarHelpers
    {
        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email)
        {
            var url = GetGravatarUrl(helper, CleanupEmail(email), 40, GetDefaultGravatarString(GravatarDefault.MysteryMan));
            return MvcHtmlString.Create(ConstructImgTag(url));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, string title) {
            var url = GetGravatarUrl(helper, CleanupEmail(email), 40, GetDefaultGravatarString(GravatarDefault.MysteryMan));
            return MvcHtmlString.Create(ConstructImgTag(url, title));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, int size)
        {
            var url = GetGravatarUrl(helper, CleanupEmail(email), size, GetDefaultGravatarString(GravatarDefault.MysteryMan));
            return MvcHtmlString.Create(ConstructImgTag(url));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, string title, int size)
        {
            var url = GetGravatarUrl(helper, CleanupEmail(email), size, GetDefaultGravatarString(GravatarDefault.MysteryMan));
            return MvcHtmlString.Create(ConstructImgTag(url, title));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, int size, string defaultImageUrl)
        {
            var url = GetGravatarUrl(helper, CleanupEmail(email), size, UrlEncode(helper, defaultImageUrl));
            return MvcHtmlString.Create(ConstructImgTag(url));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, string title, int size, string defaultImageUrl)
        {
            var url = GetGravatarUrl(helper, CleanupEmail(email), size, UrlEncode(helper, defaultImageUrl));
            return MvcHtmlString.Create(ConstructImgTag(url, title));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, int size, GravatarDefault defaultImage)
        {
            var mode = GetDefaultGravatarString(defaultImage);

            var url = GetGravatarUrl(helper, CleanupEmail(email), size, mode);
            return MvcHtmlString.Create(ConstructImgTag(url));
        }

        public static MvcHtmlString Gravatar(this HtmlHelper helper, string email, string title, int size, GravatarDefault defaultImage)
        {
            var mode = GetDefaultGravatarString(defaultImage);

            var url = GetGravatarUrl(helper, CleanupEmail(email), size, mode);
            return MvcHtmlString.Create(ConstructImgTag(url, title));
        }

        public static string GetDefaultGravatarString(GravatarDefault defaultGravatar) {
            var mode = String.Empty;
            switch (defaultGravatar)
            {
                case GravatarDefault.FileNotFound:
                    mode = "404";
                    break;
                case GravatarDefault.Identicon:
                    mode = "identicon";
                    break;
                case GravatarDefault.MysteryMan:
                    mode = "mm";
                    break;
                case GravatarDefault.MonsterID:
                    mode = "monsterid";
                    break;
                case GravatarDefault.Wavatar:
                    mode = "wavatar";
                    break;
                case GravatarDefault.Retro:
                    mode = "retro";
                    break;
                default:
                    mode = "mm";
                    break;
            }
            return mode;
        }


        private static string ConstructImgTag(string src, string title = "Gravatar")
        {
            var result = "\"Gravatar\"";
            return String.Format(result, src, title);
        }

        static string GetGravatarUrl(HtmlHelper helper, string email, int size, string defaultImage)
        {
            string result = "http://www.gravatar.com/avatar/{0}?s={1}&r=PG";
            string emailMD5 = EncryptMD5(CleanupEmail(email));

            result = (string.Format(result,
                        EncryptMD5(email), size.ToString()));

            if (false == String.IsNullOrEmpty(defaultImage))
                result += "&d=" + defaultImage;
        
            return result;
        }

        private static string UrlEncode(HtmlHelper helper, string url)
        {
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            return urlHelper.Encode(url);
        }

        private static string CleanupEmail(string email)
        {
            email = email.Trim();
            email = email.ToLower();

            return email;
        }

        private static string EncryptMD5(string value)
        {
            byte[] bytes;

            using (var md5 = MD5.Create())
            {
                bytes = Encoding.ASCII.GetBytes(value);
                bytes = md5.ComputeHash(bytes);
            }

            return String.Concat(bytes.Select(t => t.ToString("x2")));
        }
    }
}