Friday, June 3, 2011

ASP.NET Dynamic Data - Part 8 - Customizing Field Validation

In ASP.NET Dynamic Data you can customize and extend data validation in several different ways.

  • Using DataAnnotations attributes on individual data fields.
  • Overriding the partial class method that processes changes for the individual data field.
  • Override the OnValidating or Validate event, to customize validation for any data field.
  • Create a custom validation attribute

Creating a partial class for validation

The first thing we need to do, is to create the partial class that extends the data model. This makes it possible to add metadata through attributes and implementing partial class methods to create your own validation logic. We have already done this in this serie in part 2, so take a look there if you don’t know how to do this, after that we need to create the metadata class which is done in part 3.

Customize validation using attributes

This is the easiest way. It allows you to use default validation rules provided by the DataAnnotations attributes.

  1. In the partial class create a property or field with the same name as the data field to validate.
  2. Apply one of the attributes from the DataAnnotations namespace to the field or property.
Example 1

public class TableMetaData {
	[Required]
	public object Name { get; set; }

	[StringLength(10)]
	public object Description;
}

The example makes the Name attribute required and the length of the description at least 10 characters long. You can also apply several validation attributes to the same field.

Using partial class method for an individual field

Another way to do more complex validation, is to override a partial class method that processes changes made to an individual data field. The naming convention for this is On<FieldName>Changing.

  1. Override the partial class method.
  2. Add the validation logic.
Example 2

public partial class Table {
	partial void OnNameChanging(string value) {
		if (value.Length < 5) {
			throw new ValidationException("Name must be at least 5 characters long.");
		}
	}

	partial void OnPriceChanging(double price) {
		if (price < 0) {
			throw new ValidationException("Price cannot be negative!");
		}
	}
}

The example validates the name is at least 5 characters long, and the price is non-negative. This example could also be done using the built-in attrbutes. All exceptions thrown in the data model are caught by the DynamicValidator control, which also displays it in the page. The parameter is typed to match the data type in the model.

Using partial class method for all fields in the model

This method allows you to control the validation logic for all fields in the data model at the same time, which is very useful when the logic can be applied to more than one data field, and allows you to validate combinations of multiple data fields.
The way to do this is different whether you use a Linq to SQL or Entity Framework data model.

Linq to SQL

  1. Override the OnValidate method
  2. Add to validation logic
Example 3

partial void OnValidate(ChangeAction action) {
	if (this._IsStock && this._Amount <= 0) {
		throw new ValidationException("The product cannot be in stock when the amount is 0 or less");
	}
}

The example validate that a product only can be in stock, when the amount is greater than zero.

Entity Framework

  1. Create a partial class for the entity class you want to implement custom validation on
  2. Language specific step
    • If C# create a partial method called OnContextCreated which registers an event handler for the SavingChanges event
    • If VB just create an event handler for the SavingChanges event
  3. Add the logic to the partial class method
Example 4

public partial class ProductsEntities {
	partial void OnContextCreated() {
		SavingChanges += OnSavingChanges;
	}
	
	public void OnSavingChanges(object sender, EventArgs e) {
		var stateManager = ((ProductsEntities)sender).ObjectStateManager;
		var changedEntities = stateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added);
		foreach (var entry in changedEntities) {
			if (entry.Entity is Product) {
				Product prod = (Product)entry.Entity;
				if (prod.InStock && prod.Amount <= 0) {
					throw new ValidationException("Product cannot be in stock when the amount is zero or less");
				}
			}
		}
	}
}

Custom validation attribute

Let’s you create an attribute you can reuse across projects and/or models for a single data field. The attribute must derived from ValidationAttribute.

  1. Create a new class
  2. Add references to System, System.Globalization and System.ComponentModel.DataAnnotations
  3. Make the class sealed
  4. Derive the class from ValidationAttribute
  5. Apply the AttributeUsageAttribute and indicate that the attribute only can be applied to a property or field one time
  6. Override the IsValid and add the validation logic inside
  7. Optionally you can override the FormatErrorMessage to perform error-message formatting.
  8. Apply the attribute just as you would with one of the built-in validation attributes

An example of a attribute could look like this


[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false]
public sealed class CapitalizeAttribute : ValidationAttribute {
	public override bool IsValid(object value) {
		return Char.Uppercase(value.ToString()[0]);
	}

	public override string FormatErrorMessage(string name) {
		return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
	}
}

3 comments:

  1. good explanation.

    ReplyDelete

  2. Given so much information in it. its very useful .perfect explanation about Dot net framework.Thanks for your valuable information. dot net training in chennai velachery | dot net training institute in velachery

    ReplyDelete
  3. It is really a great work and the way in which u r sharing the knowledge is excellent.
    Thanks for helping me to understand basic concepts. As a beginner in Dot Net programming your post help me a lot.Thanks for your informative article. dot net training and placement in chennai | Dot Net Training in velachery

    ReplyDelete