Skip to main content

An Asp.Net Validation Framework (Part 3)

An Asp.Net Validation Framework (Part 1)

An Asp.Net Validation Framework (Part 2)

Unfortunately, if you’re using LINQ to SQL or the Entity Framework, you can’t add the custom attributes we need for validation. You could generate your entity model and then simply use those generated objects but you would lose the ability to use the designers. I prefer to leverage the code we’ve written.

public class ValidatableOrmBase
: ValidatableBase
{

private List<CustomPropertyAttributeListItem> customPropertyAttributes;

public List<CustomPropertyAttributeListItem> CustomPropertyAttributes
{
get
{
if (customPropertyAttributes == null)
{
customPropertyAttributes = new List<CustomPropertyAttributeListItem>();
}
return customPropertyAttributes;
}
}

public override bool Validate(bool clearBrokenRules)
{
base.Validate(clearBrokenRules);
foreach (CustomPropertyAttributeListItem cvli in CustomPropertyAttributes)
{
PropertyInfo theProperty = this.GetType().GetProperty(cvli.PropertyName, BindingFlags.Public | BindingFlags.Instance);
if (!cvli.CustomAttribute.IsValid(theProperty.GetValue(this, null), cvli.PropertyName))
{
BrokenRules.Add(cvli.CustomAttribute.Rule);
}
}

return BrokenRules.Count == 0;
}
}
public class CustomPropertyAttributeListItem
{
public string PropertyName { get; set; }

public ValidationAttribute CustomAttribute { get; set; }
}

All we’ve done here is create a subclass of ValidatableBase that has a CustomPropertyAttributes property of type List<CustomPropertyAttributeListItem>. Basically, we’re building a list of attributes and the the property to which they need to be applied. Validate is then overridden to call the base (just in case there are attributes) and the loop through the list.

This technique uses exactly the same code for validation, our public interface stays the same (in case they change things so we can add attributes) and we haven’t sacrificed anything from an extensibility perspective.

partial class MyLinqToSqlClass    
: ValidatableOrmBase
{
public MyLinqToSqlClass()
: base()
{
this.CustomPropertyAttributes.Add(
new CustomPropertyAttributeListItem() {
PropertyName = "FirstName",
CustomAttribute = new RequiredAttribute() {
DisplayName = "first name" } }); }
}

Now to implement, we simply create our partial class and inherit from ValidatableOrmBase. Ok, we’re all done. Wait! You can’t use the partial class on EF entities since they already inherit from another class. Rats!!!!! Don’t fret, there is a way to accomplish our goals.

First, let’s create a new base class that implements IValidatable.

public class ValidatableEfBase
: IValidatable
{

/// <summary>
/// Holds the collection of broken business rules.
/// </summary>
private BrokenRulesCollection brokenRules;

private List<CustomPropertyAttributeListItem> customPropertyAttributes;

/// <summary>
/// Gets the collection of business rules that have
/// been broken.
/// </summary>
public BrokenRulesCollection BrokenRules
{
get
{
if (this.brokenRules == null)
{
this.brokenRules = new BrokenRulesCollection();
}
return this.brokenRules;
}
}

public List<CustomPropertyAttributeListItem> CustomPropertyAttributes
{
get
{
if (customPropertyAttributes == null)
{
customPropertyAttributes = new List<CustomPropertyAttributeListItem>();
}
return customPropertyAttributes;
}
}

public EntityObject Entity { get; set; }

/// <summary>
/// Validates the objects.
/// </summary>
/// <returns>True if the object is valid, otherwise false.</returns>
public bool Validate(bool clearBrokenRules)
{
if (clearBrokenRules)
{
this.BrokenRules.Clear();
}

foreach (CustomPropertyAttributeListItem cvli in CustomPropertyAttributes)
{
PropertyInfo theProperty = Entity.GetType().GetProperty(cvli.PropertyName, BindingFlags.Public | BindingFlags.Instance);
if (!cvli.CustomAttribute.IsValid(theProperty.GetValue(Entity, null), cvli.PropertyName))
{
BrokenRules.Add(cvli.CustomAttribute.Rule);
}
}

return BrokenRules.Count == 0;
}
}

