这是一个非常令人困惑的问题,所以我会尽力详细说明。我有一个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);
}
}
答案 0 :(得分:1)
:
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框架。这是一个非常简单和天真的同步。
答案 1 :(得分:1)
是什么引发了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#编译器是否注意到它是无意义的......我不记得了我头脑中的编译规则是什么。)