Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is currently employed as .NET Technical Consultant at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
View Maarten Balliauw's MVP profile

Search

Latest Twitter

    Follow me on Twitter...

    My projects

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    Leveraging ASP.NET MVC 2 futures “ViewState”

    Let’s start this blog post with a confession: yes, I abused a feature in the ASP.NET MVC 2 futures assembly to fire up discussion. In my previous blog post, I called something “ViewState in MVC” while it is not really ViewState. To be honest, I did this on purpose, wanting to see people discuss this possibly new feature in MVC 2. Discussion started quite fast: most people do not like the word ViewState, especially when it is linked to ASP.NET MVC. As Phil Haack pointed out in a comment on my previous blog post, I used this foul word where it was not appropriate.

    (…) I think calling it ViewState is very misleading. (…) what your serializing is the state of the Model, not the View. (…)

    That’s the truth! But… how should we call this then? There is already something called ModelState, and this is something different. Troughout this blog post, I will refer to this as “Serialized Model State”, or “SMS” in short. Not an official abbreviation, just something to have a shared meaning with you as a reader.

    So, SMS… Let’s use this in a practical example.

    kick it on DotNetKicks.com

    Example: Optimistic Concurrency

    Concurrency between old train and updated train. Every developer who has worked on a business application will definitely have come to deal with optimistic concurrency. Data retrieved from the database has a unique identifier and a timestamp, used for optimistic concurrency control. When editing this data, the identifier and timestamp have to be associated with the client operation, requiring a persistence mechanism. This mechanism should make sure the identifier and timestamp are preserved to verify if another user has updated it since it was originally retrieved.

    There are some options to do this: you can store this in TempData, in a Cookie or in Session state. A more obvious choice, however, would be a mechanism like “SMS”: it allows you to persist the model state on your view, allowing to retrieve the state of your model whenever data is posted to an action method. The fact that it is on your view, means that is linked to a specific request that will happen in the future.

    Let’s work with a simple Person class, consisting of Id, Name, Email and RowState properties. RowState will contain a DateTime value when the database record was last updated. An action method fetching data is created:

    [HttpGet]
    public ActionResult Edit(int id)
    {
        // Simulate fetching Person from database
        Person initialPersonFromDatabase = new Person
        {
            Id = id,
            FirstName = "Maarten",
            LastName = "Balliauw",
            Email = "",
            RowVersion = DateTime.Now
        };
        return View(initialPersonFromDatabase);
    }

    The view renders an edit form for our person:

    <h2>Concurrency demo</h2>

    <% Html.EnableClientValidation(); %>
    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>

    <% using (Html.BeginForm()) {%>
        <%=Html.Serialize("person", Model)%>

        <fieldset>
            <legend>Edit person</legend>
            <%=Html.EditorForModel()%>
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>

    <% } %>

    Let’s have a look at this view markup. <%=Html.EditorForModel()%> renders an editor for our model class Person. based on templates. This is a new feature in ASP.NET MVC 2.

    Another thing we do in our view is <%=Html.Serialize("person", Model)%>: this is a HtmlHelper extension persisting our model to a hidden form field:

    <input name="person" type="hidden" value="/wEymwIAAQAAAP
    ////8BAAAAAAAAAAwCAAAARE12YzJWaWV3U3RhdGUsIFZlcnNpb249MS4wL
    jAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBQEA
    AAAbTXZjMlZpZXdTdGF0ZS5Nb2RlbHMuUGVyc29uBAAAABo8Rmlyc3ROYW1
    lPmtfX0JhY2tpbmdGaWVsZBk8TGFzdE5hbWU+a19fQmFja2luZ0ZpZWxkFj
    xFbWFpbD5rX19CYWNraW5nRmllbGQbPFJvd1ZlcnNpb24+a19fQmFja2luZ
    0ZpZWxkAQEBAA0CAAAABgMAAAAHTWFhcnRlbgYEAAAACEJhbGxpYXV3BgUA
    AAAAqCw1nBkWzIgL"
    />

    Yes, this looks ugly and smells like ViewState, but it’s not. Let’s submit our form to the next action method:

    [HttpPost]
    public ActionResult Edit([Deserialize]Person person, FormCollection form)
    {
        // Update model
        if (!TryUpdateModel(person, form.ToValueProvider()))
            return View(person);

        // Simulate fetching person from database
        Person currentPersonFromDatabase = new Person
        {
            Id = person.Id,
            FirstName = "Maarten",
            LastName = "Balliauw",
            Email = "maarten@maartenballiauw.be",
            RowVersion = DateTime.Now
        };

        // Compare version with version from model state
        if (currentPersonFromDatabase.RowVersion > person.RowVersion)
        {
            // Concurrency issues!
            ModelState.AddModelError("Person", "Concurrency error: person was changed in database.");

            return View(person);
        }
        else
        {
            // Validation also succeeded
            return RedirectToAction("Success");
        }
    }

    Let’s see what happens here…The previous model state is deserialized from the hidden field we created in our view, and passed into the parameter person of this action method. Edited form values are in the FormCollection parameter. In the action method body, the deserialized model is updated first with the values from the FormCollection parameter. Next, the current database row is retrieved, having a newer RowVersion timestamp. This indicates that the record has been modified in the database and that we have a concurrency issue, rendering a validation message.

    Conclusion

    “ViewState” (or “SMS” or whatever it will be called) is really a useful addition to ASP.NET MVC 2, and I hope this blog post showed you one example usage scenario where it is handy. Next to that, you are not required to use this concept: it’s completely optional. So if you still do not like it, then do not use it. Go with Session state, Cookies, hidden fields, …

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MVC

    Comments

    DotNetKicks.com | Reply

    Thursday, October 08, 2009 11:30 AM

    trackback

    Leveraging ASP.NET MVC 2 futures ViewState

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

    mogadanez Russia | Reply

    Thursday, October 08, 2009 5:21 PM

    mogadanez

    why need serialize entire Person, if really we need only  Id and Timestamp for optimistic locking?

    maartenba Belgium | Reply

    Thursday, October 08, 2009 8:10 PM

    maartenba

    I was expecting this question Smile Sure, you can easily use hidden fields to store id and/or timestamp, feel free to do so. You can also use a "PersonConcurrency" class containing only ID and Timestamp properties. The advantage of this one is that no once can tamper with data once you also encrypt and sign the "SMS". You can do this with the third parameter to Html.Serialize().

    progg.ru | Reply

    Thursday, October 08, 2009 7:52 PM

    trackback

    Leveraging ASP.NET MVC 2 futures “ViewState”

    Thank you for submitting this cool story - Trackback from progg.ru

    mogadanez Russia | Reply

    Friday, October 09, 2009 12:06 AM

    mogadanez

    Encryption has additional setup to provide persistent MAC. elsewhere sometimes you get an error like with ViewState -> "ViewState is not valid."

    Haacked United States | Reply

    Friday, October 09, 2009 1:18 AM

    Haacked

    Also, you might be working with an object that doesn't have a timestamp property. For example, if it's a true POCO object. In that case, you would need to serialize the whole object.

    mogadanez Russia | Reply

    Friday, October 09, 2009 11:04 AM

    mogadanez

    If _Model_ object does not have a timestamp, that is not  mean that it is absent in DB, so I can Fetch it from DB by Model identity.
    if no timestamp in DB, I probably want to have a Checksum instead of Entire object.

    I Think "SMS" More approaches for wizards, when i not want store data while i reach end of wizard.

    DotNetBurner - ASP.net MVC | Reply

    Friday, October 09, 2009 1:42 AM

    trackback

    Leveraging ASP.NET MVC 2 futures “ViewState”

    DotNetBurner - burning hot .net content

    Jaco Pretorius South Africa | Reply

    Friday, October 09, 2009 9:19 AM

    Jaco Pretorius

    I suppose it's a nice feature but I can't really see myself using it - I prefer fine-grained control over the generated html.  Maybe I'll change my mind at a later stage...

    I just wanted to point out that your implementation of RowVersion seems a little fishy.  The concurrency field should always be implemented as a Timestamp and NOT as a DateTime.  Timestamp != DateTime.  I guess you were doing this for demonstration purposes, but it might be worth mentioning.

    Nice article.

    maartenba Belgium | Reply

    Friday, October 09, 2009 9:27 AM

    maartenba

    Agreed on the timestamp thingy.

    There still are other situations where persisting model state on the client is a better choice than pushing stuff in session.

    DotNetShoutout | Reply

    Wednesday, October 14, 2009 12:49 PM

    trackback

    Leveraging ASP.NET MVC 2 futures “ViewState” - Maarten Balliauw

    Thank you for submitting this cool story - Trackback from DotNetShoutout

    Neil Kerkin Australia | Reply

    Wednesday, October 14, 2009 6:09 PM

    Neil Kerkin

    Just wondering what benefits this approach has over the alternatives: "TempData, in a Cookie or in Session state"?

    Maarten Belgium | Reply

    Thursday, October 15, 2009 8:00 AM

    Maarten

    None, except that there is no dependency on session state. This is also good when having multiple browser windows sharing one session.

    Boriscallens Belgium | Reply

    Thursday, October 15, 2009 1:39 PM

    Boriscallens

    I'm having a hard time seeing the merit here and I tend to agree with mogadanez.
    If it's for concurrency, there is always "something" (dtstamp, id, stateNr even hash) to compare it with. That something should normally be more interesting to save then a whole object.

    For times where you want to have an object's life span multiple requests without saving it to your repository (like in a wizard) I can imagine this is a nice way to do it without having to have some kind of session.

    Igor Loginov Czech Republic | Reply

    Tuesday, October 20, 2009 10:09 PM

    Igor Loginov

    And I'd rather vote for such serialization. The problem with ViewState in WebForms was not in keeping serialized objects in a hidden field. The problem, that there ViewState is automatic and therefore not manageable. Switching it off actually breaks the event-based server code.  So, if MVC team offers "Managable ViewState" (I mean, of developer's choice where and how to use it), it becomes just a helper for a widely used technique for storing some data in a hidden field.

    Add comment




      Country flag

    biuquote
    • Comment
    • Preview
    Loading