5

When I put a breakpoint on a getter of a property in my view model, asp.net core model binding is reading my property value. This is before the view model is used in the actual view. Is there a reason it is doing this? Model binding should be for setting the properties on your view model from the value provider, not for reading them from your view model. Is there a way to prevent this?

Edit: Since there is a vote to close this question due to not providing steps to easily reproduce, here they are. Create the following controller in an asp.net core project:

public class TestController : Controller
{
    public IActionResult Test(TestViewModel model)
    {
        return View(model);
    }

    public class TestViewModel
    {
        public string TestProperty
        {
            get
            {
                return "";
            }

            set
            {
                return;
            }
        }
    }
}

If you put your break point in the getter, and a break point in the test controller action, you will see that the getter is accessed before it actually enters the controller action to be consumed by the view. It doesn't seem like properties in your view model should be read at this point. Just look for ideas on why this is happening, and if it is possible (or a good idea) to prevent this behavior. Thanks!

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Jeremy Armstrong
  • 885
  • 9
  • 22
  • Is: `This is before the view model is used in the actual view. Is there a reason it is doing this?` ACTUALLY causing a problem? If not, then there is no point to this question. Per SO [You should only ask practical, answerable questions based on actual problems that you face](http://stackoverflow.com/help/dont-ask), if this isn't causing a problem, what does the solution solve? – Erik Philips Aug 06 '16 at 05:14
  • 1
    Sorry, yes, this is causing us an issue. Many of our properties return results based on things after model binding is complete. For example, if we had a property called CustomerID, and another lazy loaded property called CustomerOrders, we don't want something accessing CustomerOrders when CustomerID hasn't been hydrated during model binding yet, or the backing field gets set with invalid data. We could change these to privately backed methods, but I am just trying to figure out why this is even an issue, and if there is an easy way to prevent it so we can use our properties more flexibly. – Jeremy Armstrong Aug 06 '16 at 05:16
  • 1
    Excuse my ignorance, but why would you like something like this? ViewModels in ASP.NET (Core) MVC are barely more than just data structures that prepare data for the view to consume or the input of the view for the controller to consume. Unlike in WPF with MVVM pattern, there is little to no use of "presentation" logic inside a view model, as you'd do that in the controller. Seems like an odd thing to do in this context – Tseng Aug 06 '16 at 12:41
  • @Tseng -- what you describe is best practice but there is nothing that will prevent you from using a class with logic as a viewmodel in ASP.NET MVC. – David Tansey Aug 06 '16 at 13:07
  • I was trying to keep my "reproducable example" very simple, bit in our actual solution we have a custom model binder that uses our service container to take bound data and resolve view information using injected services. We do this in the view model, because doing constructor injection at the controller level was less focused/efficient. This may be a bit abnormal, but either way I am just trying to figure out why model binding needs to read properties from your view model, when in theory it should just be calling the setters to push data into them from the value provider. – Jeremy Armstrong Aug 06 '16 at 14:24

1 Answers1

1

I'm not sure what version of MVC you're using, but in MVC version 5.2.3, the DefaultModelBinder calls the model class getters before setting the request values on each property during the binding process prior to the controller method being called. I could not figure out why it does this, but I was able to change that behavior by implementing a custom model binder based on the original DefaultModelBinder source code that removes the calls to the getters.

See a more detailed explanation and my full solution here: https://stackoverflow.com/a/54431404/10987278.

In your comments you mention you already have a custom model binder, so you might be able to just add the BindProperty(...) override from my solution to get the behavior you're after.

Dave Slife
  • 131
  • 1
  • 4