欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

支付宝支付

程序员文章站 2022-04-11 15:27:31
...

对支付宝支付的二次封装,支持pc端和wap端支付

类图

支付宝支付

支付宝支付

pay(pc):

    var orderNo = ""; //订单号
    var subject = ""; //订单名称
    var fee = 0.ToString("0.##"); //付款金额
    var notifyUrl = "host/Alipay/NotifyUrl.aspx";
    var returnUrl = "host/Alipay/ReturnUrl.aspx";
    var show_url = "host";
    var alipay = new Alipay.Submit();
    alipay.Pay(orderNo, subject, fee, body, notify_url, return_url, show_url);

pay(wap):

    var orderNo = ""; //订单号
    var title = "在线捐赠(WAP):" + ""; //订单名称
    var fee = 0.ToString("0.##"); //付款金额
    var notifyUrl = "host/Alipay/NotifyUrl.aspx";
    var returnUrl = "host/Alipay/ReturnUrl.aspx";
    var show_url = "host";
    var alipay = new Alipay.Submit();
    alipay.Submit.Pay(orderNo, subject, fee, body, notify_url, return_url, show_url);

return(pc):

    public partial class NotifyUrl : Alipay.NotifyPage
    {
            protected override void OnNotifyConfirm()
            {
                //todo:业务逻辑处理
            }
    }

return(wap):


    public partial class NotifyUrl : Alipay.Wap.NotifyPage
    {
            protected override void OnNotifyConfirm()
            {
                //todo:业务逻辑处理
            }
        }

PC端的Submit.cs

using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;

namespace Alipay
{
    /// <summary>
    /// 支付宝各接口请求提交类
    /// 构造支付宝各接口表单HTML文本,获取远程HTTP数据
    /// </summary>
    public class Submit
    {
        public Submit()
        {

        }

        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="partner">合作者身份ID</param>
        /// <param name="key">交易安全校验码</param>
        /// <param name="sellerMail">卖方(收款方)支付宝账户</param>
        public Submit(string partner, string key, string sellerMail)
        {
            Config.Partner = partner;
            Config.Key = key;
            Config.SellerEmail = sellerMail;
        }

        /// <summary>
        /// 提交支付请求,get
        /// </summary>
        /// <param name="orderNo">商户订单号</param>
        /// <param name="fee">付款金额</param>
        /// <param name="title">订单名称</param>
        /// <param name="desc">订单描述</param>
        /// <param name="notifyUrl">服务器异步通知页面路径</param>
        /// <param name="returnUrl">页面跳转同步通知页面路径</param>
        /// <param name="showUrl">商品展示地址</param>
        public void Pay(string orderNo, string fee, string title, string desc, string notifyUrl,
                               string returnUrl, string showUrl)
        {
            var para = new SortedDictionary<string, string>
                {
                    {"partner", Config.Partner},
                    {"_input_charset", Config._Charset.ToLower()},
                    {"service", Config._PayMode},
                    {"payment_type", Config._PayType},
                    {"notify_url", notifyUrl},
                    {"return_url", returnUrl},
                    {"seller_email", Config.SellerEmail},
                    {"out_trade_no", orderNo},
                    {"subject", title},
                    {"total_fee", fee},
                    {"body", desc},
                    {"show_url", showUrl},
                    {"anti_phishing_key", _GetDateTimeString()}
                };
            var dicPara = BuildRequestPara(para);
            var sbHtml = new StringBuilder();
            sbHtml.AppendFormat(
                "<form id='alipaysubmit' name='alipaysubmit' action='{0}_input_charset={1}' method='get'>",
                Config._GateWay, Config._Charset);
            foreach (var temp in dicPara)
            {
                sbHtml.AppendFormat("<input type='hidden' name='{0}' value='{1}'/>", temp.Key, temp.Value);
            }
            //submit按钮控件请不要含有name属性
            sbHtml.Append("<input type='submit' value='支付' style='display:none;'></form>");
            sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");
            HttpContext.Current.Response.Write(sbHtml.ToString());
        }

