Things I Write

Simple jQuery Form Wrapper

Posted on 3/22/2010 at 3:10pm

I've created a small Javascript routine that wraps the jQuery Form plugin to provide a little more versatility around Html form posting.  This little script accommodates both Ajax and typical post-back methods:

//requires jquery.form.js
var formHandler = function(formId) {
var loadingHTML = '<div id="ajaxLoader" class="ajaxLoader"></div>';

var addHash = function(checkHash) {
if (checkHash.indexOf('#') != 0) {
checkHash = '#' + checkHash;
}
return checkHash;
}

formId = addHash(formId);

return {
submitForm: function(url) {
url = url || $(formId).attr('action');
$(formId).attr('action', url).submit();
return false;
},
ajaxSubmit: function(targetId, submitUrl) {
submitUrl = submitUrl || $(formId).attr('action');
targetId = addHash(targetId);
$(formId).ajaxSubmit(
{
url: submitUrl,
beforeSubmit: function(){$(formId).prepend(loadingHTML);},
target: targetId,
error: function(data) {
$("#ajaxLoader").remove();
alert("There was a problem with your request.");
},
success: function() {
$("#ajaxLoader").remove();
//put some success-handling code here, if desired
}
});
return false;
}
};
}

Why? You ask. Because:

  1. An "ajaxLoader" div is automatically inserted below the form tag on Ajax submit and can be styled to represent an "Ajax spinner" animated gif.
  2. Ajax (i.e. XmlHttpRequest) errors are handled gracefully.
  3. It's a one-stop shop for dynamic Ajax and traditional form posting.

Usage scenarios

Do an ajax form post using form action attribute value:

<a href=""
onclick="return formHandler('#some_form_id').ajaxSubmit('#some_target_element_id');">

Some Link</a>

Do an ajax form post using given url:

<a href=""
onclick="return formHandler('#some_form_id').ajaxSubmit('#some_target_element_id', '/some_action_url');">

Some Link</a>

Do a traditional form post to given url:

<a href=""
onclick="return formHandler('#some_form_id).submitForm('/some_action_url');">

Some link</a>

I could improve this by passing an "options" dictionary that defines the optional elements; I'd include a success function option as part of this definition. I'm also considering passing in a jQuery selector object rather than a single form Id as this might provide a little more versatility in selecting which forms to decorate with the form handler.

Fluent Validation

Posted on 1/24/2010 at 3:16pm

