ASP.NET MVC validation of uniqueness - asp.net-mvc

Rails has a very convenient uniqueness validation.
ASP.NET MVC doesn't.
I need to make sure that the e-mail address a user has entered hasn't been registered by anyone yet.
I can see only one way of doing this kind of validation: create a new data context object in the UniqueAttribute class.
But I'm afraid that wasting memory on a new data context object just for one validation is dangerous.
Am I wrong? Is there a better way to do that?
Update
This is what I got so far
public class UniqueEmailAttribute : ValidationAttribute {
public override bool IsValid(object value) {
DataContext db = new DataContext();
var userWithTheSameEmail = db.Users.SingleOrDefault(
u => u.Email == (string)value);
return userWithTheSameEmail == null;
}
}
// Usage
[UniqueEmail(ErrorMessage="This e-mail is already registered")]
public string Email { get; set; }
There are two problems.
It would be good to have just one UniqueAttribute class, not separate classes for e-mails, usernames etc. How can I do that?
Creating a new data context every time you need to validate a single attribute.
SOLUTION
So in the end I created a unique constraint on the table and now I just have to intercept SqlException in Users repository. Works great and is probably more efficient than searching for the same node in the whole table. Thanks!

Mvc 3 Relaease candidate has new New Validation Attributes as a remotevalidation -where you can register a method for validation on clientside(jquery).
see below example-
RemoteAttribute
The new RemoteAttribute validation attribute takes advantage of the jQuery Validation plug-in's remote validator, which enables client-side validation to call a method on the server that performs the actual validation logic.
In the following example, the UserName property has the RemoteAttribute applied. When editing this property in an Edit view, client validation will call an action named UserNameAvailable on the UsersController class in order to validate this field.
public class User {
[Remote("UserNameAvailable", "Users")]
public string UserName { get; set; }
}
The following example shows the corresponding controller.
public class UsersController {
public bool UserNameAvailable(string username) {
return !MyRepository.UserNameExists(username);
}
}
Mvc 3
UPDATE
public bool UserNameAvailable(string Propertyname)
{
if (Request.QueryString[0]= "UserName")
{
//validate username
}
elseif (Request.QueryString[0]= "Email")
{
//Validate Email
}
}

ASP.Net does have a feature that can automatically check the uniqueness of a user's email address when a user registers. It is the ASP.Net Membership service and you can use it to do what you want even if you don't use all of the features of it.
If you are not using the full Membership feature in your MVC application, then all you need to do is use
Membership.FindUsersByEmail(emailYouAreLookingFor);
If any values come back, you know that the address is not unique. If you ARE using the Membership service to create users, then the Membership service will check AUTOMATICALLY and return a code to you if the user's email address is not unique.
The Membership service sits in the System.Web.Security area so you would need a
using System.Web.Security;
reference in your controller.
Here is an example
MembershipCreateStatus createStatus = MembershipService.CreateUser(UserName, Password, Email);
if (createStatus == MembershipCreateStatus.DuplicateEmail)
{
//do something here
}
else
{
//do something here
}
I hope this helps!

The right way to make a generic remote unique validator in MVC can be found in this MVC forum. by counsellorben. It's based on my MVC unique remote validator article http://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx

A foolproof way of doing this is to create a validation attribute that would query the database for the email address. It would certainly add latency.
An alternative would be to create a unique constraint on the table and intercept SqlException.

Related

Custom model binding and validation in a multi-tenant environment

I am working on a multi-tenant .NET Core app where all the validations needs to be dynamic (Db Driven). How can I implement custom model validation?
You can use Remote Validation for validations where you need to go to the server (and then the db). You need to specify the action and the controller and it will be called during validation from the client side through AJAX. Then on the server side, you can do whatever you need in order to validate. In your case you will need to check the database. Here is an example:
public class User
{
[Remote(action: "VerifyEmail", controller: "Users")]
public string Email { get; set; }
}
The above is using the Remote attribute and specifying to use VerifyEmail action of the Users controller. In UsersController class you will have something like this:
[AcceptVerbs("Get", "Post")]
public IActionResult VerifyEmail(string email)
{
if (!_userRepository.VerifyEmail(email))
{
return Json(data: $"Email {email} is already in use.");
}
return Json(data: true);
}
The MVC framework will take care of all the AJAX(ing) for you so you do not need to worry about any of that. I have used this many times before and it works really well.

