简述
.NET WebAPI+微信支付在网上资源较少疑抑或过于复杂对于小白不太友好,基于自己开辟故而撰写本篇文章。
文末有少量代码不知道如何应用skit代码的可以找我拿类库,添加到你的项目即可食用。
首先必要预备注册好以及通过认证的微信小步伐如下图
存案必要营业执照
微信认证是通过第三方认证,23年12月以后关闭以后只能通过官方认证。
以及商户号
实在代码反倒更简朴,最紧张的是进行小步伐的设置以及商户号绑定,绑定以后不可解绑,留意坑,故需先商量好,好比为官方机构开辟,推荐直接开两个号,因为测试的时候利用官方的各人都懂的。
大致分为以下几部分
- 注册小步伐账号
- 小步伐认证
- 存案
- 开通支付
- 开通商户号
- 设置api v3
- 商户号与小步伐绑定
- 保存商户号,V3 API 密钥,商户证书序列号,商户证书文件内容,AppId,AppSecret
材料:营业执照,营业执照法人身份证,本人微信,电话邮箱等等(乐成办理以后可将管理员设置为自己),餐饮类必要食品安全许可证才能更新小步伐版本,更新版本也有坑
此中必要多张手机号,还有邮箱,验证,审核,过程相当,,,嗯 。
一.设置(官方扣的,但是禁绝)
1.设置API key
下载并设置商户证书
商户API证书具体利用说明可参见接口规则文档中私钥和证书https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml
商户可登录微信商户平台https://pay.weixin.qq.com/
- 微信开辟文档并未写完(现实还需解密获取商户证书序列号)这一步很关键啊,各人留意一下,这个序列号不是微信支付平台的,而是apiv3里面解析获得的
- 必要前去证书查看 (myssl.com)https://myssl.com/cert_decode.html处解析获取
2.设置应用
账号申请指引
1、申请小步伐开辟者账号,进行微信认证,获取appid登录微信公众平台https://mp.weixin.qq.com/ 注册一个小步伐的开辟者账号。小步伐账号申请指引https://mp.weixin.qq.com/debug/wxadoc/introduction/index.html
你看微信文档,存案那些都没做,就让你开支付
2、小步伐开通微信支付,即申请或复用微信支付商户号,申请完小步伐后,登录小步伐后台。点击左侧导航栏的微信支付,在页面中进行开通。
点击开通按钮后,有2种方式可以获取微信支付本领,新申请微信支付商户号或绑定一个已有的微信支付商户号,请根据你的业务必要和具体情况选择,只能二选一,肯定选新的呀,老表,你都来看我博客了。
二.skit引用以及skit支付代码文件引入
地点为开源微信支付 v3 版 .Net SDK(支持 .NET Core / Framework,完整封装全部 v3 API) | 微信开放社区 (qq.com)https://developers.weixin.qq.com/community/develop/article/doc/00020aadc384a0a5f01c3526b56813
三.设置

