├── .gitattributes
├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── LICENSE
├── OmniPay.sln
├── README.md
├── azure-pipelines.yml
├── samples
└── OmniPay.Pay
│ ├── Certs
│ ├── apiclient_cert.p12
│ ├── certs.rar
│ └── unioncerts
│ │ ├── acp_test_enc.cer
│ │ ├── acp_test_middle.cer
│ │ └── acp_test_root.cer
│ ├── Controllers
│ ├── AliPayController.cs
│ ├── HomeController.cs
│ ├── UnionPayController.cs
│ └── WeChatPayController.cs
│ ├── OmniPay.Pay.csproj
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── Views
│ ├── Home
│ │ └── Index.cshtml
│ ├── Shared
│ │ └── _Layout.cshtml
│ ├── _ViewImports.cshtml
│ └── _ViewStart.cshtml
│ ├── WeatherForecast.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── htmlpage.html
│ ├── index.html
│ └── wwwroot
│ ├── demo.css
│ ├── demo.js
│ ├── favicon.ico
│ ├── jquery-ui.min.css
│ ├── jquery-ui.min.js
│ └── jquery.min.js
├── src
├── OmniPay.Alipay
│ ├── AliPayClient.cs
│ ├── AlipayOptions.cs
│ ├── Domain
│ │ ├── AppPayModel.cs
│ │ ├── BarCodePayModel.cs
│ │ ├── BasePayModel.cs
│ │ ├── Goods.cs
│ │ ├── Payee.cs
│ │ ├── ScanPayModel.cs
│ │ └── WebPayModel.cs
│ ├── Endpoints
│ │ ├── AliScanPayEndpoint.cs
│ │ └── Result
│ │ │ └── ScanPayResult.cs
│ ├── Enums
│ │ ├── BillType.cs
│ │ ├── TransBizScene.cs
│ │ ├── TransIdentityType.cs
│ │ └── TransProductCode.cs
│ ├── Extensions
│ │ ├── AliPayApplicationBuilderExtensions.cs
│ │ └── AlipayServiceCollectionExtensions.cs
│ ├── IAliPayClient.cs
│ ├── Middleware
│ │ └── AliPayMiddleware.cs
│ ├── OmniPay.Alipay.csproj
│ ├── Request
│ │ ├── AppPayRequest.cs
│ │ ├── BarCodePayRequest.cs
│ │ ├── BillDownloadRequest.cs
│ │ ├── RefundQueryRequest.cs
│ │ ├── ScanPayRequest.cs
│ │ ├── TradeCancelRequest.cs
│ │ ├── TradeCloseRequest.cs
│ │ ├── TradeQueryRequest.cs
│ │ ├── TradeRefundRequest.cs
│ │ ├── TransferQueryRequest.cs
│ │ ├── TransferRequest.cs
│ │ ├── WapPayRequest.cs
│ │ └── WebPagePayRequest.cs
│ └── Response
│ │ ├── AppPayResponse.cs
│ │ ├── BaseResponse.cs
│ │ ├── ScanPayResponse.cs
│ │ └── WebPayResponse.cs
├── OmniPay.Core
│ ├── Configuration
│ │ └── DependencyInjection
│ │ │ ├── IOmniPayBuilder.cs
│ │ │ ├── OmniPayBuilder.cs
│ │ │ └── OmniPayServiceCollectionExtensions.cs
│ ├── Endpoints
│ │ ├── DiscoveryEndpoint.cs
│ │ ├── DiscoveryResponseGenerator.cs
│ │ └── Results
│ │ │ └── DiscoveryDocumentResult.cs
│ ├── Exceptions
│ │ └── OmniPayException.cs
│ ├── Hosting
│ │ ├── Endpoint.cs
│ │ ├── EndpointRouter.cs
│ │ ├── IEndpointHandler.cs
│ │ ├── IEndpointResult.cs
│ │ └── IEndpointRouter.cs
│ ├── OmniPay.Core.csproj
│ ├── Request
│ │ └── BaseRequest.cs
│ ├── Results
│ │ ├── ProccessErrorResult.cs
│ │ └── StatusCodeResult.cs
│ └── Utils
│ │ ├── CertUtil.cs
│ │ ├── EncryptUtil.cs
│ │ ├── Extensions.Json.cs
│ │ ├── Extensions.String.cs
│ │ ├── Extensions.cs
│ │ ├── HttpHandler.cs
│ │ ├── HttpUtil.cs
│ │ ├── IHttpHandler.cs
│ │ ├── IReadableStringCollectionExtensions.cs
│ │ ├── SecurityUtil.cs
│ │ └── UnionPayUntil.cs
├── OmniPay.Unionpay
│ ├── Domain
│ │ ├── BackTransModel.cs
│ │ ├── BasePayModel.cs
│ │ └── FrontTransModel.cs
│ ├── Extensions
│ │ ├── UnionPayApplicationBuilderExtensions.cs
│ │ └── UnionpayServiceCollectionExtensions.cs
│ ├── IUnionPayClient.cs
│ ├── Middleware
│ │ └── UnionPayMiddleware.cs
│ ├── OmniPay.Unionpay.csproj
│ ├── Request
│ │ ├── BackTransRequest.cs
│ │ └── FrontTransRequest.cs
│ ├── Response
│ │ ├── BackTransResponse.cs
│ │ ├── BaseResponse.cs
│ │ └── FrontTransResponse.cs
│ ├── UnionPayClient.cs
│ └── UnionPayOptions.cs
└── OmniPay.Wechatpay
│ ├── Domain
│ ├── AppPayModel.cs
│ ├── AppletPayModel.cs
│ ├── BasePayModel.cs
│ ├── CloseModel.cs
│ ├── PublicPayModel.cs
│ ├── QueryModel.cs
│ ├── RefundModel.cs
│ ├── ScanPayModel.cs
│ └── WapPayModel.cs
│ ├── Endpoints
│ ├── Result
│ │ ├── AppPayResult.cs
│ │ ├── AppletPayResult.cs
│ │ ├── CloseResult.cs
│ │ ├── PublicPayResult.cs
│ │ ├── QueryResult.cs
│ │ ├── ScanPayResult.cs
│ │ └── WapPayResult.cs
│ ├── WechatAppPayEndpoint.cs
│ ├── WechatAppletPayEndpoint.cs
│ ├── WechatCloseEndpoint.cs
│ ├── WechatPublicPayEndpoint.cs
│ ├── WechatQueryEndpoint.cs
│ ├── WechatScanPayEndpoint.cs
│ └── WechatWapPayEndpoint.cs
│ ├── Extensions
│ ├── WeChatPayApplicationBuilderExtensions.cs
│ └── WeChatServiceCollectionExtensions.cs
│ ├── IWeChatPayClient.cs
│ ├── Middleware
│ ├── ApiEndpointMiddleware.cs
│ └── WechatPayMiddleware.cs
│ ├── OmniPay.Wechatpay.csproj
│ ├── Request
│ ├── AppPayRequest.cs
│ ├── AppletPayRequest.cs
│ ├── CloseRequest.cs
│ ├── PublicPayRequest.cs
│ ├── QueryRequest.cs
│ ├── RefundRequest.cs
│ ├── ScanPayRequest.cs
│ └── WapPayRequest.cs
│ ├── Response
│ ├── AppPayResponse.cs
│ ├── AppletPayResponse.cs
│ ├── BaseResponse.cs
│ ├── CloseResponse.cs
│ ├── PublicPayResponse.cs
│ ├── QueryResponse.cs
│ ├── RefundResponse.cs
│ ├── ScanPayResponse.cs
│ └── WapPayResponse.cs
│ ├── Results
│ └── TestWxResult.cs
│ ├── TestPay.cs
│ ├── Validation
│ ├── Default
│ │ └── ScanPayValidator.cs
│ ├── IScanPayValidator.cs
│ ├── Models
│ │ └── ScanPayRequestValidationResult.cs
│ └── ValidationResult.cs
│ ├── WeChatPayClient.cs
│ └── WeChatPayOptions.cs
└── test
├── OmniPay.TestBase
├── BaseTest.cs
└── OmniPay.TestBase.csproj
└── Wechatpay.Test
├── Core
└── WechatBaseTest.cs
├── Endpoints
├── WechatAppPayEndpointTest.cs
├── WechatAppletPayEndpointTest.cs
├── WechatCloseEndpointTest.cs
├── WechatPublicPayEndpointTest.cs
├── WechatQueryEndpointTest.cs
├── WechatScanPayEndpointTest.cs
└── WechatWapPayEndpointTest.cs
├── WeChatPays
└── WeChatPayTest.cs
└── Wechatpay.Test.csproj
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (console)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/test/Wechatpay.Test/bin/Debug/netcoreapp3.1/Wechatpay.Test.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}/test/Wechatpay.Test",
16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
17 | "console": "internalConsole",
18 | "stopAtEntry": false
19 | },
20 | {
21 | "name": ".NET Core Attach",
22 | "type": "coreclr",
23 | "request": "attach",
24 | "processId": "${command:pickProcess}"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/test/Wechatpay.Test/Wechatpay.Test.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/test/Wechatpay.Test/Wechatpay.Test.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "${workspaceFolder}/test/Wechatpay.Test/Wechatpay.Test.csproj",
36 | "/property:GenerateFullPaths=true",
37 | "/consoleloggerparameters:NoSummary"
38 | ],
39 | "problemMatcher": "$msCompile"
40 | }
41 | ]
42 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Huei Feng
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OmniPay.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29519.181
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3642F616-626D-4205-8F66-68615D3F7D6C}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmniPay.Wechatpay", "src\OmniPay.Wechatpay\OmniPay.Wechatpay.csproj", "{4F57892F-25E8-4244-A8F8-7C84C7BE1A5C}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{719D3223-895D-4B19-B7EF-B37BE5F8017C}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DB6BE635-1CE8-4DB5-AE37-C8FB10A6EA26}"
13 | ProjectSection(SolutionItems) = preProject
14 | .gitattributes = .gitattributes
15 | .gitignore = .gitignore
16 | azure-pipelines.yml = azure-pipelines.yml
17 | LICENSE = LICENSE
18 | README.md = README.md
19 | EndProjectSection
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmniPay.Core", "src\OmniPay.Core\OmniPay.Core.csproj", "{4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7}"
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wechatpay.Test", "test\Wechatpay.Test\Wechatpay.Test.csproj", "{5CC0C897-2325-4851-958E-E00F8A28550E}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmniPay.Alipay", "src\OmniPay.Alipay\OmniPay.Alipay.csproj", "{8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C}"
26 | EndProject
27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmniPay.Unionpay", "src\OmniPay.Unionpay\OmniPay.Unionpay.csproj", "{94AEF135-EBB4-49FC-90A1-D27DAB205876}"
28 | EndProject
29 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9907DC21-7353-4DFD-A298-54A30C6784E7}"
30 | EndProject
31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OmniPay.Pay", "samples\OmniPay.Pay\OmniPay.Pay.csproj", "{C3416D37-F867-448F-8528-4DE352A4B928}"
32 | EndProject
33 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmniPay.TestBase", "test\OmniPay.TestBase\OmniPay.TestBase.csproj", "{E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9}"
34 | EndProject
35 | Global
36 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
37 | Debug|Any CPU = Debug|Any CPU
38 | Release|Any CPU = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
41 | {4F57892F-25E8-4244-A8F8-7C84C7BE1A5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {4F57892F-25E8-4244-A8F8-7C84C7BE1A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {4F57892F-25E8-4244-A8F8-7C84C7BE1A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {4F57892F-25E8-4244-A8F8-7C84C7BE1A5C}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {5CC0C897-2325-4851-958E-E00F8A28550E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {5CC0C897-2325-4851-958E-E00F8A28550E}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {5CC0C897-2325-4851-958E-E00F8A28550E}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {5CC0C897-2325-4851-958E-E00F8A28550E}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 | {8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 | {8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {94AEF135-EBB4-49FC-90A1-D27DAB205876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {94AEF135-EBB4-49FC-90A1-D27DAB205876}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {94AEF135-EBB4-49FC-90A1-D27DAB205876}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {94AEF135-EBB4-49FC-90A1-D27DAB205876}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {C3416D37-F867-448F-8528-4DE352A4B928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {C3416D37-F867-448F-8528-4DE352A4B928}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {C3416D37-F867-448F-8528-4DE352A4B928}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {C3416D37-F867-448F-8528-4DE352A4B928}.Release|Any CPU.Build.0 = Release|Any CPU
65 | {E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9}.Release|Any CPU.Build.0 = Release|Any CPU
69 | EndGlobalSection
70 | GlobalSection(SolutionProperties) = preSolution
71 | HideSolutionNode = FALSE
72 | EndGlobalSection
73 | GlobalSection(NestedProjects) = preSolution
74 | {4F57892F-25E8-4244-A8F8-7C84C7BE1A5C} = {3642F616-626D-4205-8F66-68615D3F7D6C}
75 | {4EE2E97F-7070-4C78-A382-D7C4F7CCA3F7} = {3642F616-626D-4205-8F66-68615D3F7D6C}
76 | {5CC0C897-2325-4851-958E-E00F8A28550E} = {719D3223-895D-4B19-B7EF-B37BE5F8017C}
77 | {8DAD9EA3-4A61-4843-8697-BC4C5C9BFE9C} = {3642F616-626D-4205-8F66-68615D3F7D6C}
78 | {94AEF135-EBB4-49FC-90A1-D27DAB205876} = {3642F616-626D-4205-8F66-68615D3F7D6C}
79 | {C3416D37-F867-448F-8528-4DE352A4B928} = {9907DC21-7353-4DFD-A298-54A30C6784E7}
80 | {E46A48C1-99FE-4AEF-8A9B-B2E43FA616E9} = {719D3223-895D-4B19-B7EF-B37BE5F8017C}
81 | EndGlobalSection
82 | GlobalSection(ExtensibilityGlobals) = postSolution
83 | SolutionGuid = {7E7D1B2E-48E6-4A24-8815-2CF293AA888E}
84 | EndGlobalSection
85 | EndGlobal
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | OmniPay
2 | ===============
3 |
4 | [](https://github.com/hueifeng/OmniPay/blob/master/LICENSE)
5 | [](https://dev.azure.com/dotnetserverprojects/OmniPay/_build/latest?definitionId=1&branchName=master)
6 |
7 | OmniPay支付SDK,主要打造微信支付,支付宝支付,以及银联支付等,使用OmniPay可以简化订单的创建、查询、退款和回调通知等操作
8 |
9 |
10 | # 代码贡献
11 |
12 | 如果您有其它支付网关的需求,或者发现本项目中需要改进的代码,欢迎 Fork 并提交 PR!
13 |
14 | # Wiki
15 |
16 | 支付宝支付文档:
17 |
18 | https://openhome.alipay.com/developmentDocument.htm
19 |
20 | 微信支付文档:
21 |
22 | https://pay.weixin.qq.com/wiki/doc/api/index.html
23 |
24 | 银联支付文档:
25 |
26 | https://open.unionpay.com/ajweb/product
27 |
28 | # LICENSE
29 |
30 | [MIT](https://github.com/hueifeng/OmniPay/blob/master/LICENSE)
31 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # ASP.NET Core (.NET Framework)
2 | # Build and test ASP.NET Core projects targeting the full .NET Framework.
3 | # Add steps that publish symbols, save build artifacts, and more:
4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
5 |
6 | trigger:
7 | - master
8 |
9 | pool:
10 | vmImage: 'windows-latest'
11 |
12 | variables:
13 | solution: '**/*.sln'
14 | buildPlatform: 'Any CPU'
15 | buildConfiguration: 'Release'
16 |
17 | steps:
18 | - task: NuGetToolInstaller@1
19 |
20 | - task: NuGetCommand@2
21 | inputs:
22 | restoreSolution: '$(solution)'
23 |
24 | - task: VSBuild@1
25 | inputs:
26 | solution: '$(solution)'
27 | msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
28 | platform: '$(buildPlatform)'
29 | configuration: '$(buildConfiguration)'
30 |
31 | - task: VSTest@2
32 | inputs:
33 | platform: '$(buildPlatform)'
34 | configuration: '$(buildConfiguration)'
35 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Certs/apiclient_cert.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hueifeng/OmniPay/3761886d6c1106e4018a22fd43726ff5e21e435f/samples/OmniPay.Pay/Certs/apiclient_cert.p12
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Certs/certs.rar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hueifeng/OmniPay/3761886d6c1106e4018a22fd43726ff5e21e435f/samples/OmniPay.Pay/Certs/certs.rar
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Certs/unioncerts/acp_test_enc.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEQzCCAyugAwIBAgIFEAJkkicwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC
3 | Q04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv
4 | cml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTUxMjE1MDkxMTM1WhcN
5 | MTcxMjE1MDkxMTM1WjCBgTELMAkGA1UEBhMCY24xFzAVBgNVBAoTDkNGQ0EgVEVT
6 | VCBPQ0ExMRIwEAYDVQQLEwlDRkNBIFRFU1QxFDASBgNVBAsTC0VudGVycHJpc2Vz
7 | MS8wLQYDVQQDFCYwNDFAWjIwMTQtMTEtMTFAMDAwNDAwMDA6U0lHTkAwMDAwMDAw
8 | NTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHnoPx0JZKZmFjIURxN
9 | AbLlWAw2jiFFWBnDF2MIGkya2r0fGiR0knq8zkKUnoIyC+tzEiOavniQaSu0ucuv
10 | /V4ugz66PSRxw1gaPcR2dDVdgojF00TcewxlJEA65fK3eKhUYfC3NbRaVQOMMdwv
11 | 7nNEvzxvdExE47ceMya7FmsUPyLFu9X++chFQiYfr8nH+wdDeYo8w8vCX+Jd2vRu
12 | qDOah29CQfkAmXsx3D68zg0q4AjlLI1t5gLKiU5YoG6yWrigPyreEHh716rV8HkT
13 | jGWx3cxF/HsLZ/E4SgIr5yIZA6qw8RFqaSXuyw3iDrNf6aSJGO0GKlvxnvD20oGR
14 | JokCAwEAAaOB6TCB5jAfBgNVHSMEGDAWgBTPcJ1h6518Lrj3ywJA9wmd/jN0gDBI
15 | BgNVHSAEQTA/MD0GCGCBHIbvKgEBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cu
16 | Y2ZjYS5jb20uY24vdXMvdXMtMTQuaHRtMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6
17 | Ly91Y3JsLmNmY2EuY29tLmNuL1JTQS9jcmw0NTE3LmNybDALBgNVHQ8EBAMCA+gw
18 | HQYDVR0OBBYEFGjriHHUE1MnYX7H6GrFi+8R2zmUMBMGA1UdJQQMMAoGCCsGAQUF
19 | BwMCMA0GCSqGSIb3DQEBBQUAA4IBAQAjsN0fyDqcxS9YKMpY3CIdlarCjvnus+wS
20 | ExjNnPv7n2urqhz2Jf3yJuhxVVPzdgKT51C2UiR+/i1OJPWFx0IUos/v8js/TM5j
21 | mTdPkBsRSxSDieHHiuE1nPUwGXUEO7mlOVkkzmLI75bJ86foxNflbQCF0+VvpMe7
22 | KwQoNOR8DxIBxHdlsjSxE2RKM/ftXLhptrK4GK3K4FAcSiqBMEn5PF/5V9mHp5N6
23 | 3LdkMYqBj4pRcy8vrclucq99b2glmMLw7CI6Kxu22WVoRnZESjcgXiMVLLe+qy55
24 | 0pWcZ2BChS7Ln19tj49LnS3vFp6xf4qNSqxEBaQuNLEx0ObjI6pz
25 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Certs/unioncerts/acp_test_middle.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDzjCCAragAwIBAgIKGNDz/H99Hd/CxjANBgkqhkiG9w0BAQUFADBZMQswCQYD
3 | VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g
4 | QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODMwMDMx
5 | NDMzWhcNMzEwNTExMDMxNDMzWjBYMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp
6 | bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRcwFQYDVQQDEw5D
7 | RkNBIFRFU1QgT0NBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiL
8 | J/BrdvHSbXNfLIMTwUg9tDtVjMRGXOl6aZnu9IpxjI5SMUJ4hVwgJnmbTokxs6GF
9 | IXKsCLSm5H1jHLI22ysc/ltByEybLWj5jjJuC9+Uknbl3/Ls1RBG6MogUCqZckuo
10 | hKrf5DmlV3C/jVLxGn3pUeanvmqVUi4TKpXxgm5QqKSPF8VtQY4qCpNcQwwZqbMr
11 | D+IfJtfpGAeVrP+Kg6i1t65seeEnVSaLhqpRUDU0PTblOuUv3OhiKJWA3cYWxUrg
12 | 7U7SIHNJLSEUWmjy4mKty+g7Cnjzt29F9qXFb6oB2mR8yt4GHCilw1Rc5RBXY63H
13 | eTuOwdtGE3M2p7Q++OECAwEAAaOBmDCBlTAfBgNVHSMEGDAWgBR03sWNCn0QGqpp
14 | g1tNIc6Gm8xxODAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6
15 | Ly8yMTAuNzQuNDIuMy90ZXN0cmNhL1JTQS9jcmwxLmNybDALBgNVHQ8EBAMCAQYw
16 | HQYDVR0OBBYEFM9wnWHrnXwuuPfLAkD3CZ3+M3SAMA0GCSqGSIb3DQEBBQUAA4IB
17 | AQC0JOazrbkk0XMxMMeBCc3lgBId1RjQLgWUZ7zaUISpPstGIrE5A9aB6Ppq0Sxl
18 | pt2gkFhPEKUqgOFN1CzCDEbP3n4H0chqK1DOMrgTCD8ID5UW+ECTYNe35rZ+1JiF
19 | lOPEhFL3pv6XSkiKTfDnjum8+wFwUBGlfoWK1Hcx0P2Hk1jcZZKwGTx1IAkesF83
20 | pufhxHE2Ur7W4d4tfp+eC7XXcA91pdd+VUrAfkj9eKHcDEYZz66HvHzmt6rtJVBa
21 | pwrtCi9pW3rcm8c/1jSnEETZIaokai0fD7260h/LkD/GrNCibSWxFj1CqyP9Y5Yv
22 | cj6aA5LnUcJYeNkrQ3V4XvVc
23 | -----END CERTIFICATE-----
24 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Certs/unioncerts/acp_test_root.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDkzCCAnugAwIBAgIKUhN+zB19hbc65jANBgkqhkiG9w0BAQUFADBZMQswCQYD
3 | VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g
4 | QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDUw
5 | MTI5WhcNMzIwODI5MDUwMTI5WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp
6 | bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D
7 | RkNBIFRFU1QgQ1MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
8 | rMJGruH6rOBPFxUI7T1ybydSRRtOM1xvkVjQNX0qmYir8feE6Tb0ctgtKR7a20DI
9 | YCj9kZ5ANBQqjRcj3Soq9XH3cirqhYHJ723OKyTpS0RPQ0N6vtVt3P5JQ+ztjWHd
10 | qIbbTOQ6O024TGTiqi6uHgMuz9/OVur81X3a5YVkK7jFeZ9o8cTcvQxD853/1sgZ
11 | QcmR9aUSw0RXH4XFLTrn7n4QSfWKiNotlD8Ag5gS1pH9ONUb6nGkMn3gh1xfJqjm
12 | ONMSknPXTGiNpXtqvYi8oIvByVCbUDO59IwPP1r1SYyE3P8Nr7DdQRu0KQSdXLoG
13 | iugSR3fn+toObVAQmplDAgMBAAGjXTBbMB8GA1UdIwQYMBaAFHTexY0KfRAaqmmD
14 | W00hzoabzHE4MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBR0
15 | 3sWNCn0QGqppg1tNIc6Gm8xxODANBgkqhkiG9w0BAQUFAAOCAQEAM0eTkM35D4hj
16 | RlGC63wY0h++wVPUvOrObqAVBbzEEQ7ScBienmeY8Q6lWMUTXM9ALibZklpJPcJv
17 | 3ntht7LL6ztd4wdX7E9RzZCQnRvbL9A/BU3NxWdeSpCg/OyPod5oCKP+6Uc7kApi
18 | F9OtYNWnt3l2Zp/NiedzEQD8H4qEWQLAq+0dFo5BkfVhb/jPcktndpfPOuH1IMhP
19 | tVcvo6jpFHw4U/nP2Jv59osIE97KJz/SPt2JAYnZOlIDqWwp9/Afvt0/MDr8y0PK
20 | Q9c6eqIzBx7a9LpUTUl5u1jS+xSDZ/KF2lXnjwaFp7jICLWEMlBstCoogi7KwH9A
21 | LpJP7/dj9g==
22 | -----END CERTIFICATE-----
23 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace OmniPay.Pay.Controllers
4 | {
5 | public class HomeController : Controller
6 | {
7 | public IActionResult Index()
8 | {
9 | return View();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Controllers/UnionPayController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using OmniPay.Core.Utils;
3 | using OmniPay.Unionpay;
4 | using OmniPay.Unionpay.Domain;
5 | using OmniPay.Unionpay.Request;
6 | using System.Threading.Tasks;
7 |
8 | namespace OmniPay.Pay.Controllers
9 | {
10 | public class UnionPayController : ControllerBase
11 | {
12 | private readonly IUnionPayClient _client;
13 |
14 | public UnionPayController(IUnionPayClient client)
15 | {
16 | this._client = client;
17 | }
18 |
19 | ///
20 | /// 跳转网关页面支付
21 | ///
22 | ///
23 | [HttpPost]
24 | public async Task FrontTrans(string txnAmt, string orderId)
25 | {
26 | var request = new FrontTransRequest();
27 | request.AddParameters(new FrontTransModel
28 | {
29 | TxnAmt = txnAmt,
30 | OrderId = orderId
31 | }, StringCase.Camel);
32 | return Ok(await _client.ExecuteAsync(request));
33 | }
34 |
35 | ///
36 | /// 消费撤销接口
37 | ///
38 | ///
39 | [HttpPost]
40 | public async Task BackTrans(string txnAmt, string orderId)
41 | {
42 | var request = new BackTransRequest();
43 | request.AddParameters(new BackTransModel
44 | {
45 | TxnAmt = txnAmt,
46 | OrderId = orderId,
47 | }, StringCase.Camel);
48 | return Ok(await _client.ExecuteAsync(request));
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Controllers/WeChatPayController.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Mvc;
3 | using OmniPay.Wechatpay;
4 | using OmniPay.Wechatpay.Domain;
5 | using OmniPay.Wechatpay.Request;
6 |
7 | namespace OmniPay.Pay.Controllers
8 | {
9 |
10 | public class WeChatPayController : ControllerBase
11 | {
12 | private readonly IWeChatPayClient _client;
13 |
14 | public WeChatPayController(IWeChatPayClient client)
15 | {
16 | _client = client;
17 | }
18 | ///
19 | /// 扫码支付
20 | ///
21 | ///
22 | [HttpPost]
23 | public async Task ScanPay(string Body,string Out_Trade_No,int Total_Amount)
24 | {
25 | var request = new ScanPayRequest();
26 | request.AddParameters(new ScanPayModel()
27 | {
28 | Body = Body,
29 | OutTradeNo = Out_Trade_No,
30 | TotalFee = Total_Amount
31 | });
32 | return Ok(await _client.ExecuteAsync(request));
33 | }
34 | ///
35 | /// H5支付
36 | ///
37 | ///
38 | ///
39 | ///
40 | ///
41 | [HttpPost]
42 | public async Task WapPay(string Body, string Out_Trade_No, int Total_Amount)
43 | {
44 | var request = new WapPayRequest();
45 | request.AddParameters(new WapPayModel()
46 | {
47 | Body = Body,
48 | OutTradeNo = Out_Trade_No,
49 | TotalFee = Total_Amount
50 | });
51 | return Ok(await _client.ExecuteAsync(request));
52 | }
53 | ///
54 | /// App支付
55 | ///
56 | ///
57 | ///
58 | ///
59 | ///
60 | [HttpPost]
61 | public async Task AppPay(string Body,string Out_Trade_No,int Total_Amount)
62 | {
63 | var request=new AppPayRequest();
64 | request.AddParameters(new AppPayModel()
65 | {
66 | Body = Body,
67 | OutTradeNo = Out_Trade_No,
68 | TotalFee = Total_Amount
69 | });
70 | return Ok(await _client.ExecuteAsync(request));
71 | }
72 |
73 | ///
74 | /// 公众号支付
75 | ///
76 | ///
77 | ///
78 | ///
79 | ///
80 | ///
81 | [HttpPost]
82 | public async Task PublicPay(string Body,string OutTradeNo,int TotalAmount,string OpenId)
83 | {
84 | var request=new PublicPayRequest();
85 | request.AddParameters(new PublicPayModel()
86 | {
87 | Body = Body,
88 | OutTradeNo = OutTradeNo,
89 | TotalFee = TotalAmount,
90 | OpenId = OpenId
91 | });
92 | return Ok(await _client.ExecuteAsync(request));
93 | }
94 |
95 | ///
96 | /// 小程序支付
97 | ///
98 | ///
99 | [HttpPost]
100 | public async Task AppletPay(string Body,string OutTradeNo,int TotalAmount,string OpenId)
101 | {
102 | var request=new AppletPayRequest();
103 | request.AddParameters(new AppletPayModel()
104 | {
105 | Body = Body,
106 | OutTradeNo = OutTradeNo,
107 | TotalFee = TotalAmount,
108 | OpenId = OpenId
109 | });
110 | return Ok(await _client.ExecuteAsync(request));
111 | }
112 |
113 | ///
114 | /// 查询订单
115 | ///
116 | ///
117 | ///
118 | ///
119 | [HttpPost]
120 | public async Task Query(string OuttradeNo, string TradeNo)
121 | {
122 | var request = new QueryRequest();
123 | request.AddParameters(new QueryModel()
124 | {
125 | TransactionId = TradeNo,
126 | OutTradeNo = OuttradeNo
127 | });
128 | return Ok(await _client.ExecuteAsync(request));
129 | }
130 |
131 | ///
132 | /// 关闭订单
133 | ///
134 | ///
135 | ///
136 | [HttpPost]
137 | public async Task Close(string OutTradeNo)
138 | {
139 | var request = new CloseRequest();
140 | request.AddParameters(new CloseModel()
141 | {
142 | OutTradeNo = OutTradeNo
143 | });
144 | return Ok(await _client.ExecuteAsync(request));
145 | }
146 |
147 | ///
148 | /// 申请退款
149 | ///
150 | ///
151 | ///
152 | ///
153 | ///
154 | ///
155 | ///
156 | [HttpPost]
157 | public async Task Refund(string transactionId,string outTradeNo,string outRefundNo,int refundFee,
158 | string refundDesc)
159 | {
160 | var request = new RefundRequest();
161 | request.AddParameters(new RefundModel()
162 | {
163 | OutTradeNo = outTradeNo,
164 | RefundFee = refundFee,
165 | TransactionId = transactionId,
166 | OutRefundNo = outRefundNo,
167 | RefundDesc = refundDesc
168 | });
169 | return Ok(await _client.ExecuteAsync(request));
170 | }
171 | }
172 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/OmniPay.Pay.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | OmniPay.Pay
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Always
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace OmniPay.Pay
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:6113",
8 | "sslPort": 0
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "AspNetCore.Free.Pay": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | },
25 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Configuration;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Extensions.Hosting;
6 | using OmniPay.Alipay.Extensions;
7 | using OmniPay.Core.Configuration.DependencyInjection;
8 | using OmniPay.Unionpay.Extensions;
9 | using OmniPay.Wechatpay.Extensions;
10 | using System.Net.Http;
11 | using System.Security.Cryptography.X509Certificates;
12 | using System.Text;
13 |
14 | namespace OmniPay.Pay
15 | {
16 | public class Startup
17 | {
18 | public Startup(IConfiguration configuration)
19 | {
20 | Configuration = configuration;
21 | }
22 |
23 | public IConfiguration Configuration { get; }
24 |
25 | // This method gets called by the runtime. Use this method to add services to the container.
26 | public void ConfigureServices(IServiceCollection services)
27 | {
28 | //微信支付中有些接口需要对证书配置
29 | var clientCertificate =
30 | new X509Certificate2(
31 | "Certs/apiclient_cert.p12", "1233410002");
32 | var handler = new HttpClientHandler();
33 | handler.ClientCertificates.Add(clientCertificate);
34 | //以命名式客户端处理,可延伸相关特性
35 | services.AddHttpClient("WeChatPaysHttpClientName", c =>
36 | {
37 | }).ConfigurePrimaryHttpMessageHandler(() => handler);
38 |
39 | services.AddOmniPayService(builder =>
40 | {
41 | builder.Services.AddWeChatPay(options =>
42 | {
43 | Configuration.GetSection("WeChatPays").Bind(options);
44 | }).AddValidators();
45 | builder.Services.AddAliPay(options =>
46 | {
47 | Configuration.GetSection("AliPays").Bind(options);
48 | });
49 | builder.Services.AddUnionPay(options =>
50 | {
51 | Configuration.GetSection("Unionpays").Bind(options);
52 | });
53 | });
54 |
55 | services.AddControllersWithViews();
56 | }
57 |
58 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
59 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
60 | {
61 | if (env.IsDevelopment())
62 | {
63 | app.UseDeveloperExceptionPage();
64 | }
65 |
66 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
67 | app.UseStaticFiles();
68 | app.UseRouting();
69 |
70 | app.UseAuthorization();
71 | app.UseEndpoints(endpoints =>
72 | {
73 | endpoints.MapControllerRoute(
74 | name: "default",
75 | pattern: "{controller=Home}/{action=Index}");
76 | });
77 |
78 | // app.UseOmniPay();
79 | // app.UseAliOmniPay();
80 | // app.UseUnionPay();
81 |
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"]
7 |
8 | @RenderSection("Styles", required: false)
9 |
10 |
11 | @RenderBody()
12 |
13 |
14 | @RenderSection("Scripts", required: false)
15 |
16 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OmniPay.Pay
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "WeChatPays": {
11 | "AppId": "wxdace645e0bc2c424",
12 | "AppSecret": "4693afc6b2084885ca9fbc2355b97827",
13 | "BaseUrl": "https://api.mch.weixin.qq.com",
14 | "MchId": "1900009641",
15 | "NotifyUrl": "http://localhost:6113",
16 | "Key": "b7c996fbda5a9633ee4feb6b991c3919",
17 | "HttpClientName": "WeChatPaysHttpClientName"
18 | },
19 | "Alipays": {
20 | "AppId": "2021000116668110",
21 | "NotifyUrl": "http://localhost:6113/Notify",
22 | "ReturnUrl": "http://localhost:6113/Notify",
23 | "AlipayPublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmx3bj8uy6tN1LtrouRoe0BMCRVtfgKQDRN9mYbueSnd0M5//SiJuvkRkxVfuUIylb/5xTjPGT5VdPKDiyfv3d+9UsqcQnotp/oQm3UF8SLBishvXH02ufvg2qxXiMp2sORYLCSpp0Ycq5gcyOwJdv/4nBGDhD6FWmtbqbSPmu2NZDpKpGS1IoM3PF1heZIoXx7LtBL9MKh6g1TStwRCo/QXrZAn5A4o9/TojwDob3yfdC3acnnJcfEsjGAsJ5Ivxj2Ls20LWI+DHnQVMrByDXnH5qrRyAg6LBvcidAAusUwbQZdsoJkGLu7whh3xMixLCr1Qhjr9hILcskuUoqxK4QIDAQAB",
24 | "Privatekey": "MIIEowIBAAKCAQEA2HLTSTfuFFhRDmb9xc4DVz/e8o/SCXknvPwjQuRIC+MFr+ptj4t3uF4w/j8rqYx2V0ttyGI+MA4byMI/9RYoeX2p9JDcrQHYPIrcmgYIeP5cAl1n1oRhMVjAhtQeI2hYfbelV51SdhGPfIrcUdRNjXMxErrRABeK7vjjdq69ksYdncOOJWZ5O7104Xx98+cOkgJGYABU9V11Gz+/X4P5x90g9iL2pfOmBoMzedfPVLcD4w513emjG3IhHeEdi8vVrmPw7AecF8JPYIpRJBsgM9K+LycwSXW0tMpEjmF28ioisTHvbZpEa+DSEFBIVECry6xXw/utzv7IYLmNwQM3qwIDAQABAoIBAQCWu0gGOivTATnZRMG/KVtMPE9/LcbAEB4rTo8juyOtG3jPa/rGNwK1YurNc6JtXULgQcf+/uN9xaV1pkix3a9sA6YCiYsT9C/o4W8E1+S4lbHvd6qjSecBXWQdwMQINldBnU1IeWd+j3YT7gPF/InRUoG/IFgBr2NyTeLhuIiOF56wEqLa3m1KChGjpMMkJWObBTQqoAAiWe327XxYETRz38x1qc8sfGGleyCo2QqRS6o7A7BdsrkSgMq7HAoo9gZsQBOIEKEsi0gdFq47/ybHDw43TXhMeL0PM7ezKJ4ky/bg/N9PVGP3mKlD2snXk+lUZikkmNH56mVNSAq3Wi3hAoGBAP2FF3+RODmPoNqtcfk6luMaMerZOdcgnmsys0ry/ji1VYeTysfvXwWXT6kcoWG6OFPvPKUgTtAvy2X4GV7KCnmpkM2YL309ha6HYc3dAJHrYObwLG6mPIVoOQsgxYqrNeDAL0PmcMfy9F/ergRjcQfxwwajpDIF+sAMVIfujCW7AoGBANqQ5KBjXKRPhg1eP5PTD+xIhJNffMD7nL9m1R71XjNWdMXOhdCFb1di1CBmb5V9KEHZudKSnAaL8n5jjOtoCNX3vcBOjcY7LcEpOFWrvKWu/PQ3OUSaNvjEM82TDffhXsdhPz+FXmhf4WWKytmU9KIsHK16akKSjbc17z1vfZ7RAoGAZ1LU7uLqvVryPe2uo9rjIA/PBF4gGrNqnVn+hK9gORB+mVD8tluyqH6wssW+aCwTRPIeD1aJiIPSK+7fuCgz+L3JDGHYCP0H/MekbtiBoPcDeVutYDNUOzLs/MIQgKGixcTN/qhukq9MNb51wcgdixVXXN9YziJtvdPIp9XrPH0CgYADfQiJHszdun8zO2vcWiQI62diSsXc9qcbzvJb2iK0ww5+EbvFBjwust8b3Uauph68XlM+7yQaXqVyKviW0URC1f9rUFWm8k7apGPHykPqiQ50f2UkmSmDcu44u74fVLOEjyLJSsGk/NLGIh72tg/pfra+dhO4GEq2v9+fpWXl4QKBgE4UzbW/VBN7mFF2sDuN7W9WGl0r0ikCP+2UBMCBsNPORQlHRkFbTB0wdKwbCmvrG3iRmk947KzdZKJSmkMlLjTCrKddAwog/yPzEvzIV5eUctARXyox7WTihEo/JIqwmbzTiAcXqVYhzDKUMP4k42J/Ugc0JMZXu0hXwPsV77kn",
25 | "BaseUrl": "https://openapi.alipaydev.com"
26 | },
27 | "Unionpays": {
28 | "Version": "5.1.0",
29 | "SignMethod": "01",
30 | "MerId": "777290058110048",
31 | "SignCertPath": "Certs/unioncerts/acp_test_sign.pfx",
32 | "SignCertPwd": "000000",
33 | "EncryptCertPath": "Certs/unioncerts/acp_test_enc.cer",
34 | "MiddleCertPath": "Certs/unioncerts/acp_test_middle.cer",
35 | "RootCertPath": "Certs/unioncerts/acp_test_root.cer",
36 | "BaseUrl": "https://gateway.test.95516.com/gateway/api",
37 | "BackUrl": "http://localhost:6113/",
38 | "FrontUrl": "http://localhost:6113/"
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/htmlpage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
57 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/wwwroot/demo.css:
--------------------------------------------------------------------------------
1 | @CHARSET "UTF-8";
2 | /*! index页面 */
3 | .ui-tabs-vertical {
4 | width: 51.5em;
5 | }
6 |
7 | .ui-tabs-vertical .ui-tabs-nav {
8 | padding: .2em .1em .2em .2em;
9 | float: left;
10 | width: 11em;
11 | }
12 |
13 | .ui-tabs-vertical .ui-tabs-nav li {
14 | clear: left;
15 | width: 100%;
16 | border-bottom-width: 1px !important;
17 | border-right-width: 0 !important;
18 | margin: 0 -1px .2em 0;
19 | }
20 |
21 | .ui-tabs-vertical .ui-tabs-nav li a {
22 | display: block;
23 | }
24 |
25 | .ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
26 | padding-bottom: 0;
27 | padding-right: .1em;
28 | border-right-width: 1px;
29 | border-right-width: 1px;
30 | }
31 |
32 | .ui-tabs-vertical .ui-tabs-panel {
33 | padding: 1.2em;
34 | float: right;
35 | width: 37.5em;
36 | }
37 |
38 | .ui-tabs {
39 | font-family: 微软雅黑;
40 | }
41 |
42 | div#header {
43 | width: inherit;
44 | height: 3em;
45 | }
46 |
47 | div#wrapper {
48 | font-family: 微软雅黑;
49 | width: 62em;
50 | margin: 0 auto;
51 | font-size: 16px;
52 | color: #5E5E5E;
53 | }
54 |
55 | h1, h2, h3, h4, h5, h6, h7, .ui-tooltip {
56 | font-family: 微软雅黑 !important;
57 | color: #555 !important;
58 | }
59 |
60 |
61 | /*! 各个接口的页面 */
62 | hr {
63 | height: 1px;
64 | border: none;
65 | border-top: 1px dashed #9DC45F;
66 | }
67 |
68 | .api-form {
69 | margin-left: auto;
70 | margin-right: auto;
71 | background: #F8F8F8;
72 | padding: 30px 30px 20px 30px;
73 | color: #666;
74 | border-radius: 5px;
75 | -webkit-border-radius: 5px;
76 | -moz-border-radius: 5px;
77 | }
78 |
79 | .api-form p {
80 | display: block;
81 | margin: 0px 0px 5px;
82 | }
83 |
84 | .api-form p > label {
85 | float: left;
86 | width: 10em;
87 | text-align: right;
88 | padding-right: 0.5em;
89 | margin-top: .1em;
90 | color: #5E5E5E;
91 | }
92 |
93 | .api-form input[type="text"] {
94 | border: 1px solid #E5E5E5;
95 | ;
96 | color: #555;
97 | height: 20px;
98 | line-height: 15px;
99 | margin-bottom: 16px;
100 | margin-right: 6px;
101 | margin-top: 2px;
102 | outline: 0 none;
103 | padding: 5px 0px 5px 5px;
104 | width: 65%;
105 | border-radius: 4px;
106 | -webkit-border-radius: 4px;
107 | -moz-border-radius: 4px;
108 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
109 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
110 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
111 | }
112 |
113 | .api-form input.button {
114 | font-family: 微软雅黑;
115 | background-color: #9DC45F;
116 | border-radius: 5px;
117 | -webkit-border-radius: 5px;
118 | -moz-border-border-radius: 5px;
119 | border: none;
120 | padding: 10px 25px 10px 25px;
121 | color: #FFF;
122 | text-shadow: 1px 1px 1px #949494;
123 | }
124 |
125 | .api-form input.button:hover {
126 | font-family: 微软雅黑;
127 | background-color: #80A24A;
128 | }
129 |
130 | .api-form .showFaqBtn {
131 | font-family: 微软雅黑;
132 | float: right;
133 | background-color: transparent;
134 | color: inherit;
135 | border: none;
136 | padding: 10px 25px 10px 25px;
137 | }
138 |
139 | .faq {
140 | font-size: 14px;
141 | font-weight: normal;
142 | }
143 |
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/wwwroot/demo.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | $("#tabs-api").tabs();
3 | setApiDemoTabs("#tabs-purchase-alipay");
4 | setApiDemoTabs("#tabs-purchase-wechatpay");
5 | setApiDemoTabs("#tabs-purchase-qpay");
6 | setApiDemoTabs("#tabs-purchase-jdpay");
7 | setApiDemoTabs("#tabs-purchase-unionpay");
8 | $(document).tooltip();
9 | });
10 |
11 | function setApiDemoTabs(selector) {
12 | $(selector).tabs({
13 | beforeLoad: function (event, ui) {
14 | ui.jqXHR.error(function () { ui.panel.html("加载中"); });
15 | }, load: function (event, ui) {
16 | $(".question").hide();
17 | $(".showFaqBtn").click(
18 | function () { $(".question").toggle(); });
19 | }
20 | }).addClass("ui-tabs-vertical ui-helper-clearfix");
21 | $(selector + " li").removeClass("ui-corner-top").addClass("ui-corner-left");
22 | }
--------------------------------------------------------------------------------
/samples/OmniPay.Pay/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hueifeng/OmniPay/3761886d6c1106e4018a22fd43726ff5e21e435f/samples/OmniPay.Pay/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/AliPayClient.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Microsoft.Extensions.Options;
3 | using OmniPay.Alipay.Response;
4 | using OmniPay.Core.Exceptions;
5 | using OmniPay.Core.Request;
6 | using OmniPay.Core.Utils;
7 | using System;
8 | using System.Threading.Tasks;
9 | using Newtonsoft.Json;
10 | using Newtonsoft.Json.Linq;
11 | using OmniPay.Alipay.Request;
12 |
13 | namespace OmniPay.Alipay
14 | {
15 | public class AliPayClient : IAliPayClient
16 | {
17 | private readonly AlipayOptions _alipayOptions;
18 | private readonly ILogger _logger;
19 | private readonly IHttpHandler _httpHandler;
20 |
21 | public AliPayClient(IOptions alioptions, ILogger logger,
22 | IHttpHandler httpHandler)
23 | {
24 | this._alipayOptions = alioptions.Value;
25 | this._logger = logger;
26 | this._httpHandler = httpHandler;
27 | }
28 |
29 | ///
30 | /// Execute AliPay API request implementation
31 | ///
32 | ///
33 | ///
34 | ///
35 | ///
36 | public async Task ExecuteAsync(BaseRequest request)
37 | {
38 | BuildParams(request);
39 | if (request is AppPayRequest || request is WapPayRequest || request is WebPagePayRequest)
40 | {
41 | return (TResponse)Activator.CreateInstance(typeof(TResponse), request);
42 | }
43 | string result = await _httpHandler.PostAsync(request.RequestUrl, request.ToUrl());
44 | var jObject = JObject.Parse(result);
45 | var jToken = jObject.First.First;
46 | var sign = jObject.Value("sign");
47 | if (!string.IsNullOrEmpty(sign) &&
48 | !CheckSign(jToken.ToString(Formatting.None), sign, _alipayOptions.AlipayPublicKey, _alipayOptions.SignType))
49 | {
50 | _logger.LogError("Signature verification failed:{0}", result);
51 | throw new OmniPayException("Signature verification failed.");
52 | }
53 |
54 | var baseResponse = (BaseResponse)(object)jToken.ToObject();
55 | baseResponse.Raw = result;
56 | baseResponse.Sign = sign;
57 | return (TResponse)(object)baseResponse;
58 | }
59 |
60 | private void BuildParams(BaseRequest request)
61 | {
62 | if (string.IsNullOrEmpty(_alipayOptions.AppId))
63 | {
64 | throw new OmniPayException(nameof(_alipayOptions.AppId));
65 | }
66 | request.Add("app_id", _alipayOptions.AppId);
67 | request.Add("format", _alipayOptions.Format);
68 | request.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
69 | request.Add("sign_type", _alipayOptions.SignType);
70 | request.Add("charset", _alipayOptions.Charset);
71 | request.Add("version", "1.0");
72 | request.Add("biz_content", request.ToStringCaseObj(request).ToJson());
73 | request.Add("sign", EncryptUtil.RSA(request.ToUrl(false), _alipayOptions.PrivateKey, _alipayOptions.SignType));
74 | request.RequestUrl = _alipayOptions.BaseUrl + request.RequestUrl;
75 | }
76 |
77 | internal static bool CheckSign(string data, string sign, string alipayPublicKey, string signType)
78 | {
79 | var result = EncryptUtil.RSAVerifyData(data, sign, alipayPublicKey, signType);
80 | if (!result)
81 | {
82 | data = data.Replace("/", "\\/");
83 | result = EncryptUtil.RSAVerifyData(data, sign, alipayPublicKey, signType);
84 | }
85 |
86 | return result;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/AlipayOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OmniPay.Alipay
4 | {
5 | public class AlipayOptions
6 | {
7 |
8 | ///
9 | /// 应用ID
10 | ///
11 | public string AppId { get; set; }
12 |
13 | ///
14 | /// 签名类型
15 | ///
16 | public string SignType { get; set; } = "RSA2";
17 |
18 | ///
19 | /// 格式
20 | ///
21 | public string Format => "JSON";
22 |
23 | ///
24 | /// 时间戳
25 | ///
26 | public string Timestamp => DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
27 |
28 | ///
29 | /// 版本
30 | ///
31 | public string Version => "1.0";
32 |
33 | ///
34 | /// 编码格式
35 | ///
36 | public string Charset => "UTF-8";
37 |
38 | ///
39 | /// 商户私钥
40 | ///
41 | public string PrivateKey { get; set; }
42 |
43 | ///
44 | /// 支付宝公钥
45 | ///
46 | public string AlipayPublicKey { get; set; }
47 |
48 | ///
49 | /// 返回地址
50 | ///
51 | public string ReturnUrl { get; set; }
52 |
53 | ///
54 | /// 网关回发通知URL
55 | ///
56 | public string NotifyUrl { get; set; }
57 |
58 | public string BaseUrl { get; set; }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/AppPayModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Alipay.Domain
2 | {
3 | ///
4 | /// app支付
5 | ///
6 | public class AppPayModel : BasePayModel
7 | {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/BarCodePayModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Alipay.Domain
6 | {
7 | ///
8 | /// 条码支付
9 | ///
10 | public class BarCodePayModel : BasePayModel
11 | {
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/BasePayModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Alipay.Domain
2 | {
3 | ///
4 | /// 支付宝支付基类
5 | ///
6 | public class BasePayModel
7 | {
8 | ///
9 | /// 订单金额,单位为元
10 | ///
11 | public double TotalAmount { get; set; }
12 |
13 | ///
14 | /// 对一笔交易的具体描述信息。
15 | ///
16 | public string Body { get; set; }
17 |
18 | ///
19 | /// 商户网站唯一订单号
20 | ///
21 | public string OutTradeNo { get; set; }
22 |
23 | ///
24 | /// 商品的标题/交易标题/订单标题/订单关键字等。
25 | ///
26 | public string Subject { get; set; }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/Goods.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace OmniPay.Alipay.Domain
4 | {
5 | public class Goods
6 | {
7 | ///
8 | /// 商品编码
9 | ///
10 | public string Id { get; set; }
11 |
12 | ///
13 | /// 支付宝统一商品编号
14 | ///
15 | public string AlipayGoodsId { get; set; }
16 |
17 | ///
18 | /// 商品名称
19 | ///
20 | [JsonProperty("goods_name")]
21 | public string Name { get; set; }
22 |
23 | ///
24 | /// 商品数量
25 | ///
26 | public int Quantity { get; set; }
27 |
28 | ///
29 | /// 商品单价,单位为元
30 | ///
31 | public double Price { get; set; }
32 |
33 | ///
34 | /// 商品类目
35 | ///
36 | public string Category { get; set; }
37 |
38 | ///
39 | /// 商品描述信息
40 | ///
41 | public string Body { get; set; }
42 |
43 | ///
44 | /// 展品展示地址
45 | ///
46 | public string ShowUrl { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/Payee.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Alipay.Domain
6 | {
7 | public class Payee
8 | {
9 | ///
10 | /// 收款方的唯一标识
11 | ///
12 | public string identity { get; set; }
13 |
14 | ///
15 | /// 收款方的唯一标识
16 | ///
17 | public string identity_type { get; set; }
18 |
19 | ///
20 | /// 参与方真实姓名,如果非空,将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时,本字段必填。
21 | ///
22 | public string name { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/ScanPayModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace OmniPay.Alipay.Domain
4 | {
5 | public class ScanPayModel
6 | {
7 | ///
8 | /// 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
9 | ///
10 | public string OutTradeNo { get; set; }
11 |
12 | ///
13 | /// 卖家编码,如果该值为空,则默认为商户签约账号对应的支付宝用户ID
14 | ///
15 | public string SellerId { get; set; }
16 |
17 | ///
18 | /// 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
19 | ///
20 | public double TotalAmount { get; set; }
21 |
22 | ///
23 | /// 参与优惠计算的金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]。
24 | ///
25 | public double DiscountableAmount { get; set; }
26 |
27 | ///
28 | /// 订单标题
29 | ///
30 | public string Subject { get; set; }
31 |
32 | ///
33 | /// 订单包含的商品列表信息
34 | ///
35 | public List GoodsDetail { get; set; }
36 |
37 | ///
38 | /// 订单描述
39 | ///
40 | public string Body { get; set; }
41 |
42 | ///
43 | /// 卖家端自定义的的操作员编号
44 | ///
45 | public string OperatorId { get; set; }
46 |
47 | ///
48 | /// 商户门店编号
49 | ///
50 | public string StoreId { get; set; }
51 |
52 | ///
53 | /// 禁用渠道,用户不可用指定渠道支付,当有多个渠道时用“,”分隔
54 | ///
55 | public string DisablePayChannels { get; set; }
56 |
57 | ///
58 | /// 可用渠道,用户只能在指定渠道范围内支付,当有多个渠道时用“,”分隔
59 | ///
60 | public string EnablePayChannels { get; set; }
61 |
62 | ///
63 | /// 商户的终端编号
64 | ///
65 | public string TerminalId { get; set; }
66 |
67 | ///
68 | /// 该笔订单允许的最晚付款时间,逾期将关闭交易。
69 | /// 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。
70 | /// 该参数数值不接受小数点, 如 1.5h,可转换为 90m
71 | ///
72 | public string TimeoutExpress { get; set; }
73 |
74 | ///
75 | /// 商户传入业务信息,具体值要和支付宝约定
76 | /// 将商户传入信息分发给相应系统,应用于安全,营销等参数直传场景
77 | /// 格式为json格式
78 | ///
79 | public string BusinessParams { get; set; }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Domain/WebPayModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace OmniPay.Alipay.Domain
4 | {
5 | ///
6 | /// 电脑网站支付
7 | ///
8 | public class WebPayModel : BasePayModel
9 | {
10 | ///
11 | /// 订单包含的商品列表信息
12 | ///
13 | public List GoodsDetail { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Endpoints/AliScanPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.Extensions.Logging;
3 | using OmniPay.Alipay.Endpoints.Result;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using System.Net;
7 |
8 | namespace OmniPay.Alipay.Endpoints
9 | {
10 | public class AliScanPayEndpoint : IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IAliPayClient _client;
14 |
15 | public AliScanPayEndpoint(ILogger logger, IAliPayClient client)
16 | {
17 | this._logger = logger;
18 | this._client = client;
19 | }
20 |
21 | public IEndpointResult Process(HttpContext context)
22 | {
23 | _logger.LogDebug("Start WechatScanPay request");
24 |
25 | if (!HttpMethods.IsPost(context.Request.Method))
26 | {
27 | _logger.LogWarning("Invalid HTTP method for ScanPay endpoint.");
28 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
29 | }
30 | _logger.LogTrace("End WechatScanPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
31 | return new ScanPayResult(_client);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Endpoints/Result/ScanPayResult.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using OmniPay.Core.Hosting;
3 | using System;
4 | using OmniPay.Core.Utils;
5 | using System.Threading.Tasks;
6 | using OmniPay.Alipay.Request;
7 | using OmniPay.Alipay.Domain;
8 |
9 | namespace OmniPay.Alipay.Endpoints.Result
10 | {
11 | public class ScanPayResult : IEndpointResult
12 | {
13 | private readonly IAliPayClient _client;
14 |
15 | public ScanPayResult(IAliPayClient client)
16 | {
17 | this._client = client;
18 | }
19 |
20 | public async Task ExecuteAsync(HttpContext context)
21 | {
22 | try
23 | {
24 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
25 | if (body?.Count == 0)
26 | {
27 | throw new ArgumentNullException(nameof(body));
28 | }
29 | var request = new ScanPayRequest();
30 | request.AddParameters(new ScanPayModel()
31 | {
32 | Body = body.Get("Body"),
33 | OutTradeNo = body.Get("Out_Trade_No"),
34 | TotalAmount = double.Parse(body.Get("Total_Amount")),
35 | Subject = body.Get("Subject")
36 | });
37 | await context.Response.WriteAsync((await _client.ExecuteAsync(request)).ToJson());
38 | }
39 | catch (Exception ex)
40 | {
41 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
42 | await context.Response.WriteAsync(ex.Message);
43 | }
44 | context.Response.ContentType = "application/json; charset=UTF-8";
45 | await context.Response.Body.FlushAsync();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Enums/BillType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Alipay.Enums
6 | {
7 | public enum BillType
8 | {
9 | ///
10 | /// 商户基于支付宝交易收单的业务账单
11 | /// 只有当面付接口可以下载trade类型的账单
12 | ///
13 | Trade,
14 |
15 | ///
16 | /// 于商户支付宝余额收入及支出等资金变动的帐务账单
17 | ///
18 | SignCustomer
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Enums/TransBizScene.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Alipay.Enums
6 | {
7 | public enum TransBizScene
8 | {
9 | ///
10 | /// 单笔无密转账到支付宝/银行卡, B2C现金红包
11 | ///
12 | DIRECT_TRANSFER,
13 |
14 | ///
15 | /// C2C现金红包-领红包
16 | ///
17 | PERSONAL_COLLECTION
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Enums/TransIdentityType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Alipay.Enums
6 | {
7 | public enum TransIdentityType
8 | {
9 | ///
10 | /// 支付宝的会员ID
11 | ///
12 | ALIPAY_USER_ID,
13 |
14 | ///
15 | /// 支付宝登录号,支持邮箱和手机号格式
16 | ///
17 | ALIPAY_LOGON_ID
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Enums/TransProductCode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Text;
5 |
6 | namespace OmniPay.Alipay.Enums
7 | {
8 | ///
9 | /// 转账业务产品代码
10 | ///
11 | public enum TransProductCode
12 | {
13 | ///
14 | /// 单笔无密转账到支付宝账户
15 | ///
16 | TRANS_ACCOUNT_NO_PWD,
17 |
18 | ///
19 | /// 单笔无密转账到银行卡
20 | ///
21 | TRANS_BANKCARD_NO_PWD,
22 |
23 | ///
24 | /// 收发现金红包
25 | ///
26 | STD_RED_PACKET
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Extensions/AliPayApplicationBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using OmniPay.Alipay.Middleware;
5 | using OmniPay.Core.Utils;
6 |
7 | namespace OmniPay.Alipay.Extensions
8 | {
9 | public static class AliPayApplicationBuilderExtensions
10 | {
11 | ///
12 | /// 使用OmniPay
13 | ///
14 | ///
15 | ///
16 | public static IApplicationBuilder UseAliOmniPay(this IApplicationBuilder app)
17 | {
18 | app.UseMiddleware();
19 | //var httpContextAccessor = app.ApplicationServices.GetRequiredService();
20 | //HttpUtil.Configure(httpContextAccessor);
21 | return app;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Extensions/AlipayServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using System;
3 |
4 | namespace OmniPay.Alipay.Extensions
5 | {
6 | public static class AlipayServiceCollectionExtensions
7 | {
8 | public static IServiceCollection AddAliPay(this IServiceCollection services, Action action)
9 | {
10 | //services.AddTransient();
11 | //services.AddSingleton();
12 | //services.AddSingleton(new Endpoint("aliScanPay", "/pay-api/alipay/ScanPay", typeof(AliScanPayEndpoint)));
13 | return services.AddAliServices(action);
14 | }
15 |
16 | private static IServiceCollection AddAliServices(this IServiceCollection services, Action action)
17 | {
18 | if (action != null)
19 | {
20 | services.Configure(action.Invoke);
21 | }
22 | services.AddSingleton();
23 | return services;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/IAliPayClient.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using System.Threading.Tasks;
3 |
4 | namespace OmniPay.Alipay
5 | {
6 | public interface IAliPayClient
7 | {
8 | ///
9 | /// Execute AliPay API request
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | Task ExecuteAsync(BaseRequest request);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Middleware/AliPayMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.Extensions.Logging;
3 | using OmniPay.Core.Hosting;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | namespace OmniPay.Alipay.Middleware
8 | {
9 | public class AliPayMiddleware
10 | {
11 | private readonly ILogger _logger;
12 | private readonly RequestDelegate _next;
13 |
14 | public AliPayMiddleware(ILogger logger,RequestDelegate next)
15 | {
16 | this._logger = logger;
17 | this._next = next;
18 | }
19 |
20 | public async Task InvokeAsync(HttpContext context, IEndpointRouter router)
21 | {
22 | try
23 | {
24 | var endpoint = router.Find(context);
25 | if (endpoint != null)
26 | {
27 | _logger.LogInformation("Invoking WechatPay endpoint: {endpointType} for {url}", endpoint.GetType().FullName, context.Request.Path.ToString());
28 |
29 | var result = endpoint.Process(context);
30 |
31 | if (result != null)
32 | {
33 | _logger.LogTrace("Invoking result: {type}", result.GetType().FullName);
34 | await result.ExecuteAsync(context);
35 | }
36 | }
37 | else
38 | {
39 | context.Response.StatusCode = StatusCodes.Status404NotFound;
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | _logger.LogCritical(ex, "Unhandled exception: {exception}", ex.Message);
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/OmniPay.Alipay.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | OmniPay.Alipay
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/AppPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class AppPayRequest : BaseRequest
8 | {
9 | public AppPayRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.app.pay");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/BarCodePayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 |
6 | namespace OmniPay.Alipay.Request
7 | {
8 | public class BarCodePayRequest : BaseRequest
9 | {
10 | public BarCodePayRequest()
11 | {
12 | RequestUrl = "/gateway.do?charset=UTF-8";
13 | Add("method", "alipay.trade.pay");
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/BillDownloadRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class BillDownloadRequest : BaseRequest
8 | {
9 | public BillDownloadRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.data.dataservice.bill.downloadurl.query");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/RefundQueryRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 |
6 | namespace OmniPay.Alipay.Request
7 | {
8 | public class RefundQueryRequest : BaseRequest
9 | {
10 | public RefundQueryRequest()
11 | {
12 | RequestUrl = "/gateway.do?charset=UTF-8";
13 | Add("method", "alipay.trade.fastpay.refund.query");
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/ScanPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class ScanPayRequest : BaseRequest
8 | {
9 | public ScanPayRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.precreate");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TradeCancelRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class TradeCancelRequest : BaseRequest
8 | {
9 | public TradeCancelRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.cancel");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TradeCloseRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class TradeCloseRequest : BaseRequest
8 | {
9 | public TradeCloseRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.close");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TradeQueryRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class TradeQueryRequest : BaseRequest
8 | {
9 | public TradeQueryRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.query");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TradeRefundRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class TradeRefundRequest : BaseRequest
8 | {
9 | public TradeRefundRequest()
10 | {
11 | RequestUrl = "/gateway.do?charset=UTF-8";
12 | Add("method", "alipay.trade.refund");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TransferQueryRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 |
6 | namespace OmniPay.Alipay.Request
7 | {
8 | public class TransferQueryRequest : BaseRequest
9 | {
10 | public TransferQueryRequest()
11 | {
12 | RequestUrl = "/gateway.do?charset=UTF-8";
13 | Add("method", "alipay.fund.trans.order.query");
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/TransferRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 |
6 | namespace OmniPay.Alipay.Request
7 | {
8 | public class TransferRequest : BaseRequest
9 | {
10 | public TransferRequest()
11 | {
12 | RequestUrl = "/gateway.do?charset=UTF-8";
13 | Add("method", "alipay.fund.trans.uni.transfer");
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/WapPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Response;
2 | using OmniPay.Core.Request;
3 |
4 | namespace OmniPay.Alipay.Request
5 | {
6 | public class WapPayRequest : BaseRequest
7 | {
8 | public WapPayRequest()
9 | {
10 | RequestUrl = "/gateway.do?charset=UTF-8";
11 | Add("method", "alipay.trade.wap.pay");
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Request/WebPagePayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Domain;
2 | using OmniPay.Alipay.Response;
3 | using OmniPay.Core.Request;
4 |
5 | namespace OmniPay.Alipay.Request
6 | {
7 | public class WebPagePayRequest : BaseRequest
8 | {
9 | public WebPagePayRequest()
10 | {
11 | RequestUrl = "/gateway.do";
12 | Add("method", "alipay.trade.page.pay");
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Response/AppPayResponse.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Request;
2 |
3 | namespace OmniPay.Alipay.Response
4 | {
5 | public class AppPayResponse
6 | {
7 | public AppPayResponse(AppPayRequest request)
8 | {
9 | OrderInfo = request.ToUrl();
10 | }
11 |
12 | ///
13 | /// 用于唤起App的订单参数
14 | ///
15 | public string OrderInfo { get; set; }
16 |
17 | public string Raw { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Response/BaseResponse.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace OmniPay.Alipay.Response
4 | {
5 | public abstract class BaseResponse
6 | {
7 |
8 | ///
9 | /// 返回状态码
10 | ///
11 | public string Code { get; set; }
12 |
13 | ///
14 | /// 返回码描述
15 | ///
16 | [JsonProperty("msg")]
17 | public string Message { get; set; }
18 |
19 | ///
20 | /// 明细返回码
21 | ///
22 | public string SubCode { get; set; }
23 |
24 | ///
25 | /// 明细返回码描述
26 | ///
27 | [JsonProperty("sub_msg")]
28 | public string SubMessage { get; set; }
29 |
30 | ///
31 | /// 签名
32 | ///
33 | public string Sign { get; set; }
34 |
35 | ///
36 | /// 原始值
37 | ///
38 | public string Raw { get; set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Response/ScanPayResponse.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace OmniPay.Alipay.Response
4 | {
5 | public class ScanPayResponse : BaseResponse
6 | {
7 | ///
8 | /// 商户订单号
9 | ///
10 | [JsonProperty("out_trade_no")]
11 | public string OutTradeNo { get; set; }
12 |
13 | ///
14 | /// 二维码链接
15 | ///
16 | [JsonProperty("qr_code")]
17 | public string QrCode { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Alipay/Response/WebPayResponse.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Alipay.Request;
2 |
3 | namespace OmniPay.Alipay.Response
4 | {
5 | public class WebPayResponse
6 | {
7 | public WebPayResponse(WapPayRequest request)
8 | {
9 | Html = request.ToForm(request.RequestUrl);
10 | }
11 |
12 | public WebPayResponse(WebPagePayRequest request)
13 | {
14 | Html = request.ToForm(request.RequestUrl);
15 | }
16 |
17 | ///
18 | /// 生成的Html网页
19 | ///
20 | public string Html { get; set; }
21 |
22 | public string Raw { get; set; }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Configuration/DependencyInjection/IOmniPayBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace OmniPay.Core.Configuration.DependencyInjection
4 | {
5 | public interface IOmniPayBuilder
6 | {
7 | IServiceCollection Services { get; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Configuration/DependencyInjection/OmniPayBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace OmniPay.Core.Configuration.DependencyInjection
4 | {
5 | public class OmniPayBuilder
6 | {
7 | public IServiceCollection Services { get; set; }
8 |
9 | public OmniPayBuilder(IServiceCollection services)
10 | {
11 | this.Services = services;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Configuration/DependencyInjection/OmniPayServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using System;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Utils;
5 |
6 | namespace OmniPay.Core.Configuration.DependencyInjection
7 | {
8 | public static class OmniPayServiceCollectionExtensions
9 | {
10 | public static IServiceCollection AddOmniPayService(this IServiceCollection services, Action builder)
11 | {
12 | //自动API将放到下一个里程碑计划中
13 | //services.AddTransient();
14 | //services.AddSingleton();
15 | //services.AddSingleton(new Endpoint("OmniPay", "/.well-known/openpay-configuration", typeof(DiscoveryEndpoint)));
16 | //var httpContextAccessor = services.ApplicationServices.GetRequiredService();
17 | //HttpUtil.Configure(httpContextAccessor);
18 | services.AddTransient();
19 | var omniPayBuilder = new OmniPayBuilder(services);
20 | builder(omniPayBuilder);
21 | return services;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Endpoints/DiscoveryEndpoint.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using OmniPay.Core.Endpoints.Results;
3 | using OmniPay.Core.Hosting;
4 |
5 | namespace OmniPay.Core.Endpoints
6 | {
7 | public class DiscoveryEndpoint : IEndpointHandler
8 | {
9 | public IEndpointResult Process(HttpContext context)
10 | {
11 | return new DiscoveryDocumentResult(DiscoveryResponseGenerator.DiscoveryDictionary);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Endpoints/DiscoveryResponseGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace OmniPay.Core.Endpoints
4 | {
5 | public class DiscoveryResponseGenerator
6 | {
7 | public static Dictionary DiscoveryDictionary { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Endpoints/Results/DiscoveryDocumentResult.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using OmniPay.Core.Hosting;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using OmniPay.Core.Utils;
7 |
8 | namespace OmniPay.Core.Endpoints.Results
9 | {
10 | ///
11 | /// Result for a discovery document
12 | ///
13 | ///
14 | public class DiscoveryDocumentResult : IEndpointResult
15 | {
16 | ///
17 | /// Gets the entries.
18 | ///
19 | ///
20 | /// The entries.
21 | ///
22 | public Dictionary Entries { get; }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The entries.
28 | /// entries
29 | public DiscoveryDocumentResult(Dictionary entries)
30 | {
31 | Entries = entries ?? throw new ArgumentNullException(nameof(entries));
32 | }
33 |
34 | ///
35 | /// Executes the result.
36 | ///
37 | /// The HTTP context.
38 | ///
39 | public Task ExecuteAsync(HttpContext context)
40 | {
41 | return context.Response.WriteAsync(Entries.ToJson());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Exceptions/OmniPayException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OmniPay.Core.Exceptions
4 | {
5 | public class OmniPayException : Exception
6 | {
7 | public OmniPayException(string message)
8 | : base(message)
9 | {
10 | }
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Hosting/Endpoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Http;
3 |
4 | namespace OmniPay.Core.Hosting
5 | {
6 | public class Endpoint
7 | {
8 | public Endpoint(string name, string path, Type handlerType)
9 | {
10 | Name = name;
11 | Path = path;
12 | Handler = handlerType;
13 | }
14 |
15 | ///
16 | /// Gets or sets the name
17 | ///
18 | ///
19 | /// The name
20 | ///
21 | public string Name { get; set; }
22 | ///
23 | /// Gets or sets the path
24 | ///
25 | ///
26 | /// The path
27 | ///
28 | public PathString Path { get; set; }
29 | ///
30 | /// Gets or sets the handler
31 | ///
32 | ///
33 | /// The handler
34 | ///
35 | public Type Handler { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Hosting/EndpointRouter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.Extensions.Logging;
5 |
6 | namespace OmniPay.Core.Hosting
7 | {
8 | public class EndpointRouter : IEndpointRouter
9 | {
10 |
11 | private readonly IEnumerable _endpoints;
12 | private readonly ILogger _logger;
13 |
14 | public EndpointRouter(IEnumerable endpoints, ILogger logger)
15 | {
16 | _endpoints = endpoints;
17 | _logger = logger;
18 | }
19 | public IEndpointHandler Find(HttpContext context)
20 | {
21 | if (context == null) throw new ArgumentNullException(nameof(context));
22 | foreach (var endpoint in _endpoints)
23 | {
24 | var path = endpoint.Path;
25 | if (context.Request.Path.Equals(path, StringComparison.OrdinalIgnoreCase))
26 | {
27 | var endpointName = endpoint.Name;
28 | _logger.LogDebug("Request path {path} matched to endpoint type {endpoint}", context.Request.Path, endpointName);
29 |
30 | return GetEndpointHandler(endpoint, context);
31 | }
32 | }
33 | _logger.LogTrace("No endpoint entry found for request path: {path}", context.Request.Path);
34 |
35 | return null;
36 | }
37 |
38 | private IEndpointHandler GetEndpointHandler(Endpoint endpoint, HttpContext context)
39 | {
40 | if (context.RequestServices.GetService(endpoint.Handler) is IEndpointHandler handler)
41 | {
42 | _logger.LogDebug("Endpoint enabled: {endpoint}, successfully created handler: {endpointHandler}", endpoint.Name, endpoint.Handler.FullName);
43 | return handler;
44 | }
45 | else
46 | {
47 | _logger.LogDebug("Endpoint enabled: {endpoint}, failed to create handler: {endpointHandler}", endpoint.Name, endpoint.Handler.FullName);
48 | }
49 |
50 | return null;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Hosting/IEndpointHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 |
4 | namespace OmniPay.Core.Hosting
5 | {
6 | public interface IEndpointHandler
7 | {
8 | ///
9 | /// Processes the request
10 | ///
11 | /// The HTTP context.
12 | ///
13 | IEndpointResult Process(HttpContext context);
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Hosting/IEndpointResult.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 |
4 | namespace OmniPay.Core.Hosting
5 | {
6 | ///
7 | /// Endpoint result
8 | ///
9 | public interface IEndpointResult
10 | {
11 | ///
12 | /// Executes the result
13 | ///
14 | /// The HTTP context.
15 | ///
16 | Task ExecuteAsync(HttpContext context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Hosting/IEndpointRouter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 |
3 | namespace OmniPay.Core.Hosting
4 | {
5 | ///
6 | /// The endpoint router
7 | ///
8 | public interface IEndpointRouter
9 | {
10 | ///
11 | /// Finds a matching endpoint.
12 | ///
13 | /// The HTTP context.
14 | ///
15 | IEndpointHandler Find(HttpContext context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/OmniPay.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | OmniPay.Core
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Results/ProccessErrorResult.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using OmniPay.Core.Hosting;
3 | using System.Threading.Tasks;
4 |
5 | namespace OmniPay.Core.Results
6 | {
7 | public class ProccessErrorResult : IEndpointResult
8 | {
9 | public string Error;
10 | public string ErrorDescription;
11 |
12 | public ProccessErrorResult(string error, string errorDescription = null)
13 | {
14 | Error = error;
15 | ErrorDescription = errorDescription;
16 | }
17 |
18 | public Task ExecuteAsync(HttpContext context)
19 | {
20 | context.Response.ContentType = "application/json; charset=UTF-8";
21 | context.Response.WriteAsync("{'test':'测试'}");
22 | context.Response.Body.FlushAsync();
23 | return Task.CompletedTask;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Results/StatusCodeResult.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 |
6 | namespace OmniPay.Core.Results
7 | {
8 | ///
9 | /// Result for a raw HTTP status code
10 | ///
11 | ///
12 | public class StatusCodeResult : IEndpointResult
13 | {
14 | ///
15 | /// Gets the status code.
16 | ///
17 | ///
18 | /// The status code.
19 | ///
20 | public int StatusCode { get; }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// The status code.
26 | public StatusCodeResult(HttpStatusCode statusCode)
27 | {
28 | StatusCode = (int)statusCode;
29 | }
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | ///
34 | /// The status code.
35 | public StatusCodeResult(int statusCode)
36 | {
37 | StatusCode = statusCode;
38 | }
39 |
40 | ///
41 | /// Executes the result.
42 | ///
43 | /// The HTTP context.
44 | ///
45 | public Task ExecuteAsync(HttpContext context)
46 | {
47 | context.Response.StatusCode = StatusCode;
48 |
49 | return Task.CompletedTask;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/CertUtil.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Org.BouncyCastle.Crypto;
3 | using Org.BouncyCastle.Pkcs;
4 | using Org.BouncyCastle.X509;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Text;
9 |
10 | namespace OmniPay.Core.Utils
11 | {
12 | public class Cert
13 | {
14 | public AsymmetricKeyParameter key;
15 | public X509Certificate cert;
16 | public string certId;
17 | }
18 |
19 | public class CertUtil
20 | {
21 | private static Dictionary signCerts = new Dictionary();
22 |
23 |
24 | private static void initSignCert(string certPath, string certPwd)
25 | {
26 |
27 | FileStream fileStream = null;
28 | try
29 | {
30 | fileStream = new FileStream(certPath, FileMode.Open, FileAccess.Read);
31 |
32 | Pkcs12Store store = new Pkcs12Store(fileStream, certPwd.ToCharArray());
33 |
34 | string pName = null;
35 | foreach (string n in store.Aliases)
36 | {
37 | if (store.IsKeyEntry(n))
38 | {
39 | pName = n;
40 | //break;
41 | }
42 | }
43 |
44 | Cert signCert = new Cert();
45 | signCert.key = store.GetKey(pName).Key;
46 | X509CertificateEntry[] chain = store.GetCertificateChain(pName);
47 | signCert.cert = chain[0].Certificate;
48 | signCert.certId = signCert.cert.SerialNumber.ToString();
49 |
50 | signCerts[certPath] = signCert;
51 |
52 | }
53 | catch (Exception e)
54 | {
55 | //_logger.LogError("签名证书读取失败,异常:" + e);
56 | }
57 | finally
58 | {
59 | if (fileStream != null)
60 | fileStream.Close();
61 | }
62 |
63 | }
64 |
65 | ///
66 | /// 获取签名证书的证书序列号
67 | ///
68 | ///
69 | public static string GetSignCertId(string certPath, string certPwd)
70 | {
71 | if (!signCerts.ContainsKey(certPath))
72 | {
73 | initSignCert(certPath, certPwd);
74 | }
75 | return signCerts[certPath].certId;
76 | }
77 |
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/Extensions.Json.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Data;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Converters;
5 | using Newtonsoft.Json.Linq;
6 |
7 | namespace OmniPay.Core.Utils {
8 | public static partial class Extensions {
9 | ///
10 | /// 反序列化
11 | ///
12 | ///
13 | ///
14 | public static object ToJson (this string Json) {
15 | return Json == null ? null : JsonConvert.DeserializeObject (Json);
16 | }
17 | ///
18 | /// 序列化
19 | ///
20 | ///
21 | ///
22 | public static string ToJson (this object obj) {
23 | var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
24 | return JsonConvert.SerializeObject (obj, timeConverter);
25 | }
26 | public static string ToJson (this object obj, string datetimeformats) {
27 | var timeConverter = new IsoDateTimeConverter { DateTimeFormat = datetimeformats };
28 | return JsonConvert.SerializeObject (obj, timeConverter);
29 | }
30 | public static T ToObject (this string Json) {
31 | return Json == null ? default (T) : JsonConvert.DeserializeObject (Json);
32 | }
33 | public static List ToList (this string Json) {
34 | return Json == null ? null : JsonConvert.DeserializeObject> (Json);
35 | }
36 | public static DataTable ToTable (this string Json) {
37 | return Json == null ? null : JsonConvert.DeserializeObject (Json);
38 | }
39 | public static JObject ToJObject (this string Json) {
40 | return Json == null ? JObject.Parse ("{}") : JObject.Parse (Json.Replace (" :", ""));
41 | }
42 |
43 | }
44 | }
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/Extensions.String.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace OmniPay.Core.Utils
4 | {
5 | public enum StringCase
6 | {
7 | ///
8 | /// 蛇形策略
9 | ///
10 | Snake,
11 | ///
12 | /// 驼峰策略
13 | ///
14 | Camel,
15 | ///
16 | /// 默认
17 | ///
18 | None
19 | }
20 |
21 | internal enum SnakeCaseState
22 | {
23 | Start,
24 | Lower,
25 | Upper,
26 | NewWord
27 | }
28 |
29 | public static partial class Extensions
30 | {
31 | ///
32 | /// 将字符串转换为蛇形策略
33 | ///
34 | /// 字符串
35 | ///
36 | public static string ToSnakeCase(this string s)
37 | {
38 | if (string.IsNullOrEmpty(s))
39 | {
40 | return s;
41 | }
42 |
43 | var sb = new StringBuilder();
44 | var state = SnakeCaseState.Start;
45 |
46 | for (var i = 0; i < s.Length; i++)
47 | {
48 | if (s[i] == ' ')
49 | {
50 | if (state != SnakeCaseState.Start)
51 | {
52 | state = SnakeCaseState.NewWord;
53 | }
54 | }
55 | else if (char.IsUpper(s[i]))
56 | {
57 | switch (state)
58 | {
59 | case SnakeCaseState.Upper:
60 | var hasNext = i + 1 < s.Length;
61 | if (i > 0 && hasNext)
62 | {
63 | var nextChar = s[i + 1];
64 | if (!char.IsUpper(nextChar) && nextChar != '_')
65 | {
66 | sb.Append('_');
67 | }
68 | }
69 | break;
70 | case SnakeCaseState.Lower:
71 | case SnakeCaseState.NewWord:
72 | sb.Append('_');
73 | break;
74 | }
75 |
76 | sb.Append(char.ToLowerInvariant(s[i]));
77 |
78 | state = SnakeCaseState.Upper;
79 | }
80 | else if (s[i] == '_')
81 | {
82 | sb.Append('_');
83 | state = SnakeCaseState.Start;
84 | }
85 | else
86 | {
87 | if (state == SnakeCaseState.NewWord)
88 | {
89 | sb.Append('_');
90 | }
91 |
92 | sb.Append(s[i]);
93 | state = SnakeCaseState.Lower;
94 | }
95 | }
96 |
97 | return sb.ToString();
98 | }
99 |
100 | ///
101 | /// 将字符串转换为骆驼策略
102 | ///
103 | /// 字符串
104 | ///
105 | public static string ToCamelCase(this string s)
106 | {
107 | if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0]))
108 | {
109 | return s;
110 | }
111 |
112 | var chars = s.ToCharArray();
113 |
114 | for (var i = 0; i < chars.Length; i++)
115 | {
116 | if (i == 1 && !char.IsUpper(chars[i]))
117 | {
118 | break;
119 | }
120 |
121 | var hasNext = i + 1 < chars.Length;
122 | if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
123 | {
124 | if (char.IsSeparator(chars[i + 1]))
125 | {
126 | chars[i] = char.ToLowerInvariant(chars[i]);
127 | }
128 |
129 | break;
130 | }
131 |
132 | chars[i] = char.ToLowerInvariant(chars[i]);
133 | }
134 |
135 | return new string(chars);
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OmniPay.Core.Utils
4 | {
5 | public static partial class Extensions
6 | {
7 | public static string GetNonceStr()
8 | {
9 | return Guid.NewGuid().ToString("N");
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/HttpHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using System.Net.Http.Headers;
5 | using System.Text;
6 | using System.Text.Json;
7 | using System.Threading.Tasks;
8 |
9 | namespace OmniPay.Core.Utils
10 | {
11 | public class HttpHandler : IHttpHandler
12 | {
13 | private readonly IHttpClientFactory _httpClientFactory;
14 |
15 | public HttpHandler(IHttpClientFactory httpClientFactory)
16 | {
17 | _httpClientFactory = httpClientFactory;
18 | }
19 |
20 | public HttpClient CreateHttpClient(string? name = null)
21 | {
22 | _ = _httpClientFactory ?? throw new NullReferenceException("No IHttpClientFactory provided, please add AddHttpClient() in configure services!");
23 | return _httpClientFactory.CreateClient(name);
24 | }
25 |
26 | public async Task GetAsync(string url, JsonSerializerOptions options = null)
27 | {
28 | _ = _httpClientFactory ?? throw new NullReferenceException("No IHttpClientFactory provided, please add AddHttpClient() in configure services!");
29 | var httpClient = _httpClientFactory.CreateClient();
30 |
31 | var streamTask = httpClient.GetStreamAsync(url);
32 |
33 | return await JsonSerializer.DeserializeAsync(await streamTask.ConfigureAwait(false), options);
34 | }
35 |
36 | public async Task PostAsync(string url, string request, JsonSerializerOptions options = null)
37 | {
38 | _ = _httpClientFactory ?? throw new NullReferenceException("No IHttpClientFactory provided, please add AddHttpClient() in configure services!");
39 | var httpClient = _httpClientFactory.CreateClient();
40 |
41 | var reqContent = new StringContent(request, Encoding.UTF8, "application/x-www-form-urlencoded");
42 | var response = await httpClient.PostAsync(url, reqContent);
43 | var streamTask = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
44 | return streamTask;
45 | }
46 |
47 | public async Task PostAsync(string url, string request, string logicalName, JsonSerializerOptions options = null)
48 | {
49 | _ = _httpClientFactory ?? throw new NullReferenceException("No IHttpClientFactory provided, please add AddHttpClient() in configure services!");
50 | var httpClient = _httpClientFactory.CreateClient(logicalName);
51 | if (logicalName == null)
52 | {
53 | httpClient = _httpClientFactory.CreateClient();
54 | }
55 |
56 | var reqContent = new StringContent(request, Encoding.UTF8, "application/x-www-form-urlencoded");
57 | var resp = await httpClient.PostAsync(url, reqContent);
58 | var streamTask = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
59 | return streamTask;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/IHttpHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Text.Json;
3 | using System.Threading.Tasks;
4 |
5 | namespace OmniPay.Core.Utils
6 | {
7 | public interface IHttpHandler
8 | {
9 | ///
10 | /// 返回HttpClient
11 | ///
12 | ///
13 | ///
14 | HttpClient CreateHttpClient(string? name = null);
15 |
16 | ///
17 | /// 异步GET请求
18 | ///
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | Task GetAsync(string url, JsonSerializerOptions? options = null);
25 |
26 | ///
27 | /// 异步POST请求
28 | ///
29 | ///
30 | ///
31 | ///
32 | ///
33 | ///
34 | Task PostAsync(string url, string request, JsonSerializerOptions options = null);
35 |
36 |
37 | ///
38 | /// 异步POST请求
39 | ///
40 | ///
41 | ///
42 | ///
43 | ///
44 | ///
45 | ///
46 | Task PostAsync(string url, string request, string logicalName, JsonSerializerOptions options = null);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/OmniPay.Core/Utils/IReadableStringCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections.Specialized;
3 | using System.Linq;
4 | using Microsoft.Extensions.Primitives;
5 |
6 | namespace OmniPay.Core.Utils
7 | {
8 | public static class IReadableStringCollectionExtensions
9 | {
10 | public static NameValueCollection AsNameValueCollection(this IEnumerable> collection){
11 | var nv=new NameValueCollection();
12 | foreach (var field in collection)
13 | {
14 | nv.Add(field.Key,field.Value.First());
15 | }
16 | return nv;
17 | }
18 |
19 | public static NameValueCollection AsNameValueCollection(this IDictionary collection){
20 | var nv=new NameValueCollection();
21 | foreach (var field in collection)
22 | {
23 | nv.Add(field.Key,field.Value.First());
24 | }
25 | return nv;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Domain/BackTransModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Unionpay.Domain
6 | {
7 | public class BackTransModel: BasePayModel
8 | {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Domain/BasePayModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Unionpay.Domain
6 | {
7 | public class BasePayModel
8 | {
9 | ///
10 | /// 商户订单号 商户代码merId、商户订单号orderId、订单发送时间txnTime三要素唯一确定一笔交易
11 | ///
12 | public string OrderId { get; set; }
13 |
14 | ///
15 | /// 交易金额
16 | ///
17 | public string TxnAmt { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Domain/FrontTransModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Unionpay.Domain
6 | {
7 | public class FrontTransModel : BasePayModel
8 | {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Extensions/UnionPayApplicationBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using OmniPay.Core.Utils;
5 | using OmniPay.Unionpay.Middleware;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Security.Cryptography.X509Certificates;
9 | using System.Text;
10 |
11 | namespace OmniPay.Unionpay.Extensions
12 | {
13 | public static class UnionPayApplicationBuilderExtensions
14 | {
15 | public static IApplicationBuilder UseUnionPay(this IApplicationBuilder app)
16 | {
17 | app.UseMiddleware();
18 | var httpContextAccessor = app.ApplicationServices.GetRequiredService();
19 | HttpUtil.Configure(httpContextAccessor);
20 | return app;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Extensions/UnionpayServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using OmniPay.Core.Hosting;
4 | using System;
5 |
6 | namespace OmniPay.Unionpay.Extensions
7 | {
8 | public static class UnionpayServiceCollectionExtensions
9 | {
10 | public static IServiceCollection AddUnionPay(this IServiceCollection services, Action action)
11 | {
12 | //services.AddTransient();
13 | return services.AddUnionPayServices(action);
14 | }
15 |
16 | private static IServiceCollection AddUnionPayServices(this IServiceCollection services, Action action)
17 | {
18 | if (action != null)
19 | {
20 | services.Configure(action.Invoke);
21 | }
22 | services.AddSingleton();
23 | return services;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/IUnionPayClient.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace OmniPay.Unionpay
8 | {
9 | public interface IUnionPayClient
10 | {
11 | ///
12 | ///
13 | ///
14 | ///
15 | ///
16 | ///
17 | ///
18 | Task ExecuteAsync(BaseRequest request);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Middleware/UnionPayMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.Extensions.Logging;
3 | using OmniPay.Core.Hosting;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace OmniPay.Unionpay.Middleware
10 | {
11 | public class UnionPayMiddleware
12 | {
13 | private readonly ILogger _logger;
14 | private readonly RequestDelegate _next;
15 |
16 | public UnionPayMiddleware(ILogger logger, RequestDelegate next)
17 | {
18 | this._logger = logger;
19 | this._next = next;
20 | }
21 |
22 | public async Task InvokeAsync(HttpContext context, IEndpointRouter router)
23 | {
24 | try
25 | {
26 | var endpoint = router.Find(context);
27 | if (endpoint != null)
28 | {
29 | _logger.LogInformation("Invoking WechatPay endpoint: {endpointType} for {url}", endpoint.GetType().FullName, context.Request.Path.ToString());
30 |
31 | var result = endpoint.Process(context);
32 |
33 | if (result != null)
34 | {
35 | _logger.LogTrace("Invoking result: {type}", result.GetType().FullName);
36 | await result.ExecuteAsync(context);
37 | }
38 | }
39 | else
40 | {
41 | context.Response.StatusCode = StatusCodes.Status404NotFound;
42 | }
43 | }
44 | catch (Exception ex)
45 | {
46 | _logger.LogCritical(ex, "Unhandled exception: {exception}", ex.Message);
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/OmniPay.Unionpay.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Request/BackTransRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Unionpay.Domain;
3 | using OmniPay.Unionpay.Response;
4 |
5 | namespace OmniPay.Unionpay.Request
6 | {
7 | public class BackTransRequest : BaseRequest
8 | {
9 | public BackTransRequest()
10 | {
11 | RequestUrl = "/backTransReq.do";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Request/FrontTransRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Unionpay.Domain;
3 | using OmniPay.Unionpay.Response;
4 |
5 | namespace OmniPay.Unionpay.Request
6 | {
7 | public class FrontTransRequest : BaseRequest
8 | {
9 | public FrontTransRequest()
10 | {
11 | RequestUrl = "/frontTransReq.do";
12 | }
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Response/BackTransResponse.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Unionpay.Request;
2 |
3 | namespace OmniPay.Unionpay.Response
4 | {
5 | public class BackTransResponse
6 | {
7 | public BackTransResponse(BackTransRequest request)
8 | {
9 | Html = request.ToForm(request.RequestUrl);
10 | }
11 |
12 | ///
13 | /// 生成的Html网页
14 | ///
15 | public string Html { get; set; }
16 |
17 | public string Raw { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Response/BaseResponse.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace OmniPay.Unionpay.Response
7 | {
8 | public abstract class BaseResponse
9 | {
10 | ///
11 | /// 返回状态码
12 | ///
13 | public string Code { get; set; }
14 |
15 | ///
16 | /// 返回码描述
17 | ///
18 | [JsonProperty("msg")]
19 | public string Message { get; set; }
20 |
21 | ///
22 | /// 明细返回码
23 | ///
24 | public string SubCode { get; set; }
25 |
26 | ///
27 | /// 明细返回码描述
28 | ///
29 | [JsonProperty("sub_msg")]
30 | public string SubMessage { get; set; }
31 |
32 | ///
33 | /// 签名
34 | ///
35 | public string Sign { get; set; }
36 |
37 | ///
38 | /// 原始值
39 | ///
40 | public string Raw { get; set; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/Response/FrontTransResponse.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Unionpay.Request;
2 |
3 | namespace OmniPay.Unionpay.Response
4 | {
5 | public class FrontTransResponse
6 | {
7 | public FrontTransResponse(FrontTransRequest request)
8 | {
9 | Html = request.ToForm(request.RequestUrl);
10 | }
11 |
12 | ///
13 | /// 生成的Html网页
14 | ///
15 | public string Html { get; set; }
16 |
17 | public string Raw { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/UnionPayClient.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Microsoft.Extensions.Options;
3 | using Newtonsoft.Json.Linq;
4 | using OmniPay.Core.Exceptions;
5 | using OmniPay.Core.Request;
6 | using OmniPay.Core.Utils;
7 | using OmniPay.Unionpay.Request;
8 | using OmniPay.Unionpay.Response;
9 | using System;
10 | using System.Threading.Tasks;
11 | using static OmniPay.Core.Utils.UnionPayUntil;
12 |
13 | namespace OmniPay.Unionpay
14 | {
15 | public class UnionPayClient : IUnionPayClient
16 | {
17 |
18 | private readonly UnionPayOptions _unionPayOptions;
19 | private readonly ILogger _logger;
20 |
21 | private UnionPayCertificate SignCertificate;
22 | private UnionPayCertificate EncryptCertificate;
23 | private UnionPayCertificate MiddleCertificate;
24 | private UnionPayCertificate RootCertificate;
25 |
26 |
27 | public UnionPayClient(IOptions unionPayOptions, ILogger logger)
28 | {
29 | this._unionPayOptions = unionPayOptions.Value;
30 | this._logger = logger;
31 |
32 | if (string.IsNullOrWhiteSpace(_unionPayOptions.Version))
33 | {
34 | throw new OmniPayException(nameof(_unionPayOptions.Version));
35 | }
36 | if (string.IsNullOrWhiteSpace(_unionPayOptions.SignCertPath))
37 | {
38 | throw new OmniPayException(nameof(_unionPayOptions.SignCertPath));
39 | }
40 | if (string.IsNullOrWhiteSpace(_unionPayOptions.SignCertPwd))
41 | {
42 | throw new OmniPayException(nameof(_unionPayOptions.SignCertPwd));
43 | }
44 |
45 | SignCertificate = UnionPayUntil.GetSignCertificate(_unionPayOptions.SignCertPath, _unionPayOptions.SignCertPwd);
46 | EncryptCertificate = UnionPayUntil.GetCertificate(_unionPayOptions.EncryptCertPath);
47 | MiddleCertificate = UnionPayUntil.GetCertificate(_unionPayOptions.MiddleCertPath);
48 | RootCertificate = UnionPayUntil.GetCertificate(_unionPayOptions.RootCertPath);
49 | }
50 |
51 |
52 |
53 |
54 | ///
55 | ///
56 | ///
57 | ///
58 | ///
59 | ///
60 | ///
61 | public async Task ExecuteAsync(BaseRequest request)
62 | {
63 | BuildParams(request);
64 | if (request is FrontTransRequest || request is BackTransRequest)
65 | {
66 | return (TResponse)Activator.CreateInstance(typeof(TResponse), request);
67 | }
68 |
69 | string result = await HttpUtil.PostAsync(request.RequestUrl, request.ToUrl());
70 | var jObject = JObject.Parse(result);
71 | var jToken = jObject.First.First;
72 | var baseResponse = (BaseResponse)(object)jToken.ToObject();
73 | return (TResponse)(object)baseResponse;
74 | }
75 |
76 | private void BuildParams(BaseRequest request)
77 | {
78 | //request.Add("version", _unionPayOptions.Version);
79 | //request.Add("encoding", _unionPayOptions.Encoding);
80 | //request.Add("bizType", _unionPayOptions.BizType);
81 | //request.Add("txnTime", _unionPayOptions.TxnTime);
82 | //request.Add("backUrl", _unionPayOptions.BackUrl);
83 | //request.Add("currencyCode", _unionPayOptions.CurrencyCode);
84 | //request.Add("txnType", _unionPayOptions.TxnType);
85 | //request.Add("txnSubType", _unionPayOptions.TxnSubType);
86 | //request.Add("accessType", _unionPayOptions.AccessType);
87 | //request.Add("frontUrl", _unionPayOptions.FrontUrl);
88 | //request.Add("signMethod", _unionPayOptions.SignMethod);
89 | //request.Add("channelType", _unionPayOptions.ChannelType);
90 | //request.Add("merId", _unionPayOptions.MerId);
91 | //request.Add("certId", SignCertificate.certId);
92 |
93 | request.Add("version", "5.1.0");
94 | request.Add("encoding", "UTF-8");
95 | request.Add("txnType", "01");
96 | request.Add("txnSubType", "01");
97 | request.Add("bizType", "000201");
98 | request.Add("signMethod", "01");
99 | request.Add("channelType", "08");
100 | request.Add("accessType", "0");
101 | request.Add("frontUrl", "http://localhost:8080/demo/api_02_b2b/FrontRcvResponse.aspx");
102 | request.Add("backUrl", "http://222.222.222.222:8080/demo/api_02_b2b/BackRcvResponse.aspx");
103 | request.Add("currencyCode", "156");
104 | request.Add("payTimeout", "20201106095402");
105 | request.Add("merId", "777290058110048");
106 | request.Add("orderId", "20201106093901185");
107 | request.Add("txnTime", "20201106093901");
108 | request.Add("txnAmt", "1000");
109 | request.Add("riskRateInfo", "{commodityName=测试商品名称}");
110 | request.Add("certId", "69629715588");
111 | var strData = request.ToUrl();
112 |
113 |
114 | //UnionPayUntil.Sign();
115 | //var signDigest = SecurityUtil.Sha256(strData, System.Text.Encoding.UTF8);
116 | //var stringSignDigest = BitConverter.ToString(signDigest).Replace("-", "").ToLower();
117 |
118 | //string stringSign = Convert.ToBase64String(byteSign);
119 |
120 | var stringSignDigest = SHA256.Compute(strData);
121 | var strSign = UnionPayUntil.SignSha256WithRsa(stringSignDigest, SignCertificate.key);
122 |
123 | request.Add("signature", strSign);
124 |
125 | request.RequestUrl = _unionPayOptions.BaseUrl + request.RequestUrl;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/OmniPay.Unionpay/UnionPayOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace OmniPay.Unionpay
6 | {
7 | public class UnionPayOptions
8 | {
9 | ///
10 | /// 版本号
11 | ///
12 | public string Version { get; set; }
13 |
14 | ///
15 | /// 编码方式
16 | ///
17 | public string Encoding => "UTF-8";
18 |
19 | ///
20 | /// 产品类型
21 | ///
22 | public string BizType => "000201";
23 |
24 | ///
25 | /// 订单发送时间
26 | ///
27 | public string TxnTime => DateTime.Now.ToString("yyyyMMddHHmmss");
28 |
29 | ///
30 | /// 后台通知地址
31 | ///
32 | public string BackUrl;
33 |
34 | ///
35 | /// 交易币种
36 | ///
37 | public string CurrencyCode => "156";
38 |
39 | ///
40 | /// 交易类型
41 | ///
42 | public string TxnType => "01";
43 |
44 | ///
45 | /// 交易子类
46 | ///
47 | public string TxnSubType => "01";
48 |
49 | ///
50 | /// 接入类型
51 | ///
52 | public string AccessType => "0";
53 |
54 | ///
55 | /// 签名
56 | ///
57 | public string Signature;
58 |
59 | ///
60 | /// 签名方法
61 | ///
62 | public string SignMethod { get; set; }
63 |
64 | ///
65 | /// 渠道类型
66 | ///
67 | public string ChannelType => "08";
68 |
69 | ///
70 | /// 商户代码
71 | ///
72 | public string MerId { get; set; }
73 |
74 | public string BaseUrl { get; set; }
75 |
76 | ///
77 | /// 前台通知地址
78 | ///
79 | public string FrontUrl { get; set; }
80 |
81 | ///
82 | /// 签名证书路径
83 | ///
84 | public string SignCertPath { get; set; }
85 |
86 | ///
87 | /// 签名证书密码
88 | ///
89 | public string SignCertPwd { get; set; }
90 |
91 | ///
92 | /// 加密证书
93 | ///
94 | public string EncryptCertPath { get; set; }
95 |
96 | ///
97 | /// 验签中级证书
98 | ///
99 | public string MiddleCertPath { get; set; }
100 |
101 | ///
102 | /// 验签根证书
103 | ///
104 | public string RootCertPath { get; set; }
105 |
106 | ///
107 | /// 散列方式签名密钥
108 | ///
109 | public string SecureKey { get; set; }
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/AppPayModel.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Utils;
2 |
3 | namespace OmniPay.Wechatpay.Domain
4 | {
5 | public class AppPayModel:BasePayModel
6 | {
7 | public AppPayModel()
8 | {
9 | TradeType = "APP";
10 | }
11 | ///
12 | /// 交易类型
13 | ///
14 | public string TradeType { get; set; }
15 |
16 | ///
17 | /// 机器IP
18 | ///
19 | public string SpbillCreateIp { get; set; }
20 | ///
21 | /// 用户标识
22 | ///
23 | public string OpenId { get; set; }
24 | ///
25 | /// 场景信息
26 | ///
27 | public string SceneInfo { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/AppletPayModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Domain
2 | {
3 | public class AppletPayModel:PublicPayModel
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/BasePayModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OmniPay.Wechatpay.Domain
4 | {
5 | ///
6 | /// Pay base class
7 | ///
8 | public class BasePayModel
9 | {
10 | ///
11 | /// 随机字符串
12 | ///
13 | public string NonceStr { get; set; }= Core.Utils.Extensions.GetNonceStr();
14 | ///
15 | /// 设备号
16 | ///
17 | public string DeviceInfo { get; set; }
18 | ///
19 | /// 商品描述
20 | ///
21 | public string Body { get; set; }
22 | ///
23 | /// 商品详细描述
24 | ///
25 | public string Detail { get; set; }
26 | ///
27 | /// 附加数据
28 | ///
29 | public string Attach { get; set; }
30 | ///
31 | /// 商户系统内部订单号
32 | ///
33 | public string OutTradeNo { get; set; }
34 |
35 | ///
36 | /// 标价金额,订单总金额,单位为分
37 | ///
38 | public int TotalFee { get; set; }
39 |
40 | ///
41 | /// 订单生成时间,格式为yyyyMMddHHmmss
42 | ///
43 | public string TimeStart { get; set; }=DateTime.Now.ToString("yyyyMMddHHmmss");
44 |
45 | ///
46 | /// 订单失效时间,格式为yyyyMMddHHmmss
47 | /// 注意:最短失效时间间隔必须大于5分钟
48 | ///
49 | public string TimeExpire { get; set; }
50 |
51 | ///
52 | /// 订单优惠标记,使用代金券或立减优惠功能时需要的参数,说明详见代金券或立减优惠
53 | ///
54 | public string GoodsTag { get; set; }
55 |
56 | ///
57 | /// 指定支付方式,上传此参数no_credit--可限制用户不能使用信用卡支付
58 | ///
59 | public string LimitPay { get; set; }
60 | ///
61 | /// 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
62 | ///
63 | public string SignType { get; set; } = "HMAC-SHA256";
64 |
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/CloseModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Domain
2 | {
3 | public class CloseModel
4 | {
5 | ///
6 | /// 商户订单
7 | /// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
8 | ///
9 | public string OutTradeNo { get; set; }
10 | ///
11 | /// 随机字符串
12 | ///
13 | public string NonceStr { get; } = Core.Utils.Extensions.GetNonceStr();
14 | ///
15 | /// 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
16 | ///
17 | public string SignType { get; set; } = "HMAC-SHA256";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/PublicPayModel.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Utils;
2 |
3 | namespace OmniPay.Wechatpay.Domain
4 | {
5 | public class PublicPayModel:BasePayModel
6 | {
7 | public PublicPayModel()
8 | {
9 | TradeType = "JSAPI";
10 | }
11 | ///
12 | /// 交易类型
13 | ///
14 | public string TradeType { get; set; }
15 |
16 | ///
17 | /// 机器IP
18 | ///
19 | public string SpbillCreateIp { get; set; }
20 | ///
21 | /// 用户标识
22 | ///
23 | public string OpenId { get; set; }
24 | ///
25 | /// 场景信息
26 | ///
27 | public string SceneInfo { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/QueryModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Domain
2 | {
3 | public class QueryModel
4 | {
5 | ///
6 | /// 商户系统内部订单号,该订单号和微信订单号二选一即可,如果二者都存在则优先微信订单号
7 | ///
8 | public string OutTradeNo { get; set; }
9 | ///
10 | /// 微信订单号,和商户订单号不能同时为空
11 | ///
12 | public string TransactionId { get; set; }
13 | ///
14 | /// 随机字符串
15 | ///
16 | public string NonceStr { get; } = Core.Utils.Extensions.GetNonceStr();
17 | ///
18 | /// 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
19 | ///
20 | public string SignType { get; set; } = "HMAC-SHA256";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/RefundModel.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Domain
2 | {
3 | public class RefundModel
4 | {
5 | ///
6 | /// 随机字符串
7 | ///
8 | public string NonceStr { get; } = Core.Utils.Extensions.GetNonceStr();
9 | ///
10 | /// 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
11 | ///
12 | public string SignType { get; set; } = "HMAC-SHA256";
13 |
14 | ///
15 | /// 微信订单号
16 | ///
17 | public string TransactionId { get; set; }
18 |
19 | ///
20 | /// 商户订单
21 | /// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
22 | ///
23 | public string OutTradeNo { get; set; }
24 |
25 | ///
26 | /// 商户退款单号
27 | ///
28 | public string OutRefundNo { get; set; }
29 |
30 | ///
31 | /// 订单金额
32 | ///
33 | public int TotalFee { get; set; }
34 |
35 | ///
36 | /// 退款金额
37 | ///
38 | public int RefundFee { get; set; }
39 |
40 | ///
41 | /// 退款货币种类
42 | ///
43 | public string RefundFeeType { get; set; }
44 |
45 | ///
46 | /// 退款原因
47 | ///
48 | public string RefundDesc { get; set; }
49 |
50 | ///
51 | /// 退款资金来源
52 | ///
53 | public string RefundAccount { get; set; }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/ScanPayModel.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Utils;
2 |
3 | namespace OmniPay.Wechatpay.Domain
4 | {
5 | public class ScanPayModel : BasePayModel
6 | {
7 | public ScanPayModel()
8 | {
9 | TradeType = "NATIVE";
10 | }
11 |
12 | ///
13 | /// 交易类型
14 | ///
15 | public string TradeType { get; set; }
16 |
17 | ///
18 | /// 机器IP
19 | ///
20 | public string SpbillCreateIp { get; set; }
21 | ///
22 | /// 商品ID
23 | ///
24 | public string ProductId { get; set; }
25 | ///
26 | /// 用户标识
27 | ///
28 | public string OpenId { get; set; }
29 | ///
30 | /// 场景信息
31 | ///
32 | public string SceneInfo { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Domain/WapPayModel.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Utils;
2 |
3 | namespace OmniPay.Wechatpay.Domain
4 | {
5 | public class WapPayModel: BasePayModel
6 | {
7 | public WapPayModel()
8 | {
9 | TradeType = "MWEB";
10 | }
11 | ///
12 | /// 交易类型
13 | ///
14 | public string TradeType { get; set; }
15 |
16 | ///
17 | /// 机器IP
18 | ///
19 | public string SpbillCreateIp { get; set; }
20 | ///
21 | /// 商品ID
22 | ///
23 | public string ProductId { get; set; }
24 | ///
25 | /// 用户标识
26 | ///
27 | public string OpenId { get; set; }
28 | ///
29 | /// 场景信息
30 | ///
31 | public string SceneInfo { get; set; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/AppPayResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class AppPayResult:IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public AppPayResult(IWeChatPayClient client){
15 | this._client=client;
16 | }
17 | public async Task ExecuteAsync(HttpContext context)
18 | {
19 | try
20 | {
21 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
22 | if (body?.Count == 0) {
23 | throw new ArgumentNullException (nameof (body));
24 | }
25 | var request=new AppPayRequest();
26 | request.AddParameters(new AppPayModel()
27 | {
28 | Body = body.Get("Body"),
29 | OutTradeNo = body.Get("Out_Trade_No"),
30 | TotalFee =int.Parse(body.Get("Total_Amount"))
31 | });
32 | await context.Response.WriteAsync ((await _client.ExecuteAsync (request)).ToJson());
33 | }
34 | catch (System.Exception ex)
35 | {
36 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
37 | await context.Response.WriteAsync (ex.Message);
38 | }
39 | context.Response.ContentType = "application/json; charset=UTF-8";
40 | await context.Response.Body.FlushAsync ();
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/AppletPayResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class AppletPayResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public AppletPayResult(IWeChatPayClient client)
15 | {
16 | this._client = client;
17 | }
18 |
19 | public async Task ExecuteAsync(HttpContext context)
20 | {
21 | try
22 | {
23 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
24 | if (body?.Count == 0)
25 | {
26 | throw new ArgumentNullException(nameof(body));
27 | }
28 | var request = new AppletPayRequest();
29 | request.AddParameters(new AppletPayModel()
30 | {
31 | Body = body.Get("Body"),
32 | OutTradeNo = body.Get("Out_Trade_No"),
33 | TotalFee = int.Parse(body.Get("Total_Amount")),
34 | OpenId = body.Get("OpenId")
35 | });
36 | await context.Response.WriteAsync((await _client.ExecuteAsync(request)).ToJson());
37 | }
38 | catch (System.Exception ex)
39 | {
40 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
41 | await context.Response.WriteAsync(ex.Message);
42 | }
43 | context.Response.ContentType = "application/json; charset=UTF-8";
44 | await context.Response.Body.FlushAsync();
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/CloseResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class CloseResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public CloseResult(IWeChatPayClient client){
15 | this._client=client;
16 | }
17 | public async Task ExecuteAsync(HttpContext context)
18 | {
19 | try
20 | {
21 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
22 | if (body?.Count == 0) {
23 | throw new ArgumentNullException (nameof (body));
24 | }
25 | var request = new CloseRequest();
26 | request.AddParameters(new CloseModel()
27 | {
28 | OutTradeNo = body.Get("Out_Trade_No")
29 | });
30 | await context.Response.WriteAsync ((await _client.ExecuteAsync (request)).ToJson());
31 | }
32 | catch (System.Exception ex)
33 | {
34 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
35 | await context.Response.WriteAsync (ex.Message);
36 | }
37 | context.Response.ContentType = "application/json; charset=UTF-8";
38 | await context.Response.Body.FlushAsync ();
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/PublicPayResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class PublicPayResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public PublicPayResult(IWeChatPayClient client){
15 | this._client=client;
16 | }
17 |
18 | public async Task ExecuteAsync(HttpContext context)
19 | {
20 | try
21 | {
22 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
23 | if (body?.Count == 0) {
24 | throw new ArgumentNullException (nameof (body));
25 | }
26 | var request=new PublicPayRequest();
27 | request.AddParameters(new PublicPayModel()
28 | {
29 | Body =body.Get("Body"),
30 | OutTradeNo = body.Get("Out_Trade_No"),
31 | TotalFee =int.Parse(body.Get("Total_Amount")),
32 | OpenId = body.Get("OpenId")
33 | });
34 | await context.Response.WriteAsync ((await _client.ExecuteAsync (request)).ToJson());
35 |
36 | }
37 | catch (System.Exception ex)
38 | {
39 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
40 | await context.Response.WriteAsync (ex.Message);
41 | }
42 | context.Response.ContentType = "application/json; charset=UTF-8";
43 | await context.Response.Body.FlushAsync ();
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/QueryResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class QueryResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public QueryResult(IWeChatPayClient client){
15 | this._client=client;
16 | }
17 | public async Task ExecuteAsync(HttpContext context)
18 | {
19 | try
20 | {
21 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
22 | if (body?.Count == 0) {
23 | throw new ArgumentNullException (nameof (body));
24 | }
25 | var request = new QueryRequest();
26 | request.AddParameters(new QueryModel()
27 | {
28 | TransactionId = body.Get("TradeNo"),
29 | OutTradeNo = body.Get("Out_Trade_No")
30 | });
31 | await context.Response.WriteAsync ((await _client.ExecuteAsync (request)).ToJson());
32 | }
33 | catch (System.Exception ex)
34 | {
35 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
36 | await context.Response.WriteAsync (ex.Message);
37 | }
38 | context.Response.ContentType = "application/json; charset=UTF-8";
39 | await context.Response.Body.FlushAsync ();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/ScanPayResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class ScanPayResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 |
15 | public ScanPayResult(IWeChatPayClient client)
16 | {
17 | this._client = client;
18 | }
19 |
20 | public async Task ExecuteAsync(HttpContext context)
21 | {
22 | try
23 | {
24 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
25 | if (body?.Count == 0)
26 | {
27 | throw new ArgumentNullException(nameof(body));
28 | }
29 | var request = new ScanPayRequest();
30 | request.AddParameters(new ScanPayModel()
31 | {
32 | Body = body.Get("Body"),
33 | OutTradeNo = body.Get("Out_Trade_No"),
34 | TotalFee = int.Parse(body.Get("Total_Amount"))
35 | });
36 | await context.Response.WriteAsync((await _client.ExecuteAsync(request)).ToJson());
37 | }
38 | catch (Exception ex)
39 | {
40 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
41 | await context.Response.WriteAsync(ex.Message);
42 | }
43 | context.Response.ContentType = "application/json; charset=UTF-8";
44 | await context.Response.Body.FlushAsync();
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/Result/WapPayResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Domain;
7 | using OmniPay.Wechatpay.Request;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints.Result
10 | {
11 | public class WapPayResult : IEndpointResult
12 | {
13 | private readonly IWeChatPayClient _client;
14 | public WapPayResult(IWeChatPayClient client){
15 | this._client=client;
16 | }
17 | public async Task ExecuteAsync(HttpContext context)
18 | {
19 | try
20 | {
21 | var body = (await context.Request.ReadFormAsync()).AsNameValueCollection();
22 | if (body?.Count==0)
23 | {
24 | throw new ArgumentNullException(nameof(body));
25 | }
26 | var request = new WapPayRequest();
27 | request.AddParameters(new WapPayModel()
28 | {
29 | Body =body.Get("Body"),
30 | OutTradeNo = body.Get("Out_Trade_No"),
31 | TotalFee =int.Parse(body.Get("Total_Amount"))
32 | });
33 | await context.Response.WriteAsync ((await _client.ExecuteAsync (request)).ToJson());
34 | }
35 | catch (Exception ex)
36 | {
37 | context.Response.StatusCode = StatusCodes.Status500InternalServerError;
38 | await context.Response.WriteAsync (ex.Message);
39 | }
40 | context.Response.ContentType = "application/json; charset=UTF-8";
41 | await context.Response.Body.FlushAsync ();
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatAppPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatAppPayEndpoint : IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 |
15 | public WechatAppPayEndpoint(ILogger logger,IWeChatPayClient client){
16 | this._logger=logger;
17 | this._client=client;
18 | }
19 | public IEndpointResult Process(HttpContext context)
20 | {
21 | _logger.LogDebug("Start WechatAppPay request");
22 |
23 | if (!HttpMethods.IsPost(context.Request.Method))
24 | {
25 | _logger.LogWarning("Invalid HTTP method for ScanPay endpoint.");
26 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
27 | }
28 | _logger.LogTrace("End WechatAppPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
29 | return new AppPayResult(_client);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatAppletPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatAppletPayEndpoint : IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 |
15 | public WechatAppletPayEndpoint(ILogger logger,IWeChatPayClient client){
16 | this._logger=logger;
17 | this._client=client;
18 | }
19 | public IEndpointResult Process(HttpContext context)
20 | {
21 | _logger.LogDebug("Start WechatAppletPay request");
22 |
23 | if (!HttpMethods.IsPost(context.Request.Method))
24 | {
25 | _logger.LogWarning("Invalid HTTP method for AppletPay endpoint.");
26 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
27 | }
28 | _logger.LogTrace("End WechatAppletPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
29 | return new AppletPayResult(_client);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatCloseEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatCloseEndpoint:IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 |
15 | public WechatCloseEndpoint(ILogger logger,IWeChatPayClient client){
16 | this._logger=logger;
17 | this._client=client;
18 | }
19 | public IEndpointResult Process(HttpContext context)
20 | {
21 | _logger.LogDebug("Start WechatClose request");
22 |
23 | if (!HttpMethods.IsPost(context.Request.Method))
24 | {
25 | _logger.LogWarning("Invalid HTTP method for Close endpoint.");
26 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
27 | }
28 | _logger.LogTrace("End WechatClose request. result type: {0}", this?.GetType().ToString() ?? "-none-");
29 | return new CloseResult(_client);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatPublicPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatPublicPayEndpoint:IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 |
15 | public WechatPublicPayEndpoint(ILogger logger,IWeChatPayClient client){
16 | this._logger=logger;
17 | this._client=client;
18 | }
19 | public IEndpointResult Process(HttpContext context)
20 | {
21 | _logger.LogDebug("Start WechatPublicPay request");
22 |
23 | if (!HttpMethods.IsPost(context.Request.Method))
24 | {
25 | _logger.LogWarning("Invalid HTTP method for PublicPay endpoint.");
26 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
27 | }
28 | _logger.LogTrace("End WechatPublicPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
29 | return new PublicPayResult(_client);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatQueryEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatQueryEndpoint:IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 |
15 | public WechatQueryEndpoint(ILogger logger,IWeChatPayClient client){
16 | this._logger=logger;
17 | this._client=client;
18 | }
19 | public IEndpointResult Process(HttpContext context)
20 | {
21 | _logger.LogDebug("Start WechatQuery request");
22 |
23 | if (!HttpMethods.IsPost(context.Request.Method))
24 | {
25 | _logger.LogWarning("Invalid HTTP method for PublicPay endpoint.");
26 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
27 | }
28 | _logger.LogTrace("End WechatQuery request. result type: {0}", this?.GetType().ToString() ?? "-none-");
29 | return new QueryResult(_client);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatScanPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 | using OmniPay.Wechatpay.Validation;
8 |
9 | namespace OmniPay.Wechatpay.Endpoints
10 | {
11 | public class WechatScanPayEndpoint : IEndpointHandler
12 | {
13 | private readonly ILogger _logger;
14 | private readonly IWeChatPayClient _client;
15 |
16 | public WechatScanPayEndpoint(ILogger logger, IWeChatPayClient client)
17 | {
18 | this._logger = logger;
19 | this._client = client;
20 | }
21 |
22 | public IEndpointResult Process(HttpContext context)
23 | {
24 | _logger.LogDebug("Start WechatScanPay request");
25 |
26 | if (!HttpMethods.IsPost(context.Request.Method))
27 | {
28 | _logger.LogWarning("Invalid HTTP method for ScanPay endpoint.");
29 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
30 | }
31 |
32 | //var validateResult = _validator.ValidateAsync(context).GetAwaiter().GetResult();
33 | //if (validateResult.IsError)
34 | //{
35 | // return Error(validateResult.Error);
36 | //}
37 | _logger.LogTrace("End WechatScanPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
38 | return new ScanPayResult(_client);
39 | }
40 |
41 | private IEndpointResult Error(string error, string description = null)
42 | {
43 | return new ProccessErrorResult(error, description);
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Endpoints/WechatWapPayEndpoint.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using OmniPay.Core.Hosting;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay.Endpoints.Result;
7 |
8 | namespace OmniPay.Wechatpay.Endpoints
9 | {
10 | public class WechatWapPayEndpoint : IEndpointHandler
11 | {
12 | private readonly ILogger _logger;
13 | private readonly IWeChatPayClient _client;
14 | public WechatWapPayEndpoint(ILogger logger,IWeChatPayClient client){
15 | this._logger=logger;
16 | this._client=client;
17 | }
18 | public IEndpointResult Process(HttpContext context)
19 | {
20 | _logger.LogDebug("Start WechatWapPay request");
21 | if (!HttpMethods.IsPost(context.Request.Method))
22 | {
23 | _logger.LogWarning("Invalid HTTP method for ScanPay endpoint.");
24 | return new StatusCodeResult(HttpStatusCode.MethodNotAllowed);
25 | }
26 | _logger.LogTrace("End WechatWapPay request. result type: {0}", this?.GetType().ToString() ?? "-none-");
27 | return new WapPayResult(_client);
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Extensions/WeChatPayApplicationBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using OmniPay.Core.Utils;
5 | using OmniPay.Wechatpay.Middleware;
6 |
7 | namespace OmniPay.Wechatpay.Extensions
8 | {
9 | public static class WeChatPayApplicationBuilderExtensions
10 | {
11 | //public static IEndpointConventionBuilder UseWeChatPayEndpoints(this IEndpointRouteBuilder endpoints,string pattern) {
12 | // var pipeline = endpoints.CreateApplicationBuilder()
13 | // .UseMiddleware().Build();
14 | // return endpoints.Map(pattern, pipeline).WithDisplayName("wechatpay") ;
15 | //}
16 |
17 | ///
18 | /// 使用OmniPay
19 | ///
20 | ///
21 | ///
22 | public static IApplicationBuilder UseOmniPay(this IApplicationBuilder app)
23 | {
24 | app.UseMiddleware();
25 | //var httpContextAccessor = app.ApplicationServices.GetRequiredService();
26 | //HttpUtil.Configure(httpContextAccessor);
27 | return app;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Extensions/WeChatServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.DependencyInjection.Extensions;
4 | using OmniPay.Wechatpay.Validation;
5 | using OmniPay.Wechatpay.Validation.Default;
6 | using System;
7 |
8 | namespace OmniPay.Wechatpay.Extensions
9 | {
10 | public static class WeChatServiceCollectionExtensions
11 | {
12 | public static IServiceCollection AddWeChatPay(this IServiceCollection services, Action action)
13 | {
14 | //services.AddSingleton();
15 | //services.AddSingleton();
16 | //services.AddSingleton();
17 | //services.AddSingleton();
18 | //services.AddSingleton();
19 | //services.AddSingleton(new Endpoint("wechatScanPay", "/pay-api/Wechatpay/ScanPay", typeof(WechatScanPayEndpoint)));
20 | //services.AddSingleton(new Endpoint("wechatWapPay", "/pay-api/Wechatpay/WapPay", typeof(WechatWapPayEndpoint)));
21 | //services.AddSingleton(new Endpoint("wechatAppPay", "/pay-api/Wechatpay/AppPay", typeof(WechatAppPayEndpoint)));
22 | //services.AddSingleton(new Endpoint("wechatPublicPay", "/pay-api/Wechatpay/PublicPay", typeof(WechatPublicPayEndpoint)));
23 | //services.AddSingleton(new Endpoint("wechatAppletPay", "/pay-api/Wechatpay/AppletPay", typeof(WechatAppletPayEndpoint)));
24 | return services.AddWeChatPayServices(action);
25 | }
26 |
27 | ///
28 | /// 验证
29 | ///
30 | ///
31 | ///
32 | ///
33 | /// 该验证设计目的主要用于自动api控制层,当然他的当前局限是不可以按照指定模型输出内容
34 | /// 在后期的模块设计中可以考虑该模块的自定义模型输出
35 | ///
36 | public static IServiceCollection AddValidators(this IServiceCollection services)
37 | {
38 | services.TryAddTransient();
39 | return services;
40 | }
41 |
42 | private static IServiceCollection AddWeChatPayServices(this IServiceCollection services, Action action)
43 | {
44 | if (action != null)
45 | {
46 | services.Configure(action.Invoke);
47 | }
48 | services.TryAddSingleton();
49 | services.AddSingleton();
50 | return services;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/IWeChatPayClient.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using OmniPay.Core.Request;
3 |
4 | namespace OmniPay.Wechatpay
5 | {
6 | public interface IWeChatPayClient
7 | {
8 | ///
9 | /// Execute WeChatPay API request
10 | ///
11 | ///
12 | ///
13 | ///
14 | Task ExecuteAsync(BaseRequest request);
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Middleware/ApiEndpointMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Http;
5 |
6 | namespace OmniPay.Wechatpay.Middleware
7 | {
8 | ///
9 | /// WeChat Pay middleware
10 | ///
11 | public class ApiEndpointMiddleware
12 | {
13 | private readonly RequestDelegate _next;
14 |
15 | public ApiEndpointMiddleware(RequestDelegate next)
16 | {
17 | _next = next;
18 | }
19 |
20 | public async Task InvokeAsync(HttpContext context)
21 | {
22 | //Access request method
23 | var responseContent = context.Request.Path.Value.Replace("/pay-api","");
24 | responseContent = responseContent.TrimStart('/');
25 |
26 | context.Response.ContentType = "application/json";
27 | //Reflective access methods
28 | Type t = typeof(TestPay);
29 | var tuple= GetObjectMethodTuple(t, responseContent);
30 | if (tuple.Item1 == null) throw new NotImplementedException("not implement the stack");
31 |
32 | string str = tuple.Item1.Invoke(tuple.Item2, null).ToString();
33 |
34 | await context.Response.WriteAsync(str);
35 | }
36 |
37 |
38 | public static Tuple GetObjectMethodTuple(Type type,string methodname) {
39 | object obj = Activator.CreateInstance(type);
40 | MethodInfo mt = type.GetMethod(methodname);
41 | return new Tuple(mt,obj);
42 | }
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Middleware/WechatPayMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.Extensions.Logging;
5 | using OmniPay.Core.Hosting;
6 |
7 | namespace OmniPay.Wechatpay.Middleware
8 | {
9 | public class WechatPayMiddleware
10 | {
11 | private readonly ILogger _logger;
12 | private readonly RequestDelegate _next;
13 |
14 | public WechatPayMiddleware(RequestDelegate next, ILogger logger)
15 | {
16 | _logger = logger;
17 | _next = next;
18 | }
19 |
20 | public async Task InvokeAsync(HttpContext context, IEndpointRouter router)
21 | {
22 | try
23 | {
24 | var endpoint = router.Find(context);
25 | if (endpoint != null)
26 | {
27 | _logger.LogInformation("Invoking WechatPay endpoint: {endpointType} for {url}", endpoint.GetType().FullName, context.Request.Path.ToString());
28 |
29 | var result =endpoint.Process(context);
30 |
31 | if (result != null)
32 | {
33 | _logger.LogTrace("Invoking result: {type}", result.GetType().FullName);
34 | await result.ExecuteAsync(context);
35 | }
36 | }else{
37 | context.Response.StatusCode = StatusCodes.Status404NotFound;
38 | }
39 |
40 | }
41 | catch (Exception ex)
42 | {
43 | _logger.LogCritical(ex, "Unhandled exception: {exception}", ex.Message);
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/OmniPay.Wechatpay.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | OmniPay.Wechatpay
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/AppPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class AppPayRequest : BaseRequest
8 | {
9 | public AppPayRequest()
10 | {
11 | RequestUrl = "/pay/unifiedorder";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/AppletPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class AppletPayRequest : BaseRequest
8 | {
9 | public AppletPayRequest()
10 | {
11 | RequestUrl = "/pay/unifiedorder";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/CloseRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class CloseRequest : BaseRequest
8 | {
9 | public CloseRequest()
10 | {
11 | RequestUrl = "/pay/closeorder";
12 | }
13 | public override void Execute()
14 | {
15 | Remove("notify_url");
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/PublicPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class PublicPayRequest:BaseRequest
8 | {
9 | public PublicPayRequest()
10 | {
11 | RequestUrl = "/pay/unifiedorder";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/QueryRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class QueryRequest:BaseRequest
8 | {
9 | public QueryRequest()
10 | {
11 | RequestUrl = "/pay/orderquery";
12 | }
13 | public override void Execute()
14 | {
15 | Remove("notify_url");
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/RefundRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class RefundRequest : BaseRequest
8 | {
9 | public RefundRequest()
10 | {
11 | RequestUrl = "/secapi/pay/refund";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/ScanPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class ScanPayRequest:BaseRequest
8 | {
9 | public ScanPayRequest()
10 | {
11 | RequestUrl = "/pay/unifiedorder";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Request/WapPayRequest.cs:
--------------------------------------------------------------------------------
1 | using OmniPay.Core.Request;
2 | using OmniPay.Wechatpay.Domain;
3 | using OmniPay.Wechatpay.Response;
4 |
5 | namespace OmniPay.Wechatpay.Request
6 | {
7 | public class WapPayRequest : BaseRequest
8 | {
9 | public WapPayRequest()
10 | {
11 | RequestUrl = "/pay/unifiedorder";
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/AppPayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class AppPayResponse:BaseResponse
4 | {
5 |
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/AppletPayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class AppletPayResponse:PublicPayResponse
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/BaseResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public abstract class BaseResponse
4 | {
5 | ///
6 | /// 应用ID
7 | ///
8 | public string Appid { get; set; }
9 |
10 | ///
11 | /// 商户号
12 | ///
13 | public string MchId { get; set; }
14 |
15 | ///
16 | /// 设备号
17 | ///
18 | public string DeviceInfo { get; set; }
19 |
20 | ///
21 | /// 随机字符串
22 | ///
23 | public string NonceStr { get; set; }
24 |
25 | ///
26 | /// 签名
27 | ///
28 | public string Sign { get; set; }
29 |
30 | ///
31 | /// 业务结果
32 | ///
33 | public string ReturnCode { get; set; }
34 |
35 | ///
36 | /// 错误代码
37 | ///
38 | public string ErrCode { get; set; }
39 |
40 | ///
41 | /// 错误代码描述
42 | ///
43 | public string ErrCodeDes { get; set; }
44 |
45 | ///
46 | /// 返回状态码
47 | ///
48 | public string ResultCode { get; set; }
49 |
50 | ///
51 | /// 返回信息
52 | ///
53 | public string ReturnMsg { get; set; }
54 |
55 | ///
56 | /// 原始值
57 | ///
58 | public string Raw { get; set; }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/CloseResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class CloseResponse: BaseResponse
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/PublicPayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class PublicPayResponse:BaseResponse
4 | {
5 | ///
6 | /// 交易类型
7 | ///
8 | public string TradeType { get; set; }
9 |
10 | ///
11 | /// 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
12 | ///
13 | public string PrepayId { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/QueryResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class QueryResponse:BaseResponse
4 | {
5 | ///
6 | /// 用户标识
7 | ///
8 | public string OpenId { get; set; }
9 | ///
10 | /// 是否关注公众账号
11 | /// 用户是否关注公众账号,Y-关注,N-未关注
12 | ///
13 | public string IsSubscribe { get; set; }
14 | ///
15 | /// 交易类型
16 | /// 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP,MICROPAY
17 | ///
18 | public string TradeType { get; set; }
19 | ///
20 | /// 交易状态
21 | /// SUCCESS-支付成功
22 | /// REFUND-转入退款
23 | /// NOTPAY-未支付
24 | /// CLOSED-已关闭
25 | /// REVOKED-已撤销(刷卡支付)
26 | /// USERPAYING-用户支付中
27 | /// PAYERROR-支付失败(其他原因,如银行返回失败)
28 | /// 支付状态机请见下单API页面
29 | ///
30 | public string TradeState { get; set; }
31 | ///
32 | /// 银行类型,采用字符串类型的银行标识,详见银行类型
33 | ///
34 | public string BankType { get; set; }
35 | ///
36 | /// 订单金额
37 | /// 订单总金额,单位为分
38 | ///
39 | public int TotalFree { get; set; }
40 | ///
41 | /// 现金支付货币类型
42 | /// 货币类型,符合ISO 4217标准的三位字符代码,默认人民币:CNY,其他值列表详见
43 | ///
44 | public string CashFreeType { get; set; }
45 | ///
46 | /// 代金券金额
47 | /// "代金券"金额≤订单金额,订单金额-"代金券"金额=现金支付金额
48 | ///
49 | public int CouponFree { get; set; }
50 | ///
51 | /// 代金券使用数量
52 | ///
53 | public string CouponCount { get; set; }
54 | ///
55 | /// 微信支付订单号
56 | ///
57 | public string TransactionId { get; set; }
58 | ///
59 | /// 商户订单号
60 | ///
61 | public string OutTradeNo { get; set; }
62 | ///
63 | /// 商户附加数据包
64 | ///
65 | public string Attach { get; set; }
66 | ///
67 | /// 支付完成时间
68 | ///
69 | public string TimeEnd { get; set; }
70 | ///
71 | /// 交易状态描述
72 | ///
73 | public string TradeStateDesc { get; set; }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/RefundResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class RefundResponse : BaseResponse
4 | {
5 | ///
6 | /// 微信订单号
7 | ///
8 | public string TransactionId { get; set; }
9 |
10 | ///
11 | /// 商户订单号
12 | ///
13 | public string OutTradeNo { get; set; }
14 |
15 | ///
16 | /// 商户退款单号
17 | ///
18 | public string OutRefundNo { get; set; }
19 |
20 | ///
21 | /// 微信退款单号
22 | ///
23 | public string RefundId { get; set; }
24 |
25 | ///
26 | /// 退款金额
27 | ///
28 | public int RefundFee { get; set; }
29 |
30 | ///
31 | /// 应结退款金额
32 | ///
33 | public int SettlementRefundFee { get; set; }
34 |
35 | ///
36 | /// 标价金额
37 | ///
38 | public int TotalFee { get; set; }
39 |
40 | ///
41 | /// 现金支付金额
42 | ///
43 | public int CashFee { get; set; }
44 |
45 | ///
46 | /// 现金支付币种
47 | ///
48 | public string CashFeeType { get; set; }
49 |
50 | ///
51 | /// 代金券退款总金额
52 | ///
53 | public int CouponRefundFee { get; set; }
54 |
55 | ///
56 | /// 退款代金券使用数量
57 | ///
58 | public int CouponRefundCount { get; set; }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/ScanPayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class ScanPayResponse:BaseResponse
4 | {
5 | ///
6 | /// 交易类型
7 | ///
8 | public string TradeType { get; set; }
9 |
10 | ///
11 | /// 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
12 | ///
13 | public string PrepayId { get; set; }
14 |
15 | ///
16 | /// 二维码链接
17 | ///
18 | public string CodeUrl { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Response/WapPayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Response
2 | {
3 | public class WapPayResponse:BaseResponse
4 | {
5 | ///
6 | /// 交易类型
7 | ///
8 | public string TradeType { get; set; }
9 | ///
10 | /// 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
11 | ///
12 | public string PrepayId { get; set; }
13 |
14 | ///
15 | /// 支付跳转链接
16 | /// mweb_url为拉起微信支付收银台的中间页面,可通过访问该url来拉起微信客户端,完成支付,mweb_url的有效期为5分钟。
17 | ///
18 | public string MwebUrl { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Results/TestWxResult.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 | using OmniPay.Core.Hosting;
4 |
5 | namespace OmniPay.Wechatpay.Results
6 | {
7 | public class TestWxResult : IEndpointResult
8 | {
9 | public async Task ExecuteAsync(HttpContext context)
10 | {
11 | context.Response.ContentType = "application/json; charset=UTF-8";
12 | await context.Response.WriteAsync("微信支付成功!");
13 | await context.Response.Body.FlushAsync();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/TestPay.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay
2 | {
3 | public class TestPay
4 | {
5 | public string TestWxPay() {
6 |
7 | return "微信支付成功";
8 | }
9 |
10 |
11 | public string TestaliPay()
12 | {
13 | return "支付宝支付成功";
14 | }
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Validation/Default/ScanPayValidator.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hueifeng/OmniPay/3761886d6c1106e4018a22fd43726ff5e21e435f/src/OmniPay.Wechatpay/Validation/Default/ScanPayValidator.cs
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Validation/IScanPayValidator.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Http;
3 |
4 | namespace OmniPay.Wechatpay.Validation
5 | {
6 | public interface IScanPayValidator
7 | {
8 | Task ValidateAsync(HttpContext context);
9 | }
10 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Validation/Models/ScanPayRequestValidationResult.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Validation.Models
2 | {
3 | public class ScanPayRequestValidationResult
4 | {
5 | public string Result { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/Validation/ValidationResult.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay.Validation
2 | {
3 | public class ValidationResult
4 | {
5 | ///
6 | /// Gets or sets a value indicating whether the validation was successful.
7 | ///
8 | public bool IsError { get; set; } = true;
9 |
10 | ///
11 | /// Gets or sets the error.
12 | ///
13 | ///
14 | /// The error.
15 | ///
16 | public string Error { get; set; }
17 |
18 | ///
19 | /// Gets or sets the error description.
20 | ///
21 | ///
22 | /// The error description.
23 | ///
24 | public string ErrorDescription { get; set; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/WeChatPayClient.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using Microsoft.Extensions.Options;
3 | using OmniPay.Core.Exceptions;
4 | using OmniPay.Core.Request;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay.Response;
7 | using System.Threading.Tasks;
8 |
9 | namespace OmniPay.Wechatpay
10 | {
11 | public class WeChatPayClient : IWeChatPayClient
12 | {
13 | private readonly WeChatPayOptions _weChatPayOptions;
14 | private readonly ILogger _logger;
15 | private readonly IHttpHandler _httpHandler;
16 |
17 | public WeChatPayClient(IOptions weChatPayOptions, ILogger logger,
18 | IHttpHandler httpHandler)
19 | {
20 | _weChatPayOptions = weChatPayOptions.Value;
21 | _logger = logger;
22 | _httpHandler = httpHandler;
23 | }
24 |
25 | ///
26 | /// Execute WeChatPay API request implementation
27 | ///
28 | ///
29 | ///
30 | ///
31 | ///
32 | public async Task ExecuteAsync(BaseRequest request)
33 | {
34 | BuildParams(request);
35 | var result = await _httpHandler.PostAsync(request.RequestUrl, request.ToXml(), _weChatPayOptions.HttpClientName, null);
36 | request.FromXml(result);
37 | var baseResponse = (BaseResponse)(object)request.ToObject();
38 | baseResponse.Raw = result;
39 | var repSign = request.GetStringValue("sign");
40 | if (string.IsNullOrEmpty(repSign) && !CheckSign(request, repSign, _weChatPayOptions.Key))
41 | {
42 | _logger.LogError("Signature verification failed:{0}", result);
43 | throw new OmniPayException("Signature verification failed.");
44 | }
45 | return (TResponse)(object)baseResponse;
46 | }
47 |
48 | private void BuildParams(BaseRequest request)
49 | {
50 | if (string.IsNullOrEmpty(_weChatPayOptions.AppId))
51 | {
52 | throw new OmniPayException(nameof(_weChatPayOptions.AppId));
53 | }
54 | request.Add("appid", _weChatPayOptions.AppId);
55 | request.Add("mch_id", _weChatPayOptions.MchId);
56 | request.Add("notify_url", _weChatPayOptions.NotifyUrl);
57 | request.Execute();
58 | request.Add("sign", BuildSign(request, _weChatPayOptions.Key, request.GetStringValue("sign_type") == "HMAC-SHA256"));
59 | request.RequestUrl = _weChatPayOptions.BaseUrl + request.RequestUrl;
60 | }
61 |
62 | internal static string BuildSign(BaseRequest request, string key, bool isHMACSHA256 = false)
63 | {
64 | var data = string.Join("&", $"{request.ToUrl(false)}&key={key}");
65 | return isHMACSHA256 ? EncryptUtil.HMACSHA256(data, key) : EncryptUtil.MD5(data);
66 | }
67 |
68 | internal static bool CheckSign(BaseRequest request, string sign, string key)
69 | {
70 | return BuildSign(request, key) == sign;
71 | }
72 |
73 | }
74 | }
--------------------------------------------------------------------------------
/src/OmniPay.Wechatpay/WeChatPayOptions.cs:
--------------------------------------------------------------------------------
1 | namespace OmniPay.Wechatpay
2 | {
3 | public class WeChatPayOptions
4 | {
5 | ///
6 | /// Application ID
7 | ///
8 | public string AppId { get; set; }
9 |
10 | ///
11 | /// Signature type
12 | ///
13 | public string SignType=>"MD5";
14 | ///
15 | /// WeChat pay API keys
16 | ///
17 | public string Key { get; set; }
18 | ///
19 | /// Merchant Id
20 | ///
21 | public string MchId { get; set; }
22 |
23 | ///
24 | /// App Secret
25 | ///
26 | public string AppSecret { get; set; }
27 |
28 | ///
29 | /// Notice the URL
30 | ///
31 | public string NotifyUrl { get; set; }
32 |
33 | ///
34 | /// Merchants public key
35 | ///
36 | public string PublicKey { get; set; }
37 |
38 | ///
39 | /// BaseUrl
40 | ///
41 | public string BaseUrl { get; set; }
42 |
43 | ///
44 | /// The logical name of the to configure.
45 | ///
46 | public string HttpClientName { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test/OmniPay.TestBase/BaseTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Options;
6 | using Moq;
7 | using OmniPay.Core.Utils;
8 | using OmniPay.Wechatpay;
9 |
10 | namespace OmniPay.TestBase
11 | {
12 | public class BaseTest
13 | {
14 | public IServiceCollection CreateServiceCollection()
15 | {
16 | return new ServiceCollection();
17 | }
18 |
19 | public IServiceCollection Services { get; set; }
20 |
21 | public IServiceProvider ServiceProvider { get; set; }
22 |
23 | public T GetService()
24 | {
25 | return ServiceProvider.GetService();
26 | }
27 |
28 | public T GetRequiredService()
29 | {
30 | return ServiceProvider.GetRequiredService();
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/OmniPay.TestBase/OmniPay.TestBase.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Core/WechatBaseTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using Moq;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.TestBase;
7 | using OmniPay.Wechatpay;
8 | using System.Net.Http;
9 |
10 | namespace Wechatpay.Test.Core
11 | {
12 | public class WechatBaseTest : BaseTest
13 | {
14 | public WechatBaseTest()
15 | {
16 | //添加ILogger
17 | ILogger wechatpaylogger =
18 | new LoggerFactory().CreateLogger();
19 | //添加配置参数
20 | var someOptions = Options.Create(new WeChatPayOptions
21 | {
22 | AppId = "wxdace645e0bc2c424",
23 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
24 | Key = "b7c996fbda5a9633ee4feb6b991c3919",
25 | BaseUrl = "https://api.mch.weixin.qq.com",
26 | MchId = "1900009641",
27 | NotifyUrl = "http://localhost:6113"
28 | });
29 | //mock IHttpClientFactory
30 | var mock = new Mock();
31 | mock.Setup(_ => _.CreateClient(It.IsAny())).Returns(new HttpClient());
32 | IHttpClientFactory factory = mock.Object;
33 | var client = new WeChatPayClient(someOptions, wechatpaylogger, new HttpHandler(factory));
34 |
35 | Services = CreateServiceCollection();
36 | Services.AddSingleton(client);
37 | ServiceProvider = Services.BuildServiceProvider();
38 |
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatAppPayEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Endpoints;
8 | using OmniPay.Wechatpay.Endpoints.Result;
9 | using Xunit;
10 |
11 | namespace Wechatpay.Test.Endpoints
12 | {
13 | public class WechatAppPayEndpointTest
14 | {
15 | HttpContext _context = new DefaultHttpContext ();
16 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
17 | private ILogger logger = new LoggerFactory ().CreateLogger ();
18 | IWeChatPayClient _client;
19 | private WechatAppPayEndpoint _subject;
20 |
21 | private void init () {
22 | var someOptions = Options.Create (new WeChatPayOptions {
23 | AppId = "wxdace645e0bc2c424",
24 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
25 | BaseUrl = "https://api.mch.weixin.qq.com",
26 | MchId = "1900009641"
27 | });
28 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
29 | _subject = new WechatAppPayEndpoint (logger, _client);
30 | }
31 | public WechatAppPayEndpointTest () {
32 | this.init ();
33 | }
34 |
35 | [Fact]
36 | public void Process_get_entry_point_shoud_return_405 () {
37 | _context.Request.Method = "GET";
38 | var result = _subject.Process (_context);
39 | var statusCode = result as StatusCodeResult;
40 | statusCode.Should ().NotBeNull ();
41 | statusCode.StatusCode.Should ().Be (405);
42 | }
43 |
44 | [Fact]
45 | public void Process_apppay_path_should_return_apppay_result () {
46 | _context.Request.Method = "POST";
47 | var result = _subject.Process (_context);
48 | result.Should ().BeOfType ();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatAppletPayEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Endpoints;
8 | using OmniPay.Wechatpay.Endpoints.Result;
9 | using Xunit;
10 |
11 | namespace Wechatpay.Test.Endpoints
12 | {
13 | public class WechatAppletPayEndpointTest
14 | {
15 | HttpContext _context = new DefaultHttpContext ();
16 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
17 | private ILogger logger = new LoggerFactory ().CreateLogger ();
18 | IWeChatPayClient _client;
19 | private WechatAppletPayEndpoint _subject;
20 |
21 | private void init () {
22 | var someOptions = Options.Create (new WeChatPayOptions {
23 | AppId = "wxdace645e0bc2c424",
24 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
25 | BaseUrl = "https://api.mch.weixin.qq.com",
26 | MchId = "1900009641"
27 | });
28 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
29 | _subject = new WechatAppletPayEndpoint (logger, _client);
30 | }
31 | public WechatAppletPayEndpointTest () {
32 | this.init ();
33 | }
34 |
35 | [Fact]
36 | public void Process_get_entry_point_shoud_return_405 () {
37 | _context.Request.Method = "GET";
38 | var result = _subject.Process (_context);
39 | var statusCode = result as StatusCodeResult;
40 | statusCode.Should ().NotBeNull ();
41 | statusCode.StatusCode.Should ().Be (405);
42 | }
43 |
44 | [Fact]
45 | public void Process_appletpay_path_should_return_appletpay_result () {
46 | _context.Request.Method = "POST";
47 | var result = _subject.Process (_context);
48 | result.Should ().BeOfType ();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatCloseEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Endpoints;
8 | using OmniPay.Wechatpay.Endpoints.Result;
9 | using Xunit;
10 |
11 | namespace Wechatpay.Test.Endpoints
12 | {
13 | public class WechatCloseEndpointTest
14 | {
15 | HttpContext _context = new DefaultHttpContext ();
16 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
17 | private ILogger logger = new LoggerFactory ().CreateLogger ();
18 | IWeChatPayClient _client;
19 | private WechatCloseEndpoint _subject;
20 |
21 | private void init () {
22 | var someOptions = Options.Create (new WeChatPayOptions {
23 | AppId = "wxdace645e0bc2c424",
24 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
25 | BaseUrl = "https://api.mch.weixin.qq.com",
26 | MchId = "1900009641"
27 | });
28 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
29 | _subject = new WechatCloseEndpoint (logger, _client);
30 | }
31 | public WechatCloseEndpointTest () {
32 | this.init ();
33 | }
34 |
35 | [Fact]
36 | public void Process_get_entry_point_shoud_return_405 () {
37 | _context.Request.Method = "GET";
38 | var result = _subject.Process (_context);
39 | var statusCode = result as StatusCodeResult;
40 | statusCode.Should ().NotBeNull ();
41 | statusCode.StatusCode.Should ().Be (405);
42 | }
43 |
44 | [Fact]
45 | public void Process_close_path_should_return_close_result () {
46 | _context.Request.Method = "POST";
47 | var result = _subject.Process (_context);
48 | result.Should ().BeOfType ();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatPublicPayEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Http;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Options;
6 | using OmniPay.Core.Results;
7 | using OmniPay.Core.Utils;
8 | using OmniPay.Wechatpay;
9 | using OmniPay.Wechatpay.Endpoints;
10 | using OmniPay.Wechatpay.Endpoints.Result;
11 | using Xunit;
12 |
13 | namespace Wechatpay.Test.Endpoints
14 | {
15 | public class WechatPublicPayEndpointTest
16 | {
17 |
18 | HttpContext _context = new DefaultHttpContext ();
19 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
20 | private ILogger logger = new LoggerFactory ().CreateLogger ();
21 | IWeChatPayClient _client;
22 | private WechatPublicPayEndpoint _subject;
23 |
24 |
25 | private void init () {
26 | var someOptions = Options.Create (new WeChatPayOptions {
27 | AppId = "wxdace645e0bc2c424",
28 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
29 | BaseUrl = "https://api.mch.weixin.qq.com",
30 | MchId = "1900009641"
31 | });
32 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
33 | _subject = new WechatPublicPayEndpoint (logger, _client);
34 | }
35 | public WechatPublicPayEndpointTest () {
36 | this.init ();
37 | }
38 |
39 | [Fact]
40 | public void Process_get_entry_point_shoud_return_405 () {
41 | _context.Request.Method = "GET";
42 | var result = _subject.Process (_context);
43 | var statusCode = result as StatusCodeResult;
44 | statusCode.Should ().NotBeNull ();
45 | statusCode.StatusCode.Should ().Be (405);
46 | }
47 |
48 | [Fact]
49 | public void Process_publicpay_path_should_return_publicpay_result () {
50 | _context.Request.Method = "POST";
51 | var result = _subject.Process (_context);
52 | result.Should ().BeOfType ();
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatQueryEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Endpoints;
8 | using OmniPay.Wechatpay.Endpoints.Result;
9 | using Xunit;
10 |
11 | namespace Wechatpay.Test.Endpoints
12 | {
13 | public class WechatQueryEndpointTest
14 | {
15 | HttpContext _context = new DefaultHttpContext ();
16 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
17 | private ILogger logger = new LoggerFactory ().CreateLogger ();
18 | IWeChatPayClient _client;
19 | private WechatQueryEndpoint _subject;
20 |
21 | private void init () {
22 | var someOptions = Options.Create (new WeChatPayOptions {
23 | AppId = "wxdace645e0bc2c424",
24 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
25 | BaseUrl = "https://api.mch.weixin.qq.com",
26 | MchId = "1900009641"
27 | });
28 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
29 | _subject = new WechatQueryEndpoint (logger, _client);
30 | }
31 | public WechatQueryEndpointTest () {
32 | this.init ();
33 | }
34 |
35 | [Fact]
36 | public void Process_get_entry_point_shoud_return_405 () {
37 | _context.Request.Method = "GET";
38 | var result = _subject.Process (_context);
39 | var statusCode = result as StatusCodeResult;
40 | statusCode.Should ().NotBeNull ();
41 | statusCode.StatusCode.Should ().Be (405);
42 | }
43 |
44 | [Fact]
45 | public void Process_query_path_should_return_query_result () {
46 | _context.Request.Method = "POST";
47 | var result = _subject.Process (_context);
48 | result.Should ().BeOfType ();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatScanPayEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using FluentAssertions;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Options;
6 | using OmniPay.Core.Results;
7 | using OmniPay.Wechatpay;
8 | using OmniPay.Wechatpay.Endpoints;
9 | using OmniPay.Wechatpay.Endpoints.Result;
10 | using OmniPay.Wechatpay.Validation;
11 | using Xunit;
12 |
13 | namespace Wechatpay.Test.Endpoints
14 | {
15 | public class WechatScanPayEndpointTest {
16 | HttpContext _context = new DefaultHttpContext ();
17 | private ILogger wechatpaylogger = new LoggerFactory ().CreateLogger ();
18 | private ILogger logger = new LoggerFactory ().CreateLogger ();
19 | IWeChatPayClient _client;
20 | private WechatScanPayEndpoint _subject;
21 | private IScanPayValidator _validator;
22 |
23 | private void init () {
24 | var someOptions = Options.Create (new WeChatPayOptions {
25 | AppId = "wxdace645e0bc2c424",
26 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
27 | BaseUrl = "https://api.mch.weixin.qq.com",
28 | MchId = "1900009641"
29 | });
30 | _client = new WeChatPayClient (someOptions, wechatpaylogger,null);
31 | _subject = new WechatScanPayEndpoint (logger, _client);
32 | }
33 | public WechatScanPayEndpointTest () {
34 | this.init ();
35 | }
36 |
37 | [Fact]
38 | public void Process_get_entry_point_shoud_return_405 () {
39 | _context.Request.Method = "GET";
40 | var result = _subject.Process (_context);
41 | var statusCode = result as StatusCodeResult;
42 | statusCode.Should ().NotBeNull ();
43 | statusCode.StatusCode.Should ().Be (405);
44 | }
45 |
46 | [Fact]
47 | public void Process_scanpay_path_should_return_sanpay_result () {
48 | _context.Request.Method = "POST";
49 | var result = _subject.Process (_context);
50 | result.Should ().BeOfType ();
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Endpoints/WechatWapPayEndpointTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Options;
5 | using OmniPay.Core.Results;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Endpoints;
8 | using OmniPay.Wechatpay.Endpoints.Result;
9 | using Xunit;
10 |
11 | namespace Wechatpay.Test.Endpoints
12 | {
13 | public class WechatWapPayEndpointTest
14 | {
15 | HttpContext _context = new DefaultHttpContext();
16 | private ILogger wechatpaylogger = new LoggerFactory().CreateLogger();
17 | private ILogger logger = new LoggerFactory().CreateLogger();
18 | IWeChatPayClient _client;
19 | private WechatWapPayEndpoint _subject;
20 |
21 | private void init()
22 | {
23 | var someOptions = Options.Create(new WeChatPayOptions
24 | {
25 | AppId = "wxdace645e0bc2c424",
26 | AppSecret = "4693afc6b2084885ca9fbc2355b97827",
27 | BaseUrl = "https://api.mch.weixin.qq.com",
28 | MchId = "1900009641"
29 | });
30 | _client = new WeChatPayClient(someOptions, wechatpaylogger, null);
31 | _subject = new WechatWapPayEndpoint(logger, _client);
32 | }
33 | public WechatWapPayEndpointTest()
34 | {
35 | this.init();
36 | }
37 |
38 | [Fact]
39 | public void Process_get_entry_point_shoud_return_405()
40 | {
41 | _context.Request.Method = "GET";
42 | var result = _subject.Process(_context);
43 | var statusCode = result as StatusCodeResult;
44 | statusCode.Should().NotBeNull();
45 | statusCode.StatusCode.Should().Be(405);
46 | }
47 |
48 | [Fact]
49 | public void Process_apppay_path_should_return_wappay_result()
50 | {
51 | _context.Request.Method = "POST";
52 | var result = _subject.Process(_context);
53 | result.Should().BeOfType();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/test/Wechatpay.Test/WeChatPays/WeChatPayTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using Moq;
5 | using OmniPay.Core.Utils;
6 | using OmniPay.Wechatpay;
7 | using OmniPay.Wechatpay.Domain;
8 | using OmniPay.Wechatpay.Request;
9 | using System;
10 | using System.Net.Http;
11 | using System.Threading.Tasks;
12 | using Wechatpay.Test.Core;
13 | using Xunit;
14 |
15 | namespace Wechatpay.Test.WeChatPays
16 | {
17 | public class WeChatPayTest : WechatBaseTest
18 | {
19 | private readonly IWeChatPayClient _client;
20 |
21 | public WeChatPayTest()
22 | {
23 | _client = GetRequiredService();
24 | }
25 |
26 | [Fact(DisplayName = "微信扫码支付是否返回成功")]
27 | public async Task ScanPay_shoud_return_success()
28 | {
29 | var request = new ScanPayRequest();
30 | request.AddParameters(new ScanPayModel
31 | {
32 | Body = "扫码支付",
33 | OutTradeNo = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
34 | TotalFee = 1
35 | });
36 | var result = await _client.ExecuteAsync(request);
37 | result.ResultCode.Should().Be("SUCCESS", "判断其是否返回SUCCESS");
38 |
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/test/Wechatpay.Test/Wechatpay.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------