回调函数以错误的顺序完成
本文关键字:顺序 错误 函数 回调 | 更新日期: 2023-09-27 18:33:29
非常令人困惑的问题,所以我会尽力详细说明。我有一个接受付款的Facebook画布应用程序,当用户点击付款按钮时,会发生以下情况:
我的 javascript 回调函数被调用并传递了一个付款 ID,因此我将这个付款 ID 和其他信息保存到我的订单数据库中。
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
变量声明为dynamic
?ReadToEnd()
方法永远不会返回除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框架。这是一个非常简单和幼稚的同步。