支付链接获取
if (
{
switch (dto.PayType)
{
case
return new DtoView.PostCreatePayOrder() { Url = _aliPay_H5.GetPayForm(model.TotalPrice, model.OrderNumber, "商城订单"), HandlerUrl = "" };
case
if (string.IsNullOrEmpty(model.WXPayUrl) || (model.WXPayUrlCreateTime!=null && DateTime.Now.Subtract(model.WXPayUrlCreateTime.Value).TotalMinutes>=5)) {
List<string> urlList = _wxPay_H5.UnifiedorderH5Async(model.TotalPrice, model.OrderNumber,ip, "商城订单").Result;
if (urlList == null || urlList.Count != 2) {
throw new Ex.ParameterException("微信支付链接生成错误");
}
}
return new DtoView.PostCreatePayOrder() { Url = model.WXPayUrl,HandlerUrl= model.WXPayHandlerUrl };
default:
throw new Ex.ParameterException("支付平台类型参数错误");
}
}
throw new Ex.ParameterException("订单信息错误或已支付");
支付宝支付退款公共方法
using Alipay.AopSdk.Core;
using Alipay.AopSdk.Core.Domain;
using Alipay.AopSdk.Core.Request;
using Alipay.AopSdk.Core.Response;
using Alipay.AopSdk.Core.Util;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Text;
namespace Test.Application.Common.AliPay
{
public class AliPay_H5
{
private readonly AliPay.AliOption _aliOption;
public AliPay_H5(IOptions<AliPay.AliOption> aliOption)
{
_aliOption = aliOption.Value;
}
public string GetPayForm(decimal totalfee, string orderNo, string description) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.Body = description;
model.Subject = "收款方";
model.TotalAmount = totalfee.ToString();
model.OutTradeNo = orderNo;
model.ProductCode = "QUICK_WAP_WAY";
model.QuitUrl = _aliOption.Ali_QuitUrl;
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.SetReturnUrl(_aliOption.Ali_ReturnUrl);
request.SetNotifyUrl(_aliOption.Ali_NOTIFY_URL);
request.SetBizModel(model);
AlipayTradeWapPayResponse response = null;
response = client.PageExecute(request, null, "post");
LogHelper.Info("支付宝获取支付订单返回:" + response.Body);
return response.Body;
}
public bool ValidationPayNotify(Dictionary<string, string> sArray) {
bool checkR= AlipaySignature.RSACheckV1(sArray, _aliOption.Ali_PublicKey, "UTF-8", "RSA2", false);
return checkR;
}
public string Refund(string orderNo, string refundNo, decimal refund, decimal total, string reason) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
model.OutTradeNo = orderNo;
model.TradeNo = "";
model.RefundAmount = refund.ToString();
model.RefundReason = reason;
model.OutRequestNo = refundNo;
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.SetBizModel(model);
AlipayTradeRefundResponse response = null;
response = client.Execute(request);
LogHelper.Info("支付宝订单退款返回:" + response.Body);
return response.Body;
}
public void CloseOrder(string orderNo) {
DefaultAopClient client = new DefaultAopClient(_aliOption.Ali_GatewayUrl, _aliOption.Ali_AppID, _aliOption.Ali_PrivateKey, "json", "1.0", "RSA2", _aliOption.Ali_PublicKey, "UTF-8", false);
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
model.OutTradeNo = orderNo;
model.TradeNo = "";
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
request.SetBizModel(model);
AlipayTradeCloseResponse response = null;
response = client.Execute(request);
LogHelper.Info("支付宝关闭订单返回:" + response.Body);
}
}
}
public class AliOption : IOptions<AliOption>
{
AliOption IOptions<AliOption>.Value => this;
public string Ali_AppID { get; set; }
public string Ali_GatewayUrl { get; set; }
public string Ali_PrivateKey { get; set; }
public string Ali_PublicKey { get; set; }
public string Ali_NOTIFY_URL { get; set; }
public string Ali_REFUNDNOTIFY_URL { get; set; }
public string Ali_QuitUrl { get; set; }
public string Ali_ReturnUrl { get; set; }
}
微信支付退款公共方法
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace Test.Application.Common.WxPay
{
public class WxPay_H5
{
private HttpClient _client { get; }
private readonly WxPay.WeiXinOption _weiXinOption;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly string BaseAddress = "https://api.mch.weixin.qq.com";
public WxPay_H5(HttpClient client, IOptions<WxPay.WeiXinOption> weChatOptions, IWebHostEnvironment webHostEnvironment)
{
client.DefaultRequestHeaders.Add("Accept",
"application/json");
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
_client = client;
_weiXinOption = weChatOptions.Value;
_webHostEnvironment = webHostEnvironment;
}
public async Task<List<string>> UnifiedorderH5Async(decimal totalfee, string orderNo, string description, string ip)
{
H5Pay h5Pay = new H5Pay() { appid = _weiXinOption.WX_AppID, mchid = _weiXinOption.WX_mch_ID, description = description, out_trade_no = orderNo, notify_url = _weiXinOption.WX_NOTIFY_URL, amount = new Amount { total = (int)(totalfee * 100) }, scene_info = new Scene_Info { payer_client_ip = ip, h5_info = new H5_Info { type = "Wap" } } };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5Pay);
var json = await Post(param, "/v3/pay/transactions/h5");
LogHelper.Info("微信支付创建订单微信返回:" + json);
if (json.Contains("h5_url"))
json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json)["h5_url"];
return await GetHandleUrl(json);
}
public async Task<string> GetOrderH5Async(string out_trade_no)
{
var json = await Get($"/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid=" + _weiXinOption.WX_mch_ID);
return json;
}
public async Task CloseOrderH5Async(string orderNo)
{
H5PayClose h5PayClose = new H5PayClose() { mchid = _weiXinOption.WX_mch_ID };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5PayClose);
await Post(param, $"/v3/pay/transactions/out-trade-no/{orderNo}/close");
}
public async Task<string> RefundH5Async(string orderNo, string refundNo, decimal refund, decimal total, string reason)
{
H5PayRefund h5PayRefund = new H5PayRefund() { out_trade_no = orderNo, out_refund_no = refundNo, notify_url = _weiXinOption.WX_REFUNDNOTIFY_URL, amount = new RefundAmount { total = (int)(total * 100), refund = (int)(refund * 100), currency = "CNY" } };
var param = Newtonsoft.Json.JsonConvert.SerializeObject(h5PayRefund);
LogHelper.Info("微信订单退款参数:" + param);
var json = await Post(param, "/v3/refund/domestic/refunds");
LogHelper.Info("微信订单退款返回:" + json);
if (json.Contains("status"))
json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json)["status"];
return json;
}
public class H5Pay
{
public string mchid { get; set; }
public string out_trade_no { get; set; }
public string appid { get; set; }
public string description { get; set; }
public string notify_url { get; set; }
public Amount amount { get; set; }
public Scene_Info scene_info { get; set; }
}
public class H5PayClose
{
public string mchid { get; set; }
}
#region 退款
public class H5PayRefund
{
public string out_trade_no { get; set; }
public string out_refund_no { get; set; }
public string notify_url { get; set; }
public RefundAmount amount { get; set; }
}
public class RefundAmount
{
public int refund { get; set; }
public int total { get; set; }
public string currency { get; set; }
}
public class GoodsDetailListObj
{
public string merchant_goods_id { get; set; }
public string wechatpay_goods_id { get; set; }
public string goods_name { get; set; }
public int unit_price { get; set; }
public int refund_amount { get; set; }
public int refund_quantity { get; set; }
}
#endregion
public class Amount
{
public int total { get; set; }
public string currency { get; set; } = "CNY";
}
public class Scene_Info
{
public string payer_client_ip { get; set; }
public H5_Info h5_info { get; set; }
}
public class H5_Info
{
public string type { get; set; }
}
public async Task<string> Post(string jsonData, string url)
{
CreateSign("POST", url, jsonData);
var postData = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(BaseAddress + url, postData);
LogHelper.Info("微信请求结果:" + response);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
public async Task<string> Get(string url)
{
CreateSign("GET", url, "");
var response = await _client.GetAsync(BaseAddress + url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private void CreateSign(string method, string uri, string body)
{
string nonce_str = Guid.NewGuid().ToString();
string timestamp = (Tools.UnicodeConvert.ConvertDateTimeInt(DateTime.Now) + "").Substring(0, 10);
string message = $"{method}\n{uri}\n{timestamp}\n{nonce_str}\n{body}\n";
string signature = Tools.CertificateHelper.Sign(message, _webHostEnvironment.ContentRootPath + "\\" + _weiXinOption.WX_Certificate, _weiXinOption.WX_mch_ID);
_client.DefaultRequestHeaders.Add("Authorization", $"WECHATPAY2-SHA256-RSA2048 mchid=\"{_weiXinOption.WX_mch_ID}\",serial_no=\"{_weiXinOption.WX_Serial_No}\",nonce_str=\"{nonce_str}\",timestamp=\"{timestamp}\",signature=\"{signature}\"");
}
public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(Encoding.UTF8.GetBytes(_weiXinOption.WX_AppSecret)),
128,
Encoding.UTF8.GetBytes(nonce),
Encoding.UTF8.GetBytes(associatedData));
gcmBlockCipher.Init(false, aeadParameters);
byte[] data = Convert.FromBase64String(ciphertext);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
public async Task<List<string>> GetHandleUrl(string oldUrl) {
List<string> urlList = new List<string>();
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Host", "wx.tenpay.com");
httpClient.DefaultRequestHeaders.Add("Accept-Language", "en, zh-CN; q=0.8,zh; q=0.6,en-US; q=0.4");
httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml");
httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
string[] urls = _weiXinOption.WX_NOTIFY_URL.Split('/');
httpClient.DefaultRequestHeaders.Add("Referer", "http://" + urls[2] + "/");
var response = await httpClient.GetAsync(oldUrl);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
string pattern = "\"weixin(.*?)\"";
Regex regex = new Regex(pattern);
Match matcher = regex.Match(json);
if (matcher.Success) {
if (matcher.Groups.Count > 0) {
urlList.Add(oldUrl);
urlList.Add(matcher.Groups[0].Value.Substring(1, matcher.Groups[0].Value.Length - 2));
}
}
return urlList;
}
}
}
public class WeiXinOption: IOptions<WeiXinOption>
{
WeiXinOption IOptions<WeiXinOption>.Value => this;
public string WX_AppID { get; set; }
public string WX_AppSecret { get; set; }
public string WX_mch_ID { get; set; }
public string WX_IP { get; set; }
public string WX_NOTIFY_URL { get; set; }
public string WX_REFUNDNOTIFY_URL { get; set; }
public string WX_Certificate { get; set; }
public string WX_Serial_No { get; set; }
}
支付宝支付回调
public dynamic CallBack()
{
var coll = Request.Form;
List<string> requestItem = coll.Keys.ToList();
Dictionary<string, string> sArray = new Dictionary<string, string>();
foreach (var item in requestItem)
{
sArray.Add(item, Request.Form[item]);
}
string strr = "";
foreach (var item in sArray)
{
strr +="Key="+ item.Key + ";Value=" + item.Value + ";";
}
if (_aliPay_H5.ValidationPayNotify(sArray)){
string RechargeTime = sArray.GetValueOrDefault("gmt_payment");
string RechargeMoney = sArray.GetValueOrDefault("total_amount");
string RechargeNo = sArray.GetValueOrDefault("out_trade_no");
decimal price = decimal.Zero;
if (!decimal.TryParse(RechargeMoney, out price))
{
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.PriceChangeError.GetDescription()
};
}
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.Ali;
DateTime payTime = DateTime.Now;
if (RechargeTime.Contains("T"))
{
RechargeTime = RechargeTime.Replace('T', ' ');
if (!DateTime.TryParse(RechargeTime, out payTime))
{
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.TimeChangeError.GetDescription()
};
}
}
return TestCB(RechargeNo, "", price, payType, payTime);
}
return "验证失败";
}
private dynamic TestCB(string orderNumber, string TransactionId, decimal price, int payType,DateTime payTime) {
if (payType == (int)Common.Enums.TypeEnum.ShopOrderPayType.Ali)
{
return "success";
}
else {
return new
{
code = "SUCCESS",
message = ""
};
}
}
微信支付退款回调
public dynamic PayCB()
{
#region
var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
#endregion
System.IO.Stream s = HttpContext.Request.Body;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
string notDeStr = builder;
JObject notDeObj = JObject.Parse(notDeStr);
string ciphertext = notDeObj["resource"]["ciphertext"].ToString();
string associatedData = notDeObj["resource"]["associated_data"].ToString();
string nonce = notDeObj["resource"]["nonce"].ToString();
string deData = _wxPay_H5.AesGcmDecrypt(associatedData,nonce, ciphertext);
JObject deObj = JObject.Parse(deData);
string RechargeMoney = deObj["amount"]["payer_total"].ToString();
string RechargeTime = deObj["success_time"].ToString();
string RechargeNo = deObj["out_trade_no"].ToString();
string TransactionId = deObj["transaction_id"].ToString();
decimal price = decimal.Zero;
if (decimal.TryParse(RechargeMoney, out price))
{
price = price / 100;
}
else
{
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.PriceChangeError.GetDescription()
};
}
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.WX;
DateTime payTime = DateTime.Now;
if (RechargeTime.Contains("T"))
{
RechargeTime = RechargeTime.Replace('T', ' ');
if (!DateTime.TryParse(RechargeTime, out payTime))
{
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopPayNoticeState.TimeChangeError.GetDescription()
};
}
}
return TestCB(RechargeNo, TransactionId, price, payType, payTime);
}
public dynamic TKCB()
{
#region
var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
#endregion
System.IO.Stream s = HttpContext.Request.Body;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
string notDeStr = builder;
JObject notDeObj = JObject.Parse(notDeStr);
string ciphertext = notDeObj["resource"]["ciphertext"].ToString();
string associatedData = notDeObj["resource"]["associated_data"].ToString();
string nonce = notDeObj["resource"]["nonce"].ToString();
string deData = _wxPay_H5.AesGcmDecrypt(associatedData, nonce, ciphertext);
JObject deObj = JObject.Parse(deData);
string RefundTime = deObj["success_time"].ToString();
string OrderNumber = deObj["out_trade_no"].ToString();
string RefundNo = deObj["out_refund_no"].ToString();
int payType = (int)Common.Enums.TypeEnum.ShopOrderPayType.WX;
DateTime refundTime = DateTime.Now;
if (RefundTime.Contains("T"))
{
RefundTime = RefundTime.Replace('T', ' ');
if (!DateTime.TryParse(RefundTime, out refundTime))
{
return new
{
code = "ERROR",
message = Common.Enums.StateEnum.ShopRefundNoticeState.TimeChangeError.GetDescription()
};
}
}
return new
{
code = "SUCCESS",
message = ""
};
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构