支付寶、微信支付(.NET)

風靈使發表於2018-09-14

專案結構

這裡寫圖片描述

這裡寫圖片描述

Core

基礎類庫資料夾

Common

BizResult.cs

using AW.Pay.Core.Enum;

namespace AW.Pay.Core.Common
{
    /// <summary>
    ///     HTTP請求返回資訊
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BizResult<T>
    {
        public BizResult(EnumBizCode resultCode = EnumBizCode.Success, string message = "操作成功")
        {
            Code = resultCode;
            Message = message;
        }

        /// <summary>
        ///     編碼
        /// </summary>
        public EnumBizCode Code { get; set; }

        /// <summary>
        ///     返回資訊
        /// </summary>
        public string Message { get; set; } = "";

        /// <summary>
        ///     返回物件
        /// </summary>
        public T ReturnObject { get; set; }
    }
}

Config.cs

using System.Configuration;

namespace AW.Pay.Core
{
    public static class AlipayConfig
    {
        #region Alipay config

        public static string ALIPay_URL = ConfigurationManager.AppSettings["ALIPay_URL"];
        public static string ALIPay_NotifyURL = ConfigurationManager.AppSettings["ALIPay_NotifyURL"];
        public static string ALIPay_ErrorURL = ConfigurationManager.AppSettings["ALIPay_ErrorURL"];
        public static string ALI_PARTER = ConfigurationManager.AppSettings["ALI_PARTER"];
        public static string ALI_KEY = ConfigurationManager.AppSettings["ALI_KEY"];
        public static string ALI_ACCOUNT = ConfigurationManager.AppSettings["ALI_ACCOUNT"];
        public static string CHARTSET = "utf-8"; //固定值
        public static string PAYMENT_TYPE = "1"; //固定值
        public static string ALI_SELLERID = ConfigurationManager.AppSettings["ALI_SELLERID"];
        public static string ALI_SELLEREMAIL = ConfigurationManager.AppSettings["ALI_SELLEREMAIL"];
        public static string ALI_HTTPS_VERYFY_URL = ConfigurationManager.AppSettings["ALI_HTTPS_VERYFY_URL"];

        public static string ALIPay_WAP_SERVICE = ConfigurationManager.AppSettings["ALIPay_WAP_SERVICE"];
        public static string ALIPay_WEB_SERVICE = ConfigurationManager.AppSettings["ALIPay_WEB_SERVICE"];
        public static string ALIPay_MOBILE_SERVICE = ConfigurationManager.AppSettings["ALIPay_MOBILE_SERVICE"];

        public static string ALIPay_RSA_PUBLICKEY = ConfigurationManager.AppSettings["ALIPay_RSA_PUBLICKEY"];
        public static string ALIPay_RSA_PRIVATEKEY = ConfigurationManager.AppSettings["ALIPay_RSA_PRIVATEKEY"];
        public static string ALIPay_RSA_ALI_PUBLICKEY = ConfigurationManager.AppSettings["ALIPay_RSA_ALI_PUBLICKEY"];

        #endregion
    }

    public static class WepayConfig
    {
        public static string WEPAY_CHARTSET = "utf-8";
        public static string WEPAY_PAY_URL = ConfigurationManager.AppSettings["WEPAY_PAY_URL"]; //統一下單URL
        public static string WEPAY_ORDERQUERY_URL = ConfigurationManager.AppSettings["WEPAY_ORDERQUERY_URL"];

        #region 微信開發者平臺(APP支付)

        public static string WEPAY_APP_APPID = ConfigurationManager.AppSettings["WEPAY_MP_APPID"];
        public static string WEPAY_APP_MCH_ID = ConfigurationManager.AppSettings["WEPAY_MP_MCH_ID"];
        public static string WEPAY_APP_NOTIFY_URL = ConfigurationManager.AppSettings["WEPAY_MP_NOTIFY_URL"];
        public static string WEPAY_APP_URL = ConfigurationManager.AppSettings["WEPAY_MP_URL"];
        public static string WEPAY_APP_KEY = ConfigurationManager.AppSettings["WEPAY_APP_KEY"];

        #endregion

        #region 微信公眾平臺(掃碼、公眾號支付)

        public static string WEPAY_WEB_APPID = ConfigurationManager.AppSettings["WEPAY_WEB_APPID"];
        public static string WEPAY_WEB_MCH_ID = ConfigurationManager.AppSettings["WEPAY_WEB_MCH_ID"];
        public static string WEPAY_WEB_NOTIFY_URL = ConfigurationManager.AppSettings["WEPAY_WEB_NOTIFY_URL"];
        public static string WEPAY_WEB_URL = ConfigurationManager.AppSettings["WEPAY_WEB_URL"];
        public static string WEPAY_WEB_KEY = ConfigurationManager.AppSettings["WEPAY_WEB_KEY"];

        #endregion
    }
}

HTTPHelper.cs

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

namespace AW.Pay.Core
{
    public static class HTTPHelper
    {
        public static string Post(string url, string content, string contentType = "application/x-www-form-urlencoded")
        {
            var result = string.Empty;
            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
                    var stringContent = new StringContent(content, Encoding.UTF8);
                    var response = client.PostAsync(url, stringContent).Result;
                    result = response.Content.ReadAsStringAsync().Result;
                }
            }
            catch (Exception e)
            {
                throw new Exception("POST請求錯誤" + e);
            }
            return result;
        }

        public static string Get(string url, int timeout, string contentType = "application/x-www-form-urlencoded")
        {
            var result = string.Empty;
            try
            {
                using (var client = new HttpClient())
                {
                    client.Timeout = new TimeSpan(0, 0, 0, 0, timeout);
                    var response = client.GetAsync(url).Result;
                    result = response.Content.ReadAsStringAsync().Result;
                }
                ;
            }
            catch (Exception e)
            {
                throw new Exception("GET請求錯誤" + e);
            }
            return result;
        }
    }
}

MD5Helper.cs

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

namespace AW.Pay.Core
{
    public sealed class MD5Helper
    {
        public static string Sign(string prestr, string _input_charset)
        {
            var sb = new StringBuilder(32);
            MD5 md5 = new MD5CryptoServiceProvider();
            var t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
            for (var i = 0; i < t.Length; i++)
            {
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
            }

            return sb.ToString();
        }
    }
}

