How to solve cast issues in ValidationRule classes' properties? - c#

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.

Related

Model Validation in Web API

I have to validate three things when a consumer of my API tries to do an update on a customer.
Prevent the customer to be updated if:
The first name or last name are blank
For a certain country, if the customer's inner collection of X is empty, then throw an exception. X is hard to explain, so just assume it's some collection. For all other countries, X doesn't apply / will always be empty. But if it's a certain country, then X is required. So it's almost a conditional required attribute. A customer belongs to a country, so it's figured out from the JSON being sent.
Prevent the customer from being updated if some conditions in the database are true.
So basically i'm stuck with the following problem, and I wanted some advice on the most appropriately way to solve it:
Do I create an Action Filter to do the validation on the customer entity before the saving takes place? Or would it be better to create custom validation attribute derived from ValidationAttribute and override the IsValid member function.
Basically a question of saying
if (first name is empty, if x, if y, etc) vs (!ModelState.IsValid)
And then using IsValid to cause the custom attributes to work.
It seems like validation attributes are best for "simple" validation, i.e. required field. But once you start getting into things like "I need to look at my database, or analyze the http request header for custom values, and based on that, invalid = false" then it almost seems wrong to do this sort of stuff so close to the entity.
Thoughts?
Thanks!
I like FluentValidation a lot: https://github.com/JeremySkinner/FluentValidation
As you mentioned built-in validation attributes are limited. For complex validations you had better implement your own attributes or use a library like this.
One thing I like about FluentValidation is that it performs at model-level rather than field-level, meaning that you can use related fields' values for validation. For example
RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
(Code excerpt taken from project's Wiki page)
It's also extensible so you can develop your own custom validators on top of this library as well.

How to conditionally validate properties using FluentValidation?

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.

Databound PivotControl jumps over pivots when they come from similar objects [WP7]

I have a PivotControl with bindings. Everything worked well until I added a pivot two pivots with the same title, let's call them C and C', and A an B two different pivots, ordered like this: AC'BC. Now, when I try to go from B to C everything is OK. But when I go from A to C, it does strange things: doesn't move, moves the titles but not the content... weird.
I debugged the SelectionChanged event in the PivotControl, and it's even weirdest. It's called two times: the first, a transition from C to another pivot and then another call which contains the right transition, from A to C.
I've tried everything. The databinding is a list of structs, like this:
struct Resource
{
public someenum Type;
public string Data;
public string Identifier { get {...} set {...} }
public UserToken User;
}
The title of the pivot is set by a IValueConverter, which takes the string Identifier (which is a function of Type, Data and User) as the parameter. I changed it to make the titles always different, but it still does not work. For example, when Type and Data are the same there are error, although Identifier and User are different.
I have written both operators == and != for Resource, and also for UserToken. They behave as they should, but still does this weird transition.
Stating the obvious: give them different names.
If they are different you should give them different names. Just post-fix the name with a counter.
EDIT
From the MSDN:
Name is one of the very few dependency properties that cannot be
animated (IsAnimationProhibited is true in metadata), because the name
itself is vital for targeting an animation. Data binding a Name is
technically possible, but is an extremely uncommon scenario because a
data-bound Name cannot serve the main intended purpose of the
property: to provide an identifier connection point for code-behind.
Just found the answer. After a lot of googling, I noticed that maybe GetHashCode had something to do in this mess. I modified the definition of getHashCode in the struct and, voilá! It works smoothly :)
Just a tip: to get a good GetHashCode function return a XOR of the volatile parameters of the function. In my case, the code was this:
Type.GetHashCode() ^ Data.GetHashCode() ^ User.GetHashCode();

Integration Test for All References of a Method Invocation

So, I've been searching around on the internet for a bit, trying to see if someone has already invented the wheel here. What I want to do is write an integration test that will parse the current project, find all references to a certain method, find it's arguments, and then check the database for that argument. For example:
public interface IContentProvider
{
ContentItem GetContentFor(string descriptor);
}
public class ContentProvider : IContentProvider
{
public virtual ContentItem GetContentFor(string descriptor)
{
// Fetches Content from Database for descriptor and returns in
}
}
Any other class will get an IContentProvider injected into their constructor using IOC, such that they could write something like:
contentProvider.GetContentFor("SomeDescriptor");
contentProvider.GetContentFor("SomeOtherDescriptor");
Basically, the unit test finds all these references, find the set of text ["SomeDescriptor", "SomeOtherDescriptor"], and then I can check the database to make sure I have rows defined for those descriptors. Furthermore, the descriptors are hard coded.
I could make an enum value for all descriptors, but the enum would have thousands of possible options, and that seems like kinda a hack.
Now, this link on SO: How I can get all reference with Reflection + C# basically says it's impossible without some very advanced IL parsing. To clarify; I don't need Reflector or anything - it's just to be an automated test I can run so that if any other developers on my team check in code that calls for this content without creating the DB record, the test will fail.
Is this possible? If so, does anyone have a resource to look at or sample code to modify?
EDIT: Alternatively, perhaps a different method of doing this VS trying to find all references? The end result is I want a test to fail when the record doesnt exist.
This will be very difficult: your program may compute the value of the descriptor, which will mean your test is able to know which value are possible without executing said code.
I would suggest to change the way you program here, by using an enum type, or coding using the type safe enum pattern. This way, each and every use of a GetContentFor will be safe: the argument is part of the enum, and the languages type checker performs the check.
Your test can then easily iterate on the different enum fields, and check they are all declared in your database, very easily.
Adding a new content key requires editing the enum, but this is a small inconvenient you can live with, as it help a log ensuring all calls are safe.

Validationattribute only when value is changed?

I want to write a custom ValidationAttribute that checks if the given value is unique or not.
The problem is that in the edit screen, it is not guaranteed that the user actually changed the value, resulting in a false error.
Is there a way to check in my attribute whether the value actually changed? Or can I trigger the attribute only when the value has changed?
I'm getting the feeling this requirement maybe just doesn't belong in an attribute?
When you say ValidationAttibute, do you mean using DataAnnotations? If so, then all of this applies, else, sorry, I misunderstood and only part of this will.
I think your best bet is to do this in the repository or BLL using your unique key for the record, at least this is how I did it. Get the previous values of the record and see if they changed. If they did change, then run your uniqueness checks.
If you can get this logic into the ValidationAttribute, then more power to you, but I am not sure if a validationAttribute would be the best thing since there are ways to get around them. From my understanding of these attributes, you should use them as supplements only to business logic validations and not as the only way that you validate your model.
See here for more info on DataAnnotations
EDIT:
Fair enough, now let's see if I can give an answer to help you :) Check out this link, it is the code for uniqueness checking on any property in any table. Pretty in-depth LINQ to SQL stuff, but looks like it works well. You should be able to decorate any property with this just like using the <Required> or <StringLenght> attributes.
ASP.NET Forums

Categories

Resources