        /// <summary>
        /// 提交支付请求,post
        /// </summary>
        /// <param name="notifyUrl">服务器异步通知页面路径</param>
        /// <param name="returnUrl">页面跳转同步通知页面路径</param>
        /// <param name="sellerEmail">卖家支付宝帐户</param>
        /// <param name="orderNo">商户订单号</param>
        /// <param name="subject">订单名称</param>
        /// <param name="fee">付款金额</param>
        /// <param name="title">订单描述</param>
        /// <param name="showUrl">商品展示地址</param>
        public void PostPay(string notifyUrl, string returnUrl, string sellerEmail, string orderNo, string subject
                               , string fee, string title, string showUrl)
        {
            var para = new SortedDictionary<string, string>
                {
                    {"partner", Config.Partner},
                    {"_input_charset", Config._Charset.ToLower()},
                    {"service", Config._PayMode},
                    {"payment_type", Config._PayType},
                    {"notify_url", notifyUrl},
                    {"return_url", returnUrl},
                    {"seller_email", sellerEmail},
                    {"out_trade_no", orderNo},
                    {"subject", subject},
                    {"total_fee", fee},
                    {"body", title},
                    {"show_url", showUrl},
                    {"anti_phishing_key", _GetDateTimeString()}
                };

            var encoding = Encoding.GetEncoding(Config._Charset);
            var strRequestData = BuildRequestParaToString(para, encoding);
            var bytesRequestData = encoding.GetBytes(strRequestData);
            var strUrl = string.Format("{0}_input_charset={1}", Config._GateWay, Config._Charset);

            string strResult;
            try
            {
                var myReq = (HttpWebRequest)WebRequest.Create(strUrl);
                myReq.Method = "post";
                myReq.ContentType = "application/x-www-form-urlencoded";
                myReq.ContentLength = bytesRequestData.Length;

                var requestStream = myReq.GetRequestStream();
                requestStream.Write(bytesRequestData, 0, bytesRequestData.Length);
                requestStream.Close();

                var HttpWResp = (HttpWebResponse)myReq.GetResponse();
                var myStream = HttpWResp.GetResponseStream();
                var reader = new StreamReader(myStream, encoding);
                var responseData = new StringBuilder();
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    responseData.Append(line);
                }
                myStream.Close();
                strResult = responseData.ToString();
            }
            catch (Exception ex)
            {
                strResult = "报错:" + ex.Message;
            }
            HttpContext.Current.Response.Write(strResult);
        }