RSAFromPkcs8.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace AW.Pay.Core
{
    public sealed class RSAFromPkcs8
    {
        /// <summary>
        ///     簽名
        /// </summary>
        /// <param name="content">需要簽名的內容</param>
        /// <param name="privateKey">私鑰</param>
        /// <param name="input_charset">編碼格式</param>
        /// <returns></returns>
        public static string sign(string content, string privateKey, string input_charset)
        {
            var code = Encoding.GetEncoding(input_charset);
            var Data = code.GetBytes(content);
            var rsa = DecodePemPrivateKey(privateKey);
            SHA1 sh = new SHA1CryptoServiceProvider();


            var signData = rsa.SignData(Data, sh);
            return Convert.ToBase64String(signData);
        }

        /// <summary>
        ///     驗證簽名
        /// </summary>
        /// <param name="content">需要驗證的內容</param>
        /// <param name="signedString">簽名結果</param>
        /// <param name="publicKey">公鑰</param>
        /// <param name="input_charset">編碼格式</param>
        /// <returns></returns>
        public static bool verify(string content, string signedString, string publicKey, string input_charset)
        {
            var result = false;

            var code = Encoding.GetEncoding(input_charset);
            var Data = code.GetBytes(content);
            var data = Convert.FromBase64String(signedString);
            var paraPub = ConvertFromPublicKey(publicKey);
            var rsaPub = new RSACryptoServiceProvider();
            rsaPub.ImportParameters(paraPub);

            SHA1 sh = new SHA1CryptoServiceProvider();
            result = rsaPub.VerifyData(Data, sh, data);
            return result;
        }

        /// <summary>
        ///     用RSA解密
        /// </summary>
        /// <param name="resData">待解密字串</param>
        /// <param name="privateKey">私鑰</param>
        /// <param name="input_charset">編碼格式</param>
        /// <returns>解密結果</returns>
        public static string decryptData(string resData, string privateKey, string input_charset)
        {
            var DataToDecrypt = Convert.FromBase64String(resData);
            var result = new List<byte>();

            for (var j = 0; j < DataToDecrypt.Length / 128; j++)
            {
                var buf = new byte[128];
                for (var i = 0; i < 128; i++)
                {
                    buf[i] = DataToDecrypt[i + 128 * j];
                }
                result.AddRange(decrypt(buf, privateKey, input_charset));
            }
            var source = result.ToArray();
            var asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];
            Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);
            return new string(asciiChars);
        }

        private static byte[] decrypt(byte[] data, string privateKey, string input_charset)
        {
            var rsa = DecodePemPrivateKey(privateKey);
            SHA1 sh = new SHA1CryptoServiceProvider();
            return rsa.Decrypt(data, false);
        }

        /// <summary>
        ///     解析java生成的pem檔案私鑰
        /// </summary>
        /// <param name="pemstr"></param>
        /// <returns></returns>
        private static RSACryptoServiceProvider DecodePemPrivateKey(string pemstr)
        {
            byte[] pkcs8privatekey;
            pkcs8privatekey = Convert.FromBase64String(pemstr);
            if (pkcs8privatekey != null)
            {
                var rsa = DecodePrivateKeyInfo(pkcs8privatekey);
                return rsa;
            }
            return null;
        }

        private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
        {
            byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
            var seq = new byte[15];

            var mem = new MemoryStream(pkcs8);
            var lenstream = (int)mem.Length;
            var binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
            byte bt = 0;
            ushort twobytes = 0;

            try
            {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte(); //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16(); //advance 2 bytes
                else
                    return null;


                bt = binr.ReadByte();
                if (bt != 0x02)
                    return null;

                twobytes = binr.ReadUInt16();

                if (twobytes != 0x0001)
                    return null;

                seq = binr.ReadBytes(15); //read the Sequence OID
                if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct
                    return null;

                bt = binr.ReadByte();
                if (bt != 0x04) //expect an Octet string 
                    return null;

                bt = binr.ReadByte(); //read next byte, or next 2 bytes is  0x81 or 0x82; otherwise bt is the byte count
                if (bt == 0x81)
                    binr.ReadByte();
                else if (bt == 0x82)
                    binr.ReadUInt16();
                //------ at this stage, the remaining sequence should be the RSA private key

                var rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));
                var rsacsp = DecodeRSAPrivateKey(rsaprivkey);
                return rsacsp;
            }

            catch (Exception)
            {
                return null;
            }

            finally
            {
                binr.Close();
            }
        }


        private static bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            var i = 0;
            foreach (var c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }

        private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
        {
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
            var mem = new MemoryStream(privkey);
            var binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
            byte bt = 0;
            ushort twobytes = 0;
            var elems = 0;
            try
            {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte(); //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16(); //advance 2 bytes
                else
                    return null;

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102) //version number
                    return null;
                bt = binr.ReadByte();
                if (bt != 0x00)
                    return null;


                //------  all private key components are Integer sequences ----
                elems = GetIntegerSize(binr);
                MODULUS = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                E = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                D = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                P = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                Q = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DP = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DQ = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                IQ = binr.ReadBytes(elems);

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                var RSA = new RSACryptoServiceProvider();
                var RSAparams = new RSAParameters();
                RSAparams.Modulus = MODULUS;
                RSAparams.Exponent = E;
                RSAparams.D = D;
                RSAparams.P = P;
                RSAparams.Q = Q;
                RSAparams.DP = DP;
                RSAparams.DQ = DQ;
                RSAparams.InverseQ = IQ;
                RSA.ImportParameters(RSAparams);
                return RSA;
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                binr.Close();
            }
        }

        private static int GetIntegerSize(BinaryReader binr)
        {
            byte bt = 0;
            byte lowbyte = 0x00;
            byte highbyte = 0x00;
            var count = 0;
            bt = binr.ReadByte();
            if (bt != 0x02) //expect integer
                return 0;
            bt = binr.ReadByte();

            if (bt == 0x81)
                count = binr.ReadByte(); // data size in next byte
            else if (bt == 0x82)
            {
                highbyte = binr.ReadByte(); // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt; // we already have the data size
            }


            while (binr.ReadByte() == 0x00)
            {
                //remove high order zeros in data
                count -= 1;
            }
            binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
            return count;
        }

        #region 解析.net 生成的Pem

        private static RSAParameters ConvertFromPublicKey(string pemFileConent)
        {
            var keyData = Convert.FromBase64String(pemFileConent);
            if (keyData.Length < 162)
            {
                throw new ArgumentException("pem file content is incorrect.");
            }
            var pemModulus = new byte[128];
            var pemPublicExponent = new byte[3];
            Array.Copy(keyData, 29, pemModulus, 0, 128);
            Array.Copy(keyData, 159, pemPublicExponent, 0, 3);
            var para = new RSAParameters();
            para.Modulus = pemModulus;
            para.Exponent = pemPublicExponent;
            return para;
        }

        private static RSAParameters ConvertFromPrivateKey(string pemFileConent)
        {
            var keyData = Convert.FromBase64String(pemFileConent);
            if (keyData.Length < 609)
            {
                throw new ArgumentException("pem file content is incorrect.");
            }

            var index = 11;
            var pemModulus = new byte[128];
            Array.Copy(keyData, index, pemModulus, 0, 128);

            index += 128;
            index += 2; //141
            var pemPublicExponent = new byte[3];
            Array.Copy(keyData, index, pemPublicExponent, 0, 3);

            index += 3;
            index += 4; //148
            var pemPrivateExponent = new byte[128];
            Array.Copy(keyData, index, pemPrivateExponent, 0, 128);

            index += 128;
            index += (int)keyData[index + 1] == 64 ? 2 : 3; //279
            var pemPrime1 = new byte[64];
            Array.Copy(keyData, index, pemPrime1, 0, 64);

            index += 64;
            index += (int)keyData[index + 1] == 64 ? 2 : 3; //346
            var pemPrime2 = new byte[64];
            Array.Copy(keyData, index, pemPrime2, 0, 64);

            index += 64;
            index += (int)keyData[index + 1] == 64 ? 2 : 3; //412/413
            var pemExponent1 = new byte[64];
            Array.Copy(keyData, index, pemExponent1, 0, 64);

            index += 64;
            index += (int)keyData[index + 1] == 64 ? 2 : 3; //479/480
            var pemExponent2 = new byte[64];
            Array.Copy(keyData, index, pemExponent2, 0, 64);

            index += 64;
            index += (int)keyData[index + 1] == 64 ? 2 : 3; //545/546
            var pemCoefficient = new byte[64];
            Array.Copy(keyData, index, pemCoefficient, 0, 64);

            var para = new RSAParameters();
            para.Modulus = pemModulus;
            para.Exponent = pemPublicExponent;
            para.D = pemPrivateExponent;
            para.P = pemPrime1;
            para.Q = pemPrime2;
            para.DP = pemExponent1;
            para.DQ = pemExponent2;
            para.InverseQ = pemCoefficient;
            return para;
        }

        #endregion
    }
}

Enum

列舉類資料夾

EnumAliPayTradeType.cs

namespace AW.Pay.Core
{
    /// <summary>
    ///     AliPay交易型別
    /// </summary>
    public enum EnumAliPayTradeType
    {
        /// <summary>
        ///     網站支付
        /// </summary>
        Website = 0,

        /// <summary>
        ///     wap支付
        /// </summary>
        Wap,

        /// <summary>
        ///     APP支付
        /// </summary>
        APP
    }
}

EnumBizCode.cs

namespace AW.Pay.Core.Enum
{
    /// <summary>
    ///     業務返回code
    /// </summary>
    public enum EnumBizCode
    {
        /// <summary>
        ///     成功
        /// </summary>
        Success = 1000,

        /// <summary>
        ///     失敗
        /// </summary>
        Failed
    }
}

EnumSignType.cs

namespace AW.Pay.Core
{
    public enum EnumSignType
    {
        /// <summary>
        ///     MD5
        /// </summary>
        MD5 = 0,

        /// <summary>
        ///     RSA
        /// </summary>
        RSA
    }
}

EnumWePayTradeType.cs

namespace AW.Pay.Core.Enum
{
    public enum EnumWePayTradeType
    {
        /// <summary>
        ///     公眾號支付
        /// </summary>
        JSAPI = 0,

        /// <summary>
        ///     原生掃碼支付
        /// </summary>
        NATIVE,

        /// <summary>
        ///     app支付
        /// </summary>
        APP,

        /// <summary>
        ///     wap支付(瀏覽器呼叫微信app,目前騰訊還未對外開放)
        /// </summary>
        WAP
    }
}

Interface

IAlipay.cs

using System.Web;
using AW.Pay.Core.Model;

namespace AW.Pay.Core.Interface
{
    public interface IAlipay
    {
        /// <summary>
        ///     建立支付寶支付
        /// </summary>
        /// <param name="orderNo">訂單號</param>
        /// <param name="subject">標題</param>
        /// <param name="payAmount">支付金額</param>
        /// <param name="tradeType">交易型別(網站支付、wap支付、APP支付)</param>
        /// <returns></returns>
        string BuildAliPay(string orderNo, string subject, decimal payAmount, EnumAliPayTradeType tradeType);

        /// <summary>
        ///     驗證支付寶回撥,並獲取相關返回引數
        /// </summary>
        /// <param name="request">HTTP請求</param>
        /// <param name="model">當驗證成功後,獲取主要返回引數</param>
        /// <returns>驗證結果</returns>
        bool VerifyReturnURL(HttpRequestBase request, out AliPayReturnModel model);

        /// <summary>
        ///     驗證支付寶非同步通知,並獲取相關返回引數
        /// </summary>
        /// <param name="request">HTTP請求</param>
        /// <param name="model">當驗證成功後,獲取主要返回引數</param>
        /// <returns>驗證結果</returns>
        bool VerfyNotify(HttpRequestBase request, out AliPayReturnModel model);
    }
}

IWePay.cs

using System.Web;
using AW.Pay.Core.Enum;
using AW.Pay.Core.Model;

namespace AW.Pay.Core.Interface
{
    public interface IWePay
    {
        /// <summary>
        ///     建立微信支付
        /// </summary>
        /// <param name="orderNo">訂單號</param>
        /// <param name="productName">產品名稱</param>
        /// <param name="totalFee">總金額,單位分</param>
        /// <param name="customerIP">呼叫IP</param>
        /// <param name="tradeType">交易型別(公眾號支付、掃碼支付、APP、WAP支付)</param>
        /// <returns>
        ///     掃碼支付:返回支付URL
        ///     APP支付:返回Json字串,包含支付sdk支付引數
        ///     公眾號支付&WAP支付:暫未實現
        /// </returns>
        string BuildWePay(string orderNo, string productName, int totalFee, string customerIP,
            EnumWePayTradeType tradeType);

        /// <summary>
        ///     微信支付非同步通知驗證
        /// </summary>
        /// <param name="request">HTTP請求</param>
        /// <param name="model">當驗證成功後,獲取主要返回引數</param>
        /// <returns>驗證結果</returns>
        bool VerifyNotify(HttpRequestBase request, out WePayReturnModel model);
    }
}

Model

AliPayReturnModel.cs

namespace AW.Pay.Core.Model
{
    public class AliPayReturnModel
    {
        /// <summary>
        ///     商戶訂單號
        /// </summary>
        public string OutTradeNo { get; set; }

        /// <summary>
        ///     交易訂單號
        /// </summary>
        public string TradeNo { get; set; }

        /// <summary>
        ///     交易總金額
        /// </summary>
        public decimal TotalFee { get; set; }

        /// <summary>
        ///     交易狀態
        /// </summary>
        public string TradeStatus { get; set; }
    }
}

WePayReturnModel.cs