Model Ownership Checking

In my Controller before a Model is modified (updated or deleted) I am trying to verify that the User performing the action actually owns the object they are trying to modify.
I am currently doing this at the method level and it seems a bit redundant.
[HttpPost]
public ActionResult Edit(Notebook notebook)
{
if (notebook.UserProfileId != WebSecurity.CurrentUserId) { return HttpNotFound(); }
if (ModelState.IsValid)
{
db.Entry(notebook).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(notebook);
}
Is there a generic way of doing this that could be reusable across various models?
Is it possible to do this with an ActionFilter?
A filter approach might look like:
public class VerifyOwnership : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
foreach(var parameter in filterContext.ActionParameters)
{
var owned = paramter.Value as IHaveAnOwner;
if(owned != null)
{
if(owned.OwnerId != WebSecurity.CurrentUserId)
{
// ... not found or access denied
}
}
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
That assumes models like Notebook implement a specific interface.
public interface IHaveAnOwner
{
int OwnerId { get; set; }
}
Blowdart has a good point that a user could tamper with the OwnerId in a post. I'm sure they could tamper with their auth ticket, too, but they'd have to know the other user's ticket and tamper with both to get the IDs to match for another user, I believe.
I can see one problem with what you have - you are relying on user input to perform the security check.
Consider your code
if (notebook.UserProfileId != WebSecurity.CurrentUserId)
Notebook has come from model binding. So UserProfileId has come from model binding. And you can quite happily fake that - for example I use Firefox's TamperData to change the value of the hidden UserProfileId to match my login and away I go.
What I end up doing (in a service, rather than the controller) is on a post pulling back the record from the database based on the unique id passed (Edit/2 for example would use 2), and then checking User.Identity.Name (well, the passed identity parameter) against the current owner field I have in my returned database record.
Because I pull back from the database (repository, whatever) an attribute isn't going to work for this, and I'm not sure you could be generic enough in an attribute's approach anyway.
The filter sounds like an ok approach, but it's somewhat limited. It would be nice if you could have a filter like this:
[RequireOwnership<Notebook>(n => n.UserProfileId)]
...but Attributes are limited in which data types are allowed, and I don't think that generics are allowed either. So you could have a [RequireOwnership] attribute that works by inspecting model properties using reflection, or you could create a custom validator instead, where your model looks like this:
public class Notebook
{
[MatchesCurrentUserId]
public int UserProfileId { get; set; }
}
Then your ModelState.IsValid check should suffice.
Edit:
Another option occurred to me. You could use a filter in conjunction with an attribute on your model (doesn't have to be a ValidationAttribute). The filter could inspect your request models and check for properties with [MatchesCurrentUserId], comparing with the current user ID.
When I have done things like this in the past it really hasn't been much better. For our projects we would have a method that would accept a Notebook object and check it against the currently logged in user.
You could overload this method with all of your different object types and use a consistent method for checking access. Sorry, that's the best way I know of.
[HttpPost]
public ActionResult Edit(Notebook notebook)
{
if(!SessionUser.LoggedInUser.CheckAccess(notebook))
return HttpNotFound();
//Other code...
}
P.S. SessionUser is a custom class we had basically just to manage whoever is logged in at the time. You could write something similar but don't expect it to be in .NET by default.

Remote attribute in asp.net mvc – in some situations restricts our model

I’ve got an unexpected situation when using Remote Attribute in ASP.NET MVC3.
The model type I used:
using System;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace dTweets.Models
{
// at first time, user should create his account with unique username
// as in twitter.com, user do
public class UserMetadata
{
[HiddenInput]
internal int Identity { get; set; }
[Remote("IsUserExist", "Account")] // at any HttpPost, username should
// be unique – not appropriate if
// updating/editing this model later
[Required(ErrorMessage = "username should be unique")]
public string UserName { get; set; } // user cannot change it, later
[DataType(DataType.Password)]
public string Password { get; set; } // user can also change password, later
[DataType(DataType.MultilineText)]
public string About { get; set; } // Optional field – user can edit it later
}
[MetadataType(typeof(UserMetadata))]
[Bind(Include="UserName, Password, About")]
public partial class User
{
}
}
Remote attribute validates user unique name at account creation time. But when later user wants to update/change his account, Remote attribute did not allow to update model if keeping user unique name the same one.
This is not appropriate result because rarely user changes their unique user name. They just change other fields like About field or password etc.
[Note: at account creation time, I want to check user unique name so I used Remote attribute here, but at later time when updating user account I no longer need Remote attribute]
I must remove Remote attribute for updating this model later.
I want to update/change this model without changing user unique name (remote attribute is applied to this unique name).
one way to do this is to send ID value of this record in AdditionalFields named parameter like
[Remote("IsUserExist", "Account",AdditionalFields = "Identity")]
and then you can check for uniqueness across all rows except the ones that belong to current user. and don't forget to change signature of IsUserEsists action result to receive Identity like
public ActionResutl IsUserExists(string UserName, int Identity)
{
}
Can't you just change server side validation method to something like:
public ActionResult IsUserExists(string userName)
{
if (!UserService.UserNameExists(userName) || (CurrentUser.UserName == userName))
{
return "Yeah. Is it valid.";
}
}
You have current user, because he is logged in. As long as user can only edit his data, this will work.
This is one place where buddy metadata falls short.
Edit/Add scenarios require their own view models. One size fits all scenario validation attributes only work in very trivial business CRUD apps. Add and Edit actions happen in totally different contexts and are only transiently related. This concept is very similar to the DDD bounded context idea.

Conditionally validating portions of an ASP.NET MVC Model with DataAnnotations?

I have certain panels on my page that are hidden under certain circumstances.
For instance I might have a 'billing address' and 'shipping address' and I dont want to validate 'shipping address' if a 'ShippingSameAsBilling' checkbox is checked.
I am trying to use the new DataAnnotations capabilities of ASP.NET MVC 2 (preview 1) to achieve this.
I need to prevent validation of the 'shipping address' when it is not displayed and need to find the way way to achieve this. I am talking mainly server side as opposed to by using jquery.
How can I achieve this? I have had several ideas, related to custom model binding but my current best solution is below. Any feedback on this method?
For the CheckoutModel I am using this approach (most fields hidden):
[ModelBinder(typeof(CheckoutModelBinder))]
public class CheckoutModel : ShoppingCartModel
{
public Address BillingAddress { get; set; }
public Address ShippingAddress { get; set; }
public bool ShipToBillingAddress { get; set; }
}
public class Address
{
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
[Required(ErrorMessage = "First name is required")]
public string FirstName { get; set; }
[Required()]
public string LastName { get; set; }
[Required()]
public string Address1 { get; set; }
}
The custom model binder removes all ModelState errors for fields beginning with 'ShippingAddress' if it finds any. Then 'TryUpdateModel()' will return true.
public class CheckoutModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
base.OnModelUpdated(controllerContext, bindingContext);
var model = (CheckoutModel)bindingContext.Model;
// if user specified Shipping and Billing are the same then
// remove all ModelState errors for ShippingAddress
if (model.ShipToBillingAddress)
{
var keys = bindingContext.ModelState.Where(x => x.Key.StartsWith("ShippingAddress")).Select(x => x.Key).ToList();
foreach (var key in keys)
{
bindingContext.ModelState.Remove(key);
}
}
}
}
Any better solutions?
http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html
I can see your predicament. I'm looking for other validation solutions also with regard to complex validation rules that might apply to more than one property on a given model object or even many properties from different model objects in a object graph (if your unlucky enough to be validating linked objects like this).
The limitation of the IDataErrorInfo interface is that a model object satisfies the valid state simply when none of the properties have errors. This is to say that a valid object is one where all of it's properties are also valid. However, i may have a situation where if property A, B and C are valid - then the whole object is valid.. but also if property A is not valid but B and C are, then the object satisfies validity. I simply have no way of describing this condition/rule with the IDataErrorInfo interface / DataAnnotations attributes.
So i found this delegate approach. Now many of the helpful advancements in MVC didn't exist at the time of writing this article but the core concept should help you. Rather than using attributes to define the validation conditions of an object we create delegate functions that validate more complex requirements and because they're delegated we can re-use them. Sure it's more work, but the use of delegates means that we should be able to write validation rule code once and store all the validation rules in the one place (maybe service layer) and (the kool bit) even use the MVC 2 DefaultModelBinder to invoke the validation automatically (without heaps of checking in our controller actions - like Scott's blog says we can do with DataAnnotations. Refer to the last paragraph before the 'Strongly Typed UI Helpers' heading)!
I'm sure you can beef the approach suggested in the above article up a little with anonymous delegates like Func<T> or Predicate<T> and writing custom code blocks for the validation rules will enable cross-property conditions (for example the condition you referred to where if your ShippingSameAsBilling property is true then you can ignore more rules for the shipping address, etc).
DataAnnotations serves to make simple validation rules on objects really easy with very little code. But as your requirements develop you will need to validate on more complex rules. The new virtual methods in the MVC2 model binder should continue to provide us with ways of integrating our future validation inventions into the MVC framework.
Make sure the fields you don't want validated are not posted to the action. We only validate the fields that were actually posted.
Edit: (by questioner)
This behavior has changed in MVC2 RC2 :
Default validation system validates
entire model The default validation
system in ASP.NET MVC 1.0 and in
previews of ASP.NET MVC 2 prior to RC
2 validated only model properties that
were posted to the server. In ASP.NET
MVC 2, the new behavior is that all
model properties are validated when
the model is validated, regardless of
whether a new value was posted.
Applications that depend on the
ASP.NET MVC 1.0 behavior may require
changes. For more information about
this change, see the entry Input
Validation vs. Model Validation in
ASP.NET MVC on Brad Wilson’s blog.
For the more complex cases I moved away from simple DataAnnotations to the following: Validation with visitors and extension methods.
If you want to make use of your DataAnnotations you would replace something like the following:
public IEnumerable<ErrorInfo> BrokenRules (Payment payment)
{
// snip...
if (string.IsNullOrEmpty (payment.CCName))
{
yield return new ErrorInfo ("CCName", "Credit card name is required");
}
}
with a method to validate a property by name via DataAnnotations (which I don't have atm).
I created a partial model binder that only validates the keys that were submitted. For security reasons (if I was going to take this a step farther) I'd create a data annotation attribute that marks which fields are allowed to be excluded from a model. Then, OnModelUpdated check field attributes to ensure there is no undesired underposting going on.
public class PartialModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
// default model binding to get errors
base.OnModelUpdated(controllerContext, bindingContext);
// remove errors from filds not posted
// TODO: include request files
var postedKeys = controllerContext.HttpContext.Request.Form.AllKeys;
var unpostedKeysWithErrors = bindingContext.ModelState
.Where(i => !postedKeys.Contains(i.Key))
.Select(i=> i.Key).ToList();
foreach (var key in unpostedKeysWithErrors)
{
bindingContext.ModelState.Remove(key);
}
}
}
This isn't related to DataAnnotations but have you looked at the Fluent Validation project? It gives you fine grain control over your validation and if you have object-to-object validation an aggregate object of the two objects will get you going.
Also it seems to have been build with MVC in mind but it also has its own "runtime" so that you can use it in other .NET applications as well which is another bonus in my book.