        /// <summary>
        /// 生成请求时的签名
        /// </summary>
        internal string BuildRequestMysign(Dictionary<string, string> sPara)
        {
            return MD5.Sign(Core.CreateLinkString(sPara), Config.Key, Config._Charset);
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        internal Dictionary<string, string> BuildRequestPara(SortedDictionary<string, string> sParaTemp)
        {
            var sPara = Core.FilterPara(sParaTemp);
            var mysign = BuildRequestMysign(sPara);
            sPara.Add("sign", mysign);
            sPara.Add("sign_type", Config._SignType);
            return sPara;
        }

        /// <summary>
        /// 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
        /// 注意:远程解析XML出错,与IIS服务器配置有关
        /// </summary>
        /// <returns>时间戳字符串</returns>
        private string _GetDateTimeString()
        {
            var url = string.Format("{0}service=query_timestamp&partner={1}", Config._GateWay, Config.Partner);
            var Reader = new XmlTextReader(url);
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(Reader);
            return xmlDoc.SelectSingleNode("/alipay/response/timestamp/encrypt_key").InnerText;
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        internal string BuildRequestParaToString(SortedDictionary<string, string> sParaTemp, Encoding code)
        {
            return Core.CreateLinkStringUrlencode(BuildRequestPara(sParaTemp), code);
        }

        /*
        /// <summary>
        /// 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果,带文件上传功能
        /// </summary>
        /// <param name="sParaTemp">请求参数数组</param>
        /// <param name="strMethod">提交方式。两个值可选:post、get</param>
        /// <param name="fileName">文件绝对路径</param>
        /// <param name="data">文件数据</param>
        /// <param name="contentType">文件内容类型</param>
        /// <param name="lengthFile">文件长度</param>
        /// <returns>支付宝处理结果</returns>
        internal static string BuildRequest(SortedDictionary<string, string> sParaTemp, string strMethod, string fileName, byte[] data, string contentType, int lengthFile)
        {

            //待请求参数数组
            Dictionary<string, string> dicPara = new Dictionary<string, string>();
            dicPara = BuildRequestPara(sParaTemp);

            //构造请求地址
            string strUrl = Config._GateWay + "_input_charset=" + Config._Charset;

            //设置HttpWebRequest基本信息
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(strUrl);
            //设置请求方式:get、post
            request.Method = strMethod;
            //设置boundaryValue
            string boundaryValue = DateTime.Now.Ticks.ToString("x");
            string boundary = "--" + boundaryValue;
            request.ContentType = "\r\nmultipart/form-data; boundary=" + boundaryValue;
            //设置KeepAlive
            request.KeepAlive = true;
            //设置请求数据,拼接成字符串
            StringBuilder sbHtml = new StringBuilder();
            foreach (KeyValuePair<string, string> key in dicPara)
            {
                sbHtml.Append(boundary + "\r\nContent-Disposition: form-data; name=\"" + key.Key + "\"\r\n\r\n" + key.Value + "\r\n");
            }
            sbHtml.Append(boundary + "\r\nContent-Disposition: form-data; name=\"withhold_file\"; filename=\"");
            sbHtml.Append(fileName);
            sbHtml.Append("\"\r\nContent-Type: " + contentType + "\r\n\r\n");
            string postHeader = sbHtml.ToString();
            //将请求数据字符串类型根据编码格式转换成字节流
            Encoding code = Encoding.GetEncoding(Config._Charset);
            byte[] postHeaderBytes = code.GetBytes(postHeader);
            byte[] boundayBytes = Encoding.ASCII.GetBytes("\r\n" + boundary + "--\r\n");
            //设置长度
            long length = postHeaderBytes.Length + lengthFile + boundayBytes.Length;
            request.ContentLength = length;

            //请求远程HTTP
            Stream requestStream = request.GetRequestStream();
            Stream myStream;
            try
            {
                //发送数据请求服务器
                requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                requestStream.Write(data, 0, lengthFile);
                requestStream.Write(boundayBytes, 0, boundayBytes.Length);
                HttpWebResponse HttpWResp = (HttpWebResponse)request.GetResponse();
                myStream = HttpWResp.GetResponseStream();
            }
            catch (WebException e)
            {
                return e.ToString();
            }
            finally
            {
                if (requestStream != null)
                {
                    requestStream.Close();
                }
            }

            //读取支付宝返回处理结果
            StreamReader reader = new StreamReader(myStream, code);
            StringBuilder responseData = new StringBuilder();

            String line;
            while ((line = reader.ReadLine()) != null)
            {
                responseData.Append(line);
            }
            myStream.Close();
            return responseData.ToString();
        }
        */
    }
}

wap端的Submit.cs


using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;

namespace Alipay.Wap
{
    /// <summary>
    /// 支付宝各接口请求提交类
    /// 构造支付宝各接口表单HTML文本,获取远程HTTP数据
    /// </summary>
    public class Submit
    {
        public Submit()
        {

        }

        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="partner">合作者身份ID</param>
        /// <param name="key">交易安全校验码</param>
        /// <param name="sellerMail">卖方(收款方)支付宝账户</param>
        public Submit(string partner, string key, string sellerMail)
        {
            Config.Partner = partner;
            Config.Key = key;
            Config.SellerEmail = sellerMail;
        }

