ASP.NET MVC的可降解jQuery Ajax电子邮件表单

几乎互联网上的每个网站都有一个表单,供用户通过电子邮件提供反馈到网站所有者。这个网站没有什么不同。迁移到ASP.NET MVC需要一个略有不同的方法来由Web表单开发使用的方法,因此本文使用MVC框架和jQuery来实现一种方法来实现网站联系人表单,jQuery很好地降级。据说Ajax功能是"degradable"如果为该过程提供了一种方式,即使用户没有可用的JavaScript。

表格将非常简单。它将包含接受用户名,电子邮件地址和评论的字段。此外,它还包含一个简单的方法,以验证表单的提交者是人类的。一旦提交,表单的内容将通过电子邮件发送。表单本身可以在联系人页面上看到,并使用一些CSS设置样式(如果您需要,可以从站点的CSS文件中容易地借用)。视图代码如下:

  

<div id="联系表">
    <p>
      If you feel like contacting me, please use this form to do so.</p>

    <form id="contact" action="<%= Url.Action("Index") %>" method="post">

    <fieldset>
      <legend>Message/Comments</legend>
      <div class="row">
        <span class="label">

          <label for="name">
            Your name:</label></span>
        <%=Html.TextBox("name", ViewData["name"] ?? "")%>

        <%=Html.ValidationMessage("name")%>
      </div>
      <div class="row">

        <span class="label">
          <label for="email">
            Your email address:</label></span>

        <%=Html.TextBox("email", ViewData["email"] ?? "")%>
        <%=Html.ValidationMessage("email")%>

      </div>
      <div class="row">
        <span class="label">
          <label for="comments">

            Your comments:</label></span>
        <%=Html.TextArea("comments", 
                ViewData["comments"] != null ? ViewData["comments"].ToString() : "", 
                new{cols="60", rows="8"})%>

        <%=Html.ValidationMessage("comments")%>
      </div>
      <div class="row">

        <span class="label">
          <label for="preventspam">
            &nbsp;
          </label>

        </span>
        <%=Html.TextBox("preventspam", ViewData["email"] ?? "")%>
        <%=Html.ValidationMessage("preventspam")%>

      </div>
      <div class="row">
        <span class="label">&nbsp;
          </span>

        <输入 type="submit" id="action" name="action" value="Submit" />
      </div>
    </fieldset>

    </form>
  </div>

HTMLHELPERS用于构建表单。目前,PreventsPam输入(TextBox)旁边的标签中没有任何内容。这将在下一个与控制器动作一起看。整个形式(包括一些文本欢迎评论等)被包裹在一个div 联系表。当表单提交时,jQuery将使用。更多的是稍后。与此同时,这是所承诺的代码 指数() ContactController的行动:

using System;
using System.Web.Mvc;
using System.Net.Mail;
using System.Text.RegularExpressions;

namespace MikesDotnetting.Controllers
{
  public class ContactController : BaseController
  {
    public ActionResult 指数()
    {
      if (HttpContext.Session["随机的"] == null)
      {
        var r = new Random();
        var a = r.Next(10);
        var b = r.Next(10);
        HttpContext.Session["a"] = a.ToString();
        HttpContext.Session["b"] = b.ToString();
        HttpContext.Session["随机的"] = (a + b).ToString();
      }
      return View();
    }
  }
}


当请求页面时调用这一点。它包含一点代码,它介绍了0到10之间的两个随机数。它们用于防止垃圾邮件机器人反复提交表单。用户呈现有这两个数字并要求执行一些简单的添加。然后他们输入了数字的总和 preventspam 盒子。数字和总数都存储在会话变量中。就我而言,您可以保留您不可能读取的验证码。在我在网站的Web表单版本中实现此方法之前,我用来每天获得大量垃圾邮件,并且音量正在迅速增长。一旦我实施了这一点,它就会完全停止。我还没有一个单一的Bot提交的评论。好吧,我有一个 - 或至少是这个人 声称 成为一桶机器人,并说我的预防措施不起作用,因为他们已经解决了它。什么失败者。无论如何,我挖掘......

我们需要了解这些会话值如何向用户呈现,因此这里的修订部分是相关的:

      

<div class="row">
  <span class="label">

    <label for="preventspam">
      <%= HttpContext.Current.Session["a"] %>
       +
      <%= HttpContext.Current.Session["b"]%>

    </label></span>
    <输入 type="text" id="preventspam" name="preventspam" class="required" />

</div>

这是渲染页面的外观(通过重新设计的部分方式......)

第二个控制器操作,索引()重载版本()标有带有POST参数的Acceptverbs属性,因为这是来自表单中的HTTP请求的方法:

[AcceptVerbs("POST")]

public ActionResult Index(string name, string email, string comments, string preventspam)
{
  const string emailregex = @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
  var 结果 = 错误的;
  
  ViewData["name"] = name;
  ViewData["email"] = email;
  ViewData["comments"] = comments;
  ViewData["preventspam"] = preventspam;

  if (string.IsNullOrEmpty(name))
    ViewData.ModelState.AddModelError("name", "Please enter your name!");
  if (string.IsNullOrEmpty(email))
    ViewData.ModelState.AddModelError("email", "Please enter your e-mail!");
  if (!string.IsNullOrEmpty(email) && !Regex.IsMatch(email, emailregex))
    ViewData.ModelState.AddModelError("email", "Please enter a valid e-mail!");
  if (string.IsNullOrEmpty(comments))
    ViewData.ModelState.AddModelError("comments", "Please enter a message!");
  if(string.IsNullOrEmpty(preventspam))
    ViewData.ModelState.AddModelError("preventspam", "Please enter the total");
  if (!ViewData.ModelState.IsValid)
    return View();

  if (HttpContext.Session["随机的"] != null && 
    preventspam == HttpContext.Session["随机的"].ToString())
  {
    var message = new MailMessage(email, "[email protected]")
                    {
                      Subject = "Comment Via Mikesdotnetting from " + name,
                      Body = comments
                    };

    var client = new SmtpClient("localhost");
    try
    {
      client.Send(message);
      result = 真的;
    }
    catch
    {
    }
  }
  if (Request.IsAjaxRequest())
  {
    return Content(result.ToString());
  }
  return 结果 ? View() : View("EmailError");
}


