The solution is to add the following references to the project:
- WebMatrix.Data
- WebMatrix.WebData
I found the solution here.
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 = ""; 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"))); } } }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false)] public class JRequiredAttribute : ValidationAttribute { public JRequiredAttribute() { ErrorMessageResourceName = "Required"; ErrorMessageResourceType = typeof(ValidationMessages); } public override bool IsValid(object value) { if (value == null) return false; string str = value as string; if (String.IsNullOrEmpty(str)) return false; return true; } }In the constructor I’m specifying the key in the resource file that contains the message. The second line is the type containing the resources. If I have a resource file for a given culture other than english and the user’s culture is set to that culture then the message will be shown in that culture instead of in english.
public class JRequiredValidator : DataAnnotationsModelValidator { public JRequiredValidator( ModelMetadata metadata, ControllerContext context, JRequiredAttribute attribute) : base(metadata, context, attribute) { } public override IEnumerable GetClientValidationRules() { var rule = new ModelClientValidationRule { ErrorMessage = ValidationMessages.Required, ValidationType = "jrequired" }; return new [] {rule}; } }This piece of code is is used to generate the client side JSON that is written to the page. The client side validation framework can then hook into this information to do the client side validation. Now for registration:
DataAnnotationsModelValidatorProvider.RegisterAdapter( typeof(JRequiredAttribute), typeof(JRequiredValidator));
jQuery.validator.addMethod("jrequired", function(value, element) { if (value == undefined || value == null) return false; if (value.toString().length == 0) return false; return true; });The above can be added to the top of the MicrosoftMvcJQueryValidation.js file (where is says “register custom jQuery methods”
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
private static string MakeErrorString(string displayName) { // use CurrentCulture since this message is intended for the site visitor return String.Format(CultureInfo.CurrentCulture, MvcResources.ClientDataTypeModelValidatorProvider_FieldMustBeNumeric, displayName); }And is now this:
private static string MakeErrorString(string displayName) { // use CurrentCulture since this message is intended for the site visitor return String.Format(CultureInfo.CurrentCulture, ValidationMessages.FieldMustBeNumeric); }... referencing my custom resource file.
// Remove the item that validates fields are numeric! foreach (ModelValidatorProvider prov in ModelValidatorProviders.Providers) { if (prov.GetType().Equals(typeof(ClientDataTypeModelValidatorProvider))) { ModelValidatorProviders.Providers.Remove(prov); break; } } // Add our own of the above with a custom message! ModelValidatorProviders.Providers.Add( new CustomClientDataTypeModelValidatorProvider());