MVC2: Validating User Input / Best Practices - asp.net-mvc

I'm trying to validate user input, in particular user passwords. I have some jQuery validation, but of course I also need to validate on the server side. Now my request comes in to the controller, which will hand it off to a UserService. Everything is loosely coupled, so the controller really doesn't know too much about the inner UserService. Now suppose the user entered a weak password so I need to tell him "hey, that is insufficient."
Question is: What is the best way to do this?
Somehow, I need to be able to call
ModelState.AddModelError(field, exception);
in order to indicate what went wrong, where and why - in the simple example I already know it's the password because it is really the only field on the form, but in general this is not so easy. Now I was close to writing my own Exception type to do something like
ModelState.AddModelError(ex.Field, ex.Message);, where I might need some additional mapping - which is essentiale the path taken in NerdDinner where they have RuleViolations.
However, in NerdDinner, the business object is self-validating. This doesn't seem to be the best way in this case, because the 'business object' here is really just a store for email and password that implements IIdentity. It shouldn't know anything about password lengths and should be reusable across different applications.
Moreover, ArgumentException and ValidationException don't seem to fit either because the first is made for contract violations and the latter is to be used by DataAnnotations.
All this is just the tip of an iceberg of course, because there are so many subtleties lurking around. Perhaps someone can point me in the right direction?

You can use xVal.

If I understand correctly you want to validate whether the user password is sufficient or insufficient. If you aren't using self validation on the object itself then can I suggest you put a validation method on your user service.
...
var result = userService.Validate(newUser);
if (!result.IsValid) {
result.Errors.ForEach( m => ModelState.AddModelError(m.field, m.message));
}
...
How about that?
The only issue with this approach is that to access any validation around the User object you'd have to pass it into the userService, which may or may not be what you want to do.
Answer to comment below:
Well you would have to create a ValidationResult, something like.
public class ValidationResult
{
public string Field {get;set;}
public string Message {get;set;}
}
So if I'm reading correctly, your Controller has a UserService, the UserService has a Validator, and the Validator validate the User.
As you pass this validation up from your Validator to UserService to Controller, just intercept it and use it, then pass it along.
If you don't want to role your own validation library (and you shouldn't) there are some great tools like Enterprise Library and FluentValidation. They can separately define your validation logic external of your objects if that is what you are concerned about.

Related

Preventing access to routes in MVC 4

In my MVC application I have Player and Coach objects, and a user can be one or the other. I also have Team objects and what I want to know is how I prevent a user who is in a list of Players or is the Coach of a Team gaining access to a route like /Teams/Details/2 where 2 is the id of a team other than that which he/she is part of.
Thanks in advance!
Since you want to restrict an id that they aren't a part of, this seems like a situation where you can Inherit from the AuthorizeAttribute and provide your implementation for AuthorizeCore
Your implementation could check their role/team id and decide what to do / redirect.
public class TeamAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return UserIsInTeam(httpContext); //whatever code you are using to check if the team id is right
}
}
You can now apply it like any other attribute.
[TeamAuthorize]
The very simplest solution would be to change the URLs from using IDs to random GUIDs. You would almost eliminate the chance of someone guessing another valid value. Of course, this is not secure by definition (mostly because someone could get the other URL from history or another source), but in some scenarios this is enough.
A better solution is to create a new attribute based on IActionFilter interface that implements OnActionExecuting method and checks the ID by using this.ControllerContext.HttpContext.User.Identity.Name and this.RouteData.Values["id"]. You will then apply this attribute to your controller methods.
In our current system we implemented row level security in controller methods by just adding the code that verifies the user permissions as the first line in each method. The checking code is the same as with the attribute and it requires the same amount of code to add. This approach has one additional benefit - it is easier to implement scenarios like where a coach would be able to see the details of other teams but not modify them (we have one action and view for both reading and updating depending on permissions).
You would also use the last approach if you need to go to the database to check the permissions and you are using IoC frameworks such as Ninject with constructor based injection - since you will not have access to those values in the attribute.

Testing model validation without testing implementation