namespace AW.Pay.Core.Model
{
    public class WePayReturnModel
    {
        /// <summary>
        ///     商戶訂單號
        /// </summary>
        public string OutTradeNo { get; set; }

        /// <summary>
        ///     交易訂單號
        /// </summary>
        public string TradeNo { get; set; }

        /// <summary>
        ///     交易金額(單位元)
        /// </summary>
        public decimal TotalFee { get; set; }

        /// <summary>
        ///     交易狀態
        /// </summary>
        public string TradeStatus { get; set; }

        /// <summary>
        ///     返回xml
        /// </summary>
        public string ReturnXml { get; set; }
    }
}

類庫根目錄

AliPay.cs

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;

namespace AW.Pay.Core
{
    public class AliPay : IAlipay
    {
        public string BuildAliPay(string orderNo, string subject, decimal payAmount, EnumAliPayTradeType tradeType)
        {
            return BuildRequest(orderNo, subject, payAmount, tradeType);
        }

        public bool VerifyReturnURL(HttpRequestBase request, out AliPayReturnModel model)
        {
            var requestVal = request.QueryString;
            return Verify(request, requestVal, out model);
        }

        public bool VerfyNotify(HttpRequestBase request, out AliPayReturnModel model)
        {
            var requestVal = request.Form;
            return Verify(request, requestVal, out model);
        }

        #region private method

        private bool Verify(HttpRequestBase request, NameValueCollection requestVal, out AliPayReturnModel model)
        {
            var result = false;
            var sortedDic = new SortedDictionary<string, string>();
            foreach (var item in requestVal.AllKeys)
            {
                if (item.ToLower() != "sign" && item.ToLower() != "sign_type" && !string.IsNullOrEmpty(item))
                    sortedDic.Add(item, requestVal[item]);
            }

            var requestSign = requestVal["sign"];
            var requestSigntype = requestVal["sign_type"];
            var param = CreateURLParamString(sortedDic);

            var signType = requestSigntype == "MD5"
                ? EnumSignType.MD5
                : requestSigntype == "RSA"
                    ? EnumSignType.RSA
                    : EnumSignType.MD5;

            if (signType == EnumSignType.MD5)
            {
                var sign = BuildRequestsign(param, signType);
                if (requestSign.Equals(sign))
                    result = true;
            }
            else
                result = RSAFromPkcs8.verify(param, requestSign, AlipayConfig.ALIPay_RSA_ALI_PUBLICKEY, "utf-8");

            var responseText = GetResponseTxt(requestVal["notify_id"]);

            var resultVal = result && responseText == "true";
            if (resultVal)
            {
                model = new AliPayReturnModel
                {
                    OutTradeNo = request.Form["out_trade_no"],
                    TradeNo = request.Form["trade_no"],
                    TradeStatus = request.Form["trade_status"]
                };

                decimal total_fee;
                decimal.TryParse(request.Form["total_fee"], out total_fee);
                model.TotalFee = total_fee;
            }
            else
                model = null;

            return resultVal;
        }

        private string BuildRequest(string orderNo, string subject, decimal totalAmt, EnumAliPayTradeType aliPayType)
        {
            var signType = aliPayType == EnumAliPayTradeType.APP ? EnumSignType.RSA : EnumSignType.MD5;

            var dicParam = CreateParam(orderNo, subject, totalAmt, aliPayType);
            var urlParam = CreateURLParamString(dicParam, aliPayType);

            var sign = BuildRequestsign(urlParam, signType);
            dicParam.Add("sign_type", signType.ToString());

            if (aliPayType == EnumAliPayTradeType.APP)
            {
                //APP支付URL欄位須進行URL編碼,具體出處參看官方文件
                sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);
                return urlParam + "&sign=\"" + sign + "\"&sign_type=\"" + signType + "\"";
            }
            dicParam.Add("sign", sign);
            return BuildForm(dicParam);
        }

        private string BuildForm(SortedDictionary<string, string> dicParam)
        {
            var sbHtml = new StringBuilder();
            sbHtml.Append("<form id='alipaysubmit' name='alipaysubmit' action='" + AlipayConfig.ALIPay_URL +
                          "_input_charset=" + AlipayConfig.CHARTSET + "' method='get'>");

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

            sbHtml.Append("<input type='submit' value='確認' style='display:none;'></form>");
            sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");
            return sbHtml.ToString();
        }

        private SortedDictionary<string, string> CreateParam(string orderNo, string subject, decimal totalAmt,
            EnumAliPayTradeType aliPayType)
        {
            var dic = new SortedDictionary<string, string>();

            #region BASEPARAM

            var service = aliPayType == EnumAliPayTradeType.Website
                ? AlipayConfig.ALIPay_WEB_SERVICE
                : aliPayType == EnumAliPayTradeType.Wap
                    ? AlipayConfig.ALIPay_WAP_SERVICE
                    : aliPayType == EnumAliPayTradeType.APP
                        ? AlipayConfig.ALIPay_MOBILE_SERVICE
                        : "";

            dic.Add("service", service);
            dic.Add("partner", AlipayConfig.ALI_PARTER);
            dic.Add("_input_charset", AlipayConfig.CHARTSET);
            dic.Add("notify_url", AlipayConfig.ALIPay_NotifyURL);

            //dic.Add("sign_type", SIGNTYPE); 

            #endregion

            #region BIZPARAM

            dic.Add("out_trade_no", orderNo);
            dic.Add("subject", subject);
            dic.Add("payment_type", AlipayConfig.PAYMENT_TYPE);
            dic.Add("total_fee", totalAmt.ToString("F2"));
            //dic.Add("seller_email", ALI_SELLEREMAIL);
            dic.Add("seller_id", AlipayConfig.ALI_SELLERID);
            //dic.Add("anti_phishing_key", anti_phishing_key);//防釣魚時間戳,如果已申請開通防釣魚證,則此欄位必填。
            //dic.Add("exter_invoke_ip", exter_invoke_ip);//客戶端 IP ,如果商戶申請後臺開通防釣魚 IP地址檢查選項,此欄位必填,校驗用。 

            #endregion

            if (aliPayType == EnumAliPayTradeType.APP)
                dic.Add("body", subject + "購買");

            return dic;
        }

        private string CreateURLParamString(SortedDictionary<string, string> dicArray,
            EnumAliPayTradeType type = EnumAliPayTradeType.Website)
        {
            var prestr = new StringBuilder();
            foreach (var temp in dicArray.OrderBy(o => o.Key))
            {
                if (type == EnumAliPayTradeType.APP)
                    prestr.Append(temp.Key + "=\"" + temp.Value + "\"&");
                else
                    prestr.Append(temp.Key + "=" + temp.Value + "&");
            }

            var nLen = prestr.Length;
            prestr.Remove(nLen - 1, 1);
            return prestr.ToString();
        }