控制器内引用
注:少数为编者数据操作层,留意甄别
- using Framework.Wechat.HttpClients;
- using Framework.Wechat.Repositories;
- using Framework.WePay.Services.HttpClients;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Mvc;
- using SKIT.FlurlHttpClient.Wechat.Api.Models;
- using SKIT.FlurlHttpClient.Wechat.Api;
- using Framework.Wechat.Options;
- using Framework.WePay.Options;
- using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
- using SKIT.FlurlHttpClient.Wechat.TenpayV3;
- using Microsoft.Extensions.Options;
- using System.Collections.Generic;
- using Newtonsoft.Json;
- using static SKIT.FlurlHttpClient.Wechat.Api.Models.WxaSecOrderUploadCombinedShippingInfoRequest.Types.SubOrder.Types;
- using Microsoft.AspNetCore.Authorization;
- using SKIT.FlurlHttpClient.Wechat.TenpayV3.Events;
- using System.Net;
- using System.Text;
- using NMemory.Data;
- using CQIE.FC.NOS.DataAccess.Interfaces;
- using Microsoft.Extensions.Logging;
- using Org.BouncyCastle.Bcpg;
- using System.Net.Http;
- using System.Threading.Tasks;
- using System.Security.Cryptography;
- using Newtonsoft.Json.Linq;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.OpenSsl;
- using System.Security.Cryptography.X509Certificates;
- using static SKIT.FlurlHttpClient.Wechat.Api.Models.ComponentTCBBatchCreateContainerServiceVersionRequest.Types;
- using System.Globalization;
- namespace WxPayDemo.Webapi.Controllers
- {
- [Route("api/[controller]/[action]")]
- [ApiController]
- [Authorize]
- [Authorize(Roles = "用户")]
- public class PaymentController : ControllerBase
- {
- private readonly ILogger<PaymentController> _logger;
- private readonly IWechatTenpayHttpClientFactory _tenpayHttpClientFactory;
- private readonly IWechatApiHttpClientFactory _wechatApiHttpClientFactory;
- private readonly IWechatAccessTokenEntityRepository _wechatAccessTokenEntityRepository;
- private readonly TenpayOptions _tenpayOptions;
- private readonly WechatOptions _wechatOptions;
- private IPaymentService _paymentService;
- private readonly HttpClient _httpClient;
- private readonly RSA _privateKey;
- private readonly string _merchantId;
- public PaymentController(ILogger<PaymentController> logger, IWechatTenpayHttpClientFactory wechatTenpayHttpClientFactory,
- IWechatApiHttpClientFactory wechatApiHttpClientFactory, IWechatAccessTokenEntityRepository wechatAccessTokenEntities,
- IOptions<TenpayOptions> tenpayOptions, IOptions<WechatOptions> wechatOptions,
- IPaymentService paymentService)
- {
- _logger = logger;
- _tenpayHttpClientFactory = wechatTenpayHttpClientFactory;
- _wechatApiHttpClientFactory = wechatApiHttpClientFactory;
- _wechatAccessTokenEntityRepository = wechatAccessTokenEntities;
- _tenpayOptions = tenpayOptions.Value;
- _wechatOptions = wechatOptions.Value;
- _paymentService = paymentService;
- _httpClient = new HttpClient();
- _merchantId = 配置中获取;
- }
复制代码 其他内容稳定,如微信传入电话,openid,金额
- #region 预支付生成
- public record propay(string Phone,string Openid,int Total);
- [HttpPost]
- public async Task<IActionResult> CreatorPreOrder([FromBody] propay propay)
- {
- try
- {
- int total_fee = (int)(propay.Total);
- var client = _tenpayHttpClientFactory.Create();
- var wechatAccountOptions = _wechatOptions.Accounts?.FirstOrDefault();
- var request = new CreatePayTransactionJsapiRequest()
- {
- OutTradeNumber = OrderNumberGenerator.GenerateOrderNumber(long.Parse(propay.Phone)),
- AppId = wechatAccountOptions.AppId,
- Description = "创谷餐厅",
- NotifyUrl = _tenpayOptions.SucceedNotifyUrl,
- Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = total_fee },
- Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = propay.Openid }
- };
-
- var response = await client.ExecuteCreatePayTransactionJsapiAsync(request, cancellationToken: HttpContext.RequestAborted);
- if (!response.IsSuccessful())
- {
- _logger.LogWarning("JSAPI 下单失败(状态码:{0},错误代码:{1},错误描述:{2})。", response.RawStatus, response.ErrorCode, response.ErrorMessage);
- return Ok("JSAPI 下单失败");
- }
- _logger.LogWarning("JSAPI 成功 预支付交易会话标识:{0}", response.PrepayId);
- List<IDictionary<string, string>> keyValuePairs = new List<IDictionary<string, string>>();
- var paramMap = client.GenerateParametersForJsapiPayRequest(request.AppId, response.PrepayId);
- keyValuePairs.Add(paramMap);
- IDictionary<string, string> orderdic = new Dictionary<string, string> { { "orderid", request.OutTradeNumber } };
- keyValuePairs.Add(orderdic);
-
- return Ok(keyValuePairs);
- }
- catch (Exception ex)
- {
- using (StreamWriter sw = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/error.txt"), true))
- {
- sw.WriteLine(ex.ToString());
- }
- return Ok(ex.ToString());
- }
- }
- #endregion
复制代码 结果返回到前端

前端进入支付

skit未提供获取单号故无法退款,需自己封装
必要的订单号
- #region 获取交易单号
- public record data(string outTradeNo);
- [HttpPost]
- public async Task<IActionResult> Gettransaction_id([FromBody] data data)
- {
- // outTradeNo = "23122317444300007285";
- string asd = data.outTradeNo;
- try
- {
- var request = new HttpRequestMessage(HttpMethod.Get, $"https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{asd}?mchid={_merchantId}");
- var auth = await BuildAuthAsync1(request);
- string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
- request.Headers.Add("Authorization", value);
- request.Headers.Add("Accept", "application/json");
- request.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
- var response = await _httpClient.SendAsync(request);
- if (response.IsSuccessStatusCode)
- {
- var content = await response.Content.ReadAsStringAsync();
- // _logger.LogInformation("订单查询成功:{0}", content);
- return Ok(content);
- }
- else
- {
- var errorContent = await response.Content.ReadAsStringAsync();
- //_logger.LogError("订单查询失败:{0}", errorContent);
- return BadRequest(errorContent);
- }
- }
- catch (Exception ex)
- {
- using (StreamWriter sw = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/error.txt"), true))
- {
- sw.WriteLine("newpay" + ex.Message);
- }
- // _logger.LogError("订单查询发生异常:{0}", ex.Message);
- return StatusCode(500);
- }
- }
- private async Task<string> BuildAuthAsync1(HttpRequestMessage request)
- {
- string method = request.Method.ToString();
- string body = "";
- if (method == "POST" || method == "PUT" || method == "PATCH")
- {
- var content = request.Content;
- body = await content.ReadAsStringAsync();
- }
- string uri = request.RequestUri.PathAndQuery;
- var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
- string nonceStr = Guid.NewGuid().ToString("N");
- string message = BuildMessage1(method, uri, timestamp, nonceStr, body);
- string signature = Sign(message);
- //自己填写或注入时读取
- string serial_no = "";
- return $"mchid="{_merchantId}",nonce_str="{nonceStr}",timestamp="{timestamp}",serial_no="{serial_no}",signature="{signature}"";
- }
- protected string Sign(string message)
- {
- // 也可从配置文件读取
- // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
- // 亦不包括结尾的-----END PRIVATE KEY-----
- string privateKey = "";
- byte[] keyData = Convert.FromBase64String(privateKey);
- var rsa = RSA.Create();
- rsa.ImportPkcs8PrivateKey(keyData, out _);
- byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
- return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
- }
- private string BuildMessage1(string method, string uri, long timestamp, string nonceStr, string body)
- {
- string canonicalUrl = uri;
- if (!string.IsNullOrEmpty(Request.QueryString.Value))
- {
- canonicalUrl += Request.QueryString.Value;
- }
- return $"{method}\n{canonicalUrl}\n{timestamp}\n{nonceStr}\n{body}\n";
- }
- #endregion
复制代码 中间仍有很多细节,暂时无法补充。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |