Print Page | Close Window

Dynamic verification

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3376
Printed Date: 12-Jan-2026 at 2:30pm


Topic: Dynamic verification
Posted By: jeanb
Subject: Dynamic verification
Date Posted: 05-Apr-2012 at 3:02am
I am trying to add regular expression verification to some of my entity properties depending on whether they've been given a regular expression pattern to match by the users.  In other word, a user can decide that they want to make an employee code that is 4 digits long "^[0-9]{4}$", and that they want a supplier code to be 3 uppercase - 2 digits "^[A-Z]{3}[-][0-9]{2}$".
 
One problem to overcome is that I need to dynamically add this verification to the entities at runtime.
 
I have been able to dynamically register property interceptors against the required entities so that I can access their BeforeSet or AfterSet.  I have managed to get this working fine.  But the problem is, this is only going to be called when the actual properties are set.  I cannot access this code from normal verification (so I can't check it before saving, or get property validation errors to my UI controls, etc).
 
It seems that my only options for verifications are discovery which I cannot add to at runtime, or to use VerifierEngine.Add(verifier).  My problem with VerifierEngine.Add(verifier) is that it is associated with an entity manager.  My application has many workspaces each with their own entity manager, so basically if I use this method then every time an entity manager is created I would have to add any possible format verifications to that entity manager.  This seems a bit heavy handed.
 
Does anybody have any suggestions for how to go about this?
 
 



Replies:
Posted By: jeanb
Date Posted: 05-Apr-2012 at 4:54am

As an update, this is what I have done to make it work, but I'd still love to know if there is another way to do this and I'm barking up the wrong tree ...

So when my application starts, each module will look in my database store to find if there are any formats registered against entity properties in their namespace. For each entity and property, a method is called on my base entity (the one all IdeaBlade entities inherit from).   This method saves the property name and format required in a dictionary, and once per entity only adds a property interceptor action for the whole entity.  Then finally when a property on the entity is set, the action is called and it loops through the dictionary and adds verifiers for each of the properties that need formats.  Then the property interceptor action is removed.

Here is example code:  This would be called from Module.Initialize() (hard-coded values for example purposes only)

EntityBase entity = (EntityBase)Type.GetType("Courier").GetConstructor(new

Type[0] { }).Invoke(newobject[0] { });

 

entity.RegisterPropertyInterceptor("Code", "^[0-9]{4}$");

entity.RegisterPropertyInterceptor("AccountNumber", "^[A-Z]{3}[-][0-9]{2}$");

 

 

Then this is inside my EntityBase class:

#region Property Formatting

private Dictionary<string, PropertyFormatting> propertyFormatInterceptorList = new Dictionary<string, PropertyFormatting>();

             

internal class PropertyFormatting

{

private readonly string format;

private readonly string formatMessage;                

 

internal PropertyFormatting(string format, string formatMessage, bool verifierIsLoaded)

{

this.format = format;

this.formatMessage = formatMessage;

}

 

internal string Format { get { return this.format; } }

internal string FormatMessage { get { return this.formatMessage; } }

}

             

public void RegisterFormatPropertyInterceptor(string propertyName, string format, string formatMessage)

{

string entityPropertyInterceptorKey = String.Format("{0}", this.EntityAspect.Entity.ToString());

 

if (!propertyFormatInterceptorList.ContainsKey(propertyName))

{

if (this.EntityAspect.EntityMetadata.EntityProperties.Where(ep => ep.Name == propertyName).FirstOrDefault() != null)

{

propertyFormatInterceptorList.Add(propertyName, new PropertyFormatting(format, formatMessage, false));                           

List<PropertyInterceptorAction<PropertyInterceptorArgs<Entity, Object>>> actions = PropertyInterceptorManager.CurrentInstance

.GetActions<PropertyInterceptorArgs<Entity, Object>>(this.GetType(), null, PropertyInterceptorMode.BeforeSet)

.ToList();

if (actions.Where(a => a.Key == entityPropertyInterceptorKey).FirstOrDefault() == null)

{

PropertyInterceptorManager.CurrentInstance.AddAction(

new PropertyInterceptorAction<PropertyInterceptorArgs<Entity, Object>>(

this.GetType(),

null,

PropertyInterceptorMode.BeforeSet,

new Action<PropertyInterceptorArgs<Entity, Object>>(PropertyFormatInterceptor),

0.0,

entityPropertyInterceptorKey));

}

}

}

}

 

public void PropertyFormatInterceptor(PropertyInterceptorArgs<Entity, Object> args)

{

if (args.Instance.EntityAspect.EntityManager != null && args.Instance.EntityAspect.EntityManager.VerifierEngine != null)

{

// This should only be called once

foreach (var propertyFormatter in this.propertyFormatInterceptorList)

{

PropertyFormatting propertyFormatting = propertyFormatter.Value;

Verifier formatVerifier = new RegexVerifier(this.GetType(), propertyFormatter.Key, true, new NamedRegexPattern(propertyFormatting.FormatMessage, propertyFormatting.Format));

formatVerifier.VerifierOptions.ShouldExitOnBeforeSetError = true;

formatVerifier.VerifierOptions.ExecutionModes = IdeaBlade.Validation.VerifierExecutionModes.InstanceAndOnBeforeSetTriggers;

args.Instance.EntityAspect.EntityManager.VerifierEngine.AddVerifier(formatVerifier);

}

string entityPropertyInterceptorKey = String.Format("{0}", args.Instance.EntityAspect.Entity.ToString());

List<PropertyInterceptorAction<PropertyInterceptorArgs<Entity, Object>>> actions = PropertyInterceptorManager.CurrentInstance

.GetActions<PropertyInterceptorArgs<Entity, Object>>(this.GetType(), null, PropertyInterceptorMode.BeforeSet)

.ToList();

foreach (var action in actions.Where(a => a.Key == entityPropertyInterceptorKey))

{

PropertyInterceptorManager.CurrentInstance.RemoveAction(action);

}

}

}

#endregion

I have one final problem now, but it's to do with the UI (WPF) not IdeaBlade.  The problem is that a UI textbox is bound to the entity property.  Now I have the UI text box go red and the tooltip show the validation error message when the user types in the wrong thing, BUT the UI will still display what the user has typed in even though the actual entity property is something else.  So if anyone has any answers for this that would also be a help :)

thanks


Posted By: kimj
Date Posted: 06-Apr-2012 at 9:34am
The problem with the DevForce VerifierEngine is that a new one is created automatically for each EntityManager.  You can create a VerifierEngine separately and share it among EntityManagers (by calling the EM.VerifierEngine setter) but the VerifierEngine isn't thread safe, so if you're doing any multi-threading or async validation this won't work.
 
As you noted, you could listen on EM creation and add verifiers then, but your on-demand approach of adding verifiers only for the entity types in use is a good alternative.
 
I hope other DevForce users will chime in if they've encountered this problem and have suggestions.


Posted By: jeanb
Date Posted: 10-Apr-2012 at 5:04am
Thanks Kim



Print Page | Close Window