        private string BuildRequestsign(string urlParam, EnumSignType signType)
        {
            var mysign = "";

            if (signType == EnumSignType.MD5)
            {
                var preString = urlParam + AlipayConfig.ALI_KEY;
                mysign = MD5Helper.Sign(preString, AlipayConfig.CHARTSET);
            }
            else if (signType == EnumSignType.RSA)
                mysign = RSASign(urlParam, AlipayConfig.ALIPay_RSA_PRIVATEKEY, AlipayConfig.CHARTSET);

            return mysign;
        }

        private string RSASign(string prestr, string privateKey, string input_charset)
        {
            try
            {
                return RSAFromPkcs8.sign(prestr, privateKey, input_charset);
            }
            catch (Exception e)
            {
                return e.Message;
            }
        }

        private string GetResponseTxt(string notify_id)
        {
            var veryfy_url = AlipayConfig.ALI_HTTPS_VERYFY_URL + "&partner=" + AlipayConfig.ALI_PARTER + "&notify_id=" +
                             notify_id;
            var response = HTTPHelper.Get(veryfy_url, 120000);
            return response;
        }

        #endregion
    }
}

WePay.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml;
using AW.Pay.Core.Enum;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;
using Newtonsoft.Json;

namespace AW.Pay.Core
{
    public class WePay : IWePay
    {
        public string BuildWePay(string orderNo, string productName, int totalFee, string customerIP,
            EnumWePayTradeType tradeType)
        {
            return UnifiedOrder(orderNo, productName, totalFee, customerIP, tradeType);
        }

        public bool VerifyNotify(HttpRequestBase request, out WePayReturnModel model)
        {
            var verifyResult = false;
            model = new WePayReturnModel();

            var requestXml = GetRequestXmlData(request);
            var dic = FromXml(requestXml);

            var returnCode = GetValueFromDic<string>(dic, "return_code");

            if (!string.IsNullOrEmpty(returnCode) && returnCode == "SUCCESS") //通訊成功
            {
                var result = WePayNotifyValidation(dic);
                if (result)
                {
                    var transactionid = GetValueFromDic<string>(dic, "transaction_id");

                    if (!string.IsNullOrEmpty(transactionid))
                    {
                        var queryXml = BuildQueryRequest(transactionid, dic);
                        var queryResult = HTTPHelper.Post(WepayConfig.WEPAY_ORDERQUERY_URL, queryXml);
                        var queryReturnDic = FromXml(queryResult);

                        if (ValidatonQueryResult(queryReturnDic)) //查詢成功
                        {
                            verifyResult = true;
                            model.OutTradeNo = GetValueFromDic<string>(dic, "out_trade_no");
                            model.TotalFee = GetValueFromDic<decimal>(dic, "total_fee") / 100;
                            model.TradeNo = transactionid;
                            model.TradeStatus = GetValueFromDic<string>(dic, "result_code");
                            model.ReturnXml = BuildReturnXml("OK", "成功");
                        }
                        else
                            model.ReturnXml = BuildReturnXml("FAIL", "訂單查詢失敗");
                    }
                    else
                        model.ReturnXml = BuildReturnXml("FAIL", "支付結果中微信訂單號不存在");
                }
                else
                    model.ReturnXml = BuildReturnXml("FAIL", "簽名失敗");
            }
            else
            {
                string returnmsg;
                dic.TryGetValue("return_msg", out returnmsg);
                throw new Exception("非同步通知錯誤:" + returnmsg);
            }

            return verifyResult;
        }

        #region private method

        /// <summary>
        ///     統一下單
        /// </summary>
        /// <returns></returns>
        private string UnifiedOrder(string orderNo, string productName, int totalFee, string customerIP,
            EnumWePayTradeType tradeType)
        {
            var requestXml = BuildRequest(orderNo, productName, totalFee, customerIP, tradeType);
            var resultXml = HTTPHelper.Post(WepayConfig.WEPAY_PAY_URL, requestXml);

            var dic = FromXml(resultXml);

            var returnCode = "";
            dic.TryGetValue("return_code", out returnCode);

            if (returnCode == "SUCCESS")
            {
                if (tradeType == EnumWePayTradeType.APP)
                {
                    var prepay_id = GetValueFromDic<string>(dic, "prepay_id");
                    if (!string.IsNullOrEmpty(prepay_id))
                        return BuildAppPay(prepay_id);
                    throw new Exception("支付錯誤:" + GetValueFromDic<string>(dic, "err_code_des"));
                }
                if (tradeType == EnumWePayTradeType.NATIVE)
                {
                    var codeUrl = "";
                    dic.TryGetValue("code_url", out codeUrl);
                    if (!string.IsNullOrEmpty(codeUrl))
                        return codeUrl;
                    throw new Exception("未找到對應的二維碼連結");
                }
                throw new Exception("JSAPI & WAP 未實現");
            }
            throw new Exception("後臺統一下單失敗");
        }

        private string BuildRequest(string orderNo, string productName, int totalFee, string customerIP,
            EnumWePayTradeType tradeType)
        {
            var dicParam = CreateParam(orderNo, productName, totalFee, customerIP, tradeType);

            var signString = CreateURLParamString(dicParam);
            var key = tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY;
            var preString = signString + "&key=" + key;
            var sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper();
            dicParam.Add("sign", sign);

            return BuildForm(dicParam);
        }

        private static SortedDictionary<string, string> CreateParam(string orderNo, string productName, decimal totalFee,
            string customerIP, EnumWePayTradeType tradeType)
        {
            var dic = new SortedDictionary<string, string>();
            dic.Add("appid",
                tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID); //賬號ID
            dic.Add("mch_id",
                tradeType == EnumWePayTradeType.APP ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID);
            //商戶號
            dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
            dic.Add("body", productName); //商品描述
            dic.Add("out_trade_no", orderNo); //商戶訂單號
            dic.Add("total_fee", totalFee.ToString()); //總金額
            dic.Add("spbill_create_ip", customerIP); //終端IP
            dic.Add("notify_url",
                tradeType == EnumWePayTradeType.APP
                    ? WepayConfig.WEPAY_APP_NOTIFY_URL
                    : WepayConfig.WEPAY_WEB_NOTIFY_URL); //通知地址
            dic.Add("trade_type", tradeType.ToString()); //交易型別

            return dic;
        }

        private static string CreateURLParamString(SortedDictionary<string, string> dicArray)
        {
            var prestr = new StringBuilder();
            foreach (var temp in dicArray.OrderBy(o => o.Key))
            {
                prestr.Append(temp.Key + "=" + temp.Value + "&");
            }

            var nLen = prestr.Length;
            prestr.Remove(nLen - 1, 1);
            return prestr.ToString();
        }

