We have a web application using ASP.NET MVC, which supports controller methods that take a class object as a parameter. There is automatic binding of the posted form values in order to construct and populate the class object, which occurs before the actual code of the controller method is even invoked. So far so good, but here is my problem: in the course of constructing the class object, the ASP.NET binding engine is invoking every public property of the class. Some of these properties involve some expensive calculation (iterating internal lists, doing counts and so forth), and it is irritating to have them called for no reason whatsoever and the values thrown away. These are read-only properties with only a 'get' and no 'set', so the binder cannot possibly be touching them for purposes of assigning values to them. How can we keep this from happening?
Here is what has been tried so far without success:
- Use a [Bind(Include = "...")] in the controller method declaration to limit to the other (non-read-only) properties that can actually be assigned to.
- Use a [BindNever] annotation on the read-only properties within the class definition.
Our current workaround is, we just abandon the read-only property implementation altogether and rewrite them all as methods. The binder code does not invoke methods, so this works, but we would still rather have them as properties, and it seems like a problem that should be capable of solution. Any thoughts anyone?
== EDIT =============
Additional things tried, in response to answers here, that still did not work:
- Use a [Bind(Exclude = "...")] in the controller method declaration specifying the properties we do not want to invoke. (They are still invoked anyway.)
== EDIT 2 =============
Additional details per request. I am using VS 2015, .NET Framework 4.5.2. Just now I created a sample program to demonstrate the problem:
- File -> New -> Project -> Web -> ASP.NET Web Application
- Under "ASP.NET 4.5.2 Templates", choose "MVC"
- In ManageViewModels.cs, there is a class called "AddPhoneNumberViewModel". This class occurs as a parameter of the method ManageController.AddPhoneNumber (HttpPost version). Add a public property to the class called "PropertyThatShouldNeverBeCalled" and place a breakpoint within it (see code sample below).
- Compile and run the application in Debug mode. Attempt to access the endpoint /Manage/AddPhoneNumber, you will have to create an account, then access the endpoint again, enter a phone number, and click "Submit".
- Observe that you have hit your breakpoint in PropertyThatShouldNeverBeCalled.
- Try one of the unsuccessful fixes described above (e.g. add [Bind(Exclude="PropertyThatShouldNeverBeCalled")] to the definition of ManageController.AddPhoneNumber).
- Repeat step 4 above. Observe that you have still hit your breakpoint.
Code sample 1 (from ManageViewModel.cs):
public class AddPhoneNumberViewModel
{
[Required]
[Phone]
[Display(Name = "Phone Number")]
public string Number { get; set; }
public bool PropertyThatShouldNeverBeCalled
{
get
{
bool returnVal = true; // place breakpoint here
return returnVal;
}
}
}
Code sample 2 (from ManageController.cs):
//
// POST: /Manage/AddPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber([Bind(Exclude = "PropertyThatShouldNeverBeCalled")]AddPhoneNumberViewModel model)
{
// etc.
}
P.S. The problem also occurs when the project is compiled in release mode and run without debugging. I have used logging to confirm this in my original project. For purposes of the sample project, it is just simpler to observe the problem using a breakpoint.