以前写的东西——支付宝
把以前写的最终版本支付宝接口放上来。
库的改变:
1、 增加了一个接口,
public void CommonProcessNotify(Page page, string verifyUrl, string key, Verify verify, string encode)
这个接口触发NotifyEvent事件,此事件通过NotifyEventArgs类型暴露了支付宝Notify通知的所有参数,并且不给支付宝回发“success”或者“fail”,回发由调用者实现。这个方法提供了支付宝Notify通知的所有功能。
如果仅仅需要处理下面几个事件,可以参考:http://www.cnblogs.com/bluewater/archive/
WaitBuyerPay
WaitSellerConfirmTrade
WaitSysConfirmPay
WaitSellerSendGoods
WwaitBuyerConfirmGoods
WaitSysPaySeller
TradeFinished
TradeClosed
这几个事件细化了支付宝的Notify通知,定义了最常用的几个事件,调用起来要方便些。
2、 记录了日志记录功能。
用Log4net记录了Request.Form集合,可以看到支付宝Notify发过来的整个参数,便于调试。日志默认是Error级别,并且只有在debug版本有日志输出,实际使用时应该用release版本的库(或者修改Log4net的日志级别),以免记录下许多无用的日志。
调用方式的改变:
用Notify接口模拟出了Return方式。支付宝的Return接口虽然方便调用,但是安全可靠性差,很难在实际中应用。通过下面的方式,可以用Notify模拟return,如果支付宝的Notify发送的及时还可以完全替代Return方式。
解决方法是:让提交给支付宝信息的页面一直等待,直到收到Notify通知。
AutoResetEvent ansyCard=new AutoResetEvent(false);
ansyCard.WaitOne(); //阻塞当前线程,直到Notify完成。displaycard.aspx
ansyCard.Set();//在Notify页面发解除阻塞通知,displaycard页面继续执行。Notify.aspx
思路就是上面那么简单,但实际上还有几个问题:1、支付宝服务器发Notify页面和其他的页面不在一个线程,不属于用一个Session。2、支付宝会一直发Notify,必须要保证,解锁的是设置锁的那个线程,而不能把其他的线程锁解开。
详细的实现方式可以看源代码,此方法可为解决这种类型的问题提供了一个思路。
调试:
调试支付宝必须满足两个条件:
1、 有个公网IP,如果是ADSL每次拨号也会分配一个,可以通过ipconfig命令查到此次拨号分配的IP,这样支付宝就能访问到你。
2、 必须附加到IIS,一是通过手动附加到aspnet_wp进程,二是把启动选项的服务器改称虚拟目录的地址。
满足上面两个条件就可以调试支付宝了。
源代码的使用方法:
修改web.config中的下面几项后,就可以直接运行实例程序。Temp.aspx是测试AutoResetEvent的页面。
<add key="key" value=" "/>
<add key="partner" value=""/>
<add key="sellerEmail" value=" "/>
<add key="sellerId" value=" "/>
<add key="notifyUrl" value=" "/>
关于AutoResetEvent可以看下面的文章
http://www.cnblogs.com/bluewater/archive/
string partner = ConfigurationManager.AppSettings["partner"];
string sellerEmail = ConfigurationManager.AppSettings["sellerEmail"];
string sellerId = ConfigurationManager.AppSettings["sellerId"];
string outTradeNo = Guid.NewGuid().ToString();
string url = ConfigurationManager.AppSettings["notifyUrl"].ToString();
string gatewayUrl = "https://www.alipay.com/cooperate/gateway.do";
//
AliPay ap = new AliPay();
DigitalGoods dg = new DigitalGoods("create_digital_goods_trade_p", partner, key, "MD5", subject, outTradeNo, (decimal)money, 1, sellerEmail, sellerId);
dg.Buyer_Id = "temp";
dg.Notify_Url = url;
Session["outtradeNo"] = outTradeNo;
ap.CreateDigitalTrade(gatewayUrl, dg, this);
string myScript = @"document.all['discard'].src='displayCard.aspx'";
Page.ClientScript.RegisterStartupScript(this.GetType(), "myScript", myScript, true);
display.aspx
{
//Session["outtradeNo"] = Request.QueryString["a"];
AutoResetEvent ansyCard=new AutoResetEvent(false);
Application[Session["outtradeNo"].ToString() + "Event"] = ansyCard;
ansyCard.WaitOne();
if (Application[Session["outtradeNo"].ToString()] != null)
{
string s = string.Format("<script language='javascript'>alert('你的充值卡密码是:{0}')</script>", Application[Session["outtradeNo"].ToString()]);
Response.Write(s);
}
}
notify.aspx
{
Card card = new Card();
AutoResetEvent ansyCard = (AutoResetEvent)Application[e.Out_Trade_No + "Event"];
TradeLog tradeLog = null;
try
{
tradeLog = new TradeLog(e.Buyer_Id, e.Trade_Status, e.Trade_No, e.Buyer_Id, e.Subject, (int)e.Price, 1);
SNInfo snInfo = card.GetSn((int)e.Price);
card.WriteLog(tradeLog);
Application[e.Out_Trade_No] = snInfo.Password;
ansyCard.Set();
}
catch (Exception ex)
{
//日志
//
if (tradeLog != null)
{
string t = e.Buyer_Id + e.Trade_Status + e.Trade_No + e.Buyer_Id + e.Subject + (int)e.Price + "sendgoods";
Log4net.log.Error(t, ex);
}
else
{
//
Log4net.log.Error(GetForms(Request.Form), ex);
}
ansyCard.Set();
}
}
代码:
https://files.cnblogs.com/bluewater/commonalipay2.rar