回调函数以错误的顺序完成

本文关键字:顺序 错误 函数 回调 | 更新日期: 2023-09-27 18:33:29

这是一个

非常令人困惑的问题,所以我会尽力详细说明。我有一个接受付款的Facebook画布应用程序,当用户点击付款按钮时,会发生以下情况:

  1. 我的 javascript 回调函数被调用并传递了一个付款 ID,因此我将这个付款 ID 和其他信息保存到我的订单数据库中。

  2. Facebook会调用我设置的回调网址,以便在付款完成时通知我。它只给我付款 ID,所以我使用它在数据库中搜索带有他们发送的付款 ID 的行。然后,我使用该行中的信息填充我发送给客户以确认订单的电子邮件。

我最大的问题是,由于某种原因,步骤 2 在步骤 1 之前完成,因此当我尝试在数据库中查找付款 ID 时,它尚不存在,因此我无法将电子邮件发送给客户。我该怎么做才能解决这个问题?我在下面都有这两个步骤的伪代码。

第 1 步:

using (OrderDBContext order = new OrderDBContext())
            {
                string message = Encryption.SimpleDecryptWithPassword(orderDetails.request_id, GlobalFacebookConfiguration.Configuration.AppId, 0);
                string[] finalMessage = message.Split('@');
                int orderID = Convert.ToInt16(finalMessage.ElementAtOrDefault(2));
                Models.Order row = order.Orders.Where(i => i.ID == orderID).FirstOrDefault();
                switch (orderDetails.status)
                {
                    case "completed":
                        row.PaymentID = orderDetails.payment_id;
                        row.Currency = orderDetails.currency;
                        row.HashKey = orderDetails.request_id;
                        row.Paid = true;
                        order.SaveChanges();
                        return Json(new { message = "Your payment was processed! You will receive a confirmation email soon." }, JsonRequestBehavior.AllowGet);
                    case "initiated":
                        row.PaymentID = orderDetails.payment_id;
                        row.Currency = orderDetails.currency;
                        row.HashKey = orderDetails.request_id;
                        row.Paid = false;
                        order.SaveChanges();
                        return Json(new { message = "Your payment is being processed! You will receive a confirmation email as soon as the payment is confirmed." }, JsonRequestBehavior.AllowGet);
                }
            }

第 2 步:

dynamic result = new StreamReader(request.InputStream).ReadToEnd();
                var items = JsonConvert.DeserializeObject<RootObject>(result);
                string paymentID;
                if (items.entry != null && items.entry.Count > 0)
                {
                    paymentID = items.entry[0].id;
                }
                else
                {
                    // logic when items.entry is null or doesn't have any elements
                    paymentID = null;
                }
                if (PaymentHelper.confirmPayment(paymentID, GlobalFacebookConfiguration.Configuration.AppId, GlobalFacebookConfiguration.Configuration.AppSecret))
                {
                    // if payment is confirmed then send email to us with the order details
                    // then send confirmation email to user letting them know that we are working on it
                    using (OrderDBContext order = new OrderDBContext())
                    {
                        Order row = order.Orders.Where(i => i.PaymentID == paymentID).FirstOrDefault();
                        SendEmail.sendOrderDetailsToWriter(row);
                        SendEmail.sendOrderDetailsToCustomer(row);
                    }
                }

回调函数以错误的顺序完成

是什么启动了Facebook的操作?步骤 #1 中的某些内容是否会导致步骤 #2 开始?还是两个步骤是异步和一起启动的?

假设后者(因为这是更困难的情况(,你应该做这样的事情:

readonly object o = new object();
bool databaseUpdated;
// user clicked the payment button
void onClick()
{
    databaseUpdated = false;
    StartStep1();
    StartStep2();
}
// completion routines for steps #1 and #2
void stepOneDone()
{
    lock (o)
    {
        // do the database update here...i.e. the code you posted for step #1
       databaseUpdated = true;
       Monitor.Pulse(o);
    }
}
void stepTwoDone()
{
    lock (o)
    {
        while (!databaseUpdated)
        {
            Monitor.Wait(o);
        }
        // Process Facebook response here...i.e. the code you posted for step #2
    }
}

上面使用共享锁使两个操作相互同步。databaseUpdated标志当然指示数据库更新是否已完成。如果在数据库更新成功启动之前启动步骤 #2 完成(即步骤 #2 在步骤 #1 之前获取锁(,它将检查标志,注意它尚未设置,并将等待。对Monitor.Wait()的调用释放锁,以便步骤 #1 可以接受它。然后步骤 #1 执行它需要执行的操作,设置标志,并向步骤 #2 线程发出可以继续的信号。

当然,如果步骤 #1 首先获取锁,则步骤 #2 甚至无法获得它。当锁再次可用并且步骤 #2 可以处理通过 lock 语句时,将设置标志并继续其快乐的方式。:)

有可能有一种有趣的方法可以使用新的async/await成语来解决问题,但没有更多的上下文,我不能说。以上应该肯定有效。

最后,一个小问题:为什么要将步骤#2 result变量声明为dynamicReadToEnd()方法永远不会返回除string之外的任何内容。在这里使用 dynamic 充其量是毫无意义的,最坏的情况是潜在的额外开销,因为需要动态绑定(取决于 C# 编译器是否注意到它毫无意义......我不记得那里的编译规则是什么(。

代码中的

Semaphore = 0;
function Step1() {
    //do your stuff
    Semaphore++;
}
function Step2() {
    //do your stuff
    Semaphore++;
}
function Step3() {
    while (1) { // for example a setTimer in javascript
        if ( Semaphore >= 2 ) {
            // send email
            break;
        } 
        if ( timeout() ) {
            // send error message
            break;
        }
        sleep(200);
    }
}
Step1.Start();
Step2.Start();
Step3.Start();

你肯定会找到一个允许同步两个任务的JavaScript框架。这是一个非常简单和幼稚的同步。