What's the best way of going about testing model validation without making assumptions on the implementation details of the validation (eg. DataAnnotations).
For example, if I have a Customer model object that has a Firstname property, I want to test that binding a missing value for the Firstname property will result in a validation error but I don't want to test how validation his been implemented. That is, I don't want to use DataAnotations.Validate.
I've seen several, differing, opinions on this floating around and haven't found one that I agree with.
I ended up writing a helper method that wraps ModelValidator and returns IEnumerable<ModelValidationResult>. It requires that MVC be configured with your validation provider of choice, but it means that test code need not change when your validation implementation does:
public static IEnumerable<ModelValidationResult> Validate<TModel>(TModel model)
{
var modelMetadata = ModelMetadata.FromLambdaExpression(r => r,
new ViewDataDictionary<TModel>(model));
ModelValidator validator = ModelValidator.GetModelValidator(
modelMetadata, new ControllerContext());
return validator.Validate(model);
}
This will depend on the framework you are using for validating your models. So what you are asking is not possible without taking this into account. ASP.NET MVC by default uses a data annotations model provider which invokes the validation rules for data annotations and if you want to test this you will need to do a DataAnnotations.Validate in your unit tests or verify that your model is decorated with the proper attributes.
Personally I use FluentValidation.NET which provides an elegant way for unit testing my validators so it is not much of a hassle.

Disable Model Validation in Asp.Net MVC

How do I disable Model validation for a single Action in a Controller ?
Or can I do it per model by registering the model type at startup somewhere ?
I want the ModelBinder to bind to the model, but afterwards it should not perform the model validation.
The reason why i dont want validation to happen is because i am trying to move the logic from the controllers to a service layer which will be responsible for validating the models as i cant assume that models being passed to a service contains valid data.
As I understand this is the recommend approach (to not have logic in the controllers), so I find it a bit strange that i cant seem to find anything about how the model validation can be disabled (per action or per model type).
Please notice that I dont want to disable model validation for the entire webapplication (by removing the validation providers), and i dont want to disable the input validation that checks for malicious code being posted.
UPDATE
I am using .Net 4.0 and MVC 3 Preview 1
Just remove the items you don´t need before checking if the model is valid
ModelState.Remove("Email");
if (ModelState.IsValid)
{
// your logic
}
I've solved this problem with this code:
public ActionResult Totals(MyModel model)
{
ModelState.Clear();
return View(model);
}
Not sure it's the right way though.
Unfortunately there seems to be no easy way to disable the model validation happening in the ModelBinder except for registering every single model type you don’t want to validate (including nested complex types) with a specific ModelBinder. It can be done with the following code:
ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder();
Creating a SkipValidationAttribute that can be attached to action methods or action method parameters doesn’t seem possible as it should be implemented in the ControllerActionInvoker, but there is no way of letting the ModelBinder know that it should do any validation in the SetProperty() and OnModelUpdated methods when calling BindModel() in the GetParameterValue() method.
I definitely dislike this addition in the 2.0 version, because, as you stated in your question, validation makes more sense in the Service layer. In this way you can reuse it in other non-web applications, and test it more easily without having to mock the auto-validation mechanism.
Validation in Controller layer is pointless because in this part you can only verify model data and not business rules. For example, think of a service responsible of adding new comments and a user that wants to post a new one, the data in the comment he/she is posting may be valid, but what happens if the user is banned to comment because of misbehavior in the past? You should do some validation in the Service layer to ensure this is not happening, and if it does, throwing an exception. In short, validation must be done in the Service layer.
I use xVal as my Validation framework because it's compatible with the DataAnnotationModel, allows me to place validation wherever I want and performs client-side validation without extra-effort, even remote-client side. This is how I use it at the beginning of each of my services, for example, a login service:
public void SignIn(Login login) {
var loginErrors = DataAnnotationsValidationRunner.GetErrors(login);
// Model validation: Empty fields?
if (loginErrors.Any())
throw new RulesException(loginErrors);
// Business validation: Does the user exist? Is the password correct?
var user = this._userRepository.GetUserByEmail(login.Email);
if (user == null || user.Password != login.Password)
throw new RulesException(null, "Username or password invalids");
// Other login stuff...
}
Simple, web-independent and easy... then, in the Controller:
public RedirectResult Login(Login login) {
// Login the user
try {
this._authenticationRepository.SignIn(login);
} catch (RulesException e) {
e.AddModelStateErrors(base.ModelState, "Login");
}
// Redirect
if (base.ModelState.IsValid)
return base.Redirect(base.Url.Action("Home"));
else return base.Redirect(base.Url.Action("Login"));
}
I would recommend you perform validation in both places rather than trying to turn off validation in the UI. I understand your point that the service cannot assume that it's being passed valid data - that is a valid concern and is the reason your service should have validation. But you should also have validation in your UI. This is also nice because you can have client-side validation to prevent user errors and give you users a better experience.
I know that this already been answered but what you really needed was to extend the DataAnnotationsValidatorProvider and override the GetValidators method.
Then, on startup, you would remove the DataAnnotationsValidatorProvider from ModelValidatorProviders.Providers and add your new one.
Needless to say, if you simply don't want any validation at all, you can simply have the GetValidators method returning an empty collection.
In my case, I need to remove validation only when submitting the forms while still keeping the client-side validation, hence the following:
public class DynamicModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
if (context.HttpContext.Request.HttpMethod == "POST")
{
return new ModelValidator[] { };
}
return base.GetValidators(metadata, context, attributes);
}
}
I use
[ ValidateInput( false )]
Not sure if this prevents model validation, or only IIS submit validation.

