asp.net mvc 接入最新支付宝支付+退款
asp.net mvc 接入最新支付宝支付+退款 alipay-sdk-NET-20170615110549
第1步:
https://openhome.alipay.com/developmentDocument.htm

第2步:下载sdk和demo
https://docs.open.alipay.com/270/106291/

https://docs.open.alipay.com/54/103419

第3步:将SDK放到解决方案下并在解决方案下打开下载下来的SDK项目

第4步:新建项目,项目中新建一个类存放支付宝配置相关信息

登录支付宝进入开发者中心
https://openhome.alipay.com/platform/appDaily.htm?tab=info

public class AlipayConfigHelper
{
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//支付宝网关地址
// -----开发环境地址-----
//public static string serviceUrl = "https://openfile.alipay.com/chat/multimedia.do";
// -----沙箱地址-----
public static string serviceUrl = "https://openapi.alipaydev.com/gateway.do";
// -----线上地址-----
//public static string serviceUrl = "https://openapi.alipay.com/gateway.do";
//应用ID,以2088开头由16位纯数字组成的字符串
public static string appId = "2016080500169628";
//开发者私钥,由开发者自己生成
public static string privateKey = @"******";
//支付宝的公钥,由支付宝生成
public static string alipayPublicKey = @"*****";
//服务器异步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//public static string notify_url = "http://" + System.Web.HttpContext.Current.Request.Url.Host + ":" + System.Web.HttpContext.Current.Request.Url.Port + "/College/NotifyUrl";
public static string notify_url = "http://ryan.wicp.net/College/NotifyUrl";
//页面跳转同步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//public static string return_url = "http://" + System.Web.HttpContext.Current.Request.Url.Host + ":" + System.Web.HttpContext.Current.Request.Url.Port + "/College/ReturnUrl";
public static string return_url = "http://ryan.wicp.net/College/ReturnUrl";
//参数返回格式,只支持json
public static string format = "json";
// 调用的接口版本,固定为:1.0
public static string version = "1.0";
// 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
public static string signType = "RSA2";
// 字符编码格式 目前支持utf-8
public static string charset = "utf-8";
// false 表示不从文件加载密钥
public static bool keyFromFile = false;
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
}
第5步:控制器处理

