In ASP.NET MVC3 how do you stay DRY with very similar but slightly different viewmodels? - asp.net-mvc-3

In building an app, we created a generic object model to store some values, the viewmodel looks a bit like this at the moment:
public class FooViewModel {
public int ID { get; set; }
public byte FooType { get; set; }
[Required]
[Display(Name = "Bar Name")]
public string Name { get; set; }
[Required]
public string Email { get; set; }
//etc, etc
}
The problem is: depending on the FooType, we want to have the Display Name to be different and the Email is not required for type 1 and 2, but is required for type 3 and 4.
We tried seperating out the properties that differ per type in to classes that inherit from this one, but the validation does a fallback on what is specified in the base type, so that didn't work.
Currently, the only option seems to be to create a viewmodel for each FooType (and also seperate controllers and view), which leads to a lot of code duplication.
What are other ways to keep this DRY?

To benefit a validation context (e.g. validating objects in different contexts), I strongly recommend using FluentValidation library.

You could implement a custom RequiredIf validation attribute, or you could implement IValidatableObject.

Related

Giving error while creating partial class

I am developing MVC application in which , I am trying to create the partial class of class generated by MVC application lets say Location class.
Now I want to create the partial class of Location class in new class file.
The below class code is auto genrated by MVC of Location code.
namespace CRM
{
public partial class Location
{
public int Id { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
}
}
I have added new class file which contain the partial class of above file
namespace CRMEntities.Partial_Class
{
public interface ILocation
{
[StringLength(50, ErrorMessage = "Region can accept maximum 50 characters.")]
string Region { get; set; }
[Key]
int Id { get; set; }
[Required]
string Name { get; set; }
string Remark { get; set; }
}
public partial class Location : ILocation
{
}
}
Its giving the below error...
CRMEntities.Partial_Class.Location' does not implement interface member 'CRMEntities.Partial_Class.ILocation.Name
First, you don't need to do this, what I understand is you are trying to do validation right? Think about, the object generated by EF is not ViewModel, they are domain model. Data annotation should be in View Model, not domain model.
Most of cases, often mis-use is to use domain model as view model, but it is not correct much. Because sometime, view models need more than one domain model to provide data for your UI.
So for separation of concerns, you need to define your View Model different with domain model.
Example: you have Location class, you need to add LocationViewModel class and put data annotation in here.
You can map manually or use AutoMapper for mapping bettween View Model and Domain Model.
Another solution is you can use Fluent Validation, with this way, needless to have more partial class just for validation.
You don't show the definition of ILocation in your question, but the error says that the Location.Name property is declared differently than the ILocation.Name member.
Edit: Your two partial classes appear to be in two different namespaces, hence they are actually two entirely different classes, not two parts of the same class. That would explain the compiler error.
Having said that, I do agree with the other answer (+1!) that you should do your UI validation on a view model instead.

IValidatableObject Validate() for different scenarios

I’ve been implementing IValidatableObject on Model entities, and using Validate(ValidationContext) to perform validation, often complex.
Can I use ValidationContext to distinguish different validation scenerios?
e.g. take for example a User model where I have 3 validation scenerios:
Sign up – I want to test an email is unique, and a small selection of required fields have been entered
Change details – Different email uniqueness check, bit more required details after sign up, not changing password here so it doesn't need checked
Change password – Only password field to validate
Is this a proper use for it, and if so how do I ensure the correct ValidationContext properties are set after a post and before Validate() is called? Or should I be taking a totally different approach?
The IValidatableObject is used to perform multiple validations against a single model. In your case you have a User model and you want to do three validations and you can do that perfectly by implementing the IValidatableObject in the User model.
The ValidationContext is not bringing much benefit (other than providing access to the context) since we can access all the properties directly in the Validate method.
An example of performing multiple validations related to the single model by IValidatableObject. (So what is the use of ValidationContext here?)
public class Party : IValidatableObject
{
[Required(ErrorMessage = "Start date is required")]
[FutureDateValidator(ErrorMessage = "Start date should be a future date")]
public DateTime StartDate { get; set; }
[Required(ErrorMessage = "Duration is required")]
public int DurationInHours { get; set; }
[Required(ErrorMessage = "No. of joinees is required")]
[Range(2, 10, ErrorMessage = "No. of joinees should be minimum 2 and not more than 10")]
public int NoOfJoinees { get; set; }
public bool Drinks { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (StartDate.TimeOfDay > new TimeSpan(22 - DurationInHours, 0, 0))
{
yield return new ValidationResult("The party should not exceed after 10.00 PM");
}
if (NoOfJoinees < 5 && Drinks)
{
yield return new ValidationResult("Drinks are only allowed if no. of joinees is 5 or more.");
}
}
}
For my two cents worth I would say that your model is either in a valid state (applying all validation criteria) or it isn't. If, under certain circumstances, you don't want to apply a validation then I think you should really be using a separate model (ViewModel, actually).
In your example, I would create a RegisterViewModel for sign up and a separate EditUserViewModel for changing details. Each of these would then have their own validation and they would have a single responsibility.
Creating a fat model that you reuse in many different views is, imho, a bit of a code smell. I have a number of reasons for thinking this. Firstly, let's say that you have a single model that is used for all interaction with user data. It looks like this:
public class UserModel
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdministrator { get; set; }
}
Later you decide to track the browser that was used during registration with the site. Where do you add that? It really has nothing to do with the user, so it shouldn't go on the UserModel model. If you had a separate RegisterViewModel you could modify it as needed when your registration process changes without concern as to how it would affect the other places it is used.
A more serious problem arises if, for example, you were using the above model with MVC's DefaultModelBinder. As described here, the user could create their own request and grant themselves administrator privileges even if you don't have the IsAdministrator field on the form (by exploiting a mass-assignment vulnerability). Again, if a separate ViewModel was used without the IsAdministrator property it would reduce the surface area for security holes.
The above is just an example, but I'm sure you get the point.