Validating an Email Address on jQuery postback best practice

This question title is likely to be worded poorly so feel free to adjust.
In my MVC application I have a custom attribute which i use to decorate email fields which then either passes or fails the model.
On one pge though I allow the use to submit a comment but I submit via ajax and so do not do a full postback and no model validation.
So I'd like to validate the address but not copy the code. I'd also like to avoid breaking the code out of the validator into yet another class or is this the best wAY?
Is there another way? Can I create the model in the ajax postback and validate it there and then return the partial view with the error messages?
Or is there another way?
You say, ...
So I'd like to validate the address but not copy the code. I'd also like to avoid breaking the code out of the validator into yet another class or is this the best way?
IMO, that is the best way. Factor out the common code. I see your issue though, our EmailValidator inherits from RegularExpressionValidator, so it's hard to factor out. We have a RegEx utility class that uses the same RegEx pattern. We refer to the pattern by constant in both places...
public class EmailAttribute : RegularExpressionAttribute
{
public EmailAttribute() :
base(RegExUtility.SingleEmailAddressPattern)
{
ErrorMessage = "Please enter a valid email address";
}
and
public static class RegExUtility
{
public const SingleEmailAddressPattern = #"...";
public static bool IsValidSingleEmailAddress(string email)
{
return Regex.IsMatch(email, SingleEmailAddressPattern);
For simple Ajax postback actions, I think you can often handle it in the controller or create a separate POCO ViewModel that just supports the Ajax path. I know there are articles on using the same model for both types of actions, but we've found there are usually enough differences that it's worth having separate view models. If they're complex enough, we just factor out the common code.

Partial Validation ASP.NET MVC

I've read a number of articles now in regard to validation and asp.net mvc and the majority tend to point to validation in the model. The problem I see with all of them is that they don't handle different scenarios, or at least, they don't show how they would be achieved e.g.
When creating or updating a user account the email address must match the email confirmation input. This email confirmation input isn't part of the model it's purely to assist correct user input, this might be called a virtual property. When a user logs in using their email address the validation shouldn't try and match the email against a confirmation input, however, in all the examples I've seen there is no way to differentiate between scenarios where the same data is validated in a different way.
Can anybody point me to any mvc validation articles that handle the above types of problem? Or does anybody have any advice on best practices to handle validation like this?
I had thought about introducing a "validation action" such as create, read, update, delete, and then I could validate the same bit of data depending on the context in which it is being used. Anybody have any thoughts on doing things in this manner?
Thanks in advance for any help
This is why I'm using Validators separated from Models. So, I have IValidator and different validators. For instantiate validator I use DI Container (StructureMap for example).
It was described (not by me) here:
Issues with my MVC repository pattern and StructureMap
According to my experience
1. Validator should be decoupled from controller into separate Service layer like, for instance, showed in this tutorial:
http://www.asp.net/learn/mvc/tutorial-38-cs.aspx
2. Service methods may encapsulate all the kind of validation. For example:
public bool PlaceBooking(Booking booking)
{
//Model validation
IEnumerable<ErrorInfo> errors = DataAnnotationsValidationRunner.GetErrors(booking);
if (errors.Any())
_validationDictionary.AddErrors("error", errors);
// Business rule: Can't place bookings on Sundays
if(booking.ArrivalDate.DayOfWeek == DayOfWeek.Sunday)
_validationDictionary.AddError("ArrivalDate", "Bookings are not permitted on Sundays");
if (!_validationDictionary.IsValid) return false;
//Errors comming from Data Access Layer
try
{
return _dao.Save(booking);
}
catch (DBExecutionException ex)
{
if (ex.ResultCode == ResultCodes.RES_UNIQUEINDEX)
_validationDictionary.AddError("error", "Booking already exists.");
else
_validationDictionary.AddError("error", "Some other DB issue happens.");
}
return false;
}

Resources