我正在处理用户单击“注册”按钮的表单,然后会打开一个弹出窗口供用户输入注册的详细信息....用户名应该是唯一的,因此当用户点击时提交按钮即时检查数据库是否已存在该用户名,如果已经存在,则im在同一弹出窗口中显示错误消息“用户名已存在”...
这是我点击保存按钮点击
的代码 $.ajax({
url: '@Url.Content("~/Registration/CheckUNameExists")',
type: 'GET',
data: { UName: $('#UserName').val() },
success: function (data) {
if (data == 'True') {
$('#UserAddError').html('User Name already exists!');
} else {
$("#update-message").html('');
$("#addUserForm").submit();
$(this).dialog("close");
}
}
});
public JsonResult CheckUNameExists(string UName)
{
}
[HttpPost]
public ActionResult RegisterUser(Regitration Reg)
{
}
这样做很好,但在极少数情况下这会产生问题。在用户单击保存按钮时填充弹出窗口中的详细信息有时需要3-4秒的时间进行保存,在这种情况下,用户单击保存按钮2-3次...在这种情况下保存按钮单击是第一次检查方法CheckUNameExists
然后根据用户单击保存按钮的次数多次调用RegisterUser
nd相同的记录被保存到db multiple倍..
出于测试目的,我设置了一个断点,以便我可以多次单击“保存”按钮,然后单击保存按钮4次,CheckUNameExists
仅在第一次点击,但在此之后{{1被调用4次,记录被插入4次。
不明白这里的问题以及如何摆脱它?
答案 0 :(得分:0)
您正在发送GET ajax请求以检查用户是否存在,因此浏览器可能会缓存该响应。 jQuery为ajax函数提供了一个设置,您可以使用它来启用/禁用默认启用的缓存,see the cache setting here
尝试禁用该ajax调用的缓存,将选项cache:false
添加到ajax设置:
$.ajax({
url: '@Url.Content("~/Registration/CheckUNameExists")',
type: 'GET',
data: { UName: $('#UserName').val() },
cache: false,
success: function (data) {
...
这应该解决没有调用CheckUNameExists的问题。
但是,您仍然可以拥有多个ajax调用的竞争条件。更好的解决方案是发送单个ajax POST,同时检查唯一名称和用户注册。这可以防止由于ajax调用的异步性而导致的错误,当您在第一次点击按钮之前完成用户的GET时,就会完成提交表单。
这需要一些重构:
$(".actionSubmit").click(function () {
$(".actionSubmit").attr('disabled', 'disabled');
$.ajax({
url: '@Url.Content("~/Account/RegisterUser")',
type: 'POST',
data: $("#addUserForm").serializeArray(),
success: function (data) {
if (!data.success) {
$('#UserAddError').html(data.errorMessage);
$(".actionSubmit").removeAttr('disabled');
} else {
$(this).dialog("close");
//Possibly redirect here, same logic you had in RegisterUser method
}
}
});
return false;
});
[HttpPost]
public ActionResult RegisterUser(Regitration Reg)
{
//Check if user exists, whatever you were doing in CheckUNameExists
bool userAlreadyExists = ...;
if (userAlreadyExists)
{
return Json(new { success = false, errorMessage = "User Name already exists!" });
}
//Register user
...
return Json(new { success = true });
}
您可能希望将该解决方案与禁用其Click事件上的按钮的JavaScript结合使用,并且在完成之前不会再次启用它(因为名称已存在或因为POST已完成)。我在上面的代码中展示了这一点,我在这里禁用/启用了提交按钮。
上述更改应防止与来自同一客户端的请求相关的问题。但是,您仍然可以让来自不同计算机的用户尝试使用相同的用户名同时注册。为了防止这些错误,您需要将C#代码包装在事务范围内,因此用户验证和注册都发生在事务中:
[HttpPost]
public ActionResult RegisterUser(LoginModel model)
{
using (var tran = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
//Check if user exists, whatever you were doing in CheckUNameExists
bool userAlreadyExists = ...;
if (userAlreadyExists)
{
return Json(new { success = false, errorMessage = "User Name already exists!" });
}
//Register user
...
tran.Complete();
}
return Json(new { success = true });
}
希望这有帮助!