ASP.NET MVC Contact Form

I’ve been meaning to add a contact form to the bobcravens.com web site to allow visitors an easy way to send me email. Besides the convenience to visitors, contact forms allow you to keep your email address off of your web site and away from spammers. A contact form does introduce another avenue for spammers to pester you so some care must be taken to prevent ‘spam bots’ from sending email. Here is the end result.

Note: This demo is live…the real thing. It will actually send me an email. Play around, but don’t click send unless you write something nice or you have a required field left blank to demo the validation.

Demo

Models

I will be using two models for the contact form. The first model is used as a container for information that will be collected by the contact form (EmailModel). The second model is used as a container for messages sent back to the user after the email form has been posted (MessageModel).

Below is the code for the EmailModel. The code is a bit more complex because of the added validation, but is really a wrapper that exposes a number of fields that we will collect on the form.

public class EmailModel : IDataErrorInfo
{
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                _name = value;
            }
            else
            {
                _errors.Add("Name", "'Name' is required.");
            }
        }
    }


    private string _emailAddress;
    public string EmailAddress
    {
        get
        {
            return _emailAddress;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                _emailAddress = value;
            }
            else
            {
                _errors.Add("EmailAddress", "'Email' is required.");
            }
        }
    }

    private string _phone;
    public string Phone
    {
        get
        {
            return _phone;
        }
        set
        {
            _phone = value;
        }
    }

    private string _webSite;
    public string WebSite
    {
        get
        {
            return _webSite;
        }
        set
        {
            _webSite = value;
        }
    }

    private string _subject;
    public string Subject
    {
        get
        {
            return _subject;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                _subject = value;
            }
            else
            {
                _errors.Add("Subject", "'Subject' is required.");
            }
        }
    }


    private string _message;
    public string Message
    {
        get
        {
            return _message;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
            {
                _message = value;
            }
            else
            {
                _errors.Add("Message", "'Message' is required.");
            }
        }
    }


    private Dictionary<string, string> _errors = new Dictionary<string, string>();

    #region IDataErrorInfo Members

    public string Error
    {
        get
        {
            return null;
        }
    }

    public string this[string columnName]
    {
        get
        {
            string error;
            if (_errors.TryGetValue(columnName, out error))
            {
                return error;
            }
            else
            {
                return null;
            }
        }
    }

    #endregion
}

By implementing the IDataErrorInfo interface we can leverage the  validation built into the model binders of the MVC framework. In the setters of each property, the code validates the property and populates a dictionary of errors encountered. The indexer property is used by the view to provide feedback about errors on the form.

The MessageModel shown below is much simpler. This data is internally generated and as such does not implement the IDataErrorInfo interface.

public class MessageModel
{
    public string Title { get; set; }
    public string Content { get; set; }
}

Controller

I created a new ‘EmailMe’ controller to handle the requests for my contact page features. I set up the routing to utilize the ‘EmailMe’ controller by default and with the ‘Index’ default action. When you first request (HTTP GET) the ‘EmailMe’ URL, the controller simply returns the default view as shown below.

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
    return View();
}

When the user posts (HTTP POST) the form back to the server, MVC allows you to create an action method with the same name but differentiated by the HTTP verb is accepts. The following action method handles the form post.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(EmailModel emailModel)
{
    if (ModelState.IsValid)
    {
        bool isOk = false;
        try
        {
            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("no-reply@bobcravens.com", "Website Contact Form");
            msg.To.Add("your_email_address@mail_server.com");
            msg.Subject = emailModel.Subject;
            string body = "Name: " + emailModel.Name + "n"
                        + "Email: " + emailModel.EmailAddress + "n"
                        + "Website: " + emailModel.WebSite + "n"
                        + "Phone: " + emailModel.Phone + "nn"
                        + emailModel.Message;

            msg.Body = body;
            msg.IsBodyHtml = false;

            SmtpClient smtp = new SmtpClient("mailserver_url.net", 25);

            smtp.Send(msg);

            msg.Dispose();

            isOk = true;

            MessageModel rcpt = new MessageModel();
            rcpt.Title = "Thank You";
            rcpt.Content = "Your email has been sent.";
            return View("Message", rcpt);
        }
        catch (Exception ex)
        {
        }

        // If we are here...something kicked us into the exception.
        //
        MessageModel err = new MessageModel();
        err.Title = "Email Error";
        err.Content = "The website is having an issue with sending email at this time. Sorry for the inconvenience. My email address is provided on the about page.";
        return View("Message", err);
    }
    else
    {
        return View();
    }
}

The first thing the code does is check that the model state is valid (using the validation we created on the model). If the model is not valid, we return the contact form view maintaining the form data and adding validation feedback for the user.