Ok, we have all our functionality and it’s centrally located. Now, how do we expose it. Simple, we use partial classes and defer the validation to an instance of the above. Like so.

public partial class MyEFEntity
: IValidatable
{
public BrokenRulesCollection BrokenRules
{
get
{
return validator.BrokenRules;
}
}

private ValidatableEfBase validator;

protected ValidatableEfBase Validator
{
get
{
if (validator == null)
{
validator = new ValidatableEfBase();
validator.Entity = this;
}
return validator;
}
}

public bool Validate(bool clearBrokenRules)
{
CreateCustomAttributes(false);
return Validator.Validate(clearBrokenRules);
}

protected void CreateCustomAttributes(bool clearList)
{
if (clearList)
{
Validator.CustomPropertyAttributes.Clear();
}
Validator.CustomPropertyAttributes.Add(
new CustomPropertyAttributeListItem() { PropertyName = "Name", CustomAttribute = new RequiredAttribute() { DisplayName = "name" } });
}
}

Notice we have BrokenRules and Validate so we’ve met our interface requirements, meaning it looks the same from the outside. This is important for both techniques since we want to be able to change the internal implementation if MS changes things so we can add our attributes.

What happens underneath is simple. The Validator (an instance of ValidatableEfBase) actually performs all the validation on the EF entity.

That wraps up the Validation Framework. Next, I’ll look at how to create a client side validation framework for use with Asp.Net MVC.

Comments

Popular posts from this blog

Migrating Legacy Apps to the New SimpleMembership Provider

Asp.Net MVC4 uses the new SimpleMembership provider, changes the table structure and adds a new hashing algorithm. The reasons for the changes can be found in this article by Jon Galloway. This article shows how to migrate your existing apps to the new provider.I’m assuming that you stored your passwords in the unrecoverable SHA-1 format. If you didn’t, then you’ll have to change a couple of things. All of my apps are done this way so… I’m also assuming that you have created the basic skeleton of the new app and ran it once so the correct tables will be created.First, we’ll look at the new tables. Previously, we had all of those aspnet_xxxxxx tables. Here’s the new ones.UserProfileContains all of the elements relevant to the user. This is a combination of the aspnet_Users table and the aspnet_Profiles table.webpages_MembershipStores the password info when not using OAuth, Live, Facebook, etc. This table is somewhat of a match to the aspnet_Membership table.webpages_OAuthMembershipStor…

JavaScript function to automatically add slashes to date

In converting an old Windows app to a browser app, the user wanted to be able to enter dates without the slashes. Here's a simple jscript: 1:// Function to convert short date string (MMddyy) 2:// or (MMddyyyy) to a date string (mm/dd/yyyy). 3:// txtBox is the actual textbox control 4:// with the value to be processed. 5:function FixShortDate(txtBox) { 6:if (txtBox == null) { 7:return'' } 8: 9:var re = new RegExp(/(\d{6})(\d{2})?/); 10: 11:if (re.test(txtBox.value)) 12: { 13:if (txtBox.value.length == 8) { 14: txtBox.value = txtBox.value.substring(0, 2) + '/' + txtBox.value.substring(2, 4) + '/' + txtBox.value.substring(4, 8) 15: } 16: 17:if (txtBox.value.length == 6) { 18:if (txtBox.value.substring(4, 6) < 20)

Get Asp.Net Profile properties from Sql

Ever wanted to include the profile information from an Asp.Net profile in a query? It’s not that hard once you understand the structure. I’ve written a little function that does all the work. Note: I’m using Sql Server as my repository.

First we need to understand how the profile data is stored. Looking at the aspnet_Profile table, we can see that it stores the information in two columns: PropertyNames and PropertyValuesString.

Looking at PropertyNames we can see that it has a basic structure of Property Name, Data Type, Starting Position and Length. For example, in the string “FirstName:S:0:4:Phone:S:4:10:LastName:S:14:5:” we can see that FirstName is of type string, starts at position 0 and has a length of 4. Notice the zero base for the starting position, we need to correct for that in our function. This means in the PropertyValuesString “John2175551212Smith”, we would start with the first position and proceed 4 characters to get the name.

You might be thinking …