Where should be the validation in a ASP.Net MVC scenario having Repository, Service Layer and using Model Binder?

Related: What’s the best way to implement field validation using ASP.NET MVC?
Let's suppose a solution with the following projects:
Foo; // the MVC web project
Foo.Models;
Foo.Repositories;
Foo.Services;
Foo.Models is the domain of the application with all the entities, doesn't matter if using EF, NH, POCO or whatever. Here's an example:
public class User
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
In Foo.Repositories there is a UserRepository and in Foo.Services there is a UserService.
In the web application let's consider a model binder like following:
public class UserBinder : DefaultModelBinder
{
//...
}
I see three different options on where to put the validation:
In Foo.Models like the following:
public class User
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public ICollection<KeyValuePair<string, string>> ValidateErrors()
{
//Validate if Username, Email and Password has been passed
}
}
In Foo.Services like:
public class UserService
{
public ICollection<KeyValuePair<string, string>> ValidateErrors()
{
//Validate if Username, Email and Password has been passed
}
}
In Foo inside the model binder:
public class UserBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var user = (User)bindingContext.Model;
// validate everything here
base.OnModelUpdated(controllerContext, bindingContext);
}
}
Another thing to notice is that considering the first 2 options [Model and Service] there is another decision to make: ValidateErrors method can be called directly on the controller or inside the Binder.
I have 2 questions on the scenario:
Should the validation be:
In the Model being called from the controller?
In the Model being called from the binder?
In the Service being called from the controller?
In the Service being called from the binder?
Directly in the Binder?
Any other idea?
All the above scenario discuss about the User creation. But what about User logon?
Let's say user uses the username and password to login in the application, so it won't need to validate the e-mail.
Where this validation should be?
In the Model being called from the controller?
In the Service being called from the controller?
Any other idea?
Check out the ASP.NET MVC Contact Manager Sample Application it has a very good architecture im my opinion
http://www.asp.net/learn/mvc/tutorial-26-cs.aspx'>http://www.asp.net/learn/mvc/tutorial-26-cs.aspx
I'm a big fan of putting calling the validation from the controllers and having the validation routine return an ActionResult so the controller can know what to do with the result.
For what it's worth, here's what I have scrounged up in my current project:
I have Models, Repositories (you can call them Services if you like), and ViewModels. I try to avoid writing custom model binders because (a) it's boring and (b) a strange place to put validation, IMHO. To me, a model binder is just taking items from the request and shoving them into an object. PHP, for example, doesn't do any validation when plucking items from a header into the $_POST array; it's the thing we plug the array into that cares about its contents.
My Model objects generally never allow themselves to enter an invalid state. This means that required parameters are passed in during constructors and properties will throw exceptions if they're attempted to be set with invalid values. And, in general, I try to design my Model objects to be immutable. For example, I have an Address object for mailing addresses that is constructed with an AddressBuilder object with looks at the field requirements for a given country by inspecting an AddressScheme that can be retrieved from the AddressSchemeRepository. Phew. But I think it's a good example because it takes something conceptually simple ("validate a mailing address") and makes it complicated in real world usage ("we accept addresses from over 30 countries, and those formatting rules are sitting in a database, not in my code").
Since constructing this Model object is kind of a pain--as well it should be, since it's being quite particular about the data that gets loaded into it--I have a, say, InputAddressViewModel object that my view binds to. The InputAddressViewModel implements IDataErrorInfo so that I get ASP.NET MVC's DefaultModelBinder to add errors to the ModelState automatically. For simple validation routines that I know ahead of time (phone number formatting, first name required, e-mail address format), I can implement these right in the InputAddressViewModel.
The other advantage of having a view model is that because it is shamelessly tailored to a particular view, your real model is more reusable because it doesn't have to make any weird concessions to make it suitable for UI display (e.g., needs to implement INotifyPropertyChanged or Serializable or any of that mess).
Other validation errors about the address I won't know about until I interact with my AddressScheme in my actual Model. Those errors will be there controller's job of orchestrating into the ModelState. Something like:
public ActionResult InputAddress(InputAddressViewModel model)
{
if (ModelState.IsValid)
{
// "Front-line" validation passed; let's execute the save operation
// in the our view model
var result = model.Execute();
// The view model returns a status code to help the
// controller decide where to redirect the user next
switch (result.Status)
{
case InputAddressViewModelExecuteResult.Saved:
return RedirectToAction("my-work-is-done-here");
case InputAddressViewModelExecuteResult.UserCorrectableError:
// Something went wrong after we interacted with the
// datastore, like a bogus Canadian postal code or
// something. Our view model will have updated the
// Error property, but we need to call TryUpdateModel()
// to get these new errors to get added to
// the ModelState, since they were just added and the
// model binder ran before this method even got called.
TryUpdateModel(model);
break;
}
// Redisplay the input form to the user, using that nifty
// Html.ValidationMessage to convey model state errors
return View(model);
}
}
The switch may seem repulsive, but I think it makes sense: the view model is just a plain old class and doesn't have any knowledge of the Request or the HttpContext. This makes the logic of the view model easy to test in isolation without resorting to mocking and leaves the controller code left to, well, control by interpreting the model's result in a manner that makes sense on a Web site--it could redirect, it could set cookies, etc.
And the InputAddressViewModel's Execute() methods looks something like (some people would insist on putting this code into a Service object that the controller would call, but to me the view model will do so much finagling of the data to make it fit the real model that it makes sense to put it here):
public InputAddressViewModelExecuteResult Execute()
{
InputAddressViewModelExecuteResult result;
if (this.errors.Count > 0)
{
throw new InvalidOperationException(
"Don't call me when I have errors");
}
// This is just my abstraction for clearly demarcating when
// I have an open connection to a highly contentious resource,
// like a database connection or a network share
using (ConnectionScope cs = new ConnectionScope())
{
var scheme = new AddressSchemeRepository().Load(this.Country);
var builder = new AddressBuilder(scheme)
.WithCityAs(this.City)
.WithStateOrProvinceAs(this.StateOrProvince);
if (!builder.CanBuild())
{
this.errors.Add("Blah", builder.Error);
result = new InputAddressViewModelExecuteResult()
{
Status = InputAddressViewModelExecuteStatus
.UserCorrectableError
};
}
else
{
var address = builder.Build();
// save the address or something...
result = new InputAddressViewModelExecuteResult()
{
Status = InputAddressViewModelExecuteStatus.Success,
Address = address
};
}
}
return result;
}
Does this make sense? Is it a best practice? I have no idea; it's certainly verbose; it's what I just came up with in the past two weeks after thinking about this problem. I think you're going to have some duplication of validation--your UI can't be a complete imbecile and not know what fields are required or not before submitting them to your model/repositories/services/whatever--otherwise the form could simply generate itself.
I should add that the impetus for this is that I've always kind of detested the Microsoft mentality of "set one property -> validate one property" because nothing ever works like that in reality. And you always end up getting an invalid object persisted because someone forgot to call IsValid or some such on the way to the data store. So another reason for having a view model is that it tailors itself to this concession so we get a lot of CRUD work of pulling items from the request, validation errors in the model state, etc quite easily without having to compromise the integrity of our model itself. If I have an Address object in hand, I know it's good. If I have an InputAddressViewModel object in hand, I know I need to call it's Execute() method to get that golden Address object.
I'll look forward to reading some of the other answers.
After a lot of research I think I got the answers to my question so i decided to share.
The validation code should be on Model.
As per the idea of "thin controller, fat model" AND considering that a model would know what it needs to validate or not.
For example, let's say I decide to user the Foo.Models in other solution but I decide NOT to use any other project and the validation is in other project.
I'll have to re-code the entire validation in this case what is a total waste of time, right?
OK. The validation code must be in the model but where should it be called?
This validation must be called where you're saving it to your database or file.
As in the proposed scenario I'm considering the repository as a domain, then we should consider putting the validation just before the change saving [in this example I'm using Entity Framework but it's not necessary, it's just to show]:
public class UserRepository : IRepository<User>
{
public void Create(User user)
{
user.Validate();
var db = dbFooEntities();
db.AddToUsers(user);
db.SaveChanges();
}
}
As per MS recommendation, the model validation should raise an exception and the controller must populate the ModelState with the errors found [I'll try to update this answer with a sample code on that as soon as I finish my app].
With that we have an answer for question #1.
What about question #2, regarding the login validation?
As login is not a situation where you're persisting your data, the validation should stay on the Service since logging in is a service in this case.
So, the answers for the question are:
In the Model being called from the REPOSITORY [that is called by the controller]
In the Service being called from the controller
This is very interesting and it helps me a lot in deciding where to put validation.
currently I feel the most for each model implementing a "Validate" method, which is called from a Repository or a Service.
However, what about validating if a chosen username is unique?
Should that code be inside the User model, or inside the UserService class, or in the UserRepository class?
If the uniqueness validation should be inside the User model, then the User model should have access to either the UserService or the UserRepository class. Is that OK, or is that against any "best practice" pattern?
For example:
class User
{
string Username { get; set; }
string Email { get; set; }
string Password { get; set; } // hashed and salted of course :)
IEnumerable<RuleViolation> Validate()
{
List<RuleViolation> violations = new List<RuleViolation>();
IUserService service = MyApplicationService.UserService; // MyApplicationService is a singleton class, especialy designed so that the User model can access application services
// Username is required
if ( string.IsNullOrEmpty(Username) )
violations.Add(new RuleViolation("Username", "Username is required"));
// Username must be unique: Should uniqueness be validated here?
else if( !service.IsUsernameAvailable(Username)
violations.Add(new RuleViolation("Username", "Username is already taken!"));
// Validate email etc...
return violations;
}
}
interface IUserRepository
{
void Save(User item);
}
interface IUserService
{
IUserRepository UserRepository { get; }
void Save(User item);
}
class UserService : IUserService
{
public UserService(IUserRepository userRepository)
{
this.UserRepository = userRepository;
}
IUserRepository UserRepository { get; private set}
public void Save(User user)
{
IEnumerable<RuleViolation> violations = user.Validate();
if(violations.Count() > 0)
throw new RuleViolationException(violations); // this will be catched by the Controller, which will copy the violations to the ModelState errors collection. But the question is, should we validat the user here, or in the UserRepository class?
UserRepository.Save(user);
}
}
class UserRepository : IUserRepository
{
void Save(User item)
{
IEnumerable<RuleViolation> violations = user.Validate();
if(violations.Count() > 0)
throw new RuleViolationException(violations); // this will be catched by the Controller, which will copy the violations to the ModelState errors collection. But the question is, should we validate the user here, or in the UserService class?
UserRepository.Save(user);
}
}
My guess would be that validation should be as close to the model as possible. So I'd say that the UserRepository should be the one responsible for validating it's model being added.
The most important queston for me is: Should the User model know about the IUserService / IUserRepository interfaces so that it can validate the Username uniqueness?
Or should the IUserService service validate uniqueness?
I'm curious about your views on this!
I'm using the DataAnnotations attributes in combination with a MVC model binder to do my validation and its pretty awesome. Since I treat User input as Command View Models its the cleanest way to keep domain clean from outside concerns.
http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html
This also allows me to take advantage of AutoForm by LosTechies.com:
http://www.lostechies.com/blogs/hex/archive/2009/06/17/opinionated-input-builders-part-8-the-auto-form.aspx
And I expect the client side validation tools in MVC 2, VS 2010 to take advantage of these attributes as well.
So I'm whipping out user input view models, commands, at a furious pace right now and tying them into not only the AutoForm functionality but my own custom UI templates to get AutoGrid and AutoOutput from these attributes as well.
Nothing is better than saying:
Html.AutoForm(Model);
Or
Html.AutoGrid(Model.Products);
And getting validation and html generation in a very DRY and orthogonal way. My controllers are light, my domain pristine, and my time is unoccupied by writing the same if( string.IsNullOrEmpty() ) method on every object with a FirstName property.
For me the approach was not as "philosophical" as others have written about. I'm trying to be very pragmatic about MVC development and I get a ton of bang for the buck out of these bits.

Resources