APP支付(.NET版)
---恢复内容开始---
APP支付(.NET版)
一、 支付宝支付
1、 有一个支付账号,在蚂蚁金服开放平台中登录账号→选择“管理中心”→在“开发者中心”下选择“网页&移动应用”→然后按步骤创建应用→选择需要的功能进行签约,签约成功后即可使用。
(注意事项:在签约的时候生成的私钥、公钥、还有支付宝公钥记得将文件保存。
支付签约成功会以手机短讯的方式进行通知,这时请查看你的邮箱(在签约时预留的),打开支付发送过来的邮件,通过里面的链接地址进行二次确认,才可正式签约生效)
2、 从官网下载“.NET版”SDK
3、 将SDK添加引用到项目
4、 获取预订单号,返回的预订单号直接给app端请求支付宝,不用做处理---代码如下:
/// <summary>
/// 获取预订单编号
/// </summary>
/// <param name="money">支付金额</param>
/// <param name="tradeNo">本地订单号</param>
/// <param name="payment">取卡收费,注册收费</param>这个参数可以不用,是根据自己需要加上的
public string GetOrderId(string money, string tradeNo, string payment)
{
string orderId = string.Empty;
try
{
if (!string.IsNullOrEmpty(payment))
{
//正式环境
IAopClient client = new DefaultAopClient(AlPayConfig.payUrl
, AlPayConfig.aPPID, AlPayConfig.alipayprivateKey, "json", "1.0", "RSA2"
, AlPayConfig.alipaypublicKey, AlPayConfig.charset, false);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称如:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.Body = "支付宝付款"; //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
model.Subject = payment;//商品的标题/交易标题/订单标题/订单关键字等。
model.TotalAmount = money;//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
model.ProductCode = "QUICK_MSECURITY_PAY";//销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
model.OutTradeNo = CommonMethod.StringRemove_(tradeNo);//商户网站唯一订单号
model.TimeoutExpress = "30m";//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。注:若为空,则默认为15d。
request.SetBizModel(model);
request.SetNotifyUrl(AlPayConfig.notifyUrl);//外网商户可以访问的异步地址
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = client.SdkExecute(request);
//HttpUtility.HtmlEncode是为了输出到页面时防止被浏览器将关键参数html转义,实际打印到日志以及http传输不会有这个问题
//Response.Write(HttpUtility.HtmlEncode(response.Body));
//页面输出的response.Body就是orderString 可以直接给客户端请求,无需再做处理。
string aa = response.TradeNo;
orderId = response.Body;
}
}
catch (Exception e)
{
Log.Error("AlPay", "App支付支付回调通知:" + e.Message);
}
return orderId;
}
请求参数请参考“https://docs.open.alipay.com/204/105465/”
5、 支付宝异步回调,返回支付结果及参数(参数描述请参考“https://docs.open.alipay.com/204/105301/”)
A、 获取返回的参数信息,并转换成字典
/// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
/// request回来的信息组成的数组
public IDictionary<string, string> GetRequestPost()
{
int i = 0;
IDictionary<string, string> sArray = new Dictionary<string, string>();
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.Form;
// Get names of all forms into a string array.
string[] requestItem = coll.AllKeys;
for (i = 0; i < requestItem.Length; i++)
{
sArray.Add(requestItem[i], Request.Form[requestItem[i]]);
}
return sArray;
}
B、确认是否支付成功
/// <summary>
/// App支付支付回调通知,判断是否支付成功
/// </summary
public void AppPayNotify(IDictionary<string, string> strArray)
{
//string result = string.Empty;
try
{
//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
//bool RSACheckV1(IDictionary<string, string> parameters, string alipaypublicKey, string charset, string signType, bool keyFromFile)
bool flag = AlipaySignature.RSACheckV1(strArray, AlPayConfig.alipaypublicKey, AlPayConfig.charset, "RSA2", false);
if (!UpdateData(strArray, flag))
{
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, "支付宝支付回调完成后修改数据失败!"));
}
}
catch (Exception e)
{
Log.Error("AlPay", "App支付回调通知:" + e.Message);
}
}
6、 根据服务器订单号判断是否支付成功(也可以是根据支付订单号查询支付结果)
/// <summary>
/// 根据订单号返回支付结果
/// </summary>
public AlipayTradeQueryResponse GetPayResultByPreOrderId(string orderId)
{
orderId = CommonMethod.StringRemove_(orderId);
//正式环境
IAopClient client = new DefaultAopClient(AlPayConfig.payUrl
, AlPayConfig.aPPID, AlPayConfig.alipayprivateKey, "json", "1.0", "RSA2",
AlPayConfig.alipaypublicKey, AlPayConfig.charset, false);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.BizContent = "{\"out_trade_no\":\""+ orderId + "\"," +
"\"trade_no\":\"\"}";
//string.Format(@"{ut_trade_no:{0},trade_no:""}", orderId);
AlipayTradeQueryResponse response = client.Execute(request);
//Console.WriteLine(response.Body);
return response;
}
/// <summary>
/// 根据服务器订单号判断是否支付成功
/// </summary>
/// <param name="orderId">服务器订单号</param>
private void AlTestPayByOrderID(string orderId)
{
try
{
//根据服务器订单号返回支付结果
AlipayTradeQueryResponse response = new AlPay().GetPayResultByPreOrderId(orderId);
T_TMM_RFCardPaymentService rfCardPaymentService = new T_TMM_RFCardPaymentService();
//根据TradeStatus交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)
//TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
if (response.TradeStatus.ToUpper() == "TRADE_SUCCESS")//如果支付成功,则修改数据状态
{
string tradeNoR = response.TradeNo;//支付宝交易号
string outTradeNo = CommonMethod.StringToGuidStr(response.OutTradeNo);//商户订单号(服务器订单号)
string buyerLogonId = response.BuyerLogonId;//买家支付宝账号
string paymentDate = response.SendPayDate;//交易付款时间
string payStatus = "1";//支付成功状态为1,失败为2
rfCardPaymentService.PaySuccess(outTradeNo, "1", tradeNoR, buyerLogonId, paymentDate, payStatus);
}
else
{
//将订单改为失效订单
rfCardPaymentService.SetOrderInvalid(orderId);
}
}
catch (Exception ex)
{
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, ex.Message));
}
}
二、 微信支付
1、 有微信账号及微信商户号
2、 使用微信账号登录微信开放平台,创建移动应用,根据步骤填写详细信息。等待认证通过,平台认证需要付费。
3、 在微信商户平台创建商户账号,商户账号绑定银行卡,作为APP支付的目标账户。
4、 获取预订单号
/// <summary>
/// 取得预支付ID
/// </summary>
/// <param name="money">订单金额</param>
/// <param name="out_trade_no">订单编号</param>
/// <param name="body">商品描述交易字段</param>
/// <returns></returns>
private WxPayData PrepayId(double money, string tradeNo, string body)
{
WxPayData data = new WxPayData();
data.SetValue("body", body);//商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字 - 实际商品名称,天天爱消除 - 游戏充值。
string out_trade_no = tradeNo.Replace("-", "");//微信要求商户订单号不能超过32位
data.SetValue("out_trade_no", out_trade_no);//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
data.SetValue("total_fee", (int)(money * 100));//总金额:订单总金额,单位为分,int类型
string ip = Request.UserHostAddress;
data.SetValue("spbill_create_ip", ip);//用户端实际ip
data.SetValue("notify_url", WxPayConfig.NOTIFY_URL);//支付成功回调地址
data.SetValue("trade_type", "APP");//交易类型
data.SetValue("attach", body);//附加数据,交易完成,原样返回,body参数不返回,所以用这个代替
WxPayData result = new WxPayData();
try
{
result = WxPayApi.UnifiedOrder(data);//调用统一下单接口
}
catch (System.Exception ex)
{
result.SetValue("return_code", "FAIL");
result.SetValue("return_msg", "下单失败,请返回重试。");
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, ex.Message));
}
//result.SetValue("return_code", "SUCCEED");//返回的结果已经包含当前字段
//res.Data = result.ToJson();
return result;
}
5、 微信回调修改本地数据库
/// <summary>
/// 微信支付支付结果通知处理
/// </summary>
//[HttpPost, ValidateInput(false)]
[HttpPost]
public void ProcessNotify()
{
try
{
WxResultNotify resultNotify = new WxResultNotify(this.Request, this.Response);
bool bPayRs = resultNotify.ProcessNotify();
WxPayData notifyData = resultNotify.NotifyData;
string id = string.Empty;//服务器订单号
string paymentOrderNo = string.Empty;//微信订单号
string paymentStatus = string.Empty;//支付状态
string paymentMethod = CommonConst.PayTypeWX;//支付方式
string paymentAccount = string.Empty;//用户编号
string payDate = string.Empty;//支付时间
//支付id
if (notifyData.IsSet("out_trade_no"))
{
string out_trade_no = notifyData.GetValue("out_trade_no").ToString();
if (string.IsNullOrEmpty(out_trade_no) || out_trade_no.Length != 32)//订单编号不正确
{
id = string.Empty;
return;
}
else
{
//还原订单号
StringBuilder sb = new StringBuilder();
sb.Append(out_trade_no.Substring(0, 8));
sb.Append("-");
sb.Append(out_trade_no.Substring(8, 4));
sb.Append("-");
sb.Append(out_trade_no.Substring(12, 4));
sb.Append("-");
sb.Append(out_trade_no.Substring(16, 4));
sb.Append("-");
sb.Append(out_trade_no.Substring(20, 12));
id = sb.ToString();
}
}
else
{
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, "订单号不存在!"));
return;
}
//微信支付订单号
if (notifyData.IsSet("transaction_id"))
{
paymentOrderNo = notifyData.GetValue("transaction_id").ToString();
}
//用户编号
if (notifyData.IsSet("openid"))
{
paymentAccount = notifyData.GetValue("openid").ToString();
}
//支付时间
if (notifyData.IsSet("time_end"))
{
payDate = DateTime.ParseExact(notifyData.GetValue("time_end").ToString()
, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture).ToString("yyyy-MM-dd HH:mm:ss");
}
//判断交易是否成功
if (notifyData.IsSet("result_code") && notifyData.GetValue("result_code").ToString() == "SUCCESS")//交易成功
{
paymentStatus = "1";//支付状态“成功”
}
else//交易失败
{
paymentStatus = "2"; //支付状态“失败”
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, "交易失败!"));
}
//判断是取卡支付还是注册支付
if (notifyData.IsSet("attach") && notifyData.GetValue("attach").ToString().Contains(CommonConst.PaymentQK))//取卡支付
{
//支付完成修改数据
new T_TMM_RFCardPaymentService().PaySuccess(id, paymentMethod, paymentOrderNo, paymentAccount, payDate, paymentStatus);
}
else
{
//支付完成修改数据
new T_TMM_RegisterPaymentService().PaySuccess(id, paymentMethod, paymentOrderNo, paymentAccount, payDate, paymentStatus);
new AlPay().GreateLoginAuthorityByOrderId(id);
}
}
catch (Exception ex)
{
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, ex.Message));
}
}
6、 根据服务器订单号查询是否支付成功(也可以根据支付订单号查询支付结果)
/// <summary>
/// 根据服务器订单号判断是否支付成功
/// </summary>
/// <param name="orderId">服务器订单号</param>
private void WXTestPayByOrderID(string orderId)
{
try
{
T_TMM_RFCardPaymentService rfCardPaymentService = new T_TMM_RFCardPaymentService();
//根据服务器订单号返回支付结果
WxPayData payData = new WxPayData();
payData.SetValue("out_trade_no", CommonMethod.StringRemove_(orderId));//服务器订单号
//返回查询结果
WxPayData payResult = WxPayApi.OrderQuery(payData);
//根据支付状态判断是否支付成功SUCCESS—支付成功REFUND—转入退款NOTPAY—未支付CLOSED—已关闭REVOKED—已撤销(刷卡支付)USERPAYING--用户支付中PAYERROR--支付失败(其他原因,如银行返回失败)
if (payResult.IsSet("trade_state") && payResult.GetValue("trade_state").ToString() == "SUCCESS")//支付成功
{
string tradeNoR = payResult.GetValue("transaction_id").ToString();//微信支付订单号
string outTradeNo = CommonMethod.StringToGuidStr(payResult.GetValue("out_trade_no").ToString());//商户订单号(服务器订单号)
string buyerLogonId = payResult.GetValue("openid").ToString();//买家支付宝账号
string paymentDate = DateTime.ParseExact(payResult.GetValue("time_end").ToString(),"yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture).ToString("yyyy-MM-dd HH:mm:ss"); //交易付款时间
string payStatus = "1";//支付成功状态为1,失败为2
rfCardPaymentService.PaySuccess(outTradeNo, "2", tradeNoR, buyerLogonId, paymentDate, payStatus);
}
else//支付失败
{
//将订单改为失效订单
rfCardPaymentService.SetOrderInvalid(orderId);
}
}
catch (Exception ex)
{
CommonMethod.WriteErrorLog(string.Format(CommonMethod.LOG_ERROR_FORMAT, this.GetType().FullName,
new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name, ex.Message));
}
}
注:微信开放平台创建移动应用时,开发信息中的以下信息是固定值,不能随意更换。
(如需修改,则必须通知APP开发人员,对APP作出相对应的修改)
iOS平台
iPhone
应用下载地址:未填写
Bundle ID:moon.SundyApp
测试版本Bundle ID:moon.SundyApp
iPad 无
Android平台
应用下载地址:未填写
应用签名:478c16ede90213492d8ea8eda87d1ada
包名:com.sundy.android
三、 所有与支付相关的配置信息,都在web.config文件中配置(重要)
1、 支付宝需配置的信息有
a) AL_APPID 在支付宝的管理平台“创建应用”成功后,对于已经创建的应用会生成一个APPID,这个编号是唯一的,相当于应用的身份证号。
b) AL_PUBLIC_KEY(支付宝公钥)在支付宝的管理平台“创建应用”成功后,在应用信息里面,有查看支付宝公钥的链接,将这个链接复制替换到config文件中,注意:不能出现换行和空格。
c) AL_PRIVATE_KEY(应用私钥)在支付宝“创建应用”的时候,在使用“生成密钥”的工具生成时会生成两个txt文件,分别为“应用公钥”和“应用私钥”。这里使用的就是应用私钥。(注:“应用私钥”在“应用信息”中看不到)。
d) CHARSET(编码格式)一般使用UTF-8。
e) NOTIFY_URL回调地址(服务器地址)。
f) AL_PAY_URL(支付宝-URL) 正式地址:https://openapi.alipay.com/gateway.do,沙箱环境:https://openapi.alipaydev.com/gateway.do。
2、 微信需配置的信息有
a) WX_URL_UNIFIEDORDER(统一下单url):https://api.mch.weixin.qq.com/pay/unifiedorder。
b) WX_URL_ORDERQUERY(订单查询url):https://api.mch.weixin.qq.com/pay/orderquery。
c) WX_URL_REPORT(测速上报url):https://api.mch.weixin.qq.com/payitil/report。
d) WX_APPID 在微信开放平台创建好应用后,生成的一个APPID。
e) WX_MCHID(商户号)在微信商户平台注册的微信商户编号,用来指定收款帐户。
f) WX_APIKEY(商户支付密钥)在微信商户平台注册的时间可以得到。
g) WX_REPORT_LEVENL(上报信息配置 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报)。
h) WX_LOG_LEVENL(日志级别 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息)。
3、 NOTIFY_URL(共用的回调URL,回调地址(服务器地址))
---恢复内容结束---