ASP.NET MVC 3 Hosting :: MVC 2 Strongly Typed HTML Helper and Enhanced Validation Sample
- by mbridge
In lue of the off the official release of ASP.NET MVC 2 RTM, I decided I would put together a quick sample of the enhanced HTML.Helpers and validation controls.
I am going to use my sample event site where I will have a form so a user can search for information about a certain events. So when the Search page loads the Search action is fired return my strongly typed model. to the view.
1: [HttpGet]
2: public ViewResult Search(): public ViewResult Search()
3: {
4: IList<EventsModel> result = _eventsService.GetEventList();
5: var viewModel = new EventSearchModel
6: {
7: EventList = new SelectList(result, "EventCode","EventName","Select Event")
8: };
9: return View(viewModel);
10: }
Nothing special here, although I did want to show how to load up a strongly typed drop down list because that hung me up for a little bit. So to that, I am going to pass back a SelectList to the view and my HTML helper should no how to load this.
So lets take a look at the mark up for the view.
1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
2: Inherits="System.Web.Mvc.ViewPage<EventsSample.Models.EventSearchModel>" %>
3:
4: <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
5: Search
6: </asp:Content>
7:
8: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
9:
10: <h2>Search for Events</h2>
11:
12: <% using (Html.BeginForm("Search","Events")) {%>
13: <%= Html.ValidationSummary(true) %>
14:
15: <fieldset>
16: <legend>Fields</legend>
17:
18: <div class="editor-label">
19: <%= Html.LabelFor(model => model.EventNumber) %>
20: </div>
21: <div class="editor-field">
22: <%= Html.TextBoxFor(model => model.EventNumber) %>
23: <%= Html.ValidationMessageFor(model => model.EventNumber) %>
24: </div>
25:
26: <div class="editor-label">
27: <%= Html.LabelFor(model => model.GuestLastName) %>
28: </div>
29: <div class="editor-field">
30: <%= Html.TextBoxFor(model => model.GuestLastName) %>
31: <%= Html.ValidationMessageFor(model =>
model.GuestLastName) %>
32: </div>
33:
34: <div class="editor-label">
35: <%= Html.LabelFor(model => model.EventName) %>
36: </div>
37: <div class="editor-field">
38: <%= Html.DropDownListFor(model => model.EventName, Model.EventList,"Select Event") %>
39: <%= Html.ValidationMessageFor(model => model.EventName) %>
40: </div>
41:
42: <p>
43: <input type="submit" value="Save" />
44: </p>
45: </fieldset>
46:
47: <% } %>
48:
49: <div>
50: <%= Html.ActionLink("Back to List", "Index") %>
51: </div>
52:
53: </asp:Content>
A nice feature is the scaffolding that MVC has to generate code. I simply right clicked inside my Search() action, inside the EventsController and selected “Add View” and then I selected my strongly typed object that I wanted to pass to the view and also selected that I wanted the content type be “Edit”. With that the aspx page was completely generated, although I did have to go back in and change the textbox for the Event Names to a drop down list of the names to select from.
The new feature with MVC 2 are the strongly typed HTML helpers. So now, my textboxes, drop down list, and validation helpers are all strongly typed to my model. This features gives you the benefits of intellisense and also makes it easier to debug. “The Gu” has a great post about the feature in case you want more details. The DropDownListFor function to generate the drop down list was a little tricky for me. You first need to use a Lanbda expression to pass in the property you want the selected value assigned to in your model, and then you need to pass in the list directly from the model.
Validations
To validate the form, you can use the strongly type validation HTML helpers which will inspect your model and return errors if the validation fails. The definitions of these rules are set directly on the Model itself so lets take a look.
1: using System.ComponentModel.DataAnnotations;
2: using System.Web.Mvc;
3:
4: namespace EventsSample.Models
5: {
6: public class EventSearchModel
7: {
8: [Required(ErrorMessage = "Please enter the event number.")]
9: [RegularExpression(@"\w{6}",
10: ErrorMessage = "The Event Number must be 6 letters and/or numbers.")]
11: public string EventNumber { get; set; }
12:
13: [Required(ErrorMessage = "Please enter the guest's last name.")]
14: [RegularExpression(@"^[A-Za-zÀ-ÖØ-öø-ÿ1-9 '\-\.]{1,22}$",
15: ErrorMessage = "The gueest's last name must 1 to 20 characters.")]
16: public string GuestLastName { get; set; }
17:
18: public string EventName { get; set; }
19: public SelectList EventList { get; set; }
20: }
21: }
Pretty cool!
Okay, the only thing left to do is perform the validation in the POST action.
1: [HttpPost]
2: public ViewResult Search(EventSearchModel eventSearchModel)
3: {
4: if (ModelState.IsValid) return View("SearchResults");
5: else
6: {
7: IList<EventsModel> result = _eventsService.GetEventList();
8: eventSearchModel.EventList = new SelectList(result, "EVentCode","EventName");
9:
10: return View(eventSearchModel);
11: }
12: }
13: }
If the form entries are valid, here I am simply displaying the SearchResult, but in a real world sample I would also go out get the results first. You get the idea though. In my case, when the form is not valid, I also had to reload my SelectList with the event names before I loaded the page again. Remember this is MVC, no _VieState here :)
So that’s it. Now my form is validating the data and when it fails it looks like this.