        /// <summary>
        /// 提交支付请求,get
        /// </summary>
        /// <param name="orderNo">商户订单号</param>
        /// <param name="fee">付款金额</param>
        /// <param name="title">订单名称</param>
        /// <param name="desc">订单描述</param>
        /// <param name="notifyUrl">服务器异步通知页面路径</param>
        /// <param name="returnUrl">页面跳转同步通知页面路径</param>
        /// <param name="showUrl">商品展示地址</param>
        public void Pay(string orderNo, string fee, string title, string desc, string notifyUrl,
                               string returnUrl, string showUrl)
        {
            var req_id = DateTime.Now.ToString("yyyyMMddHHmmssfff"); //请求号,须保证每次请求都是唯一
            const string format = "xml";
            const string v = "2.0";

            if (string.IsNullOrEmpty(fee)) fee = "0";
            if (string.IsNullOrEmpty(title)) title = "在线捐赠(WAP)";
            if (string.IsNullOrEmpty(orderNo)) orderNo = req_id;

            var req_dataToken =
                string.Format(
                    "<direct_trade_create_req><notify_url>{0}</notify_url><call_back_url>{1}</call_back_url><seller_account_name>{2}</seller_account_name><out_trade_no>{3}</out_trade_no><subject>{4}</subject><total_fee>{5}</total_fee><merchant_url>{6}</merchant_url></direct_trade_create_req>",
                    notifyUrl, returnUrl, Config.SellerEmail, orderNo, title, fee, showUrl);

            //创建支付宝交易订单,并获取授权码token,alipay.wap.trade.create.direct
            var sParaTempToken = new SortedDictionary<string, string>();
            sParaTempToken.Add("partner", Config.Partner);
            sParaTempToken.Add("_input_charset", Config._Charset.ToLower());
            sParaTempToken.Add("sec_id", Config._SignType.ToUpper());
            sParaTempToken.Add("service", "alipay.wap.trade.create.direct");
            sParaTempToken.Add("format", format);
            sParaTempToken.Add("v", v);
            sParaTempToken.Add("req_id", req_id);
            sParaTempToken.Add("req_data", req_dataToken);

            var sHtmlTextToken = BuildRequest(Config._GateWayWap, sParaTempToken);
            var code = Encoding.GetEncoding(Config._Charset);
            sHtmlTextToken = HttpUtility.UrlDecode(sHtmlTextToken, code);
            var dicHtmlTextToken = ParseResponse(sHtmlTextToken);
            var request_token = dicHtmlTextToken["request_token"];

            //根据授权码token调用交易接口alipay.wap.auth.authAndExecute
            var req_data = string.Format("<auth_and_execute_req><request_token>{0}</request_token></auth_and_execute_req>", request_token);
            var sParaTemp = new SortedDictionary<string, string>
                {
                    {"partner", Config.Partner},
                    {"_input_charset", Config._Charset.ToLower()},
                    {"sec_id", Config._SignType.ToUpper()},
                    {"service", "alipay.wap.auth.authAndExecute"},
                    {"format", format},
                    {"v", v},
                    {"req_data", req_data}
                };
            var sHtmlText = BuildRequest(Config._GateWayWap, sParaTemp, "get", "确认");
            HttpContext.Current.Response.Write(sHtmlText);
        }

        /// <summary>
        /// 建立请求,以表单HTML形式构造(默认)
        /// </summary>
        /// <param name="GATEWAY_NEW">支付宝网关地址</param>
        /// <param name="sParaTemp">请求参数数组</param>
        /// <param name="strMethod">提交方式。两个值可选:post、get</param>
        /// <param name="strButtonValue">确认按钮显示文字</param>
        /// <returns>提交表单HTML文本</returns>
        private string BuildRequest(string GATEWAY_NEW, SortedDictionary<string, string> sParaTemp, string strMethod, string strButtonValue)
        {
            var dicPara = BuildRequestPara(sParaTemp);

            var sbHtml = new StringBuilder();
            sbHtml.Append("<form id='alipaysubmit' name='alipaysubmit' action='" + GATEWAY_NEW + "_input_charset=" + Config._Charset + "' method='" + strMethod.ToLower().Trim() + "'>");

            foreach (var temp in dicPara)
            {
                sbHtml.Append("<input type='hidden' name='" + temp.Key + "' value='" + temp.Value + "'/>");
            }

            //submit按钮控件请不要含有name属性
            sbHtml.Append("<input type='submit' value='" + strButtonValue + "' style='display:none;'></form>");

            sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");

            return sbHtml.ToString();
        }


