diff --git a/SKIT.FlurlHttpClient.Wechat.sln b/SKIT.FlurlHttpClient.Wechat.sln index 73cb450e..4499bdc0 100644 --- a/SKIT.FlurlHttpClient.Wechat.sln +++ b/SKIT.FlurlHttpClient.Wechat.sln @@ -38,6 +38,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{35C9 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5", "samples\SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5\SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5.csproj", "{D1B321C9-3004-4645-A78D-A85C152062FA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5", "samples\SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5\SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.csproj", "{65E51735-73CE-4E9B-AA65-4BF5E4C8A705}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -88,6 +90,10 @@ Global {D1B321C9-3004-4645-A78D-A85C152062FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {D1B321C9-3004-4645-A78D-A85C152062FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {D1B321C9-3004-4645-A78D-A85C152062FA}.Release|Any CPU.Build.0 = Release|Any CPU + {65E51735-73CE-4E9B-AA65-4BF5E4C8A705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65E51735-73CE-4E9B-AA65-4BF5E4C8A705}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65E51735-73CE-4E9B-AA65-4BF5E4C8A705}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65E51735-73CE-4E9B-AA65-4BF5E4C8A705}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -105,6 +111,7 @@ Global {DBF84F66-1436-4599-93AB-7C16A3A2C3A4} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} {561E0BFB-7817-41FE-BAF2-D78817679AC1} = {C95AF531-CF44-44AA-AC90-F4DF9F941674} {D1B321C9-3004-4645-A78D-A85C152062FA} = {35C901ED-C234-4A91-9561-AD89B3BB788D} + {65E51735-73CE-4E9B-AA65-4BF5E4C8A705} = {35C901ED-C234-4A91-9561-AD89B3BB788D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F08ED64E-2517-4B51-A4BE-D33D56CC7B39} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs index 69848968..e95abdbb 100644 --- a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs +++ b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs @@ -7,10 +7,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using SKIT.FlurlHttpClient.Wechat.Security; namespace SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5.Controllers { + using SKIT.FlurlHttpClient.Wechat.Security; + [ApiController] [Route("notify")] public class WechatNotifyController : ControllerBase diff --git a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Properties/launchSettings.json b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Properties/launchSettings.json index 8c8eb175..a95f2008 100644 --- a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Properties/launchSettings.json +++ b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Properties/launchSettings.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "SKIT.FlurlHttpClient.Wechat.Api.Demo": { + "SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5": { "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": false, diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Controllers/WxpayNotifyController.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Controllers/WxpayNotifyController.cs new file mode 100644 index 00000000..968e287b --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Controllers/WxpayNotifyController.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.Controllers +{ + [ApiController] + [Route("notify")] + public class WxpayNotifyController : ControllerBase + { + private readonly ILogger _logger; + public WxpayNotifyController( + ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(GetType()); + } + + + [HttpPost] + public async Task ReceiveMessage() + { + // 接收服务器推送 + // 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml + + using var reader = new StreamReader(Request.Body, Encoding.UTF8); + string content = await reader.ReadToEndAsync(); + _logger.LogInformation("接收到微信支付推送的数据:{0}", content); + + return new JsonResult(new { code = "SUCCESS", message = "成功" }); + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Options/WechatOptions.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Options/WechatOptions.cs new file mode 100644 index 00000000..7b9c2113 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Options/WechatOptions.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.Options +{ + public partial class WechatOptions : IOptions + { + WechatOptions IOptions.Value => this; + + public WechatMerchant[] Merchants { get; set; } = Array.Empty(); + + public string CallbackEntry { get; set; } = string.Empty; + } + + partial class WechatOptions + { + public class WechatMerchant + { + public string MerchantId { get; set; } = string.Empty; + + public string SecretV3 { get; set; } = string.Empty; + + public string CertSerialNumber { get; set; } = string.Empty; + + public string CertPrivateKey { get; set; } = string.Empty; + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Program.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Program.cs new file mode 100644 index 00000000..e8b14218 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5 +{ + public class Program + { + public static void Main(string[] args) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(builder => + { + builder.UseStartup(); + }) + .Build() + .Run(); + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Properties/launchSettings.json b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Properties/launchSettings.json new file mode 100644 index 00000000..309db620 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.csproj b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.csproj new file mode 100644 index 00000000..2ce0db86 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.csproj @@ -0,0 +1,13 @@ + + + + net5.0 + enable + true + + + + + + + diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/IWechatTenpayHttpClientFactory.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/IWechatTenpayHttpClientFactory.cs new file mode 100644 index 00000000..54378a81 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/IWechatTenpayHttpClientFactory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.Services.HttpClients +{ + public interface IWechatTenpayHttpClientFactory + { + WechatTenpayClient Create(string appId); + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/Implements/WechatTenpayHttpClientFactory.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/Implements/WechatTenpayHttpClientFactory.cs new file mode 100644 index 00000000..9c44c96e --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Services/HttpClients/Implements/WechatTenpayHttpClientFactory.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Flurl; +using Flurl.Http; +using Flurl.Http.Configuration; +using Microsoft.Extensions.Options; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5.Services.HttpClients.Implements +{ + using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings; + + partial class WechatTenpayHttpClientFactory : IWechatTenpayHttpClientFactory + { + private readonly System.Net.Http.IHttpClientFactory _httpClientFactory; + private readonly Options.WechatOptions _wechatOptions; + private readonly CertificateManager _certificateManager; + + public WechatTenpayHttpClientFactory( + System.Net.Http.IHttpClientFactory httpClientFactory, + IOptions wechatOptions, + CertificateManager certificateManager) + { + _httpClientFactory = httpClientFactory; + _wechatOptions = wechatOptions.Value; + _certificateManager = certificateManager; + + FlurlHttp.GlobalSettings.FlurlClientFactory = new DelegatingFlurlClientFactory(_httpClientFactory); + } + + public WechatTenpayClient Create(string merchantId) + { + var wechatMerchant = _wechatOptions.Merchants?.FirstOrDefault(e => string.Equals(merchantId, e.MerchantId)); + if (wechatMerchant == null) + throw new Exception("未在配置项中找到该 MerchantId 对应的微信商户号。"); + + return new WechatTenpayClient(new WechatTenpayClientOptions() + { + MerchantId = wechatMerchant.MerchantId, + MerchantV3Secret = wechatMerchant.SecretV3, + MerchantCertSerialNumber = wechatMerchant.CertSerialNumber, + MerchantCertPrivateKey = wechatMerchant.CertPrivateKey, + CertificateManager = _certificateManager + }); + } + } + + partial class WechatTenpayHttpClientFactory + { + internal class DelegatingFlurlClientFactory : IFlurlClientFactory + { + private readonly System.Net.Http.IHttpClientFactory _httpClientFactory; + + public DelegatingFlurlClientFactory(System.Net.Http.IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); + } + + public IFlurlClient Get(Url url) + { + return new FlurlClient(_httpClientFactory.CreateClient(url.ToUri().Host)); + } + + public void Dispose() + { + // Do Nothing + } + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Startup.cs b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Startup.cs new file mode 100644 index 00000000..117bbac9 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/Startup.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5 +{ + using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings; + + public class Startup + { + public IConfiguration Configuration { get; } + + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + + // ע + services.AddOptions(); + services.Configure(Configuration.GetSection(nameof(Options.WechatOptions))); + + // ע빤 HTTP ͻ + services.AddHttpClient(); + services.AddSingleton(); + services.AddSingleton(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/appsettings.json b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/appsettings.json new file mode 100644 index 00000000..c0ef8455 --- /dev/null +++ b/samples/SKIT.FlurlHttpClient.Wechat.TenpayV3.Sample_Net5/appsettings.json @@ -0,0 +1,20 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + + "AllowedHosts": "*", + + "WechatOptions": { + "Merchants": [ + { + "MerchantId": "д̻" + } + ], + "CallbackEntry": "https://localhost:5001" + } +}