Sunday, January 22, 2012

a problem I am chewing on

A friend has asked that I help with a problem she is fighting in the app she is working on. It is an interesting puzzle. In an existing ASP.NET MVC2 application, form field validations are done through jQuery AJAX calls to control actions that return a string that will be interpreted for validation validity like so:

var url + "http://www.example.com/whatever/validate?value=" + content;

url = url + "&isRequired=true";

url = url + "&maxSize=5000";

var message = $.ajax({

   url: url,

   async: false

}).responseText;

 
 

content, as suggested above, would be the copy out of a form field such as a textarea. Correct me if I'm wrong, but as we are not specifying POST in the synchronous AJAX call, we are thus sending gunk across the URL line by way of a GET call to the controller action. When I inspect with firebug, this theory holds up. I see calls like this being made:

http://www.example.com/whatever/validate?value=The%20quick%20red%20fox%20jumps%20over%20the%20lazy%20brown%20dog.&isRequired=true&maxSize=5000

 
 

The original developer who rolled this no longer works were my friend works, so there is now to be some pain in supporting it. I think you can see some of the things that may go wrong:

  1. An ampersand in the value variable will sabotage the isRequired and maxSize variables downstream of the value variable. (It would have made more sense to send the value variable last.)
  2. If the value variable's value is too long the call will break as there are limits on how long the URL line may be in different browsers.

 
 

The second problem above is the problem we are trying to beat. In trying to find a fix, I set up a little form that emulates the problem. Copy may be put into a textarea and on a keyup event there is a sanity check SYNCHRONOUSLY WITH GET AJAX to see if the copy is good.


 
 

My controller:

using System.Configuration;

using System.Web.Mvc;

namespace AjaxTests.Controllers

{

   public class HomeController : Controller

   {

      public ActionResult Index()

      {

         ViewBag.WhereAmI = ConfigurationManager.AppSettings["WhereAmI"];

         return View();

      }

      

      public ActionResult SuccessfulSubmission()

      {

         return View();

      }

      

      public string Validate(string value, bool? isRequired, int maxSize)

      {

         string qualityOfCopy = "good";

         if (isRequired == true && string.IsNullOrEmpty(value))

         {

            qualityOfCopy = "You must give copy!";

         }

         if (value.Length > maxSize)

         {

            int gap = value.Length - maxSize;

            qualityOfCopy = "There are " + gap + " too many characters.";

         }

         return qualityOfCopy;

      }

   }

}

 
 

My view:

<form id="SubmissionFacilitator" method="POST"

      action="/home/successfulsubmission/">

   <textarea name="BlobOfCopy"></textarea>

   <div id="ErrorHint" style="color: #CC0000;"></div>

   <input type="submit" value="submit"/>

</form>

<script type="text/javascript">

   $(function () {

      var wrapper = $('#SubmissionFacilitator');

      var textarea = wrapper.find('textarea[name=BlobOfCopy]');

      $(textarea).keyup(function () {

         var junkbool = assesssanityconcerns($.trim(textarea.val()));

      });

      $('#SubmissionFacilitator').submit(function () {

         return assesssanityconcerns($.trim(textarea.val()));

      });

   });

   function assesssanityconcerns(content) {

      var url = "@ViewBag.WhereAmI";

      url = url + "/home/validate?value=" + content;

      url = url + "&isRequired=true";

      url = url + "&maxSize=5000";

      var message = $.ajax({

         url: url,

         async: false

      }).responseText;

      if (message == "good") {

         $('#ErrorHint').html("");

         return true;

      } else {

         $('#ErrorHint').html(message);

         return false;

      }

   }

</script>

 
 

I set this up as an MVC4 project. I stripped a lot of the noise out of the master page such as CSS classes. I left the call to jQuery there.

No comments:

Post a Comment