I have a model like this:
public class Person
{
public int ID { get; set; }
[Required(ErrorMessage="Name cant be empty")]
public string Name { get; set; }
public Person Friend { get; set; }
}
I want to create a new Person, and made a form with the fields using the strongly typed HtmlHelper
- ID
- Name
- Friend ID (dropdown with options like
<option value="Friend.ID">Friend.Name</option>
When posting the form, my controller takes in a Person object (p
), which is bound using the default modelbinder. Just to be explicit, the modelbinder does the following: The ID
and Name
properties are bound as expected. The Friend
is set to a new Person
instance whose ID
equals the ID of the person I chose in the dropdown. The Friend.Name
's value is null
because I didn't provide a value for it in the form.
The problem: I want the RequiredAttribute
to fire on the Name
textbox if it is empty - and it does. The problem is that it also fires on the Friend
's name attribute. So when I post, filling in all the fields, I get that the ModelState is invalid and the error being that p.Friend.Name
is required.
How would I solve this problem? Of couse in this case I don't want to validate the Friend
's properties. I've thought of:
- Using ViewModels for my views, which will somehow solve my problems. I haven't tried this yet as I feel I really shouldn't need to for such a simple problem
- Sending the friend's ID as a separate parameter,
friend_id
, and binding theFriend
property manually. Only theID
andName
attributes of the posted person is bound and I manually set theFriend
property. This involves getting theFriend
from my repository using thefriend_id
to make it a "real" Person object. - Checking the ModelState and removing errors I know don't count. This is just plain wrong and non-scalable (have to remember to do this if I add for example a
SecondFriend
property
I feel option 2 is the most feasable, but ideally I'd like it to be automatic. In addition, I can't use the strongly typed helper, as the friend_id
textbox' name
attribute must match the action method's parameter name.
I feel there's some point I've missed that would make this easier. Hopefully I'm right. Although I think it's a bit tedious using a ViewModel, it that's the correct thing to do, please do tell.
Edit
For now solved the problem using ViewModels with ID
, Name
and Friend_id
as its properties and the same validation attributes as the Person
model. I then map the ID
and Name
values over to a new Person
instance. The Friend property is then set by loadning the specified friend from the repository. Like newPerson.Friend = repository.Get(viewModel.Friend_id)
When I get the time I plan on looking closer at AutoMapper to do this "automatically".