        private static string BuildForm(SortedDictionary<string, string> dicParam)
        {
            var sbXML = new StringBuilder();
            sbXML.Append("<xml>");
            foreach (var temp in dicParam)
            {
                sbXML.Append("<" + temp.Key + ">" + temp.Value + "</" + temp.Key + ">");
            }

            sbXML.Append("</xml>");
            return sbXML.ToString();
        }

        private static SortedDictionary<string, string> FromXml(string xml)
        {
            var sortDic = new SortedDictionary<string, string>();
            if (string.IsNullOrEmpty(xml))
            {
                throw new Exception("將空的xml串轉換為WxPayData不合法!");
            }

            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            var xmlNode = xmlDoc.FirstChild; //獲取到根節點<xml>
            var nodes = xmlNode.ChildNodes;
            foreach (XmlNode xn in nodes)
            {
                var xe = (XmlElement)xn;

                if (!sortDic.ContainsKey(xe.Name))
                    sortDic.Add(xe.Name, xe.InnerText);
            }
            return sortDic;
        }

        private static T GetValueFromDic<T>(SortedDictionary<string, string> dic, string key)
        {
            string val;
            dic.TryGetValue(key, out val);

            var returnVal = default(T);
            if (val != null)
                returnVal = (T)Convert.ChangeType(val, typeof(T));

            return returnVal;
        }

        private static string BuildAppPay(string prepayid)
        {
            var dicParam = CreateWapAndAppPayParam(prepayid);
            var signString = CreateURLParamString(dicParam);
            var preString = signString + "&key=" + WepayConfig.WEPAY_APP_KEY;

            var sign = MD5Helper.Sign(preString, WepayConfig.WEPAY_CHARTSET).ToUpper();
            dicParam.Add("sign", sign);

            return JsonConvert.SerializeObject(
                new
                {
                    appid = dicParam["appid"],
                    partnerid = dicParam["partnerid"],
                    prepayid = dicParam["prepayid"],
                    package = dicParam["package"],
                    noncestr = dicParam["noncestr"],
                    timestamp = dicParam["timestamp"],
                    sign = dicParam["sign"]
                });
        }

        private static SortedDictionary<string, string> CreateWapAndAppPayParam(string prepayId)
        {
            var dic = new SortedDictionary<string, string>();
            dic.Add("appid", WepayConfig.WEPAY_APP_APPID); //公眾賬號ID
            dic.Add("partnerid", WepayConfig.WEPAY_APP_MCH_ID); //商戶號
            dic.Add("prepayid", prepayId); //預支付交易會話ID
            dic.Add("package", "Sign=WXPay"); //擴充套件欄位
            dic.Add("noncestr", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
            dic.Add("timestamp",
                Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds).ToString());
            //時間戳

            return dic;
        }

        private string GetRequestXmlData(HttpRequestBase request)
        {
            var stream = request.InputStream;
            var count = 0;
            var buffer = new byte[1024];
            var builder = new StringBuilder();
            while ((count = stream.Read(buffer, 0, 1024)) > 0)
            {
                builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            }
            stream.Flush();
            stream.Close();
            stream.Dispose();

            return builder.ToString();
        }

        public static bool WePayNotifyValidation(SortedDictionary<string, string> dic)
        {
            var sign = GetValueFromDic<string>(dic, "sign");
            if (dic.ContainsKey("sign"))
            {
                dic.Remove("sign");
            }

            var tradeType = GetValueFromDic<string>(dic, "trade_type");
            var preString = CreateURLParamString(dic);

            if (string.IsNullOrEmpty(tradeType))
            {
                var key = tradeType == EnumWePayTradeType.APP.ToString()
                    ? WepayConfig.WEPAY_APP_KEY
                    : WepayConfig.WEPAY_WEB_KEY;
                var preSignString = preString + "&key=" + key;
                var signString = MD5Helper.Sign(preSignString, WepayConfig.WEPAY_CHARTSET).ToUpper();
                return signString == sign;
            }
            return false;
        }

        private static string BuildReturnXml(string code, string returnMsg)
        {
            return
                string.Format(
                    "<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>",
                    code, returnMsg);
        }

        public static string BuildQueryRequest(string transactionId, SortedDictionary<string, string> dic)
        {
            var tradeType = GetValueFromDic<string>(dic, "trade_type");
            var isApp = tradeType == EnumWePayTradeType.APP.ToString();

            var dicParam = CreateQueryParam(transactionId, isApp);
            var signString = CreateURLParamString(dicParam);

            var key = isApp ? WepayConfig.WEPAY_APP_KEY : WepayConfig.WEPAY_WEB_KEY;
            var preString = signString + "&key=" + key;

            var sign = MD5Helper.Sign(preString, "utf-8").ToUpper();
            dicParam.Add("sign", sign);

            return BuildForm(dicParam);
        }

        private static SortedDictionary<string, string> CreateQueryParam(string transactionId, bool isApp)
        {
            var dic = new SortedDictionary<string, string>();
            dic.Add("appid", isApp ? WepayConfig.WEPAY_APP_APPID : WepayConfig.WEPAY_WEB_APPID); //公眾賬號ID
            dic.Add("mch_id", isApp ? WepayConfig.WEPAY_APP_MCH_ID : WepayConfig.WEPAY_WEB_MCH_ID); //商戶號
            dic.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", "")); //隨機字串
            dic.Add("transaction_id", transactionId); //隨機字串
            return dic;
        }

        private static bool ValidatonQueryResult(SortedDictionary<string, string> dic)
        {
            var result = false;

            if (dic.ContainsKey("return_code") && dic.ContainsKey("return_code"))
            {
                if (dic["return_code"] == "SUCCESS" && dic["result_code"] == "SUCCESS")
                    result = true;
            }

            if (!result)
            {
                var sb = new StringBuilder();
                foreach (var item in dic.Keys)
                {
                    sb.Append(item + ":" + dic[item] + "|");
                }
            }

            return result;
        }

        #endregion
    }
}

