Reputation: 2218
I am creating a simple login page by email and password. I have a class LoginViewModel that will have a User class as a member variable inside it. The class contains the emailAddress. The password is inside the main LoginViewModel. My User class reference is like this:
public User User { get; set; }
when the user fills the email address and password and hit submit, the LoginViewModel correctly binds the field to the email address inside the User class from the view:
@Html.TextBoxFor(m => m.User.Email) // m is the LoginViewModel model
I want to know why it doesn't work if I had the code above looked like this instead:
public User User = new User();
It shows the email inside the User instance as null value. I know that the use of the constructor is probably better than both, but what is the difference between these two.
EDIT#1: On posting at the "Login" action method, this finds the value I entered for the email field in the model:
public User User { get; set; }
this one does NOT:
public User User = new User(); // --> because of this email field value shows up null
Upvotes: 3
Views: 122
Reputation: 33381
I want to know why it doesn't work if I had the code above looked like this instead:
public User User = new User();
Because the infrastructure looks for the set
method. It needs to be property with public setter.
The peace of code provided by @Stephen doesn't describe the heart of problem.
Here is the DefaultModelBinder
's method which tries to bind properties of model.
private void BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
IEnumerable<PropertyDescriptor> properties = GetFilteredModelProperties(controllerContext, bindingContext);
foreach (PropertyDescriptor property in properties)
{
BindProperty(controllerContext, bindingContext, property);
}
}
Here we see that GetFilteredModelProperties
tries to get PropertyDescriptor
which by chain of methos calls ends up by method call TypeDescriptor.GetProperties
which returns the properties of type not the fields.
Upvotes: -2
Reputation:
This is a feature of the DefaultModelBinder
which will only bind properties with public getter/setters. If you explore the source code, the process includes initializing a new instance of your model and then attempting to set the value of its properties. The key part here is
protected virtual void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
...
if (!propertyDescriptor.IsReadOnly && !isNullValueOnNonNullableType)
{
...
propertyDescriptor.SetValue(bindingContext.Model, value) // this is where the value is set
...
}
...
}
When you use public User User = new User();
you only creating a field and the IsReadOnly
property of its PropertyDescriptor
will return false
so the code in the if
block is never executed and the value of User.Email
is null
(the default value for string
)
Upvotes: 1