How to conditionally validate properties using FluentValidation? - c#

I'm trying to implement a rule using FluentValidation where two properties have a dependency on each other. They are Unit and UnitType. Unit is a string, and UnitType is an enum. I want rules where if the Unit is filled out then the UnitType cannot be None (0), and if the UnitType is not None (0) then the Unit must be filled out. Here's the rules I've tried so far to no avail:
this.RuleFor(
p =>
p.Unit).NotEmpty().When(
l =>
(l.UnitType != UnitType.None)).WithMessage("Unit № must be filled out and must be less than 8 characters long when the Unit Type is selected");
this.RuleFor(
p =>
p.UnitType).NotEqual(UnitType.None).When(
l =>
!String.IsNullOrEmpty(l.Unit)).WithMessage("Unit Type must be selected when the Unit № is filled out");
No matter how I tweak the rules, I just keep getting an error that says: 'Unit Type' must not be empty. Since my custom error messages are not showing up, I'm thinking that the rules are being skipped somehow...
I'd appreciate any suggestions on how to get this fixed.

Well, after taking some time away from this and coming back to it, I believe I finally have it resolved. Originally in my post model I had the UnitType property as non-nullable, which is what was triggering the validation even though it's default value was UnitType.None. From what I can tell, MVC, not FluentValidation, sees that it's non-nullable property, ignores the default value and then attempts to bind the property anyway with a null value from the form post. I can kind of understand why it behaves this way, but can't help but think that it shouldn't ignore default values.
So, I changed the property to be nullable and now my two rules work as I expect them to. Still, I'm not overly happy about the way it actually works because I was hoping to use the default auto-generated value further down when mapping with AutoMapper, and now I'll have to make sure to set a default value in the constructor where it's relevant. Realistically a non-issue in the long run, so long as I don't miss setting a default somewhere.

Related

Asp.net-MVC Custom Validation - NULL vs Empty