App.config

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <appSettings>
    <!--支付寶配置-->
    <add key="ALIPay_URL" value="https://mapi.alipay.com/gateway.do?" />
    <add key="ALIPay_NotifyURL" value="" />
    <add key="ALIPay_ErrorURL" value="" />
    <add key="ALI_PARTER" value="" />
    <add key="ALI_KEY" value="" />
    <add key="ALI_ACCOUNT" value="" />

    <add key="ALI_SELLERID" value="" />
    <add key="ALI_SELLEREMAIL" value="" />
    <add key="ALI_HTTPS_VERYFY_URL" value="https://mapi.alipay.com/gateway.do?service=notify_verify" />

    <add key="ALIPay_WAP_SERVICE" value="alipay.wap.create.direct.pay.by.user" />
    <add key="ALIPay_WEB_SERVICE" value="create_direct_pay_by_user" />
    <add key="ALIPay_MOBILE_SERVICE" value="mobile.securitypay.pay" />

    <!--我的私鑰-->
    <add key="ALIPay_RSA_PRIVATEKEY" value="" />
    <!--我的公鑰-->
    <add key="ALIPay_RSA_PUBLICKEY" value="" />
    <!--支付寶公鑰-->
    <add key="ALIPay_RSA_ALI_PUBLICKEY" value="" />

    <!--微信支付配置-->
    <add key="WEPAY_CHARTSET" value="utf-8" />
    <add key="WEPAY_PAY_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
    <add key="WEPAY_ORDERQUERY_URL" value="https://api.mch.weixin.qq.com/pay/orderquery" />
    <add key="WECHAT_AUTH_URL" value="https://open.weixin.qq.com/connect/oauth2/authorize" />
    <add key="WECHAT_TOKEN_URL" value="https://api.weixin.qq.com/sns/oauth2/access_token" />
    <add key="WECHAT_CALLBACKIP_URL" value="https://api.weixin.qq.com/cgi-bin/getcallbackip" />
    <add key="WECHAT_GETTOKEN_URL" value="https://api.weixin.qq.com/cgi-bin/token" />

    <!--開發者平臺配置-->
    <add key="WEPAY_APP_APPID" value="" />
    <add key="WEPAY_APP_MCH_ID" value="" />
    <add key="WEPAY_APP_NOTIFY_URL" value="" />
    <add key="WEPAY_APP_URL" value="" />
    <add key="WEPAY_APP_KEY" value="" />

    <!--公眾號平臺配置-->
    <add key="WEPAY_WEB_APPID" value="" />
    <add key="WEPAY_WEB_MCH_ID" value="" />
    <add key="WEPAY_WEB_NOTIFY_URL" value="" />
    <add key="WEPAY_WEB_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
    <add key="WEPAY_WEB_KEY" value="" />
  </appSettings>
</configuration>

PaymentController.cs

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Mvc;
using AW.Pay.Core.Common;
using AW.Pay.Core.Enum;
using AW.Webapi.Sample.Models.PayModel;

namespace AW.Webapi.Sample.Controllers
{
    public class PaymentController : Controller
    {
        public static HttpClient _client = new HttpClient();
        // GET: Payment
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult AliPayDemo()
        {
            return View();
        }

        public async Task<string> AliPayAsync(AliPayReqParam payInfo)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:8115/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                // HTTP POST
                var gizmo = new AliPayReqParam
                {
                    OrderNo = payInfo.OrderNo,
                    Subject = payInfo.Subject,
                    TotalAmount = payInfo.TotalAmount,
                    Type = 0
                };
                var response = await client.PostAsJsonAsync("api/Payment/CreateAliPayRequestParam", gizmo);
                var resultValue = await response.Content.ReadAsAsync<BizResult<string>>();
                if (resultValue.Code == EnumBizCode.Failed)
                {
                    return string.Empty;
                }
                return resultValue.ReturnObject;
            }
        }

        public ActionResult WePayDemo()
        {
            return View();
        }

        public async Task<ActionResult> WePayAsync(WePayReqParam payInfo)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:8115/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                // HTTP POST
                var gizmo = new WePayReqParam
                {
                    OrderNo = payInfo.OrderNo,
                    ProductName = payInfo.ProductName,
                    CustomerIp = "127.0.0.1",
                    TotalFee = payInfo.TotalFee,
                    TradeType = EnumWePayTradeType.NATIVE
                };
                var response = await client.PostAsJsonAsync("api/Payment/CreateWePayRequestParam", gizmo);
                var resultValue = await response.Content.ReadAsAsync<BizResult<string>>();
                if (resultValue.Code == EnumBizCode.Failed)
                {
                    throw new Exception("微信支付失敗");
                }
                ViewBag.OrderId = payInfo.OrderNo;
                ViewBag.PayAmount = payInfo.TotalFee;
                ViewBag.PayUrl = resultValue.ReturnObject;
                return View("WePay");
            }
        }
    }
}

WePayDemo.cshtml

@model AW.Webapi.Sample.Models.PayModel.WePayReqParam


@{
    ViewBag.Title = "WePayDemo";
}


<h2>WePayDemo</h2>


@using (Html.BeginForm("WePayAsync", "Payment", FormMethod.Get))
{
    <div class="form-horizontal">

        <h4>WePayReqParam</h4>

        <hr />

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">

            @Html.LabelFor(model => model.OrderNo, new { @class = "control-label col-md-2" })
            <div class="col-md-10">

                @Html.EditorFor(model => model.OrderNo, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.OrderNo, "", new { @class = "text-danger" })
            </div>

        </div>


        <div class="form-group">

            @Html.LabelFor(model => model.ProductName, new { @class = "control-label col-md-2" })
            <div class="col-md-10">

                @Html.EditorFor(model => model.ProductName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProductName, "", new { @class = "text-danger" })
            </div>

        </div>


        <div class="form-group">

            @Html.LabelFor(model => model.TotalFee, new { @class = "control-label col-md-2" })
            <div class="col-md-10">

                @Html.EditorFor(model => model.TotalFee, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.TotalFee, "", new { @class = "text-danger" })
            </div>

        </div>


        <div class="form-group">

            <div class="col-md-offset-2 col-md-10">

                <input type="submit" value="Create" class="btn btn-default" />

            </div>

        </div>

    </div>
}


<div>

    @Html.ActionLink("Back to List", "Index")
</div>

WePay.cshtml

@{
    ViewBag.Title = "WePayAsync";
}


<h2>WePayAsync</h2>

<input type="hidden" id="hd_url" value="@ViewBag.PayUrl">

<input type="hidden" value="@ViewBag.OrderId" id="hd_order_id"/>

<div class="weixin-img">

</div>

@section scripts{
    <script src="~/Scripts/jquery.qrcode.min.js"></script>

    <script>
        var weiPay = $('#hd_url').val();
        $('.weixin-img').qrcode({
            render: "canvas", //table方式
            text: weiPay //任意內容
        });
    </script>

}

Areas\Api\Controllers\PaymentController.cs

using System.Web;
using System.Web.Http;
using AW.Pay.Core.Common;
using AW.Pay.Core.Interface;
using AW.Pay.Core.Model;
using AW.Webapi.Sample.Models.PayModel;

namespace AW.Webapi.Sample.Areas.Api.Controllers
{
    public class PaymentController : ApiController
    {
        private readonly IAlipay _aliPay;
        private readonly IWePay _wePay;

        public PaymentController(IAlipay aliPay, IWePay wePay)
        {
            _aliPay = aliPay;
            _wePay = wePay;
        }