最初,BOOL是与包含正则表达式模式的字符串启动,用于匹配有效的电子邮件地址结构。获得了ASP.NET MVC传递到该方法的值,代码检查以确保它们都针对业务规则验证 - 那里有一些东西,电子邮件有效。如果表单通过Ajax提交,所有这些都应该通过,因为客户端验证将发挥作用。但是,如果手动提交表单并且未满足任何验证规则,则返回视图,使用ViewDatdictiCtionery中保持的值和错误消息返回。如果ModelState有效(所有测试传递),下一步是确保会话["random"]有效,它与用户提交的值匹配。一旦该测试令人满意地传递,构建并发送了一封电子邮件。 Bool. 结果,最初设置为 错误的 设定为 真的 如果一切都成功了。正是在这个阶段,我们现在知道是否通过了所有测试以及是否发送了电子邮件,因此为用户准备了合适的响应。 jQuery会自动将值应用于请求标题,以便通过XMLHTTPREQUEST启动请求,请求.ISAJAXREQUEST()方法返回BOOL以指示确实是否通过AJAX表示此请求。如果表单通过Ajax提交,则返回值只是一个读取的字符串"True" or "False"。这是通过的 Controller.Content() 允许通过控制器操作返回要返回的自定义内容的方法。

但是,此阶段,对于禁用JavaScript的人员没有规定。他们将看到的只是一个单一的空白页"True" or "False"写给它。要满足此目的,已创建另一个视图 - EmailError

EmailError.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 

                                               Inherits="System.Web.Mvc.ViewPage" %>

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

</asp:Content>

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

    <h2>Contact Me</h2>
      <div id="oops">
    <p>
      Unfortunately, something went wrong and your message or comments have not been submitted
      successfully. I'll try to fix whatever the problem is as soon as I can.</p>

  </div>
</asp:Content>


如果表单未被Ajax提交,则使用Controller.View()方法返回适当的视图。

那么,这些值如何通过ajax在控制器中发布到sendmail()操作?可以通过查看已添加到索引视图的jQuery代码来回答此问题。

<script type="text/javascript">
  $(document).ready(function() {


    $("#name,#comments,#preventspam").addClass("required");
    $("#email").addClass("required email");
    $("#contact").validate({
      submitHandler: function(form) {
        $.ajax({
          type: "POST",
          url: $("#contact").attr('action'),
          data: $("#contact").serialize(),
          dataType: "text/plain",
          success: function(response) {
            $("#contactform").hide('slow');
            response == "真的" ? $("#thanks").show('slow') : $("#oops").show('slow');
          },
          error: function(response) {
            $("#contactform").hide('slow');
            $("#oops").show('slow');
          }
        });
      }
    });
    return false;
  });

</script>

这可能看起来有点块,但真的很简单。一旦页面完全加载,就会发生$(文档).ready()事件,以便jQuery可以确保DOM中的所有元素都可以访问。我用过 jquery.验证 插件到Perfom客户端验证,检查每个表单字段中有值,电子邮件地址至少是正确的格式。这仅是说明性的,并且不使用插件中可用的选项来检查最小长度,自定义错误消息等。这不是本文的重点。

但是,值得注意的是,在基本级别,可以通过各种类属性使用验证来掌握验证<input>元素。这导致Visual Studio中的警告,除非您在CSS文件中声明这些类,或者通过JavaScript应用CSS类。我选择了后一种方法,因为如果页面未通过JavaScript提交,则ASP.NET MVC的内置验证将自动添加类属性,这可能意味着根据需要进行CSS样式的问题。基本上,他们得到了曼德。值得一提的是,这不会替换之前索引在过载索引()操作中覆盖的服务器端验证。应纯粹作为用户的便利性,而不是您的应用程序的守门器。

一旦表单处于有效状态,“子系统”选项管理将值的发布到过载索引()控制器操作。响应将是真或假的,具体取决于是否存在错误或不是沿线某个位置,然后jQuery操纵显示下面适当的div(显示在索引购物文件的底部)取决于返回的值。在这两种情况下,表单本身都被缓慢地隐藏并替换为确认成功,或者在过程中缺乏成功道歉。

<div id="oops" style="display:none">
  <p>

    Unfortunately, something went wrong and your message or comments have not been submitted
    successfully. I'll try to fix whatever the problem is as soon as I can.</p>
</div>
<div id="thanks" style="display:none">

  <p>
    Thanks for you comments. They have been successfully sent to me. I will try to respond
    if necessary as soon as I can.</p>
</div>

改进空间

如果您正在采取TDD方法,则电子邮件发送并非特别可测试。如果本地计算机上没有可用的SMTP服务,则肯定不会进行可测试。理想情况下,邮寄功能将被安置在服务层中,这可能是isEndmail的实现。然后可以使用依赖注入来解决开发和生产的各种类型。可以说服务器端验证也可以说。在我的网站上的每篇文章底部的评论表单非常相似的东西。此时,我也会将验证移动到服务层。

请注意: 下面的表格不是文章指的形式的示例,所以请不要通过它与“只是测试”这样的东西发送评论。