For security and consistency I would like to test on post-back if a field is missing? In Java (servlets in particular) when we perform a request.getParameter(key) the result is either a String value or otherwise NULL if the field is missing. In MVC I've created a custom validation that I call "ThrowOnNull". The behavior I'm trying to capture is: If an intended field is missing (null) I want to throw, otherwise return success.
Consider this Custom Validator (that doesn't work):
public class ThrowOnNull: ValidationAttribute
{
public ThrowOnNull() { }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
throw new Exception(validationContext.MemberName + " field expected, but missing."));
return ValidationResult.Success;
}
}
Is it possible to do what I want here? (this validator doesn't work as expected and it's because the framework is assigning NULL to an empty value [oh dear].)
UPDATE: Per #emodendroket, the following code example now works as expected:
public class ThrowOnMissing: ValidationAttribute
{
public ThrowOnMissing() { }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (!HttpContext.Current.Request.Form.AllKeys.Contains(validationContext.MemberName))
throw new Exception(validationContext.MemberName + " field expected, but missing.");
return ValidationResult.Success;
}
}
EDIT: I've cleaned up the question and example code significantly to make it all much clearer, hope it helps.
You're missing one important point - when you submit a form, all fields belonging to that form get submitted. If the user doesn't fill them, they're blank, so the validation for null can't really work like this...
You should probably redefine what "missing value" means.
EDIT:
After some discussion it seems you're not really concerned about null values, but about the security (false forms with missing fields and stuff like that). In that case you should simply use the standard - antiforgery token and maybe check the origin of the request. You should be more than fine this way. Checking for missing fields won't help a bit, because attacker can easily send those fields as well.
Over/Under posting is a real concern. Furthermore, if fields aren't submitted (due to a hack or DOS attack of some kind)
Not really.
Overposting is handled by the action method on the controller. It won't accept more parameters than you've specified.
Underposting will be handled pretty much the same way as if you didn't fill the text fields in the form, again a non-issue if you have validated your model correctly.
DDOS attack can't be prevented a believe me, some checking for missing fields won't help a bit if someone has a network powerful enough to cause DDOS. Just look up latest cases on attacks and you'll understand, that if HUGE servers can't withstand that, you certainly can't prevent it like this.
Your data validation shouldn't be too expensive either. It's a web, people don't like to wait too much.
If you want your own validator you can look at the dictionary HttpContext.Current.Request.Form. You can then do what you've proposed with this code:
if (!HttpContext.Current.Request.Form.AllKeys.Contains("prop"))
{
throw new Exception();
}
I think you're being unreasonably paranoid here about things. Note that I said Unreasonably paranoid, since a little paranoia is a good thing.
First, let us analyze the "threats" and determine the risks. You've presented several arguments:
Over-posting
Under-posting
Validation of empty vs null
The first item is not an issue in MVC if you are using a View Model. You simply can't post information that the view isn't expecting (well, you can, but it's ignored). If you're not using a view model (or not using a properly defined one) then you can use binding attributes to prevent posting of items you don't want bound.
The second, under-posting, if it's truly a concern for your model (99.999% of the time simply treating it as required is more than fine, but ok let's take your argument. The issue here is not the validation attribute, it's the model binder. You simply have to register a custom model binder that looks for missing values in your view model and throws if they are null. This is easily accomplished by reflecting over the bound model and comparing it to the posted values, then throw.
The problem with your RequiredThrowIfNull approach is.. what if it's not required and it's under posted? That's still an error according to your argument.
Finally, validation of empty vs null... you talk about expensive validation... I don't know what kind of expensive validation you could be talking about here, but server side there is noting in attributes that could be considered expensive.
The reason your attribute doesn't work is because validation attributes are called within a try/catch block by the framework already, and if it's null it's the very mechanism that treats it like empty (this mechanism also does things like catching parsing errors when a type is incorrect, such as characters in a datetime field.)
.NET is not Java, even though it largely works similarly... trying to re-implement Java patterns in .NET is going to lead to misery on your part because many basic philosophies are just different.
Even if we accept your argument of wanting to catch errors or be notified of hacking attempts, throwing is the wrong thing to do in most cases. Instead, just log the information from the model binder and continue on as normal. Only throw if you absolutely need to abort the request, and most of the time that simply isn't the case, even if you're being hacked... throwing will just cause the attacker to vary their attack until they no longer get the exception.
Frankly, this is an over-engineered, solution looking for a problem and there are many good .net specific ways of dealing with the REAL issues you are trying to solve.
#ignatandrei from ASP.NET answered the question:
by default MVC transforms empty string to null string.
http://forums.asp.net/t/2006146.aspx?Custom+Validation+and+NULL

Structured code for limiting what values you can set for a property

What would be the correct (and best) way to code in limits as to what values a property can get?
For example, suppose I have the following simple class:
Public Class MyClass
Public Property MyDate As Date
Now, suppose MyDate gets set at run-time, but can't take any values less than a year ago.
Is it correct to throw an exception in the MyDate's setter and then program this in my main module in a Try...Catch fashion and then alert the user if the value is bad or is there a better way to do this?
I'm sure this is a stupidly simple question, but I just want to make sure I'm doing this according to best programming practices.
Yes, throwing and exception is a good idea. ArgumentOutOfRangeException seems to be the best in that situation. Following the MSDN:
The exception that is thrown when the value of an argument is outside
the allowable range of values as defined by the invoked method.
While throwing an exception is a valid option, I recommend against it. The reason is that when a programmer sets a property he/she expects very little to happen other than the value being set. In this case I'd recommend using a set function instead of a property or having the value passed as part of the constructor (where programmers expect validation logic of this sort to happen).
Check this article out. It gives an overview of Validators in the System.ComponentModel.DataAnnotations namespace. They are attributes for your model that support validation.
http://stephenwalther.com/archive/2008/09/10/asp-net-mvc-tip-43-use-data-annotation-validators.aspx
ASP.NET MVC supports surfacing those validations on forms using JS, but in other applications types you can read the attributes from the model itself and enforce the validations.

Why does one implementation of binding to a property cause "Dependency property field missing" and not another?

Many questions have been raised on this site and others regarding the "Dependency property field missing" false error that is generated by Resharper when using this implementation of binding to the Password property of a PasswordBox. Simply searching for the phrase with Google returns "About 8,550,000 results" at the time of this posting. There is also a bug report on it.
I recently found another implementation that does not generate the error, and I'm struggling to find the difference in that implementation that causes Resharper to not generate the false error.
The differences that I see:
The property that actually stores the password string (BoundPassword/Password) uses a FrameworkPropertyMetadata object in the second implementation instead of the standard PropertyMetadata object. But when I changed the first implementation to use this new type, I still got the error.
The first implementation performs casting prior to assigning in the property-changed handlers, whereas the second has both in the same statement. But this is just coding preference; the net result wouldn't change.
What am I missing?
The answer you looking for was given in RSRP-174487 issue comment 2 years ago - dependency/attached property field names should follow Microsoft notation - SomeNameProperty (have Property suffix) - to be correctly handled by ReSharper.
Dependency property registration is actually may be dynamic and performed at runtime, but this is really rare scenario and ReSharper still supports it by simply triggering of "Dependency property field missing" inspection off (Alt + Enter - Suppress inspection).
ReSharper is designed to deal with statically known dependency property registrations and validates existence of DP fields for you, but require you to follow Microsoft DP fields naming notation to work well. I think error message may be better, we will work on it.

C# construction objects with builder

Fluent builder is a well-known pattern to build objects with many properties:
Team team = teamBuilder.CreateTeam("Chelsea")
.WithNickName("The blues")
.WithShirtColor(Color.Blue)
.FromTown("London")
.PlayingAt("Stamford Bridge");
However, using it doesn't seem very clear to me due to one particular reason:
Every Team object has its minimal operational state, in other words, set of properties which have to be set (mandatory), so that the object is ready to use.
Now, how should the Fluent builder approach be used considering that you have to maintain this state?
Should the With_XYZ members modify the part of the object, that can't affect this state?
Maybe there are some general rules for this situation?
Update:
If the CreateTeam method should take the mandatory properties as arguments, what happens next?
What happens if I (for example) omit the WithNickName call?
Does this mean that the nickname should be defaulted to some DefaultNickname?
Does this mean that the example (see the link) is bad, because the object can be left in invalid state?
And, well, I suspect that in this case the fluent building approach actually loses it's "beauty", doesn't it?
CreateTeam() should have the mandatory the properties as parameters.
Team CreateTeam(string name, Color shirtColor, string Town)
{
}
Seems to me the points of Fluent Interface are:
Minimize the number of parameters to zero in a constructor while still dynamically initializing certain properties upon creation.
Makes the property/ parameter-value association very clear - in a large parameter list, what value is for what? Can't tell without digging further.
The coding style of the instantiation is very clean, readable, and editable. Adding or deleting property settings with this formatting style is less error prone. I.E. delete an entire line, rather than edit in the middle of a long parameter list; not to mention editing the wrong parameter

How to solve cast issues in ValidationRule classes' properties?

I need to create a few tests for the user roles in a web application. To minimize the description, one of the tests involves checking if a menu entry is displayed or not for an user.
For this test, I use a table called UserRoles, that looks like this:
sUserName bDoesntHaveMenuX
User1 1
User2 0
User3 1
bDoesntHaveMenuX is of type bit.
I have a class derived from ValidationRule that checks if a certain text is present in a page, based on a XPath expression to locate the node where to look for the text.
The public properties of this class are:
string XPathExpression
string Text
bool FailIfFound
The last one dictates if the rule should fail if the text is found or not found.
In the test I added a datasource for the table mentioned in the beginning, called DS.
For the request I'm interested in I added a new instance of my validation rule class, with the following values:
Text=MenuX
XPathExpression=//div[#id='menu']//td
FailIfFound={{DS.UserRoles.bDoesntHaveMenuX}}
Unfortunately, this doesn't work.
The reason seems to be that the data binding process creates a context variable
DS.UserRoles.bDoesntHaveMenuX has the value "False" or "True". The value is a string, so the binding results in a casting error.
My options, as far as I can think of, are:
Change the validation rule to accept strings for FailIfFound. Not a valid
option, for 2 reasons: it's a hack and the same rule is used in
other places.
Make a new validation rule that will use the above mentioned one,
and implement the FailIfFound as string. I also don't like this, for
the same reason as above. It's a hack.
Make the test coded and do the proper cast before passing the data
to the validation rule. I don't like this one because I prefer to
have the test as coded only if there is no other way.
Which brings me to the question. Is there another way?
Thank you.
So the fundamental issue is that you have no control over how the data-binding treats the 'bit' data type, and it's getting converted to string instead of bool.
The only solution I can think of (which is sadly still a bit of a hack, but not so egregious as changing FailIfFound to string) is to create a WebTestPlugin, and in the PreRequestDataBinding or PreRequest event, convert the value from string to bool. Don't forget to add the plugin to your test(s) (easy mistake I have made).
Then when the validation rule is created it should pick up the nice new bool value and work correctly.
e.g.
string val = e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"].ToString();
e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"] = (val == "True");
I didn't actually try this... hope it works.
EDIT: round two... a better solution
Change the FailIfFound property to string (in a subclass as you mentioned), so it can work properly with data-binding.
Implement a TypeConverter that provides a dropdown list of valid values for the property in the rule's PropertyGrid (True, False), so in the GUI it looks identical to the rule having FailIfFound as a bool. You can still type your own value into the box when necessary (e.g. for data-binding).
Add the path of the .dll containing the TypeConverter code to your test project's References section.
This is what I have started doing and it is much more satisfying than having to type 'True' or 'False' in the property's edit box.

Categories

Resources