I've recently taken an interest in some of the powerful Fluent-ly built libraries for C#. Fluent NHibernate is now my O/RM of choice and I'm really trying hard to find an excuse to implement Autofac, a Fluent Inversion of Control container, in one of my projects (as an aside: I still haven't found the tipping point that justifies introducing an IoC container).

Object validation is one area that I thought could benefit from a Fluent implementation. Fluent Validation provides a more expressive means of enforcing both data and business rules, capturing them in a way that is expressly human-readable.

In it's simplest form, a validation rule could be enforced as such:

var validator = new Validator<SomeModelObjectType>(someModelObjectInstance);

validator.Validate(m => m.SomePropertyThatCantBeEmpty).IsNotEmpty();

If this validation rule fails, the name of the property and a default error message will be placed in a Dictionary accessible via the validator instance. The validation result can also be manipulated in the following ways:

validator.Validate(m => m.SomePropertyThatCantBeEmpty)
.IsNotEmpty()
.WithMessage("You better put something here!");

Or

validator.Validate(m => m.SomePropertyThatCantBeEmpty)
.IsNotEmpty()
.AsBoolean();

Or

validator.Validate(m => m.SomePropertyThatCantBeEmpty)
.IsNotEmpty()
.WithMessage("You better put something here!")
.AsBoolean();

The WithMessage() method provides a way to override the default error value and AsBoolean() is useful for conditional statements.

This covers the basics. Here is a simple real-world example that we'll use to go into a little more depth:

public bool Validate()
{
var validator = new Validator<AccountCreationModel>(this, Errors);

return validator.Validate(m => m.Password)
.IsNotEmpty()
.WithMessage("Password is required")
.AsBoolean()

& validator.Validate(m => m.ConfirmPassword)
.IsEqualTo(m => m.Password)
.WithMessage("Passwords must match")
.AsBoolean()

& validator.Validate(m => m.Email)
.IsEmailFormat()
.WithMessage("Email must be in the proper format")
.AsBoolean()

& validator.Validate(m => m.Email)
.IsNotEmpty()
.WithMessage("Email is required")
.AsBoolean()

&& validator.Validate(m => m.Email)
.AccountIsAvailable(Repository)
.WithMessage("An Account with this email address already exists")
.AsBoolean();
}

This validates an account-creation form model that consists of three fields: Email, Password, and Confirm Password. I'm passing into the Validator constructor an Error dictionary that will be used further downstream to report validation errors to the user. Notice the AccountIsAvailable method that takes a Repository object; this is an example of how Fluent Validation can be used to enforce data-centric rules.

At the core, there are four classes at work here:

  1. Validator<T>
  2. ValidationAction<T, TResult>
  3. ValidationResult
  4. ValidationActionExtensions

The Validator class provides the Validate() method that kicks everything off:

public class Validator<T>
{
public Dictionary<string, string> ErrorDictionary
{
get;
private set;
}

private T ObjectToValidate
{
get;
set;
}

public Validator(T objectToValidate) : this(objectToValidate, null) { }

public Validator(T objectToValidate, Dictionary<string, string> errorDictionary)
{
ErrorDictionary = errorDictionary ?? new Dictionary<string, string>();
ObjectToValidate = objectToValidate;
}

public ValidationAction<T, TResult> Validate<TResult>(Expression<Func<T, TResult>> propertyToVerify)
{
var expression = ValidationHelper.AssertExpressionIsNotNull(propertyToVerify);

TResult value = propertyToVerify.Compile()(ObjectToValidate);

return new ValidationAction<T, TResult>(value, ObjectToValidate, expression, ErrorDictionary);
}
}

The call to Validate() returns an instance of the ValidationAction<T, TResult> class:

public class ValidationAction<T, TResult> : IValidationLeaf
{
public TResult PropertyValue { get; private set; }
private MemberExpression Property { get; set; }
public T ObjectToValidate { get; private set; }

internal ValidationAction(TResult propertyValue,
T objectToValidate,
MemberExpression property,
Dictionary<string, string> errors)
{
PropertyValue = propertyValue;
Property = property;
ObjectToValidate = objectToValidate;
ErrorDictionary = errors;
}

public ValidationResult GenerateResult(bool isValid)
{

if (!isValid)
{
ErrorDictionary[ValidationHelper.GetFullPropertyName(Property)] =
ValidationHelper.GetFullPropertyName(Property) + " has errors";
}

return new ValidationResult(isValid,
ValidationHelper.GetFullPropertyName(Property),
ErrorDictionary);
}

#region IValidationLeaf Members

public Dictionary<string, string> ErrorDictionary { get; private set; }

#endregion
}

And the call to GenerateResult() returns an instance of ValidationResult:

public class ValidationResult : IValidationLeaf
{
private readonly bool _validationState;
private readonly string _propertyName;

internal ValidationResult(bool validationState,
string propertyName,
Dictionary<string, string> errors)
{
ErrorDictionary = errors;
_validationState = validationState;
_propertyName = propertyName;
}

public ValidationResult WithMessage(string message)
{
if (!_validationState)
{
ErrorDictionary[_propertyName] = message;
}

return this;
}

public bool AsBoolean()
{
return _validationState;
}

#region IValidationLeaf Members

public Dictionary<string, string> ErrorDictionary { get; private set; }

#endregion
}

So where, you might ask, are all the IsEmailFormat(), IsNotEmpty(), etc. methods?

These exist entirely as extension methods, the core of which live in ValidationActionExtensions. Here is an example of one such method:

public static ValidationResult IsNotEmpty<T>(this ValidationAction<T, string> validationAction)
{
return validationAction.GenerateResult(!string.IsNullOrEmpty(validationAction.PropertyValue));
}

These extension methods do whatever special work needs to be done to enforce the validation rule and then simply returns the result of the GenerateResult() method of ValidationAction.

Extension Methods allow you to hang domain-specific validation rules onto the Fluent Validation framework. The AccountIsAvailable() method used in the example above was simply an extension added within the namespace of the web application.

Another great advantage of using Extension Methods to encapsulate the validation logic is that you can specify the type of the property to which the method will apply via the TResult parameter of the ValidationAction that it extends. For example, the following made-up rule will only apply to model properties that are of type int:

public static ValidationResult IsGreaterThanFive<T>(this ValidationAction<T, int> validationAction)
{
bool isGreaterThanFive = validationAction.PropertyValue > 5;
return validationAction.GenerateResult(isGreaterThanFive);
}

Finally, with some small changes, the ValidationResult class can be extended to perform special actions in the case of a failed validation rule (by making the _validationState and _propertyName fields publicly accessible).

For future development, I would love to apply the Fluent Validation structure such that validation can be mapped as a configuration, analogous to the way properties and relationships are mapped to Value Objects with Fluent NHibernate

The project is hosted here: http://code.google.com/p/sharpvalidation/

RuthsChris.com wins the "Featured on a Microsoft Technology Website" Award!

Posted on 9/28/2009 at 1:32pm

UPDATE: With the release of MVC 2 Microsoft has overhauled www.asp.net/mvc, removing the "featured sites" section altogether. Though this is a sad day for me, it represents a great day for web development in general. Anyway, read about what once was:

RuthsChris.com wins the unofficial "Website That Uses Microsoft Technology Featured on a Microsoft Technology Website" Award (it's unofficial because I made it up). Go to http://www.asp.net/mvc/whatisaspmvc/ and then scroll to the bottom. You'll see a collection of screen grabs that looks something like this:


Boo-yah! There it is: RuthsChris.com on the "What is ASP .Net MVC" page. I'm not totally sure how this came to be, but I think it involves Twitter: Rick Diaz, a Software Architect at my company, submitted a reply to a Phil Haack post on Twitter soliciting any sites that use .Net MVC. Rick replied with RuthChris.com and the rest is history.

Defining the Cloud

Posted on 6/22/2009 at 6:03pm

Cloud computing has started gaining traction among software product and service providers. Regardless, defining the cloud is still a difficult task, since the concept is nebulous and can be defined both in terms of technology infrastructure and business solutions.

Rather than articulating a single statement that attempts to outline the myriad perspectives inherent to the Cloud, the definition can be elucidated by answering a few questions:

Really, what is it?

Simply stated: the cloud provides "computing resources on demand." For example, if you need a computer to host your personal blog, you can fill out a form at a cloud-service provider website and they will give you one. You’re not really buying or renting a particular computer or piece of hardware; you are provisioning what is called a "virtual machine." Once you’ve acquired this virtual machine, you are charged according to how often it is used. Amazon’s billing model works like a utility: just as your electricity company charges you every month for the amount of electricity you use, Amazon charges you for how often your computing resources are used (interestingly, I’ve heard of people with particularly unpopular websites getting charged $.92 on their monthly Amazon bill). Google and Microsoft give you a certain amount of usage for free before they start charging for use.

Who provides it?

Amazon provides virtual web servers through its Elastic Compute Cloud (EC2) service and disk space for file storage through their Simple Storage Service (S3). Google and Microsoft are taking a different approach. With Google’s App Engine and Microsoft’s Azure, you don’t get direct control over virtual machines. Rather, you are provided a platform where you can upload code, images, html, and other assets that define a web application. Microsoft and Google automatically acquire the virtual computing resources for you and will install your application on them.

All of these services can be managed through web-based interfaces that allow you to upload your applications and monitor virtual computer usage. Additionally, companies that provide physical machines and bandwidth for lease, such as RackSpace, are also starting to get into the cloud-based platform business.

What are the advantages?

It’s cheap. Google gives you enough free bandwidth for 5 million page-views a month before they start charging for use. Microsoft hasn’t yet provided pricing details for their service, but it is expected to resemble Google’s pricing model.

Cloud-based platforms are also extremely scalable; if your website traffic goes from two page views on one day to three million the next, all of the virtual machines required to handle the extra load are automatically acquired, without any interaction required on the part of anyone’s IT department.

What are the risks?

Like all things internet-related, cloud services can fail. If your cloud provider does fail and your website goes down, you probably won’t find anyone you can reach on the phone for support. Theoretically, cloud service providers build enough redundancy into their infrastructure to make failures and down-time obsolete; in practice, this has not proven to always be the case.

Microsoft and Google currently limit the capabilities of programs installed in the cloud (for example, you can’t access the file system); thus developers must conform to the frameworks provided by these services. Almost any type of web application can be accommodated, but anything that is particularly specialized requires a dedicated physical machine.

Security concerns are currently a huge barrier to entry for many businesses. It is all but impossible to guarantee where sensitive data will be located; it could be spread out across massive data centers around the country. Due to the lack of control over the geographical location of the machines that store data, it is impossible to apply protocols for storing sensitive information (such as industry-standard PCI, SAS70 and ISO9000 compliance requirements). There is also a risk that some of the smaller cloud-service providers might go out of business or be acquired; what, then, happens to all the valuable information they stored?

Prepositions: things you can do to a cloud

Certain phrases are starting to arise that refer to things that are "in the Cloud" or things that come "from the Cloud." These statements allude to alternate meanings of Cloud Computing. Via our Gmail accounts or our FaceBook profiles (or Flickr streams, etc.), there is much information about us being stored in the ethereal internet infrastructure of Cloud Computing. When referring to these particular forms of information, people will sometimes refer to "the Cloud." They are substituting the qualities of the information being stored for the more accurate depiction of the way it is being stored. Having said that, "the Cloud" is now coming to be defined as a personalized version of the internet where people can store their videos, photos, thoughts, etc. and also peruse the same variety of information associated with others.

What’s the future of Cloud Computing?

At the risk of over-using an already questionable pun: "the sky’s the limit." Cloud computing already provides the advantage of cheap or free web hosting. In the future, mobile and desktop applications will start to leverage the cloud to provide ubiquitous access to our files and information. For example, imagine creating a Word Document in Microsoft Word on your computer, saving your changes, and then opening up the very same document on an entirely different computer later, without having to transfer the file between machines. The document can be stored in the cloud, tied to your login (also stored in the cloud), and then instantly accessed through a desktop application, a mobile device, or a web-browser.

This type of instantly-accessible and globally persistent data storage will change the way we think about information. No longer will the things we create or consume on a computer be tied to a particular piece of hardware; they will be available at all times from anywhere.