我构建了WebApi服务(MvcApplication(,它接收用户名和电子邮件。
我有这项服务的网址:
Ex: www.domain.com/Controller/SendUser
我有一些附属公司在他们的网站/登录页面中使用此URL到我的服务,他们向我发送带有用户名和潜在客户电子邮件的数据。
一些会员已经建立了他们提交错误的表单,并允许用户在屏幕上看到响应或重定向到下一页之前多次按发送按钮。在这里出现问题。
我收到 5-10 个带有重复数据的请求,并开始运行我所有的验证函数和插入到数据库的方法。
重要提示: 我不会在数据库级别上解决问题,我想在开始时停止请求,甚至不启动所有验证服务。
我需要收到请求,临时保存用户名+电子邮件,如果我在同一秒或接下来的10秒内收到相同的用户名+电子邮件只是为了避免它。
我尝试将静态字典添加到 Global.asax 并保存编码铅(来自用户+电子邮件(,在检查是否包含密钥(X(之前,我锁定了我的字典 GlobalMemoryLeads,并且比我添加一个键,但有些我仍然得到错误,即使字典被锁定,密钥也都准备好了。
似乎线程会抛出锁定并尝试添加相同的密钥,即使即使 GlobalMemoryLeads.ContainsKey(EncodedLead(返回false,sow另一个线程可以将密钥添加到被另一个线程锁定的字典中??我在这里错过了什么?
如何避免重复请求?
更新
我的代码:
[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
[AllowCrossSiteJson]
public ActionResult SendUser(string UserName, string Email, )
{
string response = "";
bool duplicate=false;
try
{
string Lead = UserName + email;
int EncodedLead = Lead.GetHashCode();
//here i lock my GlobalMemoryLeads dictionary
lock (MvcApplication.GlobalMemoryLeads)
{
//here i check if that key is all ready ContainsKey
if (!MvcApplication.GlobalMemoryLeads.ContainsKey(EncodedLead))
{
try
{
MvcApplication.GlobalMemoryLeads.Add(EncodedLead, false);
}
catch (Exception ex)
{
//here i get error that key is all ready exist
//how it possible if i have
//1: Globalizes lock
//2 i check ContainsKey before
return Json(new { respondNotSuccess = "Duplicate Lead" });
}
}
}
}
catch (Exception ex)
{
response = "Exception " + ex.Message;
}
return Json(new { respondSuccess = response });
}
通常,请避免锁定公共类型或代码无法控制的实例。
常见的构造 lock (this(、lock (typeof (MyType(( 和 lock ("myLock"( 违反了以下准则:
- 如果可以公开访问实例,则锁定(此(是一个问题。
- 锁(typeof (MyType((是一个问题,如果MyType是可公开访问的。
- lock("myLock"(是一个问题,因为进程中使用相同字符串的任何其他代码都将共享相同的锁。
最佳做法是定义要锁定的私有对象,或定义私有静态对象变量以保护所有实例通用的数据
尝试做这样的事情:
private Object thisLock = new Object();
lock (thisLock)
{
if (!MvcApplication.GlobalMemoryLeads.ContainsKey(EncodedLead))
{
try
{
MvcApplication.GlobalMemoryLeads.Add(EncodedLead, false);
...