If the model is valid, the code sends the email message (I am using GoDaddy and this code works for me) and returns a ‘Message’ view. The ‘Message’ view is shows the content of the MessageModel which is either populated with a success or failure message.

Contact Form View

The following is the markup for the contact form view. This view uses a master page and has a number of additional tags which we will cover.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Contact Me
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <input id="captchaPath" type="hidden" value="<%= Url.Content("~/Content/captcha") %>" />

    <div class="tab_container">
        <div id="contact" class="tab_content">
            <div class="content_area">
                <div class="content_icon"></div>
                <h1>Contact</h1>
                <div class="hr"></div>
                <div>
                    <h3>Please Note</h3>
                    <p>Thanks for taking the time to contact me. I will do my best to answer your email quickly.</p>
                    <div id="captcha">
                        <p>Sending email requires that JavaScript is enabled.</p>
                        <div class="ajax-fc-container"></div>
                    </div>

                    <%= Html.ValidationSummary("Please correct the following errors and try again.") %>

                    <% using (Html.BeginForm("Index", "EmailMe", FormMethod.Post, new { id = "email_form" }))
                    {%>
                        <div class="col1of2_34_66 contact_form">
                            <p>
                                <label for="Name">Name *</label>
                                <%= Html.TextBox("Name")%>
                                <%= Html.ValidationMessage("Name", "*")%>
                            </p>
                            <p>
                                <label for="EmailAddress">Email *</label>
                                <%= Html.TextBox("EmailAddress")%>
                                <%= Html.ValidationMessage("EmailAddress", "*")%>
                            </p>
                            <p>
                                <label for="Phone">Phone  </label>
                                <%= Html.TextBox("Phone")%>
                                <%= Html.ValidationMessage("Phone", "*")%>
                            </p>
                            <p>
                                <label for="WebSite">WebSite  </label>
                                <%= Html.TextBox("WebSite")%>
                                <%= Html.ValidationMessage("WebSite", "*")%>
                            </p>
                            <p>
                                <label for="Subject">Subject *</label>
                                <%= Html.TextBox("Subject")%>
                                <%= Html.ValidationMessage("Subject", "*")%>
                            </p>
                        </div>
                        <div class="col2of2_34_66 contact_form">
                            <p>
                                <label for="Message">Message *</label>
                                <span class="tooltip">
                                    <%= Html.TextArea("Message", new { @rows = "10", @cols = "40" })%>
                                    <span class="tooltip_pointer_outer"><span class="tooltip_pointer_inner"></span></span>
                                </span>
                                <%= Html.ValidationMessage("Message", "*")%>
                            </p>
                            <div class="send">
                                <input id="submit" type="image" value="Send" src="<%= Url.Content("~/Content/Images/submit_image.png")%>" />
                            </div>
                        </div>
                    <% } %>
                </div>
            </div>
        </div>
    </div>

</asp:Content>

For now, focus in on the content in the middle. The code uses the Html.ValidationSummary helper method. This method inserts content into the view based upon the validation we inserted into our model. Next is the actual HTML form that contains the input elements. Notice this section also leverages the Html helper methods. These helpers do the model binding and present validation for us.

The rest of the content deals with ensuring the submitter of the form is a human (CAPTCHA) and layout (CSS). I am using a modified version of a visual jQuery CAPTCHA implementation.

Note: To get the visual CAPTCHA to work, you need to specify the URL to the captcha folder. MVC was not kind to my relative path (‘../../Content/captcha’). This worked in my development environment, but never on the deployed machine. Eventually I added a hidden input (see above) and let the MVC framework generate the path.

Message View

The message view is much simpler. The markup is shown below.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Message
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <div class="tab_container">
        <div id="contact" class="tab_content">
            <div class="content_area">
                <div class="content_icon"></div>
                <h1>Contact</h1>
                <div class="hr"></div>
                <div>
                    <h3><%= Html.Encode(Model.Title) %></h3>
                    <p><%= Html.Encode(Model.Content) %></p>
                </div>
            </div>
        </div>
    </div>

</asp:Content>

Again, the code leverage the model binding provided by the Html helpers.

Summary

Creating a ASP.NET MVC based implementation of a contact form is pretty straight-forward. The MVC framework provides the structure for you to develop code that is clean. The final demo has a bit of CSS and jQuery added to spice up the user experience a bit. For example the email form is not displayed until after you prove that you are a human. Enjoy the code and if you have any questions you can contact me here.

Comments
  1. Bob Cravens
  2. Terry Cone
  3. Thomas
    • rcravens
  4. Sandeep Bhadauriya
  5. Jana
  6. Walter Khumalo

Leave a Reply

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

*