这是ASP.NET MVC

时间:2017-01-10 11:51:44

标签: asp.net-mvc multithreading locking sagepay

我有一个ASP.NET MVC项目,通过SagePay进行付款(使用Jeremy Skinnners SagePayMVC解决方案)。解决方案还使用Entity Framework和UnitOfWork模式。

SagePay付款完成后,SagePay会回复通知网址。 这是我的SagePay控制器上的一个动作,看起来像这样:

[HttpPost]
public virtual ActionResult Notify(SagePayResponse response)
{
        using (UnitOfWork unitOfWork = new UnitOfWork())
        {
            if (ResponseLegit(response,unitOfWork))
            {
                SavePaymentToDatabase(response,unitOfWork);      
            }
            unitOfWork.SaveChanges();
        }
}

总的来说,这似乎有效 - 但我们偶尔会在数据库中多次付款。似乎如果服务器特别繁忙,可能需要稍长时间才能响应,因此SagePay会发出第二个通知(有时甚至是几个)。

因此,我首次尝试阻止这种情况发生,就是添加支票,查看是否已存在与付款交易编号相匹配的付款。

    Order order =GetRelatedOrderFromSagePayResponse(unitOfWork,response);
    bool paymentAlreadyExists = PaymentExistsForOrder(order, response);
    if (!paymentAlreadyExists)
    {    
       SavePaymentToDatabase(response,unitOfWork);    
    }

然而,这并没有奏效。多笔付款会不时出现。

所以我认为正在发生的事情是服务器忙于其他一些未知任务,来自SagePay的通知开始排队,然后IIS赶上并将线程交给每个请求 - 这样它们就可以并行处理。因此,检查被否定,因为实体框架同时从数据库填充了对象,并且在检查它们时没有付款。

所以我认为解决方案是使用此方法中的Lock方法: how to lock an asp.net mvc action?

   private static object NotifyLock= new object();

   [HttpPost]
    public virtual ActionResult Notify(SagePayResponse response)
    {
          lock (NotifyLock)
          {
            using (UnitOfWork unitOfWork = new UnitOfWork())
            {
                if (ResponseLegit(response,unitOfWork))
                {
                    Order order=GetRelatedOrderFromSagePayResponse(unitOfWork,response);
                    bool paymentAlreadyExists = PaymentExistsForOrder(order, response);
                    if (!paymentAlreadyExists)
                    {    
                         SavePaymentToDatabase(response,unitOfWork);    
                    }
                }
                unitOfWork.SaveChanges();
            }
         }
    }

这是否是Lock的合法用法,是否会同时停止多个通知进入通知操作,从而允许我的多笔付款检查工作?

0 个答案:

没有答案