LA.NET [EN]

Feb 17

Today we’re going  to keep looking at the MVC platform and see how we can update an object by using the UpdateModel/TryUpdateModel methods. As we’ve seen, you can hook up an action method parameter with a binder. By doing this, the parameter will be instantiated and its properties’ values, automatically filled up from the HTTP data that is passed during the current request. Unfortunately, this might not be adequate to all the scenarios. There might be times where you need to update an existing object,  instead of creating a new one and filling it with values recovered from the current request payload.

In these cases, you can use the UpdateModel method for updating the properties of an existing object with the values submitted in the current request. To illustrate its use, we’ll assume that we have a User class that looks like this:

public class User    {
   public Int32 UserId { get; set; }
   public String Name { get; set; }
}

Now, let’s assume that we’ve got an action which recovers a user and passes it to a view which renders it:

public ActionResult User() {
    //demo code: in the real world you’d probably
    //load this info from a database or web service
    var user = new User {
                        UserId = 1,
                        Name = "Something"
                    };
    // in the real world you’d need to persist this object
    //or add more info in hidden fields in order to update the 
    //object without overriding other updates (ie, need more info
    //for optimistic locking)
    return View( user );
}

And then, the User view would look like this:

<% using( var frm = Html.BeginForm("UpdateUser","Home")) {%>
      <label for="userid">User id:</label>
      <%= Html.TextBox( "userid" ) %>
      <br />
      <label for="name">Name:</label>
      <%= Html.TextBox( "name" ) %>
      <br />
      <input type="submit" value="Confirm" />
<% } %>

As you can see,we’ll render a form that submits its data to the UpdateUser method of the Home controller. In the UpdateUser method, we need to recover the user and update it with the info submitted on the form. Instead of going through the form’s fields, we’ll just delegate that work to the UpdateModel inherited from the Controller class:

public ActionResult UpdateUser() {
    //demo code: in real world code, you’d recover this object 
    //based on the way you’ve saved it in the previous user method
     var user = new User {
                            UserId = 1,
                            Name = "Something"
                        };
    // update the object by getting the values submitted in form
    // this method might throw (see next paragraphs)
    UpdateModel( user );
    return View( "ShowInfo", user );
}

As you can see, we don’t recover the values submitted in the form. Instead, we just delegate that work to the inherited UpdateModel method. There are several overloads of this method. For instance, there’s an overload which lets you pass arrays with the name of the properties that should be included and/or excluded. This overload is useful when you don’t want to recover all the values from the form. For instance, if in the previous example you didn’t want to update the value of the UserId property), you’d just need to use the override of that method that receives an array of properties names that should be updated:

UpdateModel( user, new[]{ "Name"} );

As I’ve said, there are other overloads. For instance, there’s one overload which lets you pass a dictionary of ValueProviderResult objects which are used for recovering the form’s submitted data (more about this in future posts). Bottom line: you’ve got several overloads of this method and you should look at its signatures to decide which one is indicated for your current scenario.

There’s also another method which you can use to perform a similar operation: I’m talking about the TryUpdateModel method. The main difference between these two methods is that the UpdateModel will throw if the updated object is in an invalid state, while the latter will return false when the object is in an invalid state.

Internally, both methods delegate the work to the existing binders and that’s how you get to know if an object is on a valid or invalid state (recall that binders perform validation for objects that require it – I think I still haven’t talked about the IDataErrorInfo interface, so I’ll just say that your objects might implement this interface in order to indicate if it’s in a valid or invalid state and the binder – at least the default one – will automatically pick up this info and add eventual errors to the model state).

And that’s all for today. More about the MVC framework in future posts.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>