A name field needs to be verified as starting with a capital letter and not being allowed to take a number. I'll do this with regular expressions. Implementing the MVC pattern.
Should I have the controller send the value that was input to a checking class and send corresponding error msg's back to the UI and after checking then call the class that writes it to the DB
OR
should I have the controller send the 'value input' to the class that writes it to the DB and this method then calls the validation method?
you can use something like this (i've used for email validation)
[Required(ErrorMessageResourceType = typeof(CCSModelResources), ErrorMessageResourceName = "ANTCommonTextRequiredMessage")]
[RegularExpression(#"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$",
ErrorMessageResourceType = typeof(CCSModelResources), ErrorMessageResourceName = "ANTCommonTextRegularExpressionMessage")]
public new string EmailAddress
{
get { return base.EmailAddress; }
set { base.EmailAddress = value; }
}
and you controller code like
[Authorize]
[HttpPost]
public ActionResult UpdatePersonalDetails(FormCollection form)
{
regUserWizard.PersonalDetails = new MVCPersonalDetails();
if (!TryUpdateModel<MVCPersonalDetails>(regUserWizard.PersonalDetails, form.ToValueProvider()))
{
return View("UpdateUser", regUserWizard);
}
else
{
//you code
}
return RedirectToAction("Index", "Home");
}
you view code like
< %= Html.ValidationSummary("Account creation was unsuccessful. Please correct the errors and try again.") %> <% Html.EnableClientValidation();
using (Html.BeginForm()) { %>
//you code
The first approach seems more correct because the db access logic shouldn't be mixed with validation.
THe purpose of the controller is to validate input and provide valid input to models. Your model should not be concerned with what inputs is provided by the views. It should concentrate on Business logic only. You can add some validation code on the client side for ease-of-use as well but it needs to be present on server side too for security purpose.
Your 1st approach is correct...go ahead with it...
In my opinion, it all depends on what kind of validation you want to perform:
1. If you don't want a field to be empty, I will do that check on the view layer. This is where most regex could be applied.
2. If I want to ensure that a user input(, say a username) is unique or not , I will do that validation on the controller side and pass any feeback back to the view. In the latter, the controller might have a dependency on an abstraction of a data access layer or service layer to do the actual checking.
Related
Something I've found to be intensely annoying about ASP.NET MVC is that ModelState values are very persistent with the #Html.* extension methods during POST requests. I understand that ModelState is there to allow persisting invalid user-entered values, however, MVC's handling of ModelState continues even for properties whose user-entered values are valid. Sometimes, this is undesirable behavior.
For example, if you have an ID in the URL, and you set an ID property in your view model to a different value (this is a good sign that the ID names need to be more specific, but bear with me), the value you set will make it during a GET request, but during a POST, the value in ModelState will be used, which will have come from the route.
This also happens with posted values. If, for some reason, you need to change a value which came from the client, the new value in the model will be ignored; you must also (or instead) update ModelState.
To resolve this inconsistency, I've taken to adding this action filter to my MVC projects as a global filter:
public class RemoveValidModelStateFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
var keys = modelState.Keys.ToArray();
foreach (var key in keys)
{
var entry = modelState[key];
if (entry.Errors.Count == 0)
modelState.Remove(key);
}
}
}
It's been working well for me so far, but I'm curious if I'm unintentionally creating any problems or losing functionality. I only use this on new projects and projects which I have full control over, so it won't create hidden issues with values not being communicated.
I can see other developers potentially becoming confused when working on my projects, but I don't know of any other side-effects.
The ModelState is used to repopulate any values on the form that are not successfully submitted and read into the model. These values are then used to repopulate the form. The best example I can think if is for validation purposes e.g. you have a model:
public class TestModel
{
public DateTime { get;set;}
}
Your controller might look like this:
public class TestController : Controller
{
public ActionResult Index()
{
return View(new TestModel());
}
[HttpPost]
public ActionResult Index(TestModel model)
{
return View(model);
}
}
In your view, you might represent that date as a text box input. If a user types in a valid date, and submits the form, the page reloads with the value populated in that text box from the submitted model. So far so good. However, if a user inputs an invalid date, the TestModel cannot be poulated (as the property would be invalid), so MVC uses the ModelState instead to repopulate the text box. If you clear the model state every time, you would end up with a validation error, but a blank text box instead of what the user previously entered.
Might not be an issue in your case, but I'd be wary of clearing it on all actions just in case you ever needed this functionality later.
I have a method that validates a number, I don't have a regular expression for this as it is kind of complicated to create.
public bool IsRegistrationNumberValid(int number)
{
...
}
On my form, I have a textbox and I want to add validation for this column.
How can I create a custom annotation or hook into the ModelState object to add an error message?
My POST controller action is like:
[HttpPost]
public ActionResult Create(UserRegistrationViewData model)
{
if (ModelState.IsValid)
{
...
}
}
I'm not sure what options I have, can I just create a custom attribute to add to my model?
And/Or should i just hook into the Model state and add the error message before I check for ModelState.IsValid?
There are a few approaches to this and the best one for you will depend on the following:
Where your IsRegistrationNumberValid method is located and whether the the logic be moved?
Are you validating the integrity of the user input or the domain (you should be checking both, but the validation for each will be in a different place)?
Personal preference.
The way I see it you have the following options available:
Validate in your controllers action methods.
Validate using the IValidatableObject interface.
Use a custom ValidationAttribute.
Validate in your service layer.
Option 1: Validate in your controller:
First of all you could simply validate the value in your controllers action method and update the ModelState like so:
[HttpPost]
public ActionResult Create(UserRegistrationViewData model)
{
if (ModelState.IsValid)
{
if (!someObject.IsRegistrationNumberValid(model.value))
{
ModelState.AddModelError("PropertyName", "There is an error..");
Return View()
}
else
{
// Carry out successful action here...
}
}
}
Option 2: use the IValidatableObject interface.
A second, much cleaner way is to implement the IValidatableObject interface on your viewModel so that you can move the logic out of the controller:
public class ViewModel : IValidatableObject
{
public int Value { get; set; }
IEnumerable<ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
{
if (!staticClass.IsRegistrationNumberValid(this.Value))
{
yield return new ValidationResult("An error occured");
}
}
Option 3: Create a custom validation attribute.
As mentioned you could create a custom validation attribute by deriving from ValidationAttribute as shown in this article.
The choice between the IvalidatableObject interface and a custom validation attribute is usually down to preference, however, one case where the IValidatableObject interface wins is when your validation depends on multiple properties (E.G. checking if one date is after another).
Option 4: Validate in your service layer.
Finally, if your validation is dependant on other information from a database you might want to take a look at this tutorial on validating with a service layer. The article is not perfect (the service and controller are a bit too tightly coupled) but is a good start and with a few modifications you can pass database validation errors (such as primary key violations) into your user interface in a very transparent and user-friendly way.
You will probably end up using a mixture of options 2, 3, and 4. You don't really want to be using the first option if possible as it makes your controller methods more complicated and makes it more difficult to reuse validation logic elsewhere.
My advice would be the following:
If you are validating the integrity of the user input (E.G. checking a date is in the correct format) use a mixture of the IValidatableObject interface and the ValidationAttribute classes.
If you are validating the integrity of the domain (ensuring no duplicate entities are entered, or that relationships between entities are defined) carry out the validation in the service layer.
I have a model that contains an Address property and Latitude/Longitude properties. The model is populated in a "Create" view, where they put in most of the other fields. I populate the Lat/Lng using the Google Maps API geocoding functionality based on the entered address (no sense in making them put this in manually).
My big question is where should this be done. The code below works, but I think it's pretty clunky. Any thoughts on a better way to integrate this behavior? Should it be in the controller? Should it be part of some internal model mechanism?
[HttpPost]
public ActionResult Create(Church church)
{
try
{
if (ModelState.IsValid)
{
string address = string.Format("{0},{1},{2} {3}",
church.Street + church.Street2, church.City,
church.Region, church.PostalCode);
JObject jsonResult = GoogleApiHelper.GetAddressGeocodeData(address);
//Handle some error states here...
if (jsonResult["results"].Count() == 1)
{
church.Latitude = jsonResult.SelectToken(
"results[0].geometry.location.lat").Value<double>();
church.Longitude = jsonResult.SelectToken(
"results[0].geometry.location.lng").Value<double>();
unitOfWork.ChurchRepository.Insert(church);
unitOfWork.Save();
return RedirectToAction("Index");
}
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes.");
}
return View(church);
}
You could use a repository layer to abstract the access to the Google API and then invoke this repository from the controller to give you an already populated model. This way if tomorrow you decide to use Bing instead of Google all you have to change is the implementation of the repository. No need to touch your controller or model logic.
You could write a custom model binder and put all of your Google API code in there. That way your controller will be completely oblivious to your data access.
Here is a tutorial on custom model binders:
http://buildstarted.com/2010/09/12/custom-model-binders-in-mvc-3-with-imodelbinder/
The main question is are you going to create churches anywhere else?
If not then this is a perfectly acceptable place to put the code.
If you are then put the code into a ChurchService which can be called from both places. That way you can Keep to DRY (Don't Repeat Yourself) principles without over complicating your code.
I have a model class :
public class YearlyChageRate
{
public int Year { get; set; }
public double Rate { get; set; }
}
and I want to check that Yeae is unique or no and in condition Year is not unique application show an error message to users.How can I check the Year filed is repeated or not?
Here is a good example:
http://tugberkugurlu.com/archive/asp-net-mvc-remote-validation-for-multiple-fields-with-additionalfields-property
And here too: MVC validation for unique
You can use Remote attribute in your model to perform check for unique value in database.
This is official example of Remote attribute: http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx
And one more: http://www.a2zdotnet.com/View.aspx?Id=198
You could use the [Remote] validation attribute on your view model.
Although you can use DataAnnotations attributes for validation and the [Remote] attribute for checks against the DB, it's not a very good design choice.
Let me explain:
data access is a data-layer matter
validation is a business-layer matter
user input and feedback is a ui matter
With DataAnnotations, you're mixin 3 in 1. It can be faster, but surely not well designed.
You could try a more disciplinate approach, like this:
Have a method at business level that will take your object as a parameter, perform validation internally using a validation framework of your choiche;
This method will call the data access to persist the object only if the validation passed;
This method will always return to the UI the validated object, plus a collection of fields/errors if anything didn't validate;
When you read the output of the method in your ui, you can either display a success page if there were no errors, or redisplay the form with the validation errors returned. To do this, the use of the PRG pattern is highly recommended, as you should never display a page on a POST method. Google for the PRG pattern to learn more about it. MvcContrib has a nice ActionFilter called ModelStateToTempData to make the implementation of the PRG pattern something trivial.
I have a registration page in my application. It has 3 states and 1 error state(If any error comes):
Fill Basic Information
Select Package
Say Thanks
Error
Now I want to use state pattern here. First I created a console application which is OK. Now I want to implement this logic in my MVC application but I am confused about the structure. I mean how many views, models and controller I need and where to place my logic.
1 controller: RegistrationController
6 action methods:
GET+POST for Index (fill in basic info)
GET+POST for Package
GET for Thank you
GET for Error
This is rough code to make your mind going:
public class RegistrationController : Controller
{
public ActionResult Index()
{
RegistrationState model = RegistrationState.Init();
// just display the "Fill Basic Info" form
return View(model);
}
[HttpPost]
public ActionResult Index(RegistrationState data)
{
// process data and redirect to next step
this.TempData["RegState"] = data;
if (!this.ModelState.IsValid || data.State == State.Error)
{
// error should handle provided state and empty one as well
return RedirectToAction("Error");
}
return RedirectToAction("Package");
}
public ActionResult Package()
{
RegistrationState data = this.TempData["RegState"] as RegistrationState;
if (data == null)
{
return RedirectToAction("Error");
}
// get packages and display them
IList<Package> model = this.repository.GetPackages();
return View(new Tuple.Create(data, model));
}
[HttpPost]
public ActionResult Package(RegistrationState data)
{
// process data blah blah blah
}
// and so on and so forth
....
}
As you can see you still have to write some MVC-related code to act upon state changes. In my example everything's done in action methods. But action filters could be used as well. If you can't come up with a general action filter that can serve many different state objects then it's best to just write the code in action methods.
Another approach
If you know Asp.net MVC good enough you could take this a step further and write a state machine ControllerFactory that would work along with routing in a sense as:
{StateObjectType}/{State}
ControllerFactory would therefore be able to parse view data to a known state object type and pass execution to particular action. According to state. This would make it a specially state machine suited Asp.net MVC application.
The more important question is of course whether you can create the whole application with this pattern or are there just certain parts of it that should work like this. You could of course combine both approaches and provide appropriate routing for each.
Important notices
You should be very careful how you define your error state, because entering invalid field data shouldn't result in error state but rather in data validation errors that actually display within the view beside the field with invalid data (ie. invalid date provided as 13/13/1313). Your error state should only be used for actual object state error that's not related to user input. What would that be is beyond my imagination.
As mentioned in my comment you should check out some Asp.net MVC intro videos and you'll see how validation works in Asp.net MVC. Also rather simple stuff.
State pattern of this kind is not something a regular Asp.net MVC developer would use, because it would most likely complicate code more than taking the normal approach. Analyse before you decide. Asp.net MVC is very clean code wise so adding additional abstraction over it may become confusing. And your domain model (state classes) would most likely have a much more complex code as simple POCOs with data annotations.
In your case data validation would also be more complicated (when used with data annotations) because you object should be validated according to its state which may be different between states. POCO objects are always validated the same. This may mean that we may use more classes but they are smaller, simpler and easier to maintain.
I think you are confusing states. Examples of state are:
Awaiting for a user to register
User registered successfully
User didn't register successfully
Now each of these states would have a page:
localhost:8034/Register
localhost:8034/Register/Success
localhost:8034/Register/Failure
If user can't register because they left some fields empty, they will be in the first state and you will have to display some validation messages.
Because of this, as the minimum I'll have a controller called Register and the following action methods:
Index() GET/POST
Success() GET
Failure() GET