How do I show a different Required message to instances of the same object in MVC3? - asp.net-mvc-3

I have a Razor MVC3 project which has two user records in a form, one for the key contact and one for a backup contact. For example;
public class User
{
[Required(ErrorMessage = "First name is required")]
public string FirstName { get; set; }
}
Validation all works well except for the small issue where the user fails to fill out a field, it says 'First name is required' but I'd like to point the user to which one of the first name fields is missing. Such as 'Backup contact first name is required' or 'Key contact first name is required'.
Ideally I'd like to leave the [Required] annotation on the class as it is used elsewhere.
This seems like one of those small cases that might have been missed and is not easily achieved, but please prove me wrong.
Ryan

One way you can accomplish this is with a separate view model for this screen, instead of a single User model with all the error messages. In the new view model, you could have a BackupContactFirstName property, KeyContactFirstName property, etc each with its separate error message. (Alternatively this view model could contain separate User models as properties, but I've found that Microsoft's client validation doesn't play well with complex models and prefers flat properties).
Your view model would look like this:
public class MySpecialScreenViewModel
{
[Required(ErrorMessage = "Backup contact first name is required")]
public string BackupContactFirstName { get; set; }
[Required(ErrorMessage = "Key contact first name is required")]
public string KeyContactFirstName { get; set; }
}
Then pass your view model to the view like this:
#model MySpecialScreenViewModel
...
Your post controller action would collect the properties from the view model (or map them to separate User models) and pass them to the appropriate data processing methods.

An alternative I have stumbled across, just modify the ModelState collection. It will have the elements in a collection named by index, like 'User_0__EmailAddress' and you can adjust / amend / replace the Errors collection associated with that key.

[Required(ErrorMessage = "{0} is required")]
{0}=The DisplayName is automatically placed on it
sample
[DisplayName("Amount per square meter")]
[Required(ErrorMessage = "{0} is required")]
public int PriceMeter { get; set; }
output
Amount per square meter is required

Related

I have a complex View Model that has built complex named html elements. How do I build a matching post model?

I have a lot of data that needs to be passed from a controller to a view and I am trying to use strongly typed View Models where possible.
Take an example where you have a database of loads of people - We want to edit a person whilst also presenting a list of everyone with the same surname.
public class person
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class testviewmodel
{
public List<person> people { get; set; }
public person newperson { get; set; }
}
I can't use testviewmodel as the model for the post because there is a lot more going on in the form/data. I have managed to build a model that contains nearly all the form data, other than the ones from the View Model.
I generate some items in the form via:
<input asp-for="newperson.Firstname" class="form-control"/>
This in return generates:
<input class="form-control" disabled type="text" id="newperson_Firstname" name="newperson_Firstname" value="xxxx" />
However, I have tried adding newperson_Firstnameto my model alongside quite a few other combinations, and, I am just not able to see the data.
Can anyone please assist and let me know what I am doing wrong - or, should I just be adjusting the view model to be more fit for purpose?
...Lastly, is there any equivalent of var_dump($_REQUEST);? At the moment, I'm adding breakpoints and trying to open up different items within Locals, but, it's trial and error and taking ages... I'm just trying to find where the form is!
You shouldn't need to dig around in the Request object. If you pass an instance of your ViewModel to your post action, model binding will take care of populating the Person property automatically:
[HttpPost]
public IActionResult Edit(TestviewModel model)
{
var person = model.Person; // add a breakpoint here, should represent the posted values
}

MVC3 Registration form and model

I have a question regarding the MVC 3 and more exaclty about the views and models. I want to mention that I'm new to MVC so I'm oly learning it.
Basically for example lets take te registration form:
I have a controller, view and model, to register a new user.
AccountController
Register.chtml
AccountModel => RegisterationModel
Now, in registration model i have all the datamembers with data annotations, for example:
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
This are then rendered in view.
What bothers me, or I don't really understand how to do it properly:
Ok I have RegistrationModel ... but later on, for example if i want to render the profile of the user, should i call registrationmodel again or then it will be profilemodel? So basically I will have a lot of the same models just to render the same thing ... no?
Can't I have then one general Model, something like user, and then User i can pass with RegistrationModel/ProfileModel to view.
Maybe it is a bit difficult to understand what I mean exactly, but how I imagine it: for example a user submits a form, everything is parsed and a User object is created with all the data members, then this User object is pased to DAL, where it is submitted to DB. Later on someone visits the profile of this user and the DAL, will return User object back which is then displyed.
The answer to your question is no you should generally separate your domain models from your view models. Consider a following scenario. Let's say you have a User model and your business logic allows you to both add a new user and edit an existing user. Let's say your user model looks like this:
public class User
{
[Required]
public int? UserId {get; set;}
[Required]
public string LastName {get; set;}
[Required]
public string FirstName {get; set;}
[Required]
public string Password {get; set;}
public bool IsAdmin {get; set;}
}
Now in order for your user model to be valid you have to have User ID to make the user identifiable. When you're inserting a new user you don't need the ID because that is something database will automatically take care of on insertion. However when you're doing an update of the user then you need the user ID to be populated. So now you have a model that in one case requires a field (UserId) but in another it doesn't. How are you going to handle that?
The answer is view models and this is the reason why they exist and why it's advised to create one for each entry form you have in your project. In this case you would end up with a different insert and update user view models. I know it's tedious to convert these view models into the underlying domain models but there are libraries to help you do that automatically like AutoMapper (https://github.com/AutoMapper/AutoMapper/wiki/Getting-started).
2nd and probably more serious problem is over posting. Suppose you are using the above User model to edit the user in your database. Now the model has an IsAdmin field which specifies whether user is an admin or not. Now your edit user view will omit this field since you don't want the general user to be able to make themselves an admin. But let's say you're dealing with a really smart user and he make a hidden field with id of IsAdmin and makes it value to be true:
<input type="hidden" id="IsAdmin" value="true" />
and then he/she posts the form to your save user url. Because you are using the domain logic user model which has IsAdmin property this hidden field will map to your model and this user just managed to make himself/herself and admin in your site. This is precisely why you need view models so this scenario can never happen.

Required field not present on all pages leading to problems

I have a ‘Create’ page in my MVC3 application that has 4 input fields that are all required. I also have an ‘Edit’ page in which 3 of these 4 fields can be edited. I do not want to display the 4th field and want to maintain it at its initial value (the field is the date that the entry was created ).
I mark the 4th field as [Required] in the model then this causes the model to be declared as invalid in post action method of the Edit field. If I omit the [Required] annotation then someone can create a user with a null value for this 4th field.
How can I get around this problem?
Model Code:
[Required]
[DisplayName("User Name")]
public string UserName { get; set; }
[Required]
public string Role { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayName("Insert Date")]
public DateTime? InsertDate { get; set; }
[Required]
[DisplayName("Active")]
public bool ActiveInd { get; set; }
Controller Code:
public ActionResult Edit(int id, ZUserRoleModel mod)
{
if (ModelState.IsValid)
{
// code removed
return RedirectToAction("Index");
}
return View(mod);
}
You can make that field as hidden in edit mode.
#Html.HiddenFor(x => x.EntryDate)
Not sure if you still need an answer for this, but what you need to do in order for the
#Html.HiddenFor(x => x.EntryDate )
to work, is pass an existing model into view. So let's assume that your action for getting the user data looks like this. ( You did not supply it, so I am not sure if this is right )
Public ActionResult GetUser(int UserID)
{
ZUserRoleModel model = new ZUserRoleModel(UserID);
// Maybe this could go to your database and gather user
// It would populate the correct data into a model object
return View("Edit", model);
}
With combination of the hidden field, your view will be populated with the existing user information, and the hidden field will be populated with data, and it will be passed to your edit action.
NOTE: I wrote this without any kind of testing, but it should still work, or at the very least, I hope it points you in the right direction if you still need assistance.
You can use fluentvalidation: http://fluentvalidation.codeplex.com/
Have a rule that's something like
RuleFor(user => user.field4).NotEmpty().When(ViewContext.Controller.ValueProvider.GetValue("action").RawValue <> "edit")

MVC3 validate only one entity in ViewModel

I have an mvc3 create page using a View Model with 2 entities
like
class ViewModel1{
public User user{get;set;}
public Company company{get;set;}
}
where User and Company are EF4 entities(tables). I need to use a single page to create both(related) tables. Now the Company entity is optional under some conditions and I use jQuery to hide the corresponding section in the view.
However since company has required fields , the post back create function has ModelState.Valid as false.
What I want to do is if the Company section is hidden, I would like to skip validating the Company entity in ViewModel in Server( I avoid validation of hidden elements in Client).
Maybe there is a better and more proper approach to this?
What you have shown is not a view model. You call it a view model but it isn't because it is referencing your EF domain entities.
A more realistic view model would look like this:
class ViewModel1
{
public UserViewModel User { get;set; }
public CompanyViewModel Company { get; set; }
}
or even flattened out and containing only the properties that your view needs:
class ViewModel1
{
public int UserId { get;set; }
[Required]
public string FullUserName { get;set; }
[Required]
public string CompanyName { get; set; }
}
Now depending on your specific requirements about view model validation your UserViewModel and CompanyViewModel classes will be specifically designed for them.
Instead of putting the entities directly in the view model, put the properties for the entities in the view model and map between the view model and the actual entity objects on the server. That way you can control what properties are required for your view. Create some custom validation rules to validate that the required company properties are there when some company information is required. To do this on the server, you can have your view model implement IValidatableObject and implement the logic in the Validate method. On the client you can add rules to the jQuery validate plugin for the "required if" properties.
public class UserCreationViewModel : IValidatableObject
{
[Required]
public string Username { get; set; }
[Required]
public string FirstName { get; set; }
...
public string CompanyName { get; set; }
public string CompanyEmail { get; set; }
public IEnumerable<ValidationResult> Validate( ValidationContext context )
{
if (!string.IsNullOrEmpty(CompanyName) && string.IsNullOrEmpty(CompanyEmail))
{
return yield new ValidationResult("Company Email is required if you specify a company", new [] { "CompanyEmail" });
}
}
}
I'm not sure what I would do on the client-side. You have a choice of either adding specific rules to the validate plugin directly, but it might be hard to make it look exactly the same as using the unobtrusive validation that MVC adds. Alternatively, you could look at adding/removing the unobtrusive attributes from the "required if" elements using jQuery depending on the state of the elements that trigger their requirement. I suggest trying both ways -- look at the docs for the validate plugin to see how to add custom rules and examine the code emitted by the MVC framework for the unobtrusive validate to see what you would need to add to make that work.
Another possibility would be including/removing a partial view with the company properties in the from based on whether the company information is required or not. That is, type in a company name and use AJAX to grab the inputs required for the company and add them to the form. If the company name is deleted, delete the elements. Leave the server-side validation the way it is, but in the partial view mimic the HTML that the framework would add in for unobtrusive validation. This is sort of the best of both worlds as the jQuery code is much simpler and you get consistent validation, too.
There are many ways you can achieve,
1) more commonly donot use [Required] attribute on Company object, but have proper validation for parameters inside Company object.
In this case if Company object is null still validation will pass, but if Company object isnot null it will validate each properties.
2) If validation involves some complex business logic, then go for Self Validating Model. (inherit from IValiddatableObject, and override Validate(...).
3) By code, in the controller.
if(model.company == null)
this.ModelState.Keys.Where(k => k.Contains("company")).ToList().ForEach(k => this.ModelState.Remove(k));
first two are best approved approaches, third is just another way to achieve your functionalities

