文章目录
-
- 023 服务器的工程结构
- 024 封装支付事件
-
- 025 网络模块的封装
-
- Net/Agent.cs
- Net/NetComponent.cs
- 026 完成辅助类
-
- Tool/GettotalFeeTool.cs
- Tool/TimeTool.cs
- 027 支付宝服务器组件的实现
-
- 028 微信支付服务器
-
- 029 服务器部署
- 030 对IP使用的详细说明
- 031 客户端支付宝功能的修正
- 032 获取应用签名和测试所有功能
023 服务器的工程结构
024 封装支付事件
EventCenter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WAServer.Net;
namespace WAServer
{
class EventCenter
{
public delegate void NetEvent(Agent agent, string[] msg);
public static NetEvent WeChatPay;
public static NetEvent AliPay;
}
}
025 网络模块的封装
Net/Agent.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WAServer.Net
{
public class Agent
{
public Socket mSocket;
public string remoteIP;
private int closeReq = 0;
private bool isClose = false;
public bool IsClose
{
get {
return isClose; }
set {
isClose = value; }
}
private byte[] mTemp = new byte[0x2000];
public Agent(Socket socket)
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("建立连接" + socket.RemoteEndPoint);
this.mSocket = socket;
this.remoteIP = socket.RemoteEndPoint.ToString().Split(':')[0];
StartReceiving();
}
public void StartReceiving()
{
if (mSocket != null && mSocket.Connected && !isClose)
{
try
{
mSocket.BeginReceive(mTemp, 0, mTemp.Length, SocketFlags.None, OnReceive, mSocket);
}
catch (Exception exception)
{
Console.WriteLine("(tcp)Agent接收消息异常", exception.ToString());
Close();
}
}
}
void OnReceive(IAsyncResult result)
{
int length = 0;
if (mSocket == null)
{
Console.WriteLine("Tcp接收异常");
Close();
return;
}
try
{
length = mSocket.EndReceive(result);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
Close();
}
if (length <= 0)
{
Console.WriteLine("bytes <= 0 " + length);
Close();
}
else
{
if (length > 0)
{
string message = Encoding.UTF8.GetString(mTemp, 0, length);
if (message != "")
{
string[] msgList = message.Split(',');
switch (msgList[0])
{
case "WeChatPay":
EventCenter.WeChatPay(this, msgList);
break;
case "AliPay":
EventCenter.AliPay(this, msgList);
break;
case "getProps":
Console.ForegroundColor = ConsoleColor.DarkMagenta;
Console.WriteLine("客户端已经收到了道具");
break;
default:
break;
}
}
}
}
if (mSocket != null)
{
try
{
mSocket.BeginReceive(mTemp, 0, mTemp.Length, SocketFlags.None, OnReceive, mSocket);
}
catch (Exception exception2)
{
Console.WriteLine(exception2.Message);
Close();
}
}
}
#region 发送接口
public void SendBytes(byte[] bytes)
{
try
{
Console.WriteLine("需要发送的字节是多少:" + bytes.Length);
mSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, OnSend, null);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
Close();
}
}
private void OnSend(IAsyncResult result)
{
int num = 0;
try
{
num = mSocket.EndSend(result);
Console.WriteLine("一共发送了:" + num + "多少字节");
}
catch (Exception exception)
{
num = 0;
Close();
Console.WriteLine("tcp发送消息异常{0}", exception.Message);
return;
}
if (mSocket != null && mSocket.Connected)
{
}
else
{
Close();
}
}
#endregion
#region 关闭连接的接口
public void Close()
{
if (Interlocked.Increment(ref closeReq) != 1)
{
return;
}
if (isClose)
{
return;
}
isClose = true;
Console.WriteLine("(tcp)Agent CloseAgent");
if (mSocket != null && mSocket.Connected)
{
Console.WriteLine("CloseSocket");
try
{
mSocket.Shutdown(SocketShutdown.Both);
mSocket.Close();
}
catch (Exception exception)
{
Console.WriteLine("socket Close Error {0}", exception.ToString());
}
}
mSocket = null;
if (mSocket != null)
{
var ip = mSocket.RemoteEndPoint as IPEndPoint;
Console.WriteLine("close client: {0}", ip.Address.ToString());
}
}
#endregion
}
}
Net/NetComponent.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WAServer.Net
{
class NetComponent
{
public string client_ip;
public int client_port;
TcpListener mListener;
int mListenerPort = 7577;
private int maxConnent = 500;
Thread mThread;
private ManualResetEvent signal = new ManualResetEvent(false);
public void Init()
{
try
{
mListener = new TcpListener(IPAddress.Parse("10.186.42.84"), mListenerPort);
mListener.Server.NoDelay = true;
mListener.Start(maxConnent);
}
catch (Exception exception)
{
Console.WriteLine("Tcp启动失败{0}", exception.Message);
}
mThread = new Thread(new ThreadStart(this.AcceptClient));
mThread.Start();
}
private void AcceptClient()
{
mListener.BeginAcceptSocket(new AsyncCallback(AcceptCallback), mListener);
signal.WaitOne();
}
private void AcceptCallback(IAsyncResult result)
{
try
{
var listener = (TcpListener)result.AsyncState;
Socket clienSocket = listener.EndAcceptSocket(result);
string remoteIP = clienSocket.RemoteEndPoint.ToString();
Console.WriteLine("远程IP与端口:" + remoteIP);
Agent ag = new Agent(clienSocket);
listener.BeginAcceptSocket(new AsyncCallback(AcceptCallback), listener);
}
catch (Exception exp)
{
Console.WriteLine("Tcp接收连接异常{0}", exp.ToString());
}
}
}
}
026 完成辅助类
Tool/GettotalFeeTool.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WAServer.Tool
{
class GettotalFeeTool
{
public static int WeChatGettotalFee(string objId, string objCount)
{
int fee = int.Parse(objId) % 1000;
int totalFee = fee * (int.Parse(objCount));
return totalFee;
}
public static string AliGettotalFee(string objId, string objCount)
{
;
float fee = 0.00f;
switch (objId)
{
case "1000":
fee = 0.1f;
break;
case "1001":
fee = 1f;
break;
case "1002":
fee = 2.123f;
break;
default:
break;
}
float totalFee = fee * (int.Parse(objCount));
return String.Format("{0:F}", totalFee);
}
}
}
Tool/TimeTool.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WAServer.Tool
{
class TimeTool
{
public static int ConvertDateTimeInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
Console.WriteLine("计算后的时间戳是:" + (int)(time - startTime).TotalSeconds);
return (int)(time - startTime).TotalSeconds;
}
}
}
027 支付宝服务器组件的实现
AliPayComponent.cs
using Aop.Api;
using Aop.Api.Domain;
using Aop.Api.Request;
using Aop.Api.Response;
using Aop.Api.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using WAServer.Net;
using WAServer.Tool;
using System.Web;
namespace WAServer.Component
{
class AliPayComponent
{
#region APP_Private_Key and AliPay_Public_Key
string APP_Private_Key = @"MIIEpAIBAAKCAQEAqx0Ebk9Io0ROSf6uYWSn2fJttz7PQP+HfrkDxaZX+MqlIRsnkWlBwmujw/U6XLJ1KtCs2o7f9bBwNMDJQZC+tktTDsE0e0NbcjqdL2xWld8hyoYuOIUZ8fSM5ama04MLf7B5F56Vu/95k7nYSwtGXWjrASyQu247+ga4KrEe1U5JsY9oS1QffqNLq2riBg6Cs0XdiO3g6geU3b//2/X/pZz7qzPKvflsEBdRbs1PqPare8l6uoRB+xKbgG1dUApmzwi2FDSe+PwuuMtqdDmGgyfofNcU691ButSbPHCPL8QVJZi+CimI4M7wBGQ2wE5Jp1NcO7KD35laDxDnQSvBHwIDAQABAoIBAEGRj/YZKXNupDVUg0vMv0kTzZkPV2nHwQr9KIXfdQxf0qD5/9KHq+wtRQa8/I0y0RUD+4iQgR9racO9MCGQrpO6D2yy+kJVkEAYV80pTZCGfTNW8XU1A7kkha0nra1pJMncPLqhSS1N+y9xYoF3I5J9trevdRJtbkwjsQSi9Ha1tZxFfmgBvsR+W2rD9ORpfqtrZVL/+DJFAiD8ZozRRXYh0+oAU1WXYNYy8LQDDN+nM+2VmDBdMuRUGiVyaSqnmcN4S8QCwYVWVmVO39dNSVWY11q7LJcKCYTZmLgQa01oY3oUbZ7n154k8oDcbPVemdqqGVyH7BgZX2LeRqUiNQECgYEA2gO8eRYV9WAAJcWqP0f+k/4i3m71FGPobsoIuNQr0iz5D2rQ7UlhgZ2Y72LqN2/Srx2g+KTnPigBnck3MHxh6wiBvzwTbF3pzD6SLHoNGRjNmPE+HNXlOaSxXWM6Qvf/KN2J6vua6P0DwkZehOi58TTR1ZRQi/51xWWYp7F2uYECgYEAyO1Phx93kZ273oSz2Igxj7YVhdH/8V9cvx5SiSAnsZ8Eeq7IsFFOE6z/ttxA3qQIhHgTeF66+4LUftjBD6F3M6m39C42SJKcv+C15u31vZ9WyLwqi5RbYDlq62ITBeRIveT0G/Xc24t3vrjinobWgHSq5IX0NDT1d/lNQVnvip8CgYEA10zTRz1RaCZrXuILFD10IxDZvJMVQxK7SxYIcQdPU1uIhvo04/EQ8yEBFH+50A+Fn9yByKuJlm+J0RoSf7aGOMcI4yNgByfjqQmt73CFGODOwZiUf4OYwUlsw04oDlS9Ts0h08awICEmIii+VUFDx/ois2qp9ObRxaRkkk8GcYECgYBoQFlHLtiHQWQ87HW0H9Y3Tq6UJIW741LoBv+kDn8J9gwI669NbKIqK1TyuA0gd9PDh9nyVpSF8zf2KNjjF1AWCjVcCK45sXiLRjibfVRH8ujAdoFMsslGgAQt5VEheXUUsjrGVyck8pRK7PsIbcXWGLKip64xeFj0yvF+uv9C2QKBgQCfjoNp+wygYJlQTo6YzhsnIvdzsqv3Nyq+kldBw4QXFWoK/P69Sh0aUZ+pwSdQ3HwzynSd3EotLlfZNRgNdjK1w9td1GosMoQYJu+LKoRSb0rmCdy1cKuyHCEIkrtOiVvumGE+nUSWrHRPopdRTQo7k3nvzWwQRKB8Pq9iK0aHZA==";
string AliPay_Public_Key = @"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA37vnkTXPnA83r39o1TowQh8WChOgkbrR3ylQqWGm8eeFGn+wi1bhmNyO4MobIwgejgthVWTs/hXKr5YXUgTH3kEEZQpc+CP2YFroMyYKu5tl8my8Ki5LuPtnOnvEHNtMfXmm1TmqJzv5a+igjN3XY4x+CxKrK9hzzRplmpdoeJOtbQ1twYKk0wKRDitVY4ikbvKKy6mDaBh69pYfCpjAL9fDbewU7QjWKBg1YIFRlwOveUNSBdbflpiAr4DIS75xYrg8X/4i6u7p7M5Ma/tAV/Y0No3P++3roaiLaRzBkvmjQcL4akOlQ6klOCiKkcxYC/hEwNs1C+Gh8KuEKTFXXwIDAQAB";
#endregion
string appid = "2017051607249364";
IAopClient client;
AlipayTradeAppPayRequest request;
string aliPayResultListenerUrl = @"http://193.112.30.89:9090/";
string httpListenerUrl = @"http://10.186.42.84:9090/";
string aliServerURL = @"https://openapi.alipay.com/gateway.do";
HttpListener httpListener;
public void Init()
{
ListenerAliPayResult();
EventCenter.AliPay += AliPay;
}
Dictionary<string, AliPayOrderInfo> orderDic = new Dictionary<string, AliPayOrderInfo>();
private void AliPay(Agent agent, string[] msg)
{
string totalFee = GettotalFeeTool.AliGettotalFee(msg[1], msg[2]);
Console.WriteLine("价格是:" + totalFee);
AliPayOrderInfo model = new AliPayOrderInfo()
{
Body = "活动时装(轻语)",
Subject = "超酷的英雄外表,仅限活动期间可以进行购买",
TotalAmount = totalFee,
ProductCode = "QUICK_MSECURITY_PAY",
OutTradeNo = TimeTool.ConvertDateTimeInt(DateTime.Now).ToString(),
TimeoutExpress = "30m",
clientAgent = agent,
objID = msg[1],
objCount = msg[2],
};
orderDic.Add(model.OutTradeNo, model);
string aliRequestStr = GetAliPayParameter(model);
Console.WriteLine("阿里支付的参数:" + aliRequestStr);
string toClientStr = "AliPay" + "," + aliRequestStr;
agent.SendBytes(Encoding.UTF8.GetBytes(toClientStr));
}
public string GetAliPayParameter(AlipayTradeAppPayModel alipaymode)
{
if (client == null)
{
client = new DefaultAopClient(aliServerURL, appid, APP_Private_Key, "JSON", "1.0", "RSA2", AliPay_Public_Key, "UTF-8", false);
}
request = new AlipayTradeAppPayRequest();
request.SetBizModel(alipaymode);
request.SetNotifyUrl(aliPayResultListenerUrl);
AlipayTradeAppPayResponse response = client.SdkExecute(request);
return response.Body;
}
public void ListenerAliPayResult()
{
httpListener = new HttpListener();
httpListener.Prefixes.Add(httpListenerUrl);
httpListener.Start();
httpListener.BeginGetContext(new AsyncCallback(CheckAliPayResult), null);
}
public void CheckAliPayResult(IAsyncResult ar)
{
try
{
HttpListenerContext context = httpListener.EndGetContext(ar);
HttpListenerRequest request = context.Request;
if (context != null)
{
StreamReader body = new StreamReader(request.InputStream, Encoding.UTF8);
string pay_notice = HttpUtility.UrlDecode(body.ReadToEnd(), Encoding.UTF8);
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("支付结果来了:" + pay_notice);
Dictionary<string, string> aliPayResultDic = StringToDictionary(pay_notice);
bool result = AlipaySignature.RSACheckV1(aliPayResultDic, AliPay_Public_Key, "UTF-8", "RSA2", false);
if (result)
{
AliPayOrderInfo souceDic = orderDic[aliPayResultDic["out_trade_no"]];
if (souceDic.OutTradeNo.Equals(aliPayResultDic["out_trade_no"]))
{
Console.WriteLine("存在相同的订单");
if (souceDic.TotalAmount.Equals(aliPayResultDic["total_amount"]))
{
Console.WriteLine("金额也是一致的:" + aliPayResultDic["total_amount"] + "元");
}
else
{
Console.WriteLine("金额不一致");
}
}
else
{
Console.WriteLine("未存在的订单记录:" + aliPayResultDic["out_trade_no"]);
}
HttpListenerResponse response = context.Response;
string responseString = "success";
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
response.Close();
string toClientMsg = "sendProps" + "," + souceDic.OutTradeNo + "," + souceDic.objID + "," + souceDic.objCount;
byte[] sendByte = Encoding.UTF8.GetBytes(toClientMsg);
souceDic.clientAgent.SendBytes(sendByte);
}
else
{
Console.WriteLine("验签失败");
}
Console.WriteLine("验签结果:" + (result == true ? "支付成功" : "支付失败"));
if (aliPayResultDic.ContainsKey("trade_status"))
{
switch (aliPayResultDic["trade_status"])
{
case "WAIT_BUYER_PAY":
Console.WriteLine("交易状态:" + "交易创建,等待买家付款");
break;
case "TRADE_CLOSED":
Console.WriteLine("交易状态:" + "未付款交易超时关闭,或支付完成后全额退款");
break;
case "TRADE_SUCCESS":
Console.WriteLine("交易状态:" + "交易支付成功");
break;
case "TRADE_FINISHED":
Console.WriteLine("交易结束,不可退款");
break;
default:
break;
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (httpListener.IsListening)
{
try
{
httpListener.BeginGetContext(new AsyncCallback(CheckAliPayResult), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
public Dictionary<string, string> StringToDictionary(string value)
{
if (value.Length < 1)
{
return null;
}
Dictionary<string, string> dic = new Dictionary<string, string>();
string[] dicStrs = value.Split('&');
foreach (string str in dicStrs)
{
string[] strs = str.Split(new char[] {
'=' }, 2);
dic.Add(strs[0], strs[1]);
}
return dic;
}
}
}
public class AliPayOrderInfo : AlipayTradeAppPayModel
{
public Agent clientAgent;
public string objID;
public string objCount;
}
028 微信支付服务器
WXPayComponent.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Xml;
using WAServer.Net;
using WAServer.Tool;
namespace WAServer.Component
{
class WXPayComponent
{
static string miyao = "jflkdwoakdlxvnawrfgwt11262357895";
string appId = "wxc0d38c38f13506d4";
string merchantId = "1495064892";
string notify_url = @"http://193.112.30.89:7983";
string getWeChatPayParameterURL = @"https://api.mch.weixin.qq.com/pay/unifiedorder";
string packageValue = "Sign=WXPay";
int orderNumber = 1;
Dictionary<string, string> dic = new Dictionary<string, string>();
Dictionary<string, OrderInfo> orderDic = new Dictionary<string, OrderInfo>();
HttpListener httpListener;
string Order_Url = @"http://10.186.42.84:7983/";
public void Init()
{
WeChatPayResultListener();
EventCenter.WeChatPay += WeChatPay;
}
private void WeChatPay(Agent agent, string[] msg)
{
string nowTime = TimeTool.ConvertDateTimeInt(DateTime.Now).ToString();
Random ran = new Random();
int r_num = ran.Next(1000, 9999);
OrderInfo orderInfo = new OrderInfo();
orderInfo.appid = appId;
orderInfo.mch_id = merchantId;
orderInfo.body = "秦始皇的时装(活动限版)";
orderInfo.total_fee = GettotalFeeTool.WeChatGettotalFee(msg[1], msg[2]);
orderInfo.spbill_create_ip = agent.remoteIP;
orderInfo.notify_url = notify_url;
orderInfo.trade_type = "APP";
orderInfo.nonce_str = "nonceStr" + r_num + orderNumber + nowTime;
orderInfo.out_trade_no = "wxpay" + r_num + orderNumber + nowTime;
orderInfo.clientAgent = agent;
orderInfo.objID = msg[1];
orderInfo.objCount = int.Parse(msg[2]);
Dictionary<string, string> dics = new Dictionary<string, string>();
dics.Add("appid", orderInfo.appid);
dics.Add("mch_id", orderInfo.mch_id);
dics.Add("nonce_str", orderInfo.nonce_str);
dics.Add("body", orderInfo.body);
dics.Add("out_trade_no", orderInfo.out_trade_no);
dics.Add("total_fee", orderInfo.total_fee.ToString());
dics.Add("spbill_create_ip", orderInfo.spbill_create_ip);
dics.Add("notify_url", orderInfo.notify_url);
dics.Add("trade_type", orderInfo.trade_type);
string tempXML = GetParamSrc(dics);
string result = GetWeChatPayParameter(tempXML);
string payList = "WeChatPay" + "," + PayOrder(result, orderInfo);
if (payList != "error")
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("将参数传递给客户端:" + payList);
byte[] sendData = Encoding.UTF8.GetBytes(payList);
agent.SendBytes(sendData);
}
dics.Clear();
orderNumber++;
}
private string GetWeChatPayParameter(string postData)
{
HttpWebRequest request = null;
if (getWeChatPayParameterURL.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
request = WebRequest.Create(getWeChatPayParameterURL) as HttpWebRequest;
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request.ProtocolVersion = HttpVersion.Version11;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
request.KeepAlive = false;
ServicePointManager.CheckCertificateRevocationList = true;
ServicePointManager.DefaultConnectionLimit = 100;
ServicePointManager.Expect100Continue = false;
}
else
{
request = (HttpWebRequest)WebRequest.Create(getWeChatPayParameterURL);
}
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Referer = null;
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
request.Accept = "*/*";
byte[] data = Encoding.UTF8.GetBytes(postData);
Stream newStream = request.GetRequestStream();
//流要写入的数据和长度
newStream.Write(data, 0, data.Length);
newStream.Close();
//-------------------------------第二步:获取请求响应的结果-----------------//
//获取网页响应结果
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
string result = string.Empty;
//接收到网络消息 就进一步加工处理
using (StreamReader sr = new StreamReader(stream))
{
//从读取流中取出微信服务器返回的数据
result = sr.ReadToEnd();
}
//-------------------------------第三步:根据返回的结果,计算客户端最终需要的参数-----------------//
//将返回的参数进一步计算出客户端本次支付需要的实际参数
//并且根据协议格式 拼接客户端可以识别的网络消息
return result;//读取微信返回的数据
}
/// <summary>
/// 计算客户端调起微信支付所需要的参数
/// </summary>
/// <param name="str">微信服务器返回的数据</param>
/// <returns>由参数加逗号拼接的字符串</returns>
public string PayOrder(string str, OrderInfo orderinfo)
{
//微信支付返回的是XML 需要进行解析
XmlDocument doc = new XmlDocument();
//防止xml被外部注入修改
doc.XmlResolver = null;
doc.LoadXml(str);
XmlNode xml = doc.DocumentElement;
//状态码:SUCCESS 成功 FAIL 失败
if (xml["return_code"].InnerText == "FAIL")//获取预支付单号失败
{
Console.WriteLine("请求预支付单号异常:" + xml["return_msg"].InnerText);
//实际上这里对错误 不应该直接处理 而是需要根据错误原因做相应的逻辑
//如充值单号如果重复了 随机字符串如果重复了 就重新生成
//但是 像这类异常 应该是在请求之前 就有相应的策略 而不应该等到这里来响应处理
//错误码:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
return "error";
}
//请求参数:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
//解析得到以下的这些参数 再进行二次签名
dic.Add("appid", xml["appid"].InnerText);
dic.Add("partnerid", xml["mch_id"].InnerText);
dic.Add("prepayid", xml["prepay_id"].InnerText);
dic.Add("noncestr", xml["nonce_str"].InnerText);
dic.Add("package", "Sign=WXPay");
string timeStamp = TimeTool.ConvertDateTimeInt(DateTime.Now).ToString();
dic.Add("timestamp", timeStamp);
string sign = GetParamSrc(dic);
//缓存订单信息 以便于在微信结果出来后 进行对比校验
orderinfo.prepay_id = xml["prepay_id"].InnerText;
orderinfo.sign = sign;
orderDic.Add(orderinfo.out_trade_no, orderinfo);
//将客户端所需要的参数进行返回
string msg = xml["appid"].InnerText + "," + xml["mch_id"].InnerText + "," + xml["prepay_id"].InnerText + ","
+ xml["nonce_str"].InnerText + "," + timeStamp + "," + packageValue + "," + sign;
dic.Clear();//清空本次的数据
return msg;
}
/// <summary> 设置用于验证服务器证书的回调 </summary>
private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true; //总是接受
}
/// <summary> 签名算法 </summary>
public string GetParamSrc(Dictionary<string, string> dic)
{
//-----------第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序-----//
//格式:键=值&键=值... 意义:获取sign参数
StringBuilder str = new StringBuilder();
//排序:升序
var param1 = dic.OrderBy(x => x.Key).ToDictionary(x => x.Key, y => y.Value);
//再从字典中 获取各个元素 拼接为XML的格式 键跟值之间 用"="连接起来
foreach (string dic1 in param1.Keys)
{
str.Append(dic1 + "=" + dic[dic1] + "&");
}
//-----------------第二步:拼接商户密钥 获取签名sign-----------------------------//
str.Append("key=" + miyao);
//把空字符串给移除替换掉 得到获取sign的字符串
string getSignStr = str.ToString().Replace(" ", "");
Console.WriteLine("第一次准备获取签名的字符串{0}", getSignStr);
//从这里开始 是对str字符串进行MD5加密
MD5 md5 = new MD5CryptoServiceProvider();
byte[] bytValue, bytHash;
bytValue = Encoding.UTF8.GetBytes(getSignStr);
bytHash = md5.ComputeHash(bytValue);
md5.Clear(); //释放掉MD5对象
string tempStr = "";
//按16进制的格式 将字节数组转化为等效字符串
for (int i = 0; i < bytHash.Length; i++)
{
tempStr += bytHash[i].ToString("X").PadLeft(2, '0');
}
//转化为大写 得到 sign签名参数
string sign = tempStr.ToUpper();
//------------------第三步 返回XML格式的字符串--------------------------//
StringBuilder xmlStr = new StringBuilder();
xmlStr.Append("");
foreach (string dic1 in param1.Keys)
{
xmlStr.Append("<" + dic1 + ">" + dic[dic1] + "" + dic1 + ">");
}
//追加到XML尾部
xmlStr.Append("" + sign + "");
Console.WriteLine("预支付请求参数:" + xmlStr.ToString().Replace(" ", ""));
return xmlStr.ToString().Replace(" ", "");
}
/// <summary> 微信支付结果的监听 </summary>
public void WeChatPayResultListener()
{
//HTP监听对象 监听微信给Order_Url地址发送的反馈
if (httpListener == null)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add(Order_Url);
httpListener.Start();
httpListener.BeginGetContext(new AsyncCallback(GetContextCallback), null);
}
}
/// <summary>
/// 异步处理请求
/// </summary>
/// <param name="ar"></param>
private void GetContextCallback(IAsyncResult ar)
{
try
{
HttpListenerContext context = httpListener.EndGetContext(ar);
HttpListenerRequest request = context.Request;
if (context != null)
{
StreamReader body = new StreamReader(request.InputStream, Encoding.UTF8);//读取流,用来获取微信请求的数据
string pay_notice = HttpUtility.UrlDecode(body.ReadToEnd(), Encoding.UTF8);//HttpUtility.UrlDecode:解码 //打印看看支付宝给我们发了什么
Console.WriteLine("微信通知结果来了:" + pay_notice);
//回应结果的对象
HttpListenerResponse response = context.Response;
//微信支付返回的是XML 需要进行解析
XmlDocument doc = new XmlDocument();
//防止xml被外部注入修改
doc.XmlResolver = null;
doc.LoadXml(pay_notice);
XmlNode xml = doc.DocumentElement;
//状态码:SUCCESS 成功 FAIL 失败
if (xml["return_code"].InnerText == "SUCCESS")
{
//如果返回值是成功 就需要进一步检查 订单跟缓存 数据是否匹配
OrderInfo checkData;
if (orderDic.ContainsKey(xml["out_trade_no"].InnerText))
{
checkData = orderDic[xml["out_trade_no"].InnerText];
}
else
{
checkData = null;
}
if (checkData != null)
{
//out_trade_no 商户订单号
Console.WriteLine("支付成功:" + xml["return_code"].InnerText);
if (xml["out_trade_no"].InnerText.Contains(checkData.out_trade_no))
{
//if (xml["sign"].InnerText.Contains(checkData.sign))
//{
//安全验证 单号对应的金额
if (int.Parse(xml["total_fee"].InnerText) == checkData.total_fee)
{
Console.WriteLine("微信支付结果验证,单号金额一致");
//消息协议 SendProps,会话ID/订单号,道具ID,数量...(道具实体)
//向客户端发送道具
string out_trade_no = xml["out_trade_no"].InnerText;
string toClientMsg = "sendProps" + "," + out_trade_no + "," + checkData.objID + "," + checkData.objCount;
byte[] sendByte = Encoding.UTF8.GetBytes(toClientMsg);
checkData.clientAgent.SendBytes(sendByte);
}
else
{
Console.WriteLine("微信支付结果验证,单号金额不一致");
//Todo 再进一步验证微信支付单号 ..... 如果一致 进一步排除原因
//最终如果确认是入侵的数据 再做相应的处理即可
}
}
else
{
Console.WriteLine("订单不匹配,商户订单号:{0},error:{1}", xml["out_trade_no"].InnerText, xml["err_code"].InnerText);
}
}
//回应给微信服务器
string responseStr = @"";
byte[] buffer = Encoding.UTF8.GetBytes(responseStr);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
response.Close();
}
else
{
Console.WriteLine("支付失败:" + xml["return_msg"].InnerText);
//告诉客户端 支付失败以及具体的原因的
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (httpListener.IsListening)
{
try
{
httpListener.BeginGetContext(new AsyncCallback(GetContextCallback), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
/// <summary>
/// 订单的数据模型: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
/// </summary>
public class OrderInfo
{
public string appid = "wxc0d38c38f13506d4";//创建的应用ID
public string mch_id = "1468506502";//商户ID
public string nonce_str = "1add1a30ac87aa2db72f57a2375d8fec";//随机字符串 不长于32位
public string body = "";//商品描述
public string out_trade_no = "0078888899999988888";//订单号商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
public int total_fee = 1000;//1000分=1块钱
public string spbill_create_ip = "";//用户终端实际IP
public string notify_url = "";//139.196.112.69
public string trade_type = "APP";
public string scene_info = "大餐厅腾讯";//这里填写实际场景信息
public string prepay_id;//预支付单号
public string sign;//最终给客户端的签名
public Agent clientAgent;//本次发起支付的客户端
public string objID;//道具ID
public int objCount;//道具数量
public string transaction_id;//结果通知时返回的微信支付订单号
}
029 服务器部署
030 对IP使用的详细说明
031 客户端支付宝功能的修正
032 获取应用签名和测试所有功能