支付宝支付

对支付宝支付的二次封装,支持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>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&amp;”字符拼接成字符串
        /// </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>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&amp;”字符拼接成字符串,并对参数值做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

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}&notify_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

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
                {
                    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

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("无返回参数");
            }
        }
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值