        /// <summary>
        /// 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
        /// </summary>
        /// <param name="gateWayWap">支付宝网关地址</param>
        /// <param name="sParaTemp">请求参数数组</param>
        /// <returns>支付宝处理结果</returns>
        private string BuildRequest(string gateWayWap, SortedDictionary<string, string> sParaTemp)
        {
            var code = Encoding.GetEncoding(Config._Charset);
            var strRequestData = BuildRequestParaToString(sParaTemp,code);
            var bytesRequestData = code.GetBytes(strRequestData);
            var strUrl = string.Format("{0}_input_charset={1}", gateWayWap, Config._Charset);

            string strResult;
            try
            {
                var myReq = (HttpWebRequest)WebRequest.Create(strUrl);
                myReq.Method = "post";
                myReq.ContentType = "application/x-www-form-urlencoded";
                myReq.ContentLength = bytesRequestData.Length;

                var requestStream = myReq.GetRequestStream();
                requestStream.Write(bytesRequestData, 0, bytesRequestData.Length);
                requestStream.Close();

                var HttpWResp = (HttpWebResponse)myReq.GetResponse();
                var myStream = HttpWResp.GetResponseStream();

                var reader = new StreamReader(myStream, code);
                var responseData = new StringBuilder();
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    responseData.Append(line);
                }
                myStream.Close();
                strResult = responseData.ToString();
            }
            catch (Exception exp)
            {
                strResult = "报错:"+exp.Message;
            }
            return strResult;
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        private string BuildRequestParaToString(SortedDictionary<string, string> sParaTemp, Encoding code)
        {
            return Core.CreateLinkStringUrlencode(BuildRequestPara(sParaTemp), code);
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        private Dictionary<string, string> BuildRequestPara(SortedDictionary<string, string> sParaTemp)
        {
            var sPara = Core.FilterPara(sParaTemp);
            var mysign = MD5.Sign(Core.CreateLinkString(sPara), Config.Key, Config._Charset);
            sPara.Add("sign", mysign);
            if (sPara["service"] != "alipay.wap.trade.create.direct" && sPara["service"] != "alipay.wap.auth.authAndExecute")
            {
                sPara.Add("sign_type", Config._SignType);
            }
            return sPara;
        }

        /// <summary>
        /// 解析远程模拟提交后返回的信息
        /// </summary>
        /// <param name="strText">要解析的字符串</param>
        /// <returns>解析结果</returns>
        private Dictionary<string, string> ParseResponse(string strText)
        {
            var strSplitText = strText.Split('&');
            var dicText = new Dictionary<string, string>();
            foreach (string text in strSplitText)
            {
                var nPos = text.IndexOf('=');
                dicText.Add(text.Substring(0, nPos), text.Substring(nPos + 1, text.Length - nPos - 1));
            }

            if (dicText["res_data"] != null)
            {
                //token从res_data中解析出来(也就是说res_data中已经包含token的内容)
                var xmlDoc = new XmlDocument();
                try
                {
                    xmlDoc.LoadXml(dicText["res_data"]);
                    var strRequest_token = xmlDoc.SelectSingleNode("/direct_trade_create_res/request_token").InnerText;
                    dicText.Add("request_token", strRequest_token);
                }
                catch (Exception exp)
                {
                    dicText.Add("request_token", exp.ToString());
                }
            }
            return dicText;
        }
    }
}

Config.cs

using System.Configuration;

namespace Alipay
{
    /// <summary>
    /// 账户配置
    /// 1.登录支付宝网站(www.alipay.com)
    /// 2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm)
    /// 3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)”
    /// </summary>
    public class Config
    {
        /// <summary>
        /// 合作者身份ID
        /// </summary>
        public static string Partner{ internal get; set; }

        /// <summary>
        /// 交易安全校验码
        /// </summary>
        public static string Key { internal get; set; }

        /// <summary>
        /// 卖方(收款方)支付宝账户
        /// </summary>
        public static string SellerEmail { internal get; set; }

        /// <summary>
        /// 字符编码格式:utf-8
        /// </summary>
        internal static string _Charset { get { return "utf-8"; } }

        /// <summary>
        /// 签名方式:MD5
        /// </summary>
        internal static string _SignType { get { return "MD5"; } }

        /// <summary>
        /// 支付宝网关地址pc
        /// </summary>
        internal static string _GateWay { get { return "https://mapi.alipay.com/gateway.do?"; } }

        /// <summary>
        /// 支付宝网关地址wap
        /// </summary>
        internal static string _GateWayWap { get { return "http://wappaygw.alipay.com/service/rest.htm?"; } }

        /// <summary>
        /// 支付宝消息验证地址
        /// </summary>
        internal static string _VeryfyUrl { get { return "https://mapi.alipay.com/gateway.do?service=notify_verify&"; } }

        /// <summary>
        /// 交易方式:即时到账交易pc
        /// </summary>
        internal static string _PayMode { get { return "create_direct_pay_by_user"; } }

        /// <summary>
        /// 支付类型:1
        /// </summary>
        internal static string _PayType { get { return "1"; } }

        /// <summary>
        /// 日志路径:/log/Alipay
        /// </summary>
        internal static string _LogPath { get { return "/log/Alipay"; } }

