ASP.NET MVC Preview 5 and Form Posting Scenarios
page 5 of 9
by Scott Guthrie
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 39290/ 55

Unit Testing and UpdateModel

In this week's Preview 5 drop the UpdateModel methods always work against the Request object's Form post collection to retrieve values.  This means that to test the above form post action method you'd need to mock the request object in your unit test. 

With the next MVC drop we'll also add an overloaded UpdateModel method that allows you to pass in your own collection of values to use instead.  For example, we would be able to use the new FormCollection type in preview 5 (which has a ModelBuilder that automatically populates it with all form post values) and pass it to the UpdateModel method as an argument like so:

Using an approach like above will allow us to unit test our form-post scenario without having to use any mocking. Below is an example unit test we could write that tests that a POST scenario successfully updates with new values and redirects back to the GET version of our action method.  Notice that we do not need to mock anything (nor do we have to rely on any special helper methods) in order to unit test all the functionality in our controller:

Handling Error Scenarios - Redisplaying Forms with Error Messages

One of the important things to take care of when handling form post scenarios are error conditions.  These includes cases where an end-user posts incorrect input (for example: a string instead of a number for a Decimal unit-price), as well as cases where the input format is valid, but the business rules behind the application disallow something from being created/updated/saved (for example: making a new order for a discontinued product).

If a user makes a mistake when filling out a form, the form should be redisplayed with informative error messages that guide them towards fixing it.  The form should also preserve the input data the user originally entered - so that they don't have to refill this manually.  This process should repeat as many times as necessary until the form successfully completes.

Basic Form Entry Error Handling and Input Validation with ASP.NET MVC

In our product edit sample above we haven't written much error handling code in either our Controller or our View.  Our Edit post action simply wraps a try/catch error handling block around the UpdateModel() input mapping call, as well as the database save SubmitChanges() call.  If an error occurs, the controller saves an output message in the TempData collection, and then returns our edit view to be redisplayed:

With earlier preview releases of ASP.NET MVC the above code wouldn't be enough to deliver a good end-user experience (since it wouldn't highlight the problem, nor preserve user input if there was an error).

However, with "Preview 5" you'll find that you now get a decent end-user error experience out of the box with just the above code.  Specifically, you'll find that when our edit view is redisplayed because of an input error it now highlights all input controls that have problems, and preserves their input for us to fix:

How, you might ask, did the Unit Price textbox highlight itself in red and know to output the originally entered user value?

"Preview 5" introduces a new "ModelState" collection that is passed as part of the "ViewData" sent from the Controller to the View when it renders.  The ModelState collection provides a way for Controllers to indicate that an error exists with a model object or model property being passed to the View, and allows a human friendly error message to be specified that describes the issue, as well as the original value entered by the end-user.

Developers can explicitly write code to add items into the ModelState collection within their Controller actions.  ASP.NET MVC's ModelBinders and UpdateModel() helper methods also automatically populate this collection by default when they encounter input errors.  Because we were using the UpdateModel() helper method in our Edit action above, when it failed in its attempt to map the UnitPrice TextBox's "gfgff23.02" input to the Product.UnitPrice property (which is of type Decimal) it automatically added an entry to the ModelState collection.

Html helper methods inside the View by default now check the ModelState collection when rendering output.  If an error for an item they are rendering exists, they will now render the originally entered user value as well as a CSS error class to the HTML input element.  For example, for our "Edit" View above we are using the Html.TextBox() helper method to render the UnitPrice of our Product object:

When the view was rendered during the error scenario above the Html.TextBox() method checked the ViewData.ModelState collection to see if there were any issues with the "UnitPrice" property of our Product object, and when it saw that there was rendered the originally entered user input ("gfgff23.02") and added a css class to the <input type="textbox"/> it output:

You can customize the appearance of the the error css classes to look however you want.  The default CSS error rule for input elements in the stylesheet created in new ASP.NET MVC projects looks like below:

Adding Additional Validation Messages

The built-in HTML form helpers provide basic visual identification of input fields with issues.  Let's now add some more descriptive error messages to the page as well.  To-do this we can use the new Html.ValidationMessage() helper method in "Preview 5".  This method will output the error message in the ModelState collection that is associated with a given Model or Model property.

For example: we could update our view to use the Html.ValidationMessage() helper to the right of the textboxes like so:

Now when the page renders with an error, an error message will be displayed next to the fields with problems:

There is an overloaded version of the Html.ValidationMessage() method that takes a second parameter that allows the view to specify an alternative text to display:

One common use case is to output the * character next to the input fields, and then add the new Html.ValidationSummary() helper method (new in "Preview 5") near the top of the page to list all the error messages:

The Html.ValidationSummary() helper method will then render a <ul><li></ul> list of all the error messages our ModelState collection, and a * and red border will indicate each input element that has a problem:

Note that we haven't had to change our ProductsController class at all to achieve this.

Supporting Business Rules Validation

Supporting input validation scenarios like above is useful, but rarely sufficient for most applications.  In most scenarios you also want to be able to enforce business rules, and have your application UI cleanly integrate with them.

ASP.NET MVC supports any data layer abstraction (both ORM and non-ORM based), and allows you to structure your domain model, as well as associated rules/constraints, however you want.  Capabilities like Model Binders, the UpdateModel helper method, and all of the error display and validation message support are explicitly designed so that you can use whatever preferred data access story you want within your MVC applications (including LINQ to SQL, LINQ to Entities, NHibernate, SubSonic, CSLA.NET, LLBLGen Pro, WilsonORMapper, DataSets, ActiveRecord, and any other).

View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 

Community Advice: ASP | SQL | XML | Regular Expressions | Windows

©Copyright 1998-2024  |  Page Processed at 2024-06-22 8:43:31 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search