Asp.net-MVC Custom Validation - NULL vs Empty - c#

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

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.

infinitive loop at the end of action method

Recently I have faced with a very strange problem. My Action method must return JsonResult,and all is good untill the last break point before return (At this moment I have correct json result).Then in browser console I see error 500 (Internal server error).Nothing exception in debugger.When I start to chek every step in debugger with F10,F11 I have noticed something strange.Unexpected infinitive invokes to my model properties (sometimes to model properties,sometimes infinitive invoking functions and then model proerties).I decide that this infinitive loop provoked error (but I still misunderstanding why I couldn't see it in debugger - perhaps this is aspect of IIS debugging).Code hasnt got weak places (I dont show it because it will take much more than few space).I know that my question is not constructive in stackoverflow terminalogy but I hope that somebody has encountered the same problem.I need only ideas.Thanks.
SOLUTION
As noticed #mreyeros and # LastCoder self referencing can be the reason of such behavior.I have cheked my model in details and found this place:
private IEnumerable<CollegeEstimateModel> _initialModels;
public IEnumerable<CollegeEstimateModel> InitialModels
{
get { return _initialModels = _initialModels ?? CreateInitialModelsList(); }
}
where CollegeEstimateModel contains above properties
I have added [ScriptIgnore] attribute and all become ok.
You should start by checking to see if the model that you are trying to serialize to your JSON result does not contain a property with a self referencing property. For example you have an Order object that contains a collection of details. The detail record has a navigation property back up to the parent order, thus causing a loop during serialization of the order object. This is just a guess of course, but hope that it helps

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.

ASP.NET MVC UpdateModel() parameter conversion woes

A forewarning: I've relatively new to MVC and its paradigm and to some of its inner workings, but I'm pretty comfortable with it. This is my second ground-up MVC application and I'm a little stumped with how to solve a "problem" one of our testers found.
What the users get is an edit screen given an effective date for daily LIBOR rates that come from Treasury (percentages). The rates are always between 0 and 100 and consequently I've tried to constrain that range using a RangeAttribute in the metadata for one of my domain objects. I've specified the range like so:
[Required, DisplayName("Published Rate"), Range(typeof(decimal), "0", "100")]
public object PublishedRate { get; set; }
Notice that I'm passing in string values as the RangeAttribute does not have an overloaded constructor that takes decimals. This seem to work great until a user goes and enters something out of the ordinary, like:
"0.000000000000000000000000000000001"
This causes UpdateModel() to fail; the ModelState shows this error (three times for the same ModelState value, curiously):
The parameter conversion from type 'System.String' to type 'System.Decimal' failed.
Digging into the errors reveals the cause. The first line below is what's reported by the validation for the field. I found it curious that this did not bubble up to the model validation errors (i.e. did not show up in the summary validation list for the model):
"0.000000000000000000000000000000001 is not a valid value for Decimal."
"Value was either too large or too small for a Decimal."
System.Web.Mvc.ValueProviderResult.ConvertSimpleType() and System.ComponentModel.BaseNumberConverter.ConvertFrom() are throwing the exceptions.
A user is never going to enter a value such as this, but I wouldn't mind knowing if there are any mechanisms built in to MVC that could or will prevent this (server-side, that is). There doesn't seem to be an issue with numbers like the following, it only seems to break with ones that are very small.
"0.555555555555555555555555555555555"
At the end of the day I really only need 9 digits of precision. The database table column backing these values is a decimal(9,6). I know I could implement a custom model binder for my model and manually collect the values from the Request, but there's got to be something a little easier, such as a custom FilterAttribute or something that can correct the value before its attempted to be bound to the model, I'm just not sure what, and am looking for suggestions.
I seem to recall reading about some issues with trying to constrain decimal values using a RangeAttribute but I can't recall the issue. Perhaps you MVC gurus out there can shed some light on the situation.
You could use a Regex attribute to contain the decimal to a precision of 9. This would also allow you to add a custom message when the Regex fails, such as "Your value may have a maximum of 9 places after the decimal." or something similar. Also if you have client side validation enabled, the Regex will work in both client and server side validation.
So after a couple of hours of head banging I settled on the following custom model binder for decimals. It makes sure that all decimal values are parseable before binding them.
public class TreasuryIndexRateDecimalBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var providerResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (providerResult != null)
{
decimal value;
if (!decimal.TryParse(providerResult.AttemptedValue, NumberStyles.Float, CultureInfo.CurrentCulture, out value))
{
// TODO: Decide whether to show an error
// bindingContext.ModelState.AddModelError(bindingContext.ModelName, "error message");
return 0m;
}
return Math.Round(value, 6);
}
return base.BindModel(controllerContext, bindingContext);
}
}
The binding is set up in Application_Start() to register it for all decimal values.
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(decimal), new TreasuryIndexRateDecimalBinder());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
Unless somebody comes along with a more interesting approach I think I'll stick with this.

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