        /// <summary>
        ///     生成支付寶請求引數
        /// </summary>
        /// <param name="payInfo"></param>
        /// <returns></returns>
        [HttpPost]
        public BizResult<string> CreateAliPayRequestParam(AliPayReqParam payInfo)
        {
            var biz = new BizResult<string>();
            biz.ReturnObject = _aliPay.BuildAliPay(payInfo.OrderNo, payInfo.Subject, payInfo.TotalAmount, payInfo.Type);
            ;
            return biz;
        }

        /// <summary>
        ///     支付寶支付結果非同步通知
        /// </summary>
        /// <returns>Form表單</returns>
        [HttpPost]
        public void AlipayNotify()
        {
            var payResult = new AliPayReturnModel();
            var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; //獲取傳統context     
            var request = context.Request; //定義傳統request物件
            var result = _aliPay.VerfyNotify(request, out payResult);
        }

        /// <summary>
        ///     生成支付寶請求引數
        /// </summary>
        /// <param name="payInfo"></param>
        /// <returns></returns>
        [HttpPost]
        public BizResult<string> CreateWePayRequestParam(WePayReqParam payInfo)
        {
            var biz = new BizResult<string>();
            biz.ReturnObject = _wePay.BuildWePay(payInfo.OrderNo, payInfo.ProductName, payInfo.TotalFee,
                payInfo.CustomerIp, payInfo.TradeType);
            ;
            return biz;
        }

        /// <summary>
        ///     微信支付支付結果非同步通知
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public void WePayNotify()
        {
            var payResult = new WePayReturnModel();
            var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; //獲取傳統context     
            var request = context.Request; //定義傳統request物件
            var result = _wePay.VerifyNotify(request, out payResult);
        }
    }
}

PayModel

AliPayReqParam.cs

using AW.Pay.Core;

namespace AW.Webapi.Sample.Models.PayModel
{
    public class AliPayReqParam
    {
        public string OrderNo { get; set; }
        public string Subject { get; set; }
        public decimal TotalAmount { get; set; }
        public EnumAliPayTradeType Type { get; set; }
    }
}

WePayReqParam.cs

using AW.Pay.Core.Enum;

namespace AW.Webapi.Sample.Models.PayModel
{
    public class WePayReqParam
    {
        public string OrderNo { get; set; }
        public string ProductName { get; set; }
        public int TotalFee { get; set; }
        public string CustomerIp { get; set; }
        public EnumWePayTradeType TradeType { get; set; }
    }
}

Bootstrapper.cs

using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
using AW.Pay.Core;
using AW.Pay.Core.Interface;

namespace AW.Webapi.Sample.App_Start
{
    public class Bootstrapper
    {
        public static void Run()
        {
            SetAutoFacContainer();
        }

        private static void SetAutoFacContainer()
        {
            var builder = new ContainerBuilder();

            //Get HttpConfiguration
            var config = GlobalConfiguration.Configuration;

            //Register MVC Controller
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

            //Register Web Api Controller
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            //Register Pay Interface
            builder.RegisterType<AliPay>().As<IAlipay>().InstancePerRequest();
            builder.RegisterType<WePay>().As<IWePay>().InstancePerRequest();

            //Set the dependency resolver to be Autofac
            var container = builder.Build();
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container); //Web Api
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); //MVC
        }
    }
}

Global.asax

using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using AW.Webapi.Sample.App_Start;

namespace AW.Webapi.Sample
{
    public class WebApiApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            Bootstrapper.Run();
        }
    }
}

Web.config

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <configSections>
    <section name="entityFramework"
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
             requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="DefaultConnection"
         connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-AW.Webapi.Sample-20160201054737.mdf;Initial Catalog=aspnet-AW.Webapi.Sample-20160201054737;Integrated Security=True"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
  <appSettings>
    <!--支付寶配置-->
    <add key="ALIPay_URL" value="https://mapi.alipay.com/gateway.do?" />
    <add key="ALIPay_NotifyURL" value="" />
    <add key="ALIPay_ErrorURL" value="" />
    <add key="ALI_PARTER" value="" />
    <add key="ALI_KEY" value="" />
    <add key="ALI_ACCOUNT" value="" />

    <add key="ALI_SELLERID" value="" />
    <add key="ALI_SELLEREMAIL" value="" />
    <add key="ALI_HTTPS_VERYFY_URL" value="https://mapi.alipay.com/gateway.do?service=notify_verify" />

    <add key="ALIPay_WAP_SERVICE" value="alipay.wap.create.direct.pay.by.user" />
    <add key="ALIPay_WEB_SERVICE" value="create_direct_pay_by_user" />
    <add key="ALIPay_MOBILE_SERVICE" value="mobile.securitypay.pay" />

    <!--我的私鑰-->
    <add key="ALIPay_RSA_PRIVATEKEY" value="" />
    <!--我的公鑰-->
    <add key="ALIPay_RSA_PUBLICKEY" value="" />
    <!--支付寶公鑰-->
    <add key="ALIPay_RSA_ALI_PUBLICKEY" value="" />

    <!--微信支付配置-->
    <add key="WEPAY_CHARTSET" value="utf-8" />
    <add key="WEPAY_PAY_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
    <add key="WEPAY_ORDERQUERY_URL" value="https://api.mch.weixin.qq.com/pay/orderquery" />
    <add key="WECHAT_AUTH_URL" value="https://open.weixin.qq.com/connect/oauth2/authorize" />
    <add key="WECHAT_TOKEN_URL" value="https://api.weixin.qq.com/sns/oauth2/access_token" />
    <add key="WECHAT_CALLBACKIP_URL" value="https://api.weixin.qq.com/cgi-bin/getcallbackip" />
    <add key="WECHAT_GETTOKEN_URL" value="https://api.weixin.qq.com/cgi-bin/token" />

    <!--開發者平臺配置-->
    <add key="WEPAY_APP_APPID" value="" />
    <add key="WEPAY_APP_MCH_ID" value="" />
    <add key="WEPAY_APP_NOTIFY_URL" value="" />
    <add key="WEPAY_APP_URL" value="" />
    <add key="WEPAY_APP_KEY" value="" />

    <!--公眾號平臺配置-->
    <add key="WEPAY_WEB_APPID" value="" />
    <add key="WEPAY_WEB_MCH_ID" value="" />
    <add key="WEPAY_WEB_NOTIFY_URL" value="" />
    <add key="WEPAY_WEB_URL" value="https://api.mch.weixin.qq.com/pay/unifiedorder" />
    <add key="WEPAY_WEB_KEY" value="" />
  </appSettings>
  <system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" />
  </system.web>
  <system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*"
           type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient"
                type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                warningLevel="4"
                compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
</configuration>

相關文章