        /// <summary>
        /// 商户的私钥,如果签名方式设置为“0001”时,请设置该参数
        /// </summary>
        internal static string _PrivateKey { get { return ""; } }

        /// <summary>
        /// 商户的公钥,如果签名方式设置为“0001”时,请设置该参数
        /// </summary>
        internal static string _PublicKey { get { return ""; } }

        static Config()
        {
            if (string.IsNullOrEmpty(Partner))
                Partner = ConfigurationManager.AppSettings["Alipay.Partner"];
            if (string.IsNullOrEmpty(Key))
                Key = ConfigurationManager.AppSettings["Alipay.Key"];
            if (string.IsNullOrEmpty(SellerEmail))
                SellerEmail = ConfigurationManager.AppSettings["Alipay.SellerEmail"];
        }
    }
}

Core.cs

using System.Linq;
using System.Web;
using System.Text;
using System.IO;
using System;
using System.Collections.Generic;
using System.Globalization;

namespace Alipay
{
    internal class Core
    {
        /// <summary>
        /// 除去数组中的空值和签名参数并以字母a到z的顺序排序
        /// </summary>
        internal static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
        {
            return
                dicArrayPre.Where(
                    temp =>
                    temp.Key.ToLower() != "sign" && temp.Key.ToLower() != "sign_type" &&
                    !string.IsNullOrEmpty(temp.Value)).ToDictionary(temp => temp.Key, temp => temp.Value);
        }

        /// <summary>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        /// </summary>
        internal static string CreateLinkString(Dictionary<string, string> dicArray)
        {
            var prestr = new StringBuilder();
            foreach (var temp in dicArray)
            {
                prestr.Append(temp.Key + "=" + temp.Value + "&");
            }
            prestr.Remove(prestr.Length - 1, 1);
            return prestr.ToString();
        }

        /// <summary>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对参数值做urlencode
        /// </summary>
        internal static string CreateLinkStringUrlencode(Dictionary<string, string> dicArray, Encoding code)
        {
            var prestr = new StringBuilder();
            foreach (var temp in dicArray)
            {
                prestr.AppendFormat("{0}={1}&", temp.Key, HttpUtility.UrlEncode(temp.Value, code));
            }
            prestr.Remove(prestr.Length - 1, 1);
            return prestr.ToString();
        }

        /// <summary>
        /// 写日志
        /// </summary>
        internal static void LogResult(string text)
        {
            var strPath = HttpContext.Current.Server.MapPath(Config._LogPath);
            var dateFloderName = DateTime.Now.ToString("yyyyMM");
            strPath = string.Format("{0}/{1}", strPath, dateFloderName);
            if (!Directory.Exists(strPath))
            {
                Directory.CreateDirectory(strPath);
            }
            strPath = strPath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmssffff", DateTimeFormatInfo.InvariantInfo) + ".txt";
            var fs = new StreamWriter(strPath, true, Encoding.Default);
            fs.Write(text);
            fs.Close();
        }

        /// <summary>
        /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
        /// </summary>
        internal static SortedDictionary<string, string> GetRequestPost()
        {
            int i;
            var sArray = new SortedDictionary<string, string>();
            var coll = HttpContext.Current.Request.Form;
            var requestItem = coll.AllKeys;
            for (i = 0; i < requestItem.Length; i++)
                sArray.Add(requestItem[i], HttpContext.Current.Request.Form[requestItem[i]]);
            return sArray;
        }