RIA service default required attribute

I have an EF4 model with table's columns doesn't allow null.
At the SL client application I always receieve the "columnName is required" because I have the binding in xaml with [NotifyOnValidationError=True,ValidatesOnExceptions=True] for the textboxes.
My questions is:
I can overide the default required errormessage at the metadata class, but how can I have it as a custom validation? I mean I don't wnat to do this at the sealed metadata class:
[Required(ErrorMessage = "Coin English Name Is required")]
[CustomValidation(typeof (CustomCoinVaidation), "ValidateCoinName")]
public string coin_name_1 { get; set; }
I want to have it inside the custom validation method that I will define for all types of errors regards that coin_name_1, as follows:
public static ValidationResult ValidateCoinName(string name, ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(name))
{
return new ValidationResult("The Coin Name should be specified", new [] { "Coin Name" });
}
return ValidationResult.Success;
}
Why?
for two reasons :
1- Group all the validation isdie one container (for easy localization further).
2- I don't want the coin_name_1 to be displayed to the end-user, but a meanigful as "Coin English Name".
Second question:
I have a ValidationSummary control on my xaml page where all the errors are displayed but is displaying the orignal name of the column "coin_name_1" how can I chnge that to be a meanigfil also.
Best regards
Waleed
A1:
I just left the required as it is implemented right now..
A2:
I went through different sources and find this artical.
It shows how to style the validation summary:
http://www.ditran.net/common-things-you-want-know-about-silverlight-validationsummary
I am also implementing a client-side validation asyncronizly.
Regards

Resources