In my forgotten password form, the jquery ajax message is run multiple times (one after each view). Therefore, if the user enters an invalid email address 3 times, and then a valid email address, the user receives 4 letters with the password changed. It seems that the event accumulates every time an error occurs, and they all quit in the next view. Here is all my relevant code. What am I doing wrong?
Js
RetrievePassword = function () {
var $popup = $("#fancybox-outer");
var form = $popup.find("form");
form.submit(function (e) {
var data = form.serialize();
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json",
success: function (response) {
ShowMessageBar(response.Message);
$.fancybox.close()
},
error: function (xhr, status, error) {
ShowMessageBar(xhr.statusText);
}
});
return false;
});
};
CONTROLLER / ACTION MVC
[HandlerErrorWithAjaxFilter, HttpPost]
public ActionResult RetrievePassword(string email)
{
User user = _userRepository.GetByEmail(email);
if (user == null)
throw new ClientException("The email you entered does not exist in our system. Please enter the email address you used to sign up.");
string randomString = SecurityHelper.GenerateRandomString();
user.Password = SecurityHelper.GetMD5Bytes(randomString);
_userRepository.Save();
EmailHelper.SendPasswordByEmail(randomString);
if (Request.IsAjaxRequest())
return Json(new JsonAuth { Success = true, Message = "Your password was reset successfully. We've emailed you your new password.", ReturnUrl = "/Home/" });
else
return View();
}
HandlerErrorWithAjaxFilter
public class HandleErrorWithAjaxFilter : HandleErrorAttribute
{
public bool ShowStackTraceIfNotDebug { get; set; }
public string ErrorMessage { get; set; }
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var content = ShowStackTraceIfNotDebug || filterContext.HttpContext.IsDebuggingEnabled ? filterContext.Exception.StackTrace : string.Empty;
filterContext.Result = new ContentResult
{
ContentType = "text/plain",
Content = content
};
string message = string.Empty;
if (!filterContext.Controller.ViewData.ModelState.IsValid)
message = GetModeStateErrorMessage(filterContext);
else if (filterContext.Exception is ClientException)
message = filterContext.Exception.Message.Replace("\r", " ").Replace("\n", " ");
else if (!string.IsNullOrEmpty(ErrorMessage))
message = ErrorMessage;
else
message = "An error occured while attemting to perform the last action. Sorry for the inconvenience.";
filterContext.HttpContext.Response.Status = "500 " + message;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
else
{
base.OnException(filterContext);
}
}
private string GetModeStateErrorMessage(ExceptionContext filterContext)
{
string errorMessage = string.Empty;
foreach (var key in filterContext.Controller.ViewData.ModelState.Keys)
{
var error = filterContext.Controller.ViewData.ModelState[key].Errors.FirstOrDefault();
if (error != null)
{
if (string.IsNullOrEmpty(errorMessage))
errorMessage = error.ErrorMessage;
else
errorMessage = string.Format("{0}, {1}", errorMessage, error.ErrorMessage);
}
}
return errorMessage;
}
}
Here is more JS. I use the fancybox plugin as my lightbox. The Password reset link is in the lightbox of the login.
$(document).ready(function () {
$(".login").fancybox({
'hideOnContentClick': false,
'titleShow': false,
'onComplete': function () {
$("#signup").fancybox({
'hideOnContentClick': false,
'titleShow':false,
'onComplete': function () {
}
});
$("#retrievepassword").fancybox({
'hideOnContentClick': false,
'titleShow': false,
'onComplete': function () {
}
});
}
});
});