        /*
        /// <summary>
        /// 获取文件的md5摘要
        /// </summary>
        /// <param name="sFile">文件流</param>
        /// <returns>MD5摘要结果</returns>
        internal static string GetAbstractToMD5(Stream sFile)
        {
            System.Security.Cryptography.MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(sFile);
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x").PadLeft(2, '0'));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获取文件的md5摘要
        /// </summary>
        /// <param name="dataFile">文件流</param>
        /// <returns>MD5摘要结果</returns>
        internal static string GetAbstractToMD5(byte[] dataFile)
        {
            System.Security.Cryptography.MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(dataFile);
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x").PadLeft(2, '0'));
            }
            return sb.ToString();
        }
        */
    }
}

MD5.cs

using System.Text;
using System.Security.Cryptography;

namespace Alipay
{
    internal sealed class MD5
    {
        /// <summary>
        /// 签名字符串
        /// </summary>
        /// <param name="str">需要签名的字符串</param>
        /// <param name="key">**</param>
        /// <param name="charset">编码格式</param>
        /// <returns>签名结果</returns>
        internal static string Sign(string str, string key, string charset)
        {
            var sb = new StringBuilder(32);
            str += key;
            var md5 = new MD5CryptoServiceProvider();
            var t = md5.ComputeHash(Encoding.GetEncoding(charset).GetBytes(str));
            for (var i = 0; i < t.Length; i++)
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
            return sb.ToString();
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="prestr">需要签名的字符串</param>
        /// <param name="sign">签名结果</param>
        /// <param name="key">**</param>
        /// <param name="charset">编码格式</param>
        /// <returns>验证结果</returns>
        internal static bool Verify(string prestr, string sign, string key, string charset)
        {
            var mysign = Sign(prestr, key, charset);
            return mysign == sign;
        }
    }
}

Notify.cs

Notify.cs

using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;

namespace Alipay
{
    /// <summary>
    /// 处理支付宝各接口通知返回
    /// </summary>
    internal class Notify
    {
        /// <summary>
        /// 验证消息是否是支付宝发出的合法消息
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <param name="notifyId">通知验证ID</param>
        /// <param name="sign">支付宝生成的签名结果</param>
        /// <returns>验证结果</returns>
        internal bool Verify(SortedDictionary<string, string> inputPara, string notifyId, string sign)
        {
            var isSign = GetSignVeryfy(inputPara, sign);
            var responseTxt = "true";
            if (!string.IsNullOrEmpty(notifyId)) { responseTxt = GetResponseTxt(notifyId); }

            //判断responsetTxt是否为true,isSign是否为true
            //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            //isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
            return responseTxt == "true" && isSign;
        }

        /// <summary>
        /// 获取返回时的签名验证结果
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <param name="sign">对比的签名结果</param>
        /// <returns>签名验证结果</returns>
        private bool GetSignVeryfy(SortedDictionary<string, string> inputPara, string sign)
        {
            var sPara = Core.FilterPara(inputPara); //过滤空值、sign与sign_type参数
            var preSignStr = Core.CreateLinkString(sPara); //获取待签名字符串
            return MD5.Verify(preSignStr, sign, Config.Key, Config._Charset);
        }

