 |
|
 |
Hi!
At first thanks for your great works! You really saved me from a lot of work 
Unfortunately your ValidationManager caused a little memory leak in our application. I think the source of the problem is the static event "GlobalValidatorsChanged".
Let’s assume you have two classes extending the abstract class ValidatableBase (I think the same applies if you implement IValidatable since you will use ValidationManager, too):
ClassA : ValidatableBase ClassB : ValidatableBase
Next I create two Lists (List<ClassA> and List<ClassB> ) and populate them with instances of my two classes. After that I call Clean() for List<A> sothat all instances of ClassA will be collected by GC.
Because we have a static event in ValidationManager this will not occure since intances of ClassB share the same event object and therfore the same handlers. Although instances of ClassA are not referenced by the List<ClassA> anymore, there is still a reference to the other ValidationManagers contained by ClassB instances.
To solve the problem, I used the Mediator implementation by Sacha Barbers MVVM Project found here:
WPF: If Heineken did MVVM Frameworks by Sacha Barbers
The Mediator uses WeakReferences to hold the handler references internally – object can be reclaimed by GC although a reference exists.
Best regards, Dominik
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I think you have done a great job here.
I have just one suggestion. In order for the object to be validatable it has to derive from validationbase.
Properties like IsValid should have the Browsable(false) attribute so that it will be hidden in databinding scenarios.
I've just been playing around implementing the ITypedList interface in a ORM framework I'm developing. It's common for implementors of this interface to display all properties, except those with Browsable(false)
It's not often you see such a great idea implemented in such a nice way. Code is well structured too.
This is gonna fit like a glove into my ORM framework.
Another thing that might improve performance, is the way you ask for the property value.
The line "this.propertyInfo.GetValue(instance, null);" has the potential to be called very often and while reflection is a great thing, it is not something that should be executed to often.
I used this code as a basis for my property setters/getters and it works like a charm.
http://codecube.net/item.asp?cc_itemid=307[^]
It uses emits the code needed to access properties. Anyway keep up the good work.
"May the source be with you" //seesharper
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for the comments. To address your first concern, the object does not have to inherit from ValidattionBase, it just can. This is there for short circuiting some common scenarios. I don't use data binding that often, so I didn't place the attribute on the object, but you're right, it should be there.
As I've mentioned before, I have rewritten this entire library and integrated it into a much larger framework we use in my department. It is configurable via XML and most of all, it caches all the reflection and uses DynamicMethods to speed up the "reflective" calls. I assume when you say you use emits, you are referring to DynamicMethod creation at runtime.
Anyways, thanks for your comments and let me know if I can aid you in your framework building.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi again Craig!
I've just starting looking at the sourcecode for you validation framework.
First of all I must say that your code is very organized and well structured.
There's one thing that bothers me, though.
ValidationBase implements the IDataErrorInfo interface.
I see that validation for the property is performed when the indexer is accessed.
My experience is that the datasource that is binded to the ErrorProvider, calls this indexer very often.
This may cause a performance problem as I see it.
Would it be a better solution to perform the actual validation in the property setters?
//seesharper
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
That is always a solution, but think about the repercussions. Any property you want validated would need to fire a method that it has changed and subsequently validate that property. But, what if another property's validation scenario is based upon another property. How would we know we need to fire that validation scenario as well?
For instance, given a User class with two properties, Password and ConfirmPassword. Obviously, ConfirmPassword depends on Password. Let's say we change password and then check to see if everything is ok. Somehow, we would need to know that ConfirmPassword's validation scenario is tied to Password's value and that when Password changes, we need to rerun ConfirmPassword's validation scenario as well. This could all be hooked up manually, but using a framework like this makes it much more difficult to do out of the box.
Let me know if you have any ideas about this...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi again.
I do have an idea how this can be solved.
First of all another reason why validation should not be done in the IDataErrorInfo indexer. If you choose to use the LenghtValidator that includes a minimum length parameter. This is a problem if the ex password member variable is set to null by default. This would cause the errorprovide to display its icon next to the control even before the user gets at chance to edit the data.
Moving the validation from the indexer proposes another challenge. Intercepting that the property setter has been called.
I do this by a using a property setter method, like SetPropertyValue(string propertyname,T value), implemented in the base class.
This method will in turn use the DynamicMethodCompiler to set the member variable.
This method (SetPropertyValue) would be the natural place to call the validation sequence.
In my ORM framework, this is how I fake/avoid proxying the objects.
Anyway, back to the password scenario.
As you mentioned there is a dependency between password and confirmedpassword.
I think one should implement a PropertyCompareValidator that takes the ComparisonOperator and the target propertyname as the parameters.
Then the validator could be installed both on the Password property and the target property (ConfirmedPassword).
There should also be possible to put this attribute on both propeties in case you want to have distinct error message for the properties.
In addition it should only perform validation if both the properties has been modified. This to avoid the validation to trigger when the user has entered the password and not yet the confirmed password.
When all this is done I think you would have a validation framework that takes care of 90% of the normal tidious validation logic.
Another think I'm currently working on is using the attributes when it comes to databinding.
Ex. If the MaxLength is set to 10 characters, the textbox in the UI should restrict the user so that the validation error never occours. The validation still has to reside in the businessobject because the value can also be changed from code.
Also when it comes to numeric values. I'm thinking of a numeric format attribute. If this could be set on the property you would be sure to have a consise edit and display format for this property in whatever context it may be used(grid, textbox, ..)
seesharper
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Your ideas sound great. What ORM framework do you use?
You mentioned SetPropertyValue... Are you then storing your properties in a field or an IDictionary or something? WPF stores properties in a dictionary somewhere and has GetValue and SetValue members.
You mentioned a DynamicMethodCompiler. I also have one those in my core libraries, but if you are creating one of those for every instance, that is a lot of overhead. I would hope you are doing it statically, once per type.
So, back to your ideas. I think if you were to begin to use dependencies between your properties and all that jazz, you are going to need to use some graphing theory in order to eliminate cyclic validation. It would also be a brand new way to store validation scenarios... Graphs with vectors and edges.
I would like to caution here though... At some point, we are getting beyond a simple, easy to use validation framework and into a full blown Rules Engine which is a completely different animal.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I use my own ORM since my needs for a particular project was rather extreme.
I'm planning to post an article here when I get it finished enough
I needed to load 120000 record/objects into memory in one operation. The object model is a complex tree structure that has a lot of parent/child relations.
While Nhibernate did it in 3 hours, I did it in 30 seconds.
The basics of my ORM is to reduce the need to access the datastore so often.
Yes, of cource, I do cache the dynamic methods per type/property so that the overhead is minimal.
You are absolutely right aboubt keeping things simple. But you know how tempting it is to just put one more thing in there
I'm gonna give it a try anyway. I will let you know if I get it to work.
I think I know a way to implement the PropertyCompareValidator without the need for graphs and so on.
//seesharper
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
First of all, big thanks to C. Wilson for a great article.
To seesharper, have you done your implementation? If you have, could you post it here so I can get some insight on how to implement the ORM?
Thank you in advance.
Henry
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I really like the library.
I did overload the constructor on some of the validators - thought you might consider it as well if you ever release this again:
ie. public CompareValidatorAttribute(ComparisionOperator comparisionOperator, objct valueToCompare, string errorMessage)
This way, you can pass in your own error message.
Works great!
Thanks Steve
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yeah, my rewrite exposes some of that better including localization resource keys.
Thanks for the comments.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Craig
First of all, thank you for your awesome work. Your framework is great!
I'm trying to implement it with a Strongly Typed Dataset and so far it is working very well.
As an example, the following code in my dataset partial class add a RequiredValidator to one DataColumn (EGR_A_NameEN) of a DataRow definition (EGR_EnumerationGroupRow) in my dataset:
Validator val = RequiredValidator.CreateValidator(this.EGR_EnumerationGroup.EGR_A_NameENColumn.ColumnName); ValidationManager.AddGlobalValidator(val);
This work just fine.
The only problem I've got is with CustomValidator.
When I add this CustomValidator:
Validator val = CustomValidator.CreateValidator("Custom error", this.EGR_EnumerationGroup.EGR_A_NameENColumn.ColumnName, "MyMethod"); ValidationManager.AddGlobalValidator(val);
Followed by this method definition:
public bool MyMethod(string value) { if (value.ToString() == "test") return false; else return true; }
I've got the following error when I try to validate one of those DataRow:
"Error binding to target method."
The exception occured at the following line in DoIsValid method of CustomValidator class:
Delegate d = Delegate.CreateDelegate(this.methodType,instance,this.methodName);
If we take a look in the dataset designer code for the corresponding property definition, we find this:
[System.Diagnostics.DebuggerNonUserCodeAttribute()] public string EGR_A_NameEN { get { try { return ((string)(this[this.tableEGR_EnumerationGroup.EGR_A_NameENColumn])); } catch (System.InvalidCastException e) { throw new System.Data.StrongTypingException("The value for column \'EGR_A_NameEN\' in table \'EGR_EnumerationGroup\' is DBNull.", e); } } set { this[this.tableEGR_EnumerationGroup.EGR_A_NameENColumn] = value; } }
The property is a string as well as the parameter of MyMethod. I don't know what I'm doing wrong. Do you see something?
Thank you
Raoul Guenette QC, Canada
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for your comments. It's been a little while since I looked at this and I don't use DataSets so I'll do my best. Be sure that the method you are attempting to use to validate exists inside the class that is being validated. The only other thing I can really think of is that it simply can't find the method, and I think that that is fairly obvious.
Why don't you stick a breakpoint on the CreateDelegate line and see the parameters that are being passed in. I think you'll find that one of them is a little awry.
Sorry I can't be of more assistance. Let me know if you find some more things out that may help narrow the problem down.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I found the problem (with your help)...
MyMethod was not accessible to the CreateDelegate because it was not in the same class. The wizard of VS create many classes for a strongly typed dataset and there is one for each DataRow definition. So the solution was to declare MyMethod in a partial class for that row. And it's now working.
public partial class EGR_EnumerationGroupRow { public bool MyMethod(System.String value) { if (value.ToString() == "test") return false; else return true; } }
Thank's again!
Raoul Guenette QC, Canada
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Good work! I was searching yesterday for an attribute based validation framework and finaly take one by bltoolkit[^]
Yours and his programmability fits better to me but have you any idea how to implement a resource based localization for errors messages?
Cordialement,
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks. Yeah, you basically use resources for all your messages. I used resources for my default messages, but you would simply make some location specific ones and "change" the culture info. I've never really done it, but there are plenty of articles here on Code Project to help you out.
Bltoolkit has some good stuff from what I've seen in the past.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yes but for business specific messages (ex: "the rule must containt at least one constraint" ), localized messages cannot be done in attributes cause they accept only fixed string.
The work-around I found what to pass only a resource key to the attribute and localize messages just after the validation process.
So if somebody has a much elegant method with the attributes, I'll take it! ;o)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I had intended to implement something very like this myself, but you've beaten me to it. Well done.
I do have some ideas for further work though. The first relates to XML serialisation. In an XML schema you can specify constraints on element values, for example by specifying a pattern that the value must conform to. However, when you use the XSD utility to generate a C# wrapper class the restrictions are ignored. Your validation attributes would be a way for preserving the restrictions in the wrapper class.
There is a similar problem with wrapping relational tables. Any check constraints on the column values could be translated to validation attributes. Then we could validate property values in the business logic before attempting to update the database and getting a constraint violation error.
Finally it would be neat if the validation attributes could be used to automatically generate a Windows Form for editing an object. For each public property of the class we could generate a appropriate control, then use the validation attribute to set the properties of the control. For example, if we had an integer property with a range validation on it we could automaticaly create a spin control and set the upper and lower bound.
Anyone out there with some time on their hands?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Some great ideas. I say run with it. I have refactored a lot of the code an added Xml configuration to the validators so that instead of attributes, it could be specified in an xml file (or the config file). With your line of thinking, given the Xml, you could write a build provider to generate the classes for you.
Keep up the good thoughts
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Craig,
One more thank you for your great work!
Just wondering if that "refactored" version of your framework with Xml configuration is the one available for download in your article. If not, would you consider making it available?
thanks a lot!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It is not the one downloadable from here. The refactored version is a part of a much larger framework now with a dependency on a common library. Since I cannot release the core just yet, releasing the validation portion is rather useless... At some point though, the core will get open sourced.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Keith Barrett wrote: Finally it would be neat if the validation attributes could be used to automatically generate a Windows Form for editing an object.
On a side note, my article about my Fluid Geometry[^] application does something like that. Maybe it is similar to what you have in mind.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have downloaded and just started looking at your code. Thanks for making this available!
I didn't see anything about a license on use.
Is it free like a BSD license? Is it now public domain? I would like some clarification on this before I think seriously about incorporating it into any projects.
Thanks, -Mark E.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Let's go with public domain. Do anything you want with it. In a future revision, I might stick a license on it, but for this copy, use it how you like .
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for that clarification. I look forward to seeing how my projects can benefit from it.
Do you have any plans to make a dedicated/hosted OpenSource project out of it? Just wondering as it could be useful to several projects (OpenSource and Commercial) that provide some sort of Object / Relation mapping.
Thanks again for the great article and your contribution.
-Mark E.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |