Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

About the author

Maarten Balliauw is currently employed as a Technical Evangelist at JetBrains. 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 Pro NuGet Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
Maarten Balliauw - MVP - Most Valuable Professional
Maarten Balliauw - ASPInsider

Search

Archive

Disclaimer

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

© Copyright Maarten Balliauw 2013


Form validation with ASP.NET MVC preview 5

In earlier ASP.NET MVC previews, form validation was something that should be implemented "by hand". Since the new ASP.NET MVC preview 5, form validation has become more handy. Let me show you how you can add validation in such a ridiculously easy manner.

Here's an example controller:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;

namespace ValidationExample.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        // ... some other action methods ...

        [AcceptVerbs("GET")]
        public ActionResult Contact()
        {
            return View();
        }

        [AcceptVerbs("POST")]
        public ActionResult Contact(string name, string email, string message)
        {
            // Add data to view
            ViewData["name"] = name;
            ViewData["email"] = email;
            ViewData["message"] = message;

            // Validation
            if (string.IsNullOrEmpty(name))
                ViewData.ModelState.AddModelError("name", name, "Please enter your name!");
            if (string.IsNullOrEmpty(email))
                ViewData.ModelState.AddModelError("email", email, "Please enter your e-mail!");
            if (!string.IsNullOrEmpty(email) && !email.Contains("@"))
                ViewData.ModelState.AddModelError("email", email, "Please enter a valid e-mail!");
            if (string.IsNullOrEmpty(message))
                ViewData.ModelState.AddModelError("message", message, "Please enter a message!");

            // Send e-mail?
            if (ViewData.ModelState.IsValid)
            {
                // send email...
                return RedirectToAction("Index");
            }
            else
            {
                return View();
            }
        }
    }
}

You may notice an starnge thing here... Why is Contact defined twice, and why is it with this strange AcceptVerbs attribute? The AcceptVerbs attribute determines which action method to call, based on the HTTP method of the request. In this case, when I do not post a form, the first action method will be called, simply rendering a view. When posting a form, the second action method will be called, allowing me to do some validations.

Speaking of validations... Notice that I can set errors on the ViewData.ModelState collection, and use this ViewData.ModelState.IsValid property to check if everything is OK.

UPDATE: You can also use the controller's UpdateModel method (which updates a model object with form values) for setting data on the model. If the model throws an exception, this will be added to the ViewData.ModelState dictionary too.

One thing left with validation: the view itself!


<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Contact.aspx.cs" Inherits="ValidationExample.Views.Home.Contact" %>


<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Contact Us</h2>
    <p><%=Html.ValidationSummary()%></p>
    <% using (Html.Form<ValidationExample.Controllers.HomeController>( c => c.Contact("", "", ""), FormMethod.Post)) { %>
        <table border="0" cellpadding="2" cellspacing="0">
            <tr>
                <td>Name:</td>
                <td>
                    <%=Html.TextBox("name", ViewData["name"] ?? "")%>
                    <%=Html.ValidationMessage("name")%>
                </td>
            </tr>
            <tr>
                <td>Email:</td>
                <td>
                    <%=Html.TextBox("email", ViewData["email"] ?? "")%>
                    <%=Html.ValidationMessage("email")%>
                </td>
            </tr>
            <tr>
                <td colspan="2">Message:</td>
            </tr>
            <tr>
                <td colspan="2">
                    <%=Html.TextArea("message", ViewData["message"] ?? "")%>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <%=Html.ValidationMessage("message")%>
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <%=Html.SubmitButton("send", "Send e-mail")%>
                </td>
            </tr>
        </table>
    <% } %>
</asp:Content>

Notice that there are 2 new HtmlHelper extension methods: ValidationMessage and ValidationSummary. The first one displays a validation message for one key in the ViewData.ModelState collection, while the latter displays a validation summary of all messages. Here's what my invalid post looks like:

Validation example

kick it on DotNetKicks.com


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

Comments (13) -

Troy Goode United States |

Friday, August 29, 2008 4:41 PM

Troy Goode

Looks like an improvement, but it really is only half a solution without any way to propagate the rules down for client-side validation. Hopefully they'll do something with that in Preview 6?

maartenba Belgium |

Friday, August 29, 2008 4:45 PM

maartenba

Agree with that, but it is a step forward. Bit strange they did not think of client-side validation immediately too?

Simone Italy |

Friday, August 29, 2008 4:46 PM

Simone

That's a good thing... I don't think these things have been added to the readme file of P5

maartenba Belgium |

Friday, August 29, 2008 4:54 PM

maartenba

There's even more undocumented goodies in there Smile Will post one more next monday.

Jesse United States |

Friday, August 29, 2008 6:24 PM

Jesse

I'm not sure about the pessimists above. I would just use Ajax to post to the action you nicely summarized above and I would have client side validation.
This is very cool.

Sean United States |

Friday, August 29, 2008 7:31 PM

Sean

Ok, stupid question. What are those HTML helper methods for? Do they render as client-side JavaScript validation?

Brad Wilson United States |

Sunday, August 31, 2008 6:43 AM

Brad Wilson

This:

<% using (Html.Form<ValidationExample.Controllers.HomeController>( c => c.Contact("", "", ""), FormMethod.Post)) { %>

could just be:

<% using (Html.Form()) { %>

maartenba Belgium |

Monday, September 01, 2008 7:56 AM

maartenba

@Sean: these helper methods simply render some HTML tags. For example, HtmlHelper.Form() will render a <form> tag, HtmlHelper.ValidationSummary() will render an <ul> with validation messages.

@Brad: True! Thanks for noticing. Will fix in this post.

Mike |

Tuesday, September 02, 2008 9:10 PM

Mike

Client side validation is possible, you have to look for a validation framework that uses attributes. These attributes can be inspected, and correct javascript can be written to the page based on them (such as required, compare, regex).

But you have to get the name of the form element coupled with the property of your model class somehow. Hopefully the modelbinder is capable of that.

nishzone Australia |

Sunday, December 07, 2008 3:18 PM

nishzone

I'm created an mvc project with the first beta release and automatically the AccountController had generated ModelState.AddModelError like your example. When I updated to preview 5 from codeplex, I could no longer access ModelState.AddModelError from System.web.mvc.dll....How come you don't seem to be having this issue? Am I missing something?

maartenba Belgium |

Sunday, December 07, 2008 10:35 PM

maartenba

I would say: stick with beta 1 as it is a newer version than preview 5.

Naresh Yadav United States |

Thursday, October 15, 2009 12:29 PM

Naresh Yadav

Shouldn't email be verified as name@domainname.tld . In your example even N@resh will be a valid email.

Maarten Belgium |

Thursday, October 15, 2009 12:37 PM

Maarten

True, this was just an example of the concept.

Pingbacks and trackbacks (6)+

Comments are closed