Jacob Stamm
Jacob Stamm

Reputation: 1873

MVC post not returning the proper ViewResult

In the POST endpoint for my site's Contact page, which sends an email to the site owner based on user input, I am returning a ViewResult of the same view, but with a newly initialized (empty) view model.

My goal for the client is, upon receiving the POST response, give the user the same page, but with all the form fields emptied. Rather than this taking place, however, the user ends up on the same page with all of the same form information still filled out. The email is sent successfully, and no errors are thrown.

Any ideas?

Here are my GET and POST endpoints:

[HttpGet]
public ViewResult contact()
{
    return View(new ContactUsViewModel());
}

[HttpPost]
public async Task<ViewResult> contact(ContactUsViewModel inputModel)
{
    try
    {
        if (ModelState.IsValid)
        {
            string body = 
                "<div style='font-family: Arial, Helvetica, sans-serif; font-size: 13px; color: #444444;'>" +
                "<p style='font-size: 17px;'>Email from <strong>{0}</strong> ({1})</p>" +
                "<p>Date: {2}</p>" +
                "<p>Phone: {3}</p>" +
                "<p>Message:</p><p style='margin-left: 24px;'>{4}</p>" +
                "</div>";
            string to = ConfigurationManager.AppSettings["ContactUsEmailAddress"];
            MailMessage message = new MailMessage();
            message.To.Add(new MailAddress(to));
            message.Subject = "Message from " + inputModel.Name;
            message.Body = String.Format(body, new string[]
                {
                    inputModel.Name, inputModel.Email, DateTime.Now.ToLongDateString(), inputModel.Phone, inputModel.UserMessage
                }
            );
            message.IsBodyHtml = true;

            using (var smtp = new SmtpClient())
            {
                await smtp.SendMailAsync(message);
                // the "true" parameter in the constructor just sets a "Message sent" 
                // confirmation message in the view model that is displayed on the view 
                // via Razor.
                return View(new ContactUsViewModel(true));
            }
        }
        else
        {
            return View(inputModel);
        }
    }
    catch (Exception ex)
    {
        string ourEmailAddress = ConfigurationManager.AppSettings["ContactUsEmailAddress"];
        inputModel.PublicErrorMessage = "There was a problem sending your message. Please send an email directly to " +
            "<a href='mailto:" + ourEmailAddress + "'>" + ourEmailAddress + "</a> so we can hear from you :)";
        inputModel.InternalErrorMessage = ex.Message;
        return View(inputModel);
    }
}

In case this is relevant, here is my ContactUsViewModel as well:

public class ContactUsViewModel : BaseViewModel
{
    public ContactUsViewModel() { }
    public ContactUsViewModel(bool messageSent)
    {
        this.MessageSentConfirmation = "Your message has been sent. We will get back to you shortly!";
    }

    [Required(ErrorMessage = "Please include your name.")]
    public string Name { get; set; }

    [Required(ErrorMessage = "Please enter a valid email address.")]
    [EmailAddress(ErrorMessage = "Please enter a valid email address.")]
    public string Email { get; set; }

    [Phone(ErrorMessage = "Please enter a valid phone number.")]
    public string Phone { get; set; }

    [Required(ErrorMessage = "Please enter a message.")]
    public string UserMessage { get; set; }

    public string MessageSentConfirmation { get; private set; }
}

EDIT: I know that the Post-Redirect-Get design pattern would technically circumvent this issue, but it doesn't really resolve the technical limitation of not being able to return the same view with an empty view model. For that reason, I do not consider implementing PRG the solution.

Upvotes: 0

Views: 325

Answers (1)

Jacob Stamm
Jacob Stamm

Reputation: 1873

This is @StephenMuecke 's solution from the comments section. Executing ModelState.Clear() in my controller method before my return statement solves the issue.

Upvotes: 1

Related Questions