        /// <summary>
        /// 获取是否是支付宝服务器发来的请求的验证结果
        /// </summary>
        /// <param name="notifyId">通知验证ID</param>
        /// <returns>验证结果</returns>
        private string GetResponseTxt(string notifyId)
        {
            var veryfyUrl = string.Format("{0}partner={1}¬ify_id={2}", Config._VeryfyUrl, Config.Partner, notifyId);

            //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
            try
            {
                var myReq = (HttpWebRequest)WebRequest.Create(veryfyUrl);
                myReq.Timeout = 120000;
                var HttpWResp = (HttpWebResponse)myReq.GetResponse();
                var myStream = HttpWResp.GetResponseStream();
                var sr = new StreamReader(myStream, Encoding.Default);
                var strBuilder = new StringBuilder();
                while (-1 != sr.Peek())
                {
                    strBuilder.Append(sr.ReadLine());
                }
                return strBuilder.ToString();
            }
            catch (Exception exp)
            {
                return string.Format("错误:{0}", exp.Message);
            }
        }
    }
}

PC端的NotifyPage.cs

PC端的NotifyPage.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace Alipay
{
    /// <summary>
    /// pc网页支付接口接入页
    /// </summary>
    public abstract class NotifyPage : System.Web.UI.Page
    {
        /// <summary>
        /// 商户订单号
        /// </summary>
        protected string OrderNo { get; private set; }

        /// <summary>
        /// 支付宝交易号
        /// </summary>
        protected string TradeNo { get; private set; }

        /// <summary>
        /// 交易状态
        /// </summary>
        protected string TradeStatus { get; private set; }

        /// <summary>
        /// 业务逻辑处理
        /// </summary>
        protected abstract void OnNotifyConfirm();

        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack) return;
            var sPara = GetRequestPost();
            Core.LogResult(Request.Url.ToString());

            if (sPara.Count > 0) //判断是否有带返回参数
            {
                var formString = Request.Form.Keys.Cast<string>()
                                        .Aggregate("", (current, key) =>
                                                   current + string.Format("{0} = {1}\r\n", key.PadLeft(30, ' '),
                                                                 Request.Form[key]));
                Core.LogResult(formString);

                var aliNotify = new Notify();
                var verifyResult = aliNotify.Verify(sPara, Request.Form["notify_id"], Request.Form["sign"]);
                if (verifyResult)//验证成功
                {
                    OrderNo = Request.Form["out_trade_no"];
                    TradeNo = Request.Form["trade_no"];
                    TradeStatus = Request.Form["trade_status"];

                    //该种交易状态只在一种情况下出现——开通了高级即时到账,买家付款成功后。
                    if (TradeStatus == "TRADE_FINISHED" || TradeStatus == "TRADE_SUCCESS")
                    {
                        OnNotifyConfirm(); //业务逻辑处理
                        Core.LogResult(string.Format("业务逻辑处理,OrderNo:{0},TradeNo:{1},TradeStatus:{2}", OrderNo, TradeNo, TradeStatus));
                    }
                    Response.Write("success");
                }
                else
                {
using System;
using System.Linq;
using System.Xml;

namespace Alipay.Wap
{
    /// <summary>
    /// 手机网页支付接口接入页
    /// </summary>
    public abstract class NotifyPage : System.Web.UI.Page
    {
        /// <summary>
        /// 商户订单号
        /// </summary>
        protected string OrderNo { get; private set; }

        /// <summary>
        /// 支付宝交易号
        /// </summary>
        protected string TradeNo { get; private set; }

        /// <summary>
        /// 交易状态
        /// </summary>
        protected string TradeStatus { get; private set; }

        /// <summary>
        /// 业务逻辑处理
        /// </summary>
        protected abstract void OnNotifyConfirm();


        protected bool PaySucceed = false;
        protected string PayMsg = "";

        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack) return;
            var sPara = Core.GetRequestPost();
            Core.LogResult(Request.Url.ToString());

            if (sPara.Count > 0) //判断是否有带返回参数
            {
                var formString = Request.Form.Keys.Cast<string>()
                                        .Aggregate("", (current, key) =>
                                                   current + string.Format("{0} = {1}\r\n", key.PadLeft(30, ' '),
                                                                 Request.Form[key]));
                Core.LogResult(formString);

                var aliNotify = new Alipay.Notify();
                var verifyResult = aliNotify.Verify(sPara, Request.Form["notify_id"], Request.Form["sign"]);

                if (verifyResult) //验证成功
                {
                    try
                    {
                        var xmlDoc = new XmlDocument();
                        xmlDoc.LoadXml(sPara["notify_data"]);

                        OrderNo = xmlDoc.SelectSingleNode("/notify/out_trade_no").InnerText; //商户订单号
                        TradeNo = xmlDoc.SelectSingleNode("/notify/trade_no").InnerText; //支付宝交易号
                        TradeStatus = xmlDoc.SelectSingleNode("/notify/trade_status").InnerText; //交易状态

                        //该种交易状态只在两种情况下出现
                        //1、开通了普通即时到账,买家付款成功后。
                        //2、开通了高级即时到账,从该笔交易成功时间算起,过了签约时的可退款时限(如:三个月以内可退款、一年以内可退款等)后
                        if (TradeStatus == "TRADE_FINISHED" || TradeStatus == "TRADE_SUCCESS")
                        {
                            try
                            {
                                OnNotifyConfirm();
                                Core.LogResult(string.Format("业务逻辑处理,OrderNo:{0},TradeNo:{1},TradeStatus:{2}", OrderNo, TradeNo, TradeStatus));
                                Response.Write("success");
                            }
                            catch
                            {
                            }
                        }
                        else
                        {
                            Response.Write(TradeStatus);
                        }
                    }
                    catch (Exception exc)
                    {
                        Response.Write(exc.ToString());
                    }
                }
                else //验证失败
                {
                    Response.Write("fail");
                }
            }
            else
            {
                Response.Write("无返回参数");
            }
        }
    }
}

Response.Write("fail"); } } else { Response.Write("无返回参数"); } } /// <summary> /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组 /// </summary> private SortedDictionary<string, string> GetRequestPost() { int i; var sArray = new SortedDictionary<string, string>(); var coll = Request.Form; var requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) sArray.Add(requestItem[i], Request.Form[requestItem[i]]); return sArray; } }}

wap端的NotifyPage.cs



相关标签: 支付宝 支付