(1)初始化配置文件信息
#region 初始化配置文件信息
private IAopClient GetAlipayClient()
{
//支付宝网关地址
string serviceUrl = AlipayConfigHelper.serviceUrl;
//应用ID,以2088开头由16位纯数字组成的字符串
string appId = AlipayConfigHelper.appId;
//商户私钥
string privateKey = AlipayConfigHelper.privateKey;
//支付宝的公钥
string alipayPublicKey = AlipayConfigHelper.alipayPublicKey;
string format = AlipayConfigHelper.format;
string version = AlipayConfigHelper.version;
string signType = AlipayConfigHelper.signType;
string charset = AlipayConfigHelper.charset;
bool keyFromFile = false;
IAopClient client = new DefaultAopClient(serviceUrl, appId, privateKey, format, version, signType, alipayPublicKey, charset, keyFromFile);
return client;
}
#endregion
(2)调用SDK生成支付表单
#region 调用SDK生成支付表单
public ActionResult CreatePayForm()
{
try
{
IAopClient client = GetAlipayClient();
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
//在公共参数中设置回跳和通知地址
request.SetReturnUrl(AlipayConfigHelper.return_url);
request.SetNotifyUrl(AlipayConfigHelper.notify_url);
var RRR=Request["orderNo"].ToString();
//获取订单信息
DataTable dr = collegeService.GetOrderInfo(RRR).Tables[0];
//方法1:
AlipayTradePayModel model = new AlipayTradePayModel();
//填充业务参数
model.Body = "商学院报名"; //订单描述
model.Subject = "商学院报名"; //订单标题
model.OutTradeNo = Request["orderNo"]; //商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
model.TotalAmount = (Convert.ToInt32(dr.Rows[0]["Amount"])*1.0/100).ToString(); //订单总金额,单位为元,精确到小数点后两位
model.ProductCode = "FAST_INSTANT_TRADE_PAY"; //销售产品码,商家和支付宝签约的产品码 (如 FAST_INSTANT_TRADE_PAY)
request.SetBizModel(model);
//方法2:
/**************************************************
string Body = "商学院报名";
string Subject = "商学院报名";
string OutTradeNo = Request["orderNo"];
string TotalAmount = Request["amount"];
string ProductCode = "FAST_INSTANT_TRADE_PAY";
request.BizContent = "{" +
" \"body\":\""+ Body + "\"," +
" \"subject\":\""+ Subject + "\"," +
" \"out_trade_no\":\""+ OutTradeNo + "\"," +
" \"total_amount\":"+ TotalAmount + "," +
" \"product_code\":\""+ ProductCode + "\"" +
" }";
*********************************************************/
//调用SDK生成表单
AlipayTradePagePayResponse response = client.pageExecute(request);
string form = response.Body;
//Response.Write(form);
return Content(form);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion
(3)面跳转同步通知页面
#region 页面跳转同步通知页面
/// <summary>
/// 功能:页面跳转同步通知页面
/// </summary>
public ActionResult ReturnUrl()
{
// http://localhost:10231/College/ReturnUrl?
// total_amount =0.01
// ×tamp=2017-07-24+17%3A57%3A08
// &sign=********
// &trade_no=2017072421001004930200313969
// &sign_type=RSA2
// &auth_app_id=2016080500169628
// &charset=utf-8
// &seller_id=2088102169996595
// &method=alipay.trade.page.pay.return
// &app_id=2016080500169628
// &out_trade_no=GM201707241756580000000001
// &version=1.0
//将同步通知中收到的所有参数都存放到map中
IDictionary<string, string> map = GetRequestGet();
if (map.Count > 0) //判断是否有带返回参数
{
try
{
//支付宝的公钥
string alipayPublicKey = AlipayConfigHelper.alipayPublicKey;
string signType = AlipayConfigHelper.signType;
string charset = AlipayConfigHelper.charset;
bool keyFromFile = false;
// 获取支付宝GET过来反馈信息
bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile);
if (verify_result)
{
// 验证成功
Response.Redirect("/College/Index?id=1");
return Content("ok");
}
else
{
return Content("验证失败");
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
else
{
return Content("无返回参数");
}
}
/// <summary>
/// 获取支付宝GET过来通知消息,并以“参数名=参数值”的形式组成数组
/// </summary>
/// <returns>request回来的信息组成的数组</returns>
public IDictionary<string, string> GetRequestGet()
{
int i = 0;
IDictionary<string, string> sArray = new Dictionary<string, string>();
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.QueryString;
// 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.QueryString[requestItem[i]]);
}
return sArray;
}
#endregion
(4)服务器异步通知页面
#region 服务器异步通知页面
/// <summary>
/// 功能:服务器异步通知页面
/// 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格
/// 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
/// 该页面调试工具请使用写文本函数logResult。
/// 如果没有收到该页面返回的 success 信息,支付宝会在24小时内按一定的时间策略重发通知
/// GmkCollege
/// </summary>
public void NotifyUrl()
{
// 获取支付宝Post过来反馈信息
IDictionary<string, string> map = GetRequestPost();
if (map.Count > 0) //判断是否有带返回参数
{
try
{
//支付宝的公钥
string alipayPublicKey = AlipayConfigHelper.alipayPublicKey;
string signType = AlipayConfigHelper.signType;
string charset = AlipayConfigHelper.charset;
bool keyFromFile = false;
bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile);
// 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
if (verify_result)
{
//商户订单号
string out_trade_no = map["out_trade_no"];
//支付宝交易号
string trade_no = map["trade_no"];
//交易创建时间
string gmt_create = map["gmt_create"];
//交易付款时间
string gmt_payment = map["gmt_payment"];
//通知时间
string notify_time = map["notify_time"];
//通知类型 trade_status_sync
string notify_type = map["notify_type"];
//通知校验ID
string notify_id = map["notify_id"];
//开发者的app_id
string app_id = map["app_id"];
//卖家支付宝用户号
string seller_id = map["seller_id"];
//买家支付宝用户号
string buyer_id = map["buyer_id"];
//实收金额
string receipt_amount = map["receipt_amount"];
//交易状态
//交易状态TRADE_FINISHED的通知触发条件是商户签约的产品不支持退款功能的前提下,买家付款成功;
//或者,商户签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限
//状态TRADE_SUCCESS的通知触发条件是商户签约的产品支持退款功能的前提下,买家付款成功
if (map["trade_status"] == "TRADE_FINISHED" || map["trade_status"] == "TRADE_SUCCESS")
{
//判断该笔订单是否在商户网站中已经做过处理
DataTable dd=collegeService.OrderPayNot(out_trade_no).Tables[0];
if (Convert.ToInt32(dd.Rows[0]["Status"]) == 0)
{
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
#region 将数据提添加到集合中
Dictionary<string, string> myDic = new Dictionary<string, string>();
myDic.Add("PayTradeNo", trade_no);
myDic.Add("Status", "1");
myDic.Add("Type", "0");
myDic.Add("PayTime", gmt_payment);
myDic.Add("BuyerId", buyer_id);
myDic.Add("OrderNo", out_trade_no);
#endregion
#region 添加数据到数据库
bool res = collegeService.AddPayInfo(myDic);
if (res == false)
{
Response.Write("添加支付信息失败!");
}
#endregion
Response.Write("success"); //请不要修改或删除
}
}
}
// 验签失败则记录异常日志,并在response中返回failure.
else
{
Response.Write("验证失败");
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
else
{
Response.Write("无返回参数");
}
}
/// <summary>
/// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
/// </summary>
/// <returns>request回来的信息组成的数组</returns>
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;
}
#endregion
(5)退款
#region 退款
/// <summary>
/// 支付宝退款
/// </summary>
/// <returns></returns>
public string Refund(string OrderNo)
{
//查询要退款的订单信息
DataTable dt = collegeService.GetOrderInfo(OrderNo).Tables[0];
IAopClient client = GetAlipayClient();
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradePayModel model = new AlipayTradePayModel();
//填充业务参数
request.BizContent = "{" +
" \"out_trade_no\":\"" + dt.Rows[0]["OrderNo"] + "\"," +
" \"trade_no\":\"" + dt.Rows[0]["TradeNo"] + "\"," +
" \"refund_amount\":" + ((int)dt.Rows[0]["Amount"] * 1.0 / 100) + "," +
" \"refund_reason\":\"正常退款\"," +
" \"operator_id\":\"OP001\"," +
" \"store_id\":\"NJ_S_001\"," +
" \"terminal_id\":\"NJ_T_001\"" +
" }";
AlipayTradeRefundResponse response = client.Execute(request);
string Info = response.Body;
//{ "alipay_trade_refund_response":{
//"code":"10000",
//"msg":"Success",
//"buyer_logon_id":"xso***@sandbox.com",
//"buyer_user_id":"2088102172262939",
//"fund_change":"Y",
//"gmt_refund_pay":"2017-07-31 15:28:08",
//"open_id":"20881027348761637209827442915993",
//"out_trade_no":"GM201707311527020000000001",
//"refund_fee":"33.33",
//"send_back_fee":"0.00",
//"trade_no":"2017073121001004930200315623"},
//"sign":"**********"}
if (response.Code == "10000")
{
int RefundAmount =Convert.ToInt32(Convert.ToDecimal(response.RefundFee)*100);
DateTime RefundTime =Convert.ToDateTime(response.GmtRefundPay);
int Status = 2; //已退
bool res=collegeService.UpdateRefundInfo(OrderNo,RefundAmount, RefundTime, Status);
return JsonHelper.DataJson(0, "退款成功!");
}
else
{
return JsonHelper.DataJson(1, "退款失败!");
}
}
#endregion
第6步:新建支付订单确认页面
<div class="zhezhaoceng dd" style="display: none">
<div class="duihuakuang ee" style="display: none">
<div class="success-alert ">
<p>支付核实:</p>
</div>
<form method="post" id="OrderForm">
<div>
<input type="hidden" name="OrderNo" id="orderNo" value="" />
<input type="hidden" name="Amount" id="amount" value="" />
<div>
<p>商学院报名</p>
<p>订单号:<span id="OrderNo"></span></p>
<p>支付金额:<font color="red"><b><span id="Currency">¥</span><span id="Amount"></span></b></font></p>
</div>
<div>
<input class="submit next-btn" type="button" value="立即支付" onclick="go_pay()" />
</div>
</div>
</form>
</div>
</div>
<div class="pay_method" style="display: none">
<div class="pay-alert ">
<p>支付方式</p>
<p><span id="pay_button"></span></p>
</div>
</div>
第7步:js处理
function go_pay() {
$("#OrderForm").ajaxSubmit({
url: "/College/CreatePayForm",
type: "post",
success: function (data) {
$(".detail-message8").css({ "display": "none" });
$(".dd").css({ "display": "none" });
$(".ee").css({ "display": "none" });
$(".pay_method").css({ "display": "none" });
$("#pay_button").html(data);
}
});
}
第8步:花生壳
由于支付宝异步回调测试需要将网站发布到公网,所以需要将本地域名映射到公网
(1)登录
用户名:************
密 码:*********
(2)实名认证

(3)添加映射



(4)访问将localhost换成zouke1220.oicp.net进行访问
http://zouke1220.oicp.net/College/Index

点击“报名”

点击“下一步”
function next_step() {
$("#formID").ajaxSubmit({
url: "/College/ValidateUserInfo",
type: "post",
success: function (data) {
if (data == "ok") {
$(".detail-message8").css({ "display": "none" });
$(".detail-message6").css({ "display": "none" });
$(".detail-message7").css({ "display": "block" });
} else {
alert(data);
return false;
}
}
});
}
点击“同意”
function iAgree(){
if ($("#checkedd").is(":checked")) {
$(".detail-message6").css({ "display": "none" });
$(".detail-message7").css({ "display": "none" });
$(".detail-message8").css({ "display": "block" });
} else {
return false;
}
}


点击“去支付”跳到订单确认页
function order_confirm() {
$("#SignUpForm").ajaxSubmit({
url: "/College/SignUp",
type: "post",
success: function (data) {
var obj=eval('(' + data + ')'); //json转json对象
if (obj.code == 0) {
$(".dd").css({ "display": "block" });
$(".ee").css({ "display": "block" });
$("#OrderNo").html(obj.data.OrderNo);
$("#Amount").html(obj.data.Amount);
$("#orderNo").val(obj.data.OrderNo);
$("#amount").val(obj.data.Amount);
} else {
alert(obj.msg);
return false;
}
}
});
}

点击“立即支付”
function go_pay() {
$("#OrderForm").ajaxSubmit({
url: "/College/CreatePayForm",
type: "post",
success: function (data) {
$(".detail-message8").css({ "display": "none" });
$(".dd").css({ "display": "none" });
$(".ee").css({ "display": "none" });
$(".pay_method").css({ "display": "none" });
$("#pay_button").html(data);
}
});
}

点击“登录账户付款”

点击“下一步”

点击“确认付款”


自动跳转到异步回调页面,将支付成功信息插入数据库
http://zouke1220.oicp.net/College/NotifyUrl
并跳转到同步通知页面显示支付成功页面
http://zouke1220.oicp.net/College/ReturnUrl

第9步:所有测试通过后将第4步配置信息换成正式环境的
注:部分页面还需要美化,完整版项目参见:http://www.gmkcn.com/


浙公网安备 33010602011771号