POCO - if POCO means pure .net class with only properties, where i can write validations in MVC

Very new to POCO, find some google links but found many different stories.
Some connected with Entity framework, lazy loading etc. Some says its a pure .det class.
Atleast MSDN.
LINK FOR DEFINE POCO FROM MSDN:
msdn.microsoft.com/en-us/library/dd456872.aspx
I trust MSDN(a simple defination), and assume that it is a pure .NET Class.
Now let me come to the point.
IF it is pure .net class with only properties inside it than it is equilateral to "MODEL" in MVC.
example.
[Required(ErrorMessage = "Full Name required.")]
[StringLength(20, ErrorMessage = "Username must be under 20 chars.")]
public string UserName { get; set; }
[Required(ErrorMessage = "Email required.")]
[RegularExpression(".+#.+\\..+", ErrorMessage = "Email not valid.")]
public string Email { get; set; }
[Required(ErrorMessage = "PassWord required.")]
[StringLength(20, ErrorMessage = "Maximum 20 chars. allow")]
[DataType(DataType.Password)]
public string Password { get; set; }
Upto this level it is clear to me. Now if i want to write my own validation (conditional) in MODEL
using
ValidationAttribute
or
IValidatableObject
this will be not pure .net class if i am not wrong.
example.... (Something like below)
public class Wizard : ValidationAttribute,IValidatableObject
{
public override bool IsValid(object value)
{
return base.IsValid(value);
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
throw new NotImplementedException();
}
[Required(ErrorMessage = "Full Name required.")]
[StringLength(20, ErrorMessage = "Username must be under 20 chars.")]
public string UserName { get; set; }
[Required(ErrorMessage = "Email required.")]
[RegularExpression(".+#.+\\..+", ErrorMessage = "Email not valid.")]
public string Email { get; set; }
[Required(ErrorMessage = "PassWord required.")]
[StringLength(20, ErrorMessage = "Maximum 20 chars. allow")]
[DataType(DataType.Password)]
public string Password { get; set; }
}
Is this the POCO still?
If yes, how can it contains methods.(opposite to MSDN link)
IF NO, where should i write down my validation code (of course conditional validation in MVC).
Looking for a really great answer with an example.
POCOs mean you do not have to inherit from some framework defined base class in order to implement functionality. Basically you are free to design your class hierarchy.
You can add your own methods be it validation or some business logic.
A counter example would be to inherit from EntityObject class for entities in Entity Framework.
The linked article doesn't say that POCO mustn't have methods. Clear description what POCO is can be found on Wikipedia:
... the term is used to contrast a simple object with one that is
designed to be used with a complicated, special object frameworks such
as an ORM component. Another way to put it is that POCOs are objects
unencumbered with inheritance or attributes needed for specific
frameworks.
POCO can have all methods or logic you need. The difference between POCO and non-POCO is that POCO is class you can use always even if you don't use specific framework (EF) but non-POCO can be used only when specific framework is linked or even worse initialized and used.
For purists data annotations violates POCO as well because they also demand specific API but in pragmatic approach data annotations are OK (except special annotations used in EF Code first to define mapping) because they bring dependency only to the way how entity is validated but not the dependency to the way how entity is persisted (non-POCO EF object). Dependency on persistence can demand reference to EF in assemblies where you never expect to use EF - for example presentation layer like MVC application.
Personally I like to make my POCOs partial classes with the basic properties needed to define that model and then put and validation logic in a separate class. e.g:
public partial class Wizard
{
public string UserName { get; set; }
public string EmailAddress { get; set; }
}
and then if I wanted to add validation to UserName:
public partial class Wizard
{
[Required]
[StringLength(20)]
public string UserName { get; set; }
}
I know the complier just amalgamates the two classes anyway and you may be repeating properties but I think its the cleanest approach.
Another option is to use the MetadataType attribute.

MVC3 - Recommended way to create fields for IEnumerables with Editor Templates

I want to create a form for an entity. One of the members is an IEnumerable of a different type (that also has an IEnumerable member), for example:
public class Person
{
public string Fullname { get; set; }
public int Age { get; set; }
public IEnumerable<Position> Jobs { get; set; }
}
public class Position
{
public string Title { get; set; }
public IEnumerable<string> PhoneNumbers { get; set; }
}
I'm trying to find a good example of creating multiple fields in the html, how would I allow to enter more than one position? I think I read somewhere about someone who's cloning that part of the form with jQuery - is that the way to go?
Thanks
This blog post talks about editing a variable length list and may be what you are after.
Possible duplicate of Editing a Variable Length List, ASP.NET MVC 3 Style with Table
I personnally use an improved version of BeginCollectionItem, but I find it still too complicated when used with child views.
This is a great fail of ASP.NET MVC promises (it should be simple, fluid and powerful).

MVC DataAnnotations - Require at least one field in a group to be filled

How can I use DataAnnotations to validate that at least one of these fields are filled in?
public string Name { get; set; }
public string State { get; set;}
public string Zip { get; set;}
To do it using DataAnnotations you will need to make a custom attribute because as far as I know there is no built in attribute that will handle this.
To get you started, when you start a new MVC project there is a class called "PropertiesMustMatchAttribute" that is applied at the class level. You could base it off that without much difficulty

Resources