-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
375 lines (180 loc) · 145 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>DotNet实现简单微信SDK</title>
<link href="/2024/03/18/dotnet/007-DotNet%E5%AE%9E%E7%8E%B0%E7%AE%80%E5%8D%95%E7%9A%84%E5%BE%AE%E4%BF%A1SDK/"/>
<url>/2024/03/18/dotnet/007-DotNet%E5%AE%9E%E7%8E%B0%E7%AE%80%E5%8D%95%E7%9A%84%E5%BE%AE%E4%BF%A1SDK/</url>
<content type="html"><![CDATA[<h1 id="DotNet实现简单微信SDK"><a href="#DotNet实现简单微信SDK" class="headerlink" title="DotNet实现简单微信SDK"></a>DotNet实现简单微信SDK</h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>上一篇文章<a href="https://blog.ihuadz.top/2024/03/04/dotnet/006-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E6%89%AB%E7%A0%81%E7%99%BB%E5%BD%95_%E7%BB%95%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E5%B9%B3%E5%8F%B0/">C#实现微信扫码登录(绕过微信开发平台) - ihuadz</a> 提到封装微信接口,本篇文章将从以下方面介绍如何使用C#实现简单的微信SDK。</p><p>仓库地址:<a href="https://github.com/ihuadz/QI.WxSdk.git">https://github.com/ihuadz/QI.WxSdk.git</a></p><ul><li>核心类库</li><li>配置</li><li>具体实现</li><li>如何使用</li></ul><h2 id="核心类库介绍"><a href="#核心类库介绍" class="headerlink" title="核心类库介绍"></a>核心类库介绍</h2><ul><li>WebApiClient</li></ul><p><a href="https://webapiclient.github.io/guide/">WebApiClient</a> 是一个集高性能高可扩展性于一体的声明式http客户端库,具体使用方法可以查看一下官方文档</p><p>其他的都是使用dotnet提供的类库</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>配置文件长这样,可配置多个小程序</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-comment"># 微信应用(公众号/小程序)</span><br><span class="hljs-attr">WeixinSetting:</span><br> <span class="hljs-comment"># 应用配置数组,可配置多个</span><br> <span class="hljs-attr">App:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">AppId:</span> <span class="hljs-string">xxxxxxxxxxxxxx</span><br> <span class="hljs-attr">AppSecret:</span> <span class="hljs-string">xxxxxxxxxxxxxxxxxxxxxxx</span><br> <span class="hljs-attr">Name:</span> <span class="hljs-string">xxxxxxxxxxxxxxx</span><br> <span class="hljs-bullet">-</span> <span class="hljs-attr">AppId:</span> <span class="hljs-string">xxxxxxxxxxxxxx</span><br> <span class="hljs-attr">AppSecret:</span> <span class="hljs-string">xxxxxxxxxxxxxxxxxxxxxxx</span><br> <span class="hljs-attr">Name:</span> <span class="hljs-string">xxxxxxxxxxxxxxx</span><br></code></pre></td></tr></table></figure><h2 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h2><p>封装代码太多,文章内就放出核心代码,全部sdk查看<a href="#%E6%A6%82%E8%BF%B0">概述</a>。</p><ul><li>IWxApiBase</li></ul><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 微信接口映射API</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><br>[<span class="hljs-meta">JsonNetReturn(EnsureMatchAcceptContentType = false)</span>]<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IWxApiBase</span><br>{<br>}<br></code></pre></td></tr></table></figure><ul><li>获取Access Token</li></ul><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs C#"><span class="hljs-comment">// <summary></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 获取全局接口调用凭据, 用于小程序和公众号</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> [<span class="hljs-meta">HttpHost(<span class="hljs-string">"https://api.weixin.qq.com/cgi-bin/"</span>)</span>]<br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IWxTokenApi</span> : <span class="hljs-title">IWxApiBase</span><br> {<br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 获取全局接口调用 Access token</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><remarks></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 用于小程序和公众号</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></remarks></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="appId"></span>公众号或小程序的应用id<span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="secret"></span>应用密钥,即appsecret<span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="grant_type"></span>授权类型,获取access_token填写client_credential<span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> [<span class="hljs-meta">HttpGet(<span class="hljs-string">"token"</span>)</span>]<br> <span class="hljs-function">Task<TokenApiResult> <span class="hljs-title">GetAsync</span>(<span class="hljs-params">[Required] <span class="hljs-built_in">string</span> appId, [Required] <span class="hljs-built_in">string</span> secret, <span class="hljs-built_in">string</span> grant_type = <span class="hljs-string">"client_credential"</span></span>)</span>;<br><br> }<br></code></pre></td></tr></table></figure><ul><li>将AccessToken缓存</li></ul><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 检查应用配置数据</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CheckAppSetting</span>()</span><br>{<br> <span class="hljs-keyword">if</span> (CurApp == <span class="hljs-literal">null</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WxException(<span class="hljs-string">"应用配置不能空"</span>);<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">string</span>.IsNullOrEmpty(CurApp.AppId)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WxException(<span class="hljs-string">"应用AppId能空"</span>);<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">string</span>.IsNullOrEmpty(CurApp.AppSecret)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WxException(<span class="hljs-string">"应用AppSecret能空"</span>);<br>}<br><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 获取Access Token</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><remarks></span>如果可能,会进行缓存<span class="hljs-doctag"></remarks></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">async</span> Task<<span class="hljs-built_in">string</span>> <span class="hljs-title">GetAccessTokenAsync</span>()</span><br>{ <br> CheckAppSetting();<br><br> <span class="hljs-comment">//获取token,先查询缓存</span><br> <span class="hljs-built_in">string</span> token = <span class="hljs-keyword">await</span> GetAccessTokenFromCacheAsync();<br> <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">string</span>.IsNullOrEmpty(token)) <span class="hljs-keyword">return</span> token;<br><br> <span class="hljs-comment">//如果缓存中没有,调用Wx Api获取Token</span><br> IWxTokenApi tokenApi = GetService<IWxTokenApi>();<br> TokenApiResult result = <span class="hljs-keyword">await</span> tokenApi.GetAsync(CurApp.AppId, CurApp.AppSecret);<br><br> <span class="hljs-comment">//缓存token</span><br> <span class="hljs-keyword">await</span> SetAccessTokenToCacheAsync(result.AccessToken, result.Expires);<br><br> <span class="hljs-keyword">return</span> result.AccessToken;<br>}<br></code></pre></td></tr></table></figure><ul><li>最主要的是这一步,使用WebApiClient过滤器将access_token设置到每次请求微信的url中</li></ul><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> WebApiClient过滤器,自动设置url的access_token请求参数</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AccessTokenApiFilter</span> : <span class="hljs-title">ApiFilterAttribute</span><br>{<br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 请求</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="context"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">OnRequestAsync</span>(<span class="hljs-params">ApiRequestContext context</span>)</span><br> {<br> <span class="hljs-keyword">var</span> tokenManager = context.HttpContext.ServiceProvider.GetRequiredService<ITokenManager>();<br> <span class="hljs-built_in">string</span> accessToken = <span class="hljs-keyword">await</span> tokenManager.GetAccessTokenAsync();<br> context.HttpContext.RequestMessage.AddUrlQuery(<span class="hljs-string">"access_token"</span>, accessToken);<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 响应</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="context"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> Task <span class="hljs-title">OnResponseAsync</span>(<span class="hljs-params">ApiResponseContext context</span>)</span><br> {<br> <span class="hljs-keyword">if</span>(context.Result <span class="hljs-keyword">is</span> ApiResultBase apiResult && apiResult!=<span class="hljs-literal">null</span>)<br> {<br> <span class="hljs-comment">//如果请求的accesstoken过期,清除当前缓存的过期token</span><br> <span class="hljs-keyword">if</span> (apiResult.IsAccessTokenInvalid)<br> {<br> <span class="hljs-keyword">var</span> tokenManager = context.HttpContext.ServiceProvider.GetRequiredService<ITokenManager>();<br> tokenManager.ClearAccessTokenAsync();<br> }<br> }<br><br> <span class="hljs-keyword">return</span> Task.CompletedTask;<br> }<br>}<br></code></pre></td></tr></table></figure><p>以上次文章中使用到的请求短链为例,实现请求微信端。</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 小程序 URL Link, URL Scheme 接口</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IWxMpUrllinkApi</span> : <span class="hljs-title">IWxApiWithAccessTokenFilter</span><br>{<br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 获取小程序 URL Link</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><remarks></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-link.html</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></remarks></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="input"></span>请求数据<span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> [<span class="hljs-meta">HttpPost(<span class="hljs-string">"https://api.weixin.qq.com/wxa/generate_urllink"</span>)</span>]<br> <span class="hljs-function">ITask<GenerateUrlLinkResult> <span class="hljs-title">GenerateUrllinkAsync</span>(<span class="hljs-params">[JsonNetContent] GenerateUrlLinkInput input</span>)</span>;<br>}<br></code></pre></td></tr></table></figure><p>IWxApiWithAccessTokenFilter</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> WebApiClient过滤器,自动设置url的access_token请求参数</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br>[<span class="hljs-meta">JsonNetReturn(EnsureMatchAcceptContentType = false)</span>]<br>[<span class="hljs-meta">AccessTokenApiFilter</span>]<br><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IWxApiWithAccessTokenFilter</span><br>{<br>}<br></code></pre></td></tr></table></figure><p>然后就是WxMpApiService,这里就只放短链相关</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 微信小程序接口聚合服务, 生命周期为Scoped</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WxMpApiService</span> : <span class="hljs-title">WxApiServiceBase</span><br>{<br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 小程序 URL Link, URL Scheme 接口</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-keyword">public</span> IWxMpUrllinkApi IUrllinkApi => GetService<IWxMpUrllinkApi>();<br>}<br></code></pre></td></tr></table></figure><p>WxApiServiceBase 接口聚合服务 基类</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> Wx接口聚合服务 基类</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WxApiServiceBase</span><br>{<br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 微信接口集合服务</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="tokenManager"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WxApiServiceBase</span>(<span class="hljs-params">ITokenManager tokenManager</span>)</span><br> {<br> TokenManager = tokenManager;<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 微信AccessToken管理器</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> ITokenManager TokenManager { <span class="hljs-keyword">get</span>; }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 得到服务对象</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><typeparam name="T"></span><span class="hljs-doctag"></typeparam></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> T <span class="hljs-title">GetService</span><<span class="hljs-title">T</span>>()</span><br> {<br> <span class="hljs-keyword">return</span> TokenManager.GetService<T>();<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 设置当前的应用</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="wxApp"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SetCurApp</span>(<span class="hljs-params">WxAppSetting wxApp</span>)</span><br> {<br> TokenManager.SetCurApp(wxApp);<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 设置当前的应用,根据Appid从WxContext中查找</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="appId"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SetCurApp</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> appId</span>)</span><br> {<br> TokenManager.SetCurApp(appId);<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 得到会话当前AppId</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GetCurAppId</span>()</span><br> {<br> <span class="hljs-keyword">return</span> TokenManager?.GetCurAppId() ?? <span class="hljs-built_in">string</span>.Empty;<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 当前应用</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> WxAppSetting <span class="hljs-title">GetCurApp</span>()</span><br> {<br> <span class="hljs-keyword">return</span> TokenManager.GetCurApp();<br> }<br>}<br></code></pre></td></tr></table></figure><p>至于ITokenManager,自己设计一下就好,都是读取配置和缓存AccessToken的一些操作,也可以查看源码<a href="#%E6%A6%82%E8%BF%B0">概述</a>。</p><p>最后就是如何使用了。添加一个扩展类,将封装好的Api注册</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 添加WxSdk 接口、服务,IWxSession会话</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="services"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddWxSdkAll</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span><br>{<br> <span class="hljs-comment">//注册接口,服务</span><br> services.AddWxSdkApiAndServices();<br> <span class="hljs-comment">//注册token管理器</span><br> services.AddWxSdkTokenManager();<br><br> <span class="hljs-keyword">return</span> services;<br>}<br><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 注册token管理器,会话服务</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="services"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddWxSdkTokenManager</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span><br>{<br> <span class="hljs-comment">//添加WxSession</span><br> services.AddScoped<ITokenManager, TokenManager>();<br><br> <span class="hljs-keyword">return</span> services;<br>}<br><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 添加WxSdk 接口、服务</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="services"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IServiceCollection <span class="hljs-title">AddWxSdkApiAndServices</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IServiceCollection services</span>)</span><br>{<br> services<br> .AddWebApiClient()<br> .UseJsonFirstApiActionDescriptor();<br><br> <span class="hljs-comment">//添加Wx上下文</span><br> services.AddSingleton<WxConfig>();<br><br> <span class="hljs-comment">//添加微信API映射</span><br> <span class="hljs-comment">//公众接口</span><br> services.AddHttpApi<IWxTokenApi>();<br><br> <span class="hljs-comment">//注册聚合/扩展服务 -公众号</span><br> services.AddScoped<WxPaApiService>();<br><br> <span class="hljs-comment">//小程序接口</span><br> services.AddHttpApi<IWxMpUrllinkApi>();<br><br><br> <span class="hljs-comment">//注册聚合/扩展服务 -小程序</span><br> services.AddScoped<WxMpApiService>();<br><br> <span class="hljs-keyword">return</span> services;<br>}<br></code></pre></td></tr></table></figure><h2 id="如何使用"><a href="#如何使用" class="headerlink" title="如何使用"></a>如何使用</h2><p>在你的应用中添加注册</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment">//注册微信Sdk集成</span><br>services.AddWxSdkAll();<br></code></pre></td></tr></table></figure><p>在service里注入后调用</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment">//请求微信短链接口</span><br> <span class="hljs-keyword">var</span> urlResult = <span class="hljs-keyword">await</span> _wxMpService.IUrllinkApi.GenerateUrllinkAsync(<span class="hljs-keyword">new</span> GenerateUrlLinkInput()<br> {<br> Path = path,<br> Query = query,<br> EnvironmentVersion = environmentVersion,<br> ExpireTimestamp = DateTime.Now.AddMinutes(<span class="hljs-number">10</span>).ConvertToTimeStamp()<br> });<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
<tag>微信小程序</tag>
</tags>
</entry>
<entry>
<title>不用科学上网无阻访问github</title>
<link href="/2024/03/06/essays/002-GitHub%E5%8A%A0%E9%80%9F/"/>
<url>/2024/03/06/essays/002-GitHub%E5%8A%A0%E9%80%9F/</url>
<content type="html"><![CDATA[<h1 id="不用科学上网无阻访问GitHub"><a href="#不用科学上网无阻访问GitHub" class="headerlink" title="不用科学上网无阻访问GitHub"></a>不用科学上网无阻访问GitHub</h1><p>相信点开这篇文章的人都很清楚GitHub是啥了,并且很可能在GitHub里尝到了不少甜头</p><p>但是有不少朋友访问GitHub时经常被拦下,下面介绍一下我自己使用了很久能正常访问GitHub的方式</p><h1 id="FastGitHub"><a href="#FastGitHub" class="headerlink" title="FastGitHub"></a>FastGitHub</h1><p>这个项目的来源呢就不多介绍了,感兴趣可以自己搜搜看,现在这个项目的地址已经404了,也不知道为啥。</p><p>运行后像这样,就可以正常访问了</p><p><img src="/../../img/20240306/fastgithub.png" alt="fastgithub"></p><p>不想使用这个的话,可以添加到windows服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">fastgithub.exe start<br><br>//卸载删除<br>fastgithub.ext stop<br></code></pre></td></tr></table></figure><h2 id="使用nssm"><a href="#使用nssm" class="headerlink" title="使用nssm"></a>使用nssm</h2><p>这是一个安装window服务的小工具,挺好用</p><p>将nssm.exe复制到fastgithub目录下,运行命令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">nssm install FastGithub<br></code></pre></td></tr></table></figure><p>会有一个设置service的信息的弹框,输入对应信息即可</p><blockquote><p>这两个工具都能搜索到,懒得找的话留言邮箱,我会发送工具以及使用方法</p></blockquote>]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title>C#实现微信扫码登录(绕过微信开发平台)</title>
<link href="/2024/03/04/dotnet/006-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E6%89%AB%E7%A0%81%E7%99%BB%E5%BD%95_%E7%BB%95%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E5%B9%B3%E5%8F%B0/"/>
<url>/2024/03/04/dotnet/006-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E6%89%AB%E7%A0%81%E7%99%BB%E5%BD%95_%E7%BB%95%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E5%B9%B3%E5%8F%B0/</url>
<content type="html"><![CDATA[<h1 id="C-实现微信扫码登录"><a href="#C-实现微信扫码登录" class="headerlink" title="C#实现微信扫码登录"></a>C#实现微信扫码登录</h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>最近公司打算引进触屏终端,需要将已有小程序打包为APP,并且实现微信扫码登录终端。</p><p>查阅微信官方文档后发现微信提供了APP端SDK,直接调用接口即可获得登录授权二维码,wow,那岂不是没有我后端啥事了,果断把链接丢给前端,官方文档:<a href="https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Login_via_Scan.html">微信移动应用扫码登录</a>。</p><p>然而,因为APP是直接用uniapp打包的,没有找到使用微信SDK的方法;时间紧,也懒得去研究uniapp那一套(有知道咋处理的小伙伴可以告知一下),然后就想了另外一套方案。</p><p>使用微信的<a href="https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html">OAuth2.0授权登录</a>,打算使用做个中间页获取到授权信息;</p><p>流程大概是:</p><ul><li>将微信小程序绑定至微信开放平台</li><li>在微信开放平台中创建一个网站应用</li><li>使用新创建的应用的appid和code去登录</li><li>拿到access_token、openid、unionid</li><li>最终获取用户信息</li></ul><p>这样处理有几个问题:</p><ul><li>获取到openid和小程序的不是同一个应用的openid,无法绑定用户</li><li>可以使用unionid去获取用户信息,但是小程序已经上线一段时间了,上线的时候没有绑定开放平台(我也不知道为什么不绑定,可能之前就没有想过现在这种情况),所以用户都没有unionid,无法绑定用户</li><li>使用code换取手机号?OAuth2.0好像没有提供,文档上是没说,也懒得试了(需要微信开放平台创建应用、上传审核资料balabalabala …)</li></ul><p>好吧,那只能再换一个方案了。</p><h2 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h2><p><img src="/../../img/20240304/WXScanQr.png" alt="WXScanQr"></p><p>大概流程就是:</p><ul><li>APP终端向后端获取登录二维码</li><li>后端返回终端qrid参数以及base64二维码图片,并将二维码信息缓存</li><li>用户扫码(可用微信或其他扫码浏览器)</li><li>APP终端轮询二维码状态接口</li><li>后端获取微信调起小程序短链,并将二维码状态更改,重定向短链</li><li>用户同意打开小程序,授权登录</li><li>后端将登录成功token存入刚才的二维码缓存信息内</li><li>此时APP端轮询获取的登录信息,成功登录</li></ul><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>获取二维码</p><blockquote><p>生成二维码的代码<code>QRCodeHelper.GenerateQrCodeBase64(qrUrl)</code>就不放了,一搜一大堆</p></blockquote><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 获取登录二维码</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task<KeyValuePair<<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>>> GetLoginQrAsync()<br>{<br> <span class="hljs-comment">//构建扫码回调链接</span><br> <span class="hljs-keyword">var</span> request = App.HttpContext.Request;<br> <span class="hljs-built_in">string</span> protocol = request.IsHttps ? <span class="hljs-string">"https"</span> : <span class="hljs-string">"http"</span>;<br> <span class="hljs-built_in">string</span> host = request.Host.Value;<br> <span class="hljs-built_in">string</span> fullHost = <span class="hljs-string">$"<span class="hljs-subst">{protocol}</span>://<span class="hljs-subst">{host}</span>"</span>;<br><br> <span class="hljs-keyword">var</span> url = <span class="hljs-string">$"<span class="hljs-subst">{fullHost}</span>/api/auth/scan-qr-cb?qrId="</span>;<br> <span class="hljs-keyword">var</span> qrId = <span class="hljs-string">$"qr_<span class="hljs-subst">{GuidHelper.GenerateSequentialGuid16String()}</span>"</span>;<br> <span class="hljs-keyword">var</span> qrUrl = <span class="hljs-string">$"<span class="hljs-subst">{url}</span><span class="hljs-subst">{qrId}</span>"</span>;<br><br> <span class="hljs-comment">//构建扫描二维码状态</span><br> <span class="hljs-keyword">var</span> scanQrStatus = <span class="hljs-keyword">new</span> ScanQrStatus(qrId, QrStatus.NotScan, <span class="hljs-built_in">string</span>.Empty);<br><br> <span class="hljs-comment">//保存到缓存</span><br> <span class="hljs-keyword">var</span> cacheKey = <span class="hljs-string">$"<span class="hljs-subst">{CachesConst.CacheKey_Auth_LoginQr}</span>:<span class="hljs-subst">{qrId}</span>"</span>;<br> CacheSetOptions cacheOption = <span class="hljs-keyword">new</span>()<br> {<br> Expiration = (<span class="hljs-built_in">int</span>)TimeSpan.FromMinutes(<span class="hljs-number">10</span>).TotalSeconds,<br> ExpirationType = ExpirationType.Absolute<br> };<br> <span class="hljs-keyword">await</span> _cache.SetAsync(cacheKey, scanQrStatus, cacheOption);<br><br> <span class="hljs-comment">//返回二维码图片</span><br> <span class="hljs-keyword">var</span> qrImg = QRCodeHelper.GenerateQrCodeBase64(qrUrl);<br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> KeyValuePair<<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>>(qrId, qrImg);<br>}<br></code></pre></td></tr></table></figure><p>扫码回调,用户扫码后进入该接口,修改状态以及重定向至微信短链</p><blockquote><p>此处_wxMpService中封装了调用微信接口的方法,包括token管理,可参考微信官方文档自行封装:<a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html">获取小程序URL Link</a></p></blockquote><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 扫码回调</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task<IActionResult> <span class="hljs-title">GetScanQrCbAsync</span>(<span class="hljs-params">[FromQuery] <span class="hljs-built_in">string</span> qrId</span>)</span><br>{<br> <span class="hljs-comment">//更新扫描二维码状态</span><br> ScanQrStatus scanQrStatus = <span class="hljs-keyword">await</span> GetQrStatusAsync(qrId);<br> <span class="hljs-keyword">if</span> (scanQrStatus.Status != QrStatus.NotScan)<br> Throws.BizException(<span class="hljs-string">"二维码已使用,请重新获取"</span>);<br> scanQrStatus.Status = QrStatus.Scanned;<br><br> <span class="hljs-keyword">var</span> cacheKey = <span class="hljs-string">$"<span class="hljs-subst">{CachesConst.CacheKey_Auth_LoginQr}</span>:<span class="hljs-subst">{qrId}</span>"</span>;<br> <span class="hljs-keyword">await</span> _cache.SetAsync(cacheKey, scanQrStatus);<br><br> <span class="hljs-comment">//获取微信提供的小程序短链接</span><br> <span class="hljs-keyword">var</span> path = <span class="hljs-string">$"/pages/tabbar/mine/index"</span>;<br> <span class="hljs-keyword">var</span> query = <span class="hljs-string">$"addCode=<span class="hljs-subst">{qrId}</span>"</span>;<br><br> <span class="hljs-keyword">var</span> environmentVersion = <span class="hljs-string">"release"</span>;<br> <span class="hljs-keyword">if</span> (appSetting.IsDevMode)<br> {<br> environmentVersion = <span class="hljs-string">"develop"</span>;<br> }<br><br> <span class="hljs-comment">//请求微信短链接口</span><br> <span class="hljs-keyword">var</span> urlResult = <span class="hljs-keyword">await</span> _wxMpService.IUrllinkApi.GenerateUrllinkAsync(<span class="hljs-keyword">new</span> GenerateUrlLinkInput()<br> {<br> Path = path,<br> Query = query,<br> EnvironmentVersion = environmentVersion,<br> ExpireTimestamp = DateTime.Now.AddMinutes(<span class="hljs-number">10</span>).ConvertToTimeStamp()<br> });<br><br> <span class="hljs-keyword">if</span> (!urlResult.IsSuccess)<br> Throws.BizLogException(<span class="hljs-string">$"获取小程序短链失败:<span class="hljs-subst">{urlResult.Message}</span>"</span>);<br><br> <span class="hljs-comment">//重定向短链接</span><br> <span class="hljs-keyword">var</span> redirectUrl = urlResult.UrlLink;<br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RedirectResult(redirectUrl);<br>}<br></code></pre></td></tr></table></figure><p>轮询获取扫码状态及登录数据接口</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 获取二维码状态</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="qrId"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task<ScanQrStatus> <span class="hljs-title">GetQrStatusAsync</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> qrId</span>)</span><br>{<br> <span class="hljs-keyword">var</span> cacheKey = <span class="hljs-string">$"<span class="hljs-subst">{CachesConst.CacheKey_Auth_LoginQr}</span>:<span class="hljs-subst">{qrId}</span>"</span>;<br> <span class="hljs-keyword">var</span> status = <span class="hljs-keyword">await</span> _cache.GetAsync<ScanQrStatus>(cacheKey);<br> <span class="hljs-keyword">if</span> (status.IsNull()) Throws.BizException(<span class="hljs-string">"二维码已失效,请重新获取!"</span>);<br> <span class="hljs-keyword">return</span> status;<br>}<br></code></pre></td></tr></table></figure><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>总的来说呢,还是解决了当前问题,建议设计时就考虑到后期扩展的问题,直接将应用添加到微信开放平台,这样就不用那么麻烦了。</p><blockquote><p>代码中的已封装的部分没有展示,主要是一个解决遇到问题的方案,大部分都能自行实现,若需要微信接口封装代码后期可考虑写篇文章</p></blockquote>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
<tag>微信小程序</tag>
<tag>扫码登录</tag>
</tags>
</entry>
<entry>
<title>使用C#版第三方微信SDK集成微信支付</title>
<link href="/2024/02/23/dotnet/005-%E4%BD%BF%E7%94%A8CSharp%E7%89%88%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BE%AE%E4%BF%A1SDK%E9%9B%86%E6%88%90%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98/"/>
<url>/2024/02/23/dotnet/005-%E4%BD%BF%E7%94%A8CSharp%E7%89%88%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BE%AE%E4%BF%A1SDK%E9%9B%86%E6%88%90%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98/</url>
<content type="html"><![CDATA[<h1 id="使用C-版第三方微信SDK集成微信支付"><a href="#使用C-版第三方微信SDK集成微信支付" class="headerlink" title="使用C#版第三方微信SDK集成微信支付"></a>使用C#版第三方微信SDK集成微信支付</h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>最近在工作中要开发一个微信支付的功能,项目比较急,第一反应就是去<a href="https://pay.weixin.qq.com/docs/merchant/sdk-tools/sdk-tool.html">官方文档</a>找SDK,发现官方只提供了JAVA、PHP、Go的SDK。(对C#玩家真不友好!=_=!)。好在微信支付的开发者社区有位大哥<a href="https://github.com/fudiwei">fudiwei (RHQYZ) (github.com)</a>提供了C#版的SDK,项目地址:<a href="https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat">DotNetCore.SKIT.FlurlHttpClient.Wechat</a>,果断Install一下。</p><h2 id="SDK简介"><a href="#SDK简介" class="headerlink" title="SDK简介"></a>SDK简介</h2><p>SKIT.FlurlHttpClient.Wechat是基于 <code>Flurl.Http</code> 的微信 HTTP API SDK,目前已包含公众平台、开放平台、商户平台、企业微信、广告平台、对话开放平台等模块。</p><p>看了一下文档,已经把微信已知的API都封装了,而且更新的还比较快,github上作者Issues回复也很快,还是比较稳定,完全够用啦。</p><h2 id="接入使用"><a href="#接入使用" class="headerlink" title="接入使用"></a>接入使用</h2><p>我这里只用到了JSAPI支付,其他的需求可查看项目文档,都有详细介绍。</p><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><ul><li>申请商户号</li><li>开启V3 api权限</li><li>下载密钥和序列号</li></ul><h3 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h3><p>我是新建了一个叫tenpay_setting.json的配置文件,也可以直接加到appsetting.json</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"Tenpay"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"Merchants"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"MerchantId"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"********"</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">//商户号</span><br> <span class="hljs-attr">"SecretV3"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"*********"</span><span class="hljs-punctuation">,</span> <span class="hljs-comment">//V3版本Api的Secret</span><br> <span class="hljs-attr">"CertificateSerialNumber"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"*********"</span><span class="hljs-punctuation">,</span><span class="hljs-comment">//证书序列号</span><br> <span class="hljs-attr">"CertificatePrivateKey"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"apiclient_key.pem"</span><span class="hljs-comment">//api key 可以直接将内容复制上来,我嫌太长,用的路径</span><br> <span class="hljs-punctuation">}</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"NotifyUrl"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"http://www.host.com/api/notify/wx/{merchant_id}/pay"</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><h3 id="请求客户端创建"><a href="#请求客户端创建" class="headerlink" title="请求客户端创建"></a>请求客户端创建</h3><p>项目文档上是在多租户的情况下使用factory创建,我这里没有分租户。</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 创建微信支付客户端</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><exception cref="Exception"></span><span class="hljs-doctag"></exception></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> WechatTenpayClient <span class="hljs-title">CreateClient</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> merchantId</span>)</span><br>{<br> <span class="hljs-keyword">var</span> tenpayMerchantConfig = GetDefaultMerchant(merchantId);<br><br> <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> WechatTenpayClientOptions()<br> {<br> <span class="hljs-comment">//商户号</span><br> MerchantId = tenpayMerchantConfig.MerchantId,<br> <span class="hljs-comment">//v3Secret</span><br> MerchantV3Secret = tenpayMerchantConfig.SecretV3,<br> <span class="hljs-comment">//证书序列号</span><br> MerchantCertificateSerialNumber = tenpayMerchantConfig.CertificateSerialNumber,<br> <span class="hljs-comment">//私钥</span><br> MerchantCertificatePrivateKey = GetCertPrivateKey(tenpayMerchantConfig.CertificatePrivateKey),<br> <span class="hljs-comment">//证书管理器</span><br> PlatformCertificateManager = _redisCertificateManager,<br> <span class="hljs-comment">//开启自动加密</span><br> AutoEncryptRequestSensitiveProperty = <span class="hljs-literal">true</span>,<br> <span class="hljs-comment">//开启自动解密</span><br> AutoDecryptResponseSensitiveProperty = <span class="hljs-literal">true</span><br> };<br> <span class="hljs-keyword">var</span> wechatTenpayClient = WechatTenpayClientBuilder.Create(options).Build();<br> <span class="hljs-keyword">return</span> wechatTenpayClient;<br>}<br></code></pre></td></tr></table></figure><h3 id="读取私钥内容"><a href="#读取私钥内容" class="headerlink" title="读取私钥内容"></a>读取私钥内容</h3><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 读取私钥内容</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="path"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><exception cref="BizException"></span><span class="hljs-doctag"></exception></span></span><br><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GetCertPrivateKey</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> path</span>)</span><br>{<br> <span class="hljs-keyword">try</span><br> {<br> <span class="hljs-comment">// 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----</span><br> <span class="hljs-comment">// 亦不包括结尾的 -----END PRIVATE KEY-----</span><br> <span class="hljs-keyword">var</span> certPath = path;<br> <span class="hljs-keyword">var</span> certPrivateKey = File.ReadAllText(certPath);<br> <span class="hljs-comment">//以前的版本需要移出这两行,现在好像不需要了</span><br> <span class="hljs-comment">//certPrivateKey = certPrivateKey.Replace("-----BEGIN PRIVATE KEY-----", string.Empty);</span><br> <span class="hljs-comment">//certPrivateKey = certPrivateKey.Replace("-----END PRIVATE KEY-----", string.Empty);</span><br> <span class="hljs-comment">//certPrivateKey = certPrivateKey.Trim();</span><br> <span class="hljs-keyword">return</span> certPrivateKey;<br> }<br> <span class="hljs-keyword">catch</span> (Exception ex)<br> {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BizException(<span class="hljs-string">$"获取证书内容失败!:<span class="hljs-subst">{ex.Message}</span>"</span>);<br> }<br>}<br></code></pre></td></tr></table></figure><blockquote><p>注意,新版本中不需要处理<code>-----BEGIN PRIVATE KEY-----</code>和<code>-----END PRIVATE KEY-----</code>,否则会出现<code>Private key format is not supported.</code></p></blockquote><h3 id="自动刷新证书"><a href="#自动刷新证书" class="headerlink" title="自动刷新证书"></a>自动刷新证书</h3><p>项目simple中是使用内存管理证书,我这项目需要其他微服务使用,就用redis缓存管理</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> redis缓存管理证书</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RedisCertificateManager</span> : <span class="hljs-title">ICertificateManager</span>, <span class="hljs-title">ITransient</span><br>{<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> REDIS_KEY_PREFIX = <span class="hljs-string">"wxpaypc-"</span>;<br> <span class="hljs-keyword">private</span> ICacheManager _cache;<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 构造</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="cacheManager"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RedisCertificateManager</span>(<span class="hljs-params">ICacheManager cacheManager</span>)</span><br> {<br> _cache = cacheManager;<br> }<br><br> <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-built_in">string</span> <span class="hljs-title">GenerateRedisKey</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> serialNumber</span>)</span><br> {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">$"<span class="hljs-subst">{REDIS_KEY_PREFIX}</span><span class="hljs-subst">{serialNumber}</span>"</span>;<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 获得所有证书</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> IEnumerable<CertificateEntry> <span class="hljs-title">AllEntries</span>()</span><br> {<br><br> <span class="hljs-keyword">var</span> certs = _cache.GetByPrefix<CertificateEntry>(<span class="hljs-string">$"<span class="hljs-subst">{REDIS_KEY_PREFIX}</span>*"</span>) ?? <span class="hljs-keyword">new</span> Dictionary<<span class="hljs-built_in">string</span>, CertificateEntry>();<br> <span class="hljs-keyword">if</span> (certs.Any())<br> {<br> <span class="hljs-keyword">return</span> certs<br> .Select(t => t.Value)<br> .ToArray();<br> }<br><br> <span class="hljs-keyword">return</span> Array.Empty<CertificateEntry>();<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 添加证书</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="entry"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddEntry</span>(<span class="hljs-params">CertificateEntry entry</span>)</span><br> {<br> <span class="hljs-built_in">string</span> key = GenerateRedisKey(entry.SerialNumber);<br> _cache.Set(key, entry);<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 获得最新的证书</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="serialNumber"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-keyword">public</span> CertificateEntry? GetEntry(<span class="hljs-built_in">string</span> serialNumber)<br> {<br> <span class="hljs-built_in">string</span> key = GenerateRedisKey(serialNumber);<br> <span class="hljs-keyword">var</span> values = AllEntries();<br> <span class="hljs-keyword">if</span> (values.Any())<br> {<br> <span class="hljs-keyword">return</span> values.OrderByDescending(a => a.ExpireTime).FirstOrDefault();<br> }<br><br> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br> }<br><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> 移出一个证书</span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="serialNumber"></span><span class="hljs-doctag"></param></span></span><br> <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-built_in">bool</span> <span class="hljs-title">RemoveEntry</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> serialNumber</span>)</span><br> {<br> <span class="hljs-built_in">string</span> key = GenerateRedisKey(serialNumber);<br> _cache.Remove(key);<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><p>Worker干的事,为了以后可能出现多商户,也搞了循环商户数组</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-keyword">while</span> (!stoppingToken.IsCancellationRequested)<br>{<br> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> tenpayMerchantOptions <span class="hljs-keyword">in</span> _tenpayOptions.Merchants)<br> {<br> <span class="hljs-keyword">try</span><br> {<br> <span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> ALGORITHM_TYPE = <span class="hljs-string">"RSA"</span>;<br> <span class="hljs-keyword">var</span> client = _tenpayService.CreateClient(tenpayMerchantOptions.MerchantId);<br> <span class="hljs-keyword">var</span> request = <span class="hljs-keyword">new</span> QueryCertificatesRequest() { AlgorithmType = ALGORITHM_TYPE };<br> <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> client.ExecuteQueryCertificatesAsync(request, cancellationToken: stoppingToken);<br> <span class="hljs-keyword">if</span> (response.IsSuccessful())<br> {<br> <span class="hljs-comment">// NOTICE:</span><br> <span class="hljs-comment">// 如果构造 Client 时启用了 `AutoDecryptResponseSensitiveProperty` 配置项,则无需再执行下面一行的手动解密方法:</span><br> <span class="hljs-comment">//response = client.DecryptResponseSensitiveProperty(response);</span><br><br> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> certificate <span class="hljs-keyword">in</span> response.CertificateList)<br> {<br> client.PlatformCertificateManager.AddEntry(CertificateEntry.Parse(ALGORITHM_TYPE, certificate));<br> }<br><br> _logger.LogInformation(<span class="hljs-string">"刷新微信商户平台证书成功。"</span>);<br> }<br> <span class="hljs-keyword">else</span><br> {<br> _logger.LogWarning(<br> <span class="hljs-string">"刷新微信商户平台证书失败(状态码:{0},错误代码:{1},错误描述:{2})。"</span>,<br> response.GetRawStatus(), response.ErrorCode, response.ErrorMessage<br> );<br> }<br> }<br> <span class="hljs-keyword">catch</span> (Exception ex)<br> {<br> _logger.LogError(ex, <span class="hljs-string">"刷新微信商户平台证书遇到异常。"</span>);<br> }<br> }<br><br> <span class="hljs-keyword">await</span> Task.Delay(TimeSpan.FromDays(<span class="hljs-number">1</span>), stoppingToken); <span class="hljs-comment">// 每隔 1 天轮询刷新</span><br>}<br></code></pre></td></tr></table></figure><h3 id="创建订单"><a href="#创建订单" class="headerlink" title="创建订单"></a>创建订单</h3><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 通过Jsapi创建订单</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="requestModel"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task<CreatePayTransactionJsapiResponse> <span class="hljs-title">CreateOrderByJsapi</span>(<span class="hljs-params">CreateOrderByJsapiRequest requestModel</span>)</span><br>{<br> <span class="hljs-keyword">var</span> client = CreateClient(requestModel.MerchantId);<br><br> <span class="hljs-keyword">var</span> notifyUrl = _tenpayOptions.NotifyUrl;<br> <span class="hljs-keyword">if</span> (notifyUrl.Contains(<span class="hljs-string">"{merchant_id}"</span>))<br> notifyUrl = notifyUrl.Replace(<span class="hljs-string">"{merchant_id}"</span>, requestModel.MerchantId);<br><br> <span class="hljs-keyword">var</span> amount = Convert.ToInt32(requestModel.Amount * <span class="hljs-number">100</span>);<br> <span class="hljs-keyword">var</span> request = <span class="hljs-keyword">new</span> CreatePayTransactionJsapiRequest()<br> {<br> OutTradeNumber = requestModel.OutTradeNumber,<br> AppId = requestModel.AppId,<br> Description = requestModel.Description,<br> NotifyUrl = notifyUrl,<br> Amount = <span class="hljs-keyword">new</span> CreatePayTransactionJsapiRequest.Types.Amount() { Total = amount },<br> Payer = <span class="hljs-keyword">new</span> CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = requestModel.OpenId }<br> };<br> CreatePayTransactionJsapiResponse response = <span class="hljs-keyword">await</span> client.ExecuteCreatePayTransactionJsapiAsync(request);<br> <span class="hljs-keyword">if</span> (!response.IsSuccessful())<br> {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span>(<br> <span class="hljs-string">$"JSAPI 下单失败(状态码:<span class="hljs-subst">{response.GetRawStatus()}</span>,错误代码:<span class="hljs-subst">{response.ErrorCode}</span>,错误描述:<span class="hljs-subst">{response.ErrorMessage}</span>)。"</span><br> );<br> }<br> <span class="hljs-keyword">return</span> response;<br>}<br></code></pre></td></tr></table></figure><h3 id="生成客户端参数"><a href="#生成客户端参数" class="headerlink" title="生成客户端参数"></a>生成客户端参数</h3><p>拿着下单后的PrepayId就可以去获取客户端所需参数了</p><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 生成客户端 JSAPI / 小程序调起支付所需的参数字典</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br><span class="hljs-function"><span class="hljs-keyword">public</span> IDictionary<<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>> <span class="hljs-title">GetParametersForJsapiPayRequest</span>(<span class="hljs-params">ParametersForJsapiPayRequest requestModel</span>)</span><br>{<br> <span class="hljs-keyword">try</span><br> {<br> <span class="hljs-comment">// 创建客户端</span><br> <span class="hljs-keyword">var</span> client = CreateClient(requestModel.MerchantId);<br> <span class="hljs-keyword">var</span> res = client.GenerateParametersForJsapiPayRequest(requestModel.AppId, requestModel.PrepayId);<br> <span class="hljs-keyword">var</span> ret = <span class="hljs-keyword">new</span> Dictionary<<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>>(res)<br> {<br> <span class="hljs-comment">// 加上生成的业务单号,方便查询订单</span><br> { <span class="hljs-string">"billno"</span>, requestModel.BillNo }<br> };<br> <span class="hljs-keyword">return</span> ret;<br> }<br> <span class="hljs-keyword">catch</span> (Exception ex)<br> {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span>(<span class="hljs-string">"生成客户端 JSAPI / 小程序调起支付所需的参数字典异常"</span>, ex);<br> }<br><br>}<br></code></pre></td></tr></table></figure><h3 id="回调方法"><a href="#回调方法" class="headerlink" title="回调方法"></a>回调方法</h3><figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><code class="hljs c#"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> 微信支付回调</span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"></summary></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="merchantId"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="timestamp"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="nonce"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="signature"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><param name="serialNumber"></span><span class="hljs-doctag"></param></span></span><br><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag"><returns></span><span class="hljs-doctag"></returns></span></span><br>[<span class="hljs-meta">HttpPost</span>]<br>[<span class="hljs-meta">Route(<span class="hljs-string">"wx/{merchant_id}/pay"</span>)</span>]<br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task<IActionResult> <span class="hljs-title">ReceiveMessage</span>(<span class="hljs-params"></span></span><br><span class="hljs-params"><span class="hljs-function"> [FromRoute(Name = <span class="hljs-string">"merchant_id"</span></span>)] <span class="hljs-built_in">string</span> merchantId,</span><br><span class="hljs-function"> [<span class="hljs-title">FromHeader</span>(<span class="hljs-params">Name = <span class="hljs-string">"Wechatpay-Timestamp"</span></span>)] <span class="hljs-built_in">string</span> timestamp,</span><br><span class="hljs-function"> [<span class="hljs-title">FromHeader</span>(<span class="hljs-params">Name = <span class="hljs-string">"Wechatpay-Nonce"</span></span>)] <span class="hljs-built_in">string</span> nonce,</span><br><span class="hljs-function"> [<span class="hljs-title">FromHeader</span>(<span class="hljs-params">Name = <span class="hljs-string">"Wechatpay-Signature"</span></span>)] <span class="hljs-built_in">string</span> signature,</span><br><span class="hljs-function"> [<span class="hljs-title">FromHeader</span>(<span class="hljs-params">Name = <span class="hljs-string">"Wechatpay-Serial"</span></span>)] <span class="hljs-built_in">string</span> serialNumber)</span><br>{<br> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> reader = <span class="hljs-keyword">new</span> StreamReader(App.HttpContext.Request.Body, Encoding.UTF8);<br> <span class="hljs-built_in">string</span> content = <span class="hljs-keyword">await</span> reader.ReadToEndAsync();<br> <span class="hljs-comment">//_logger.LogInformation("接收到微信支付推送的数据:{0}", content);</span><br><br> <span class="hljs-keyword">var</span> client = _tenPayService.CreateClient(merchantId);<br> <span class="hljs-built_in">bool</span> valid = client.VerifyEventSignature(<br> webhookTimestamp: timestamp,<br> webhookNonce: nonce,<br> webhookBody: content,<br> webhookSignature: signature,<br> webhookSerialNumber: serialNumber<br> );<br> <span class="hljs-keyword">if</span> (!valid)<br> {<br> <span class="hljs-comment">// NOTICE:</span><br> <span class="hljs-comment">// 需提前注入 CertificateManager、并下载平台证书,才可以使用扩展方法执行验签操作。</span><br> <span class="hljs-comment">// 请参考本示例项目 TenpayCertificateRefreshingBackgroundService 后台任务中的相关实现。</span><br> <span class="hljs-comment">// 有关 CertificateManager 的完整介绍请参阅《开发文档 / 基础用法 / 如何验证回调通知事件签名?》。</span><br> <span class="hljs-comment">// 后续如何解密并反序列化,请参阅《开发文档 / 基础用法 / 如何解密回调通知事件中的敏感数据?》。</span><br><br> <span class="hljs-comment">//记录验签失败日志</span><br> <span class="hljs-keyword">await</span> ExceptionLogHelper.WriteRequestToLogAsync(_logger, App.HttpContext, <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"微信支付验签失败"</span>), App.Configuration);<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> JsonResult(<span class="hljs-keyword">new</span> { code = <span class="hljs-string">"FAIL"</span>, message = <span class="hljs-string">"验签失败"</span> });<br> }<br><br> WechatTenpayEvent callbackModel = client.DeserializeEvent(content);<br> <span class="hljs-keyword">var</span> eventType = callbackModel.EventType?.ToUpper();<br> <span class="hljs-comment">//解密数据</span><br> TransactionResource callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel);<br> <span class="hljs-keyword">switch</span> (eventType)<br> {<br> <span class="hljs-keyword">case</span> <span class="hljs-string">"TRANSACTION.SUCCESS"</span>:<br> {<br><br> <span class="hljs-comment">//_logger.LogInformation("接收到微信支付推送的订单支付成功通知,商户订单号:{0}", callbackResource.OutTradeNumber);</span><br> <span class="hljs-comment">// 成功情况</span><br> _vipService.DoPaySuccessOp(callbackResource, callbackModel);<br> }<br> <span class="hljs-keyword">break</span>;<br><br> <span class="hljs-literal">default</span>:<br> {<br> <span class="hljs-keyword">if</span> (callbackResource.IsNull())<br> {<br> <span class="hljs-comment">//记录其他情况日志</span><br> <span class="hljs-keyword">await</span> ExceptionLogHelper.WriteRequestToLogAsync(_logger, App.HttpContext, <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"微信支付通知失败"</span>), App.Configuration);<br> }<br><br> <span class="hljs-comment">// 其他情况默认失败</span><br> <span class="hljs-keyword">await</span> _vipService.DoPayFailureOpAsync(<span class="hljs-string">$"回调发生错误:<span class="hljs-subst">{callbackModel.Summary}</span>"</span>, callbackResource.OutTradeNumber, callbackModel.CreateTime.ToDate(), JToken.FromObject(callbackModel));<br> }<br> <span class="hljs-keyword">break</span>;<br> }<br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> JsonResult(<span class="hljs-keyword">new</span> { code = <span class="hljs-string">"SUCCESS"</span>, message = <span class="hljs-string">"成功"</span> });<br>}<br></code></pre></td></tr></table></figure><p>至此就ok啦,业务处理的代码就不放了,根据自己的情况编写。</p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><h3 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h3><p>本地测试时,支付用的时wx官方提供的小程序示例,其中有个模块叫接口能力——发起支付,改改提交方法即可</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js">wx.<span class="hljs-property">requestPayment</span><br>(<br> {<br> <span class="hljs-string">"appId"</span>: <span class="hljs-string">"**********"</span>,<br> <span class="hljs-string">"timeStamp"</span>: <span class="hljs-string">"1708416150"</span>,<br> <span class="hljs-string">"nonceStr"</span>: <span class="hljs-string">""</span>**********<span class="hljs-string">","</span>,<br> <span class="hljs-string">"package"</span>: <span class="hljs-string">"prepay_id="</span>**********<span class="hljs-string">","</span>,<br> <span class="hljs-string">"signType"</span>: <span class="hljs-string">"RSA"</span>,<br> <span class="hljs-string">"paySign"</span>: <span class="hljs-string">""</span>**********<span class="hljs-string">","</span>,<br> <span class="hljs-string">"billno"</span>: <span class="hljs-string">"cz_517123880726597"</span>,<br> <span class="hljs-string">"success"</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>){},<br> <span class="hljs-string">"fail"</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>){},<br> <span class="hljs-string">"complete"</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>){}<br> }<br>)<br></code></pre></td></tr></table></figure><h3 id="回调测试"><a href="#回调测试" class="headerlink" title="回调测试"></a>回调测试</h3><p>如果没有测试服务器,像我一样,可以使用natapp内网穿透,如果在公司测试的话开个内网穿透就ok了</p><p>如果有其他啥好方法也可以分享一下!</p>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
<tag>微信支付</tag>
</tags>
</entry>
<entry>
<title>使用acme.sh配置ssl证书并自动续签</title>
<link href="/2024/02/18/linux/001-%E4%BD%BF%E7%94%A8acme.sh%E8%87%AA%E5%8A%A8%E7%BB%AD%E7%AD%BEssl%E8%AF%81%E4%B9%A6/"/>
<url>/2024/02/18/linux/001-%E4%BD%BF%E7%94%A8acme.sh%E8%87%AA%E5%8A%A8%E7%BB%AD%E7%AD%BEssl%E8%AF%81%E4%B9%A6/</url>
<content type="html"><![CDATA[<h1 id="使用acme-sh配置SSL证书并自动续签"><a href="#使用acme-sh配置SSL证书并自动续签" class="headerlink" title="使用acme.sh配置SSL证书并自动续签"></a>使用acme.sh配置SSL证书并自动续签</h1><p>参考官网</p><p><a href="https://github.com/acmesh-official/acme.sh/wiki">Home · acmesh-official/acme.sh Wiki (github.com)</a></p><p>acme.sh用于生成免费的ssl证书,其完整实现了acme协议,并且由纯Shell脚本语言编写,没有过多的依赖项,安装和使用都非常方便。</p><p>支持多个ssl签发平台,如<a href="https://letsencrypt.org/">Let’s Encrypt (letsencrypt.org)</a>、<a href="https://zerossl.com/">Free SSL Certificates and SSL Tools - ZeroSSL</a></p><p>本文使用Let’s Encrypt</p><h2 id="准备环境:"><a href="#准备环境:" class="headerlink" title="准备环境:"></a>准备环境:</h2><ul><li>域名</li><li>Linux版本<code>Ubuntu22.04</code></li><li>代理服务器<code>Nginx1.18.0</code></li><li>acem.sh</li></ul><h3 id="下载安装acme-sh"><a href="#下载安装acme-sh" class="headerlink" title="下载安装acme.sh"></a>下载安装acme.sh</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">curl https://get.acme.sh | sh -s [email protected]<br></code></pre></td></tr></table></figure><p>使用这个安装干了些啥</p><ul><li><p>部署acme.sh程序到用户文件夹</p></li><li><p>为脚本创建新名称<code> acme.sh=~/.acme.sh/acme.sh</code></p><blockquote><p>需重启终端,不想重启的话<code> .acme.sh# alias acme.sh=~/.acme.sh/acme.sh</code></p></blockquote></li><li><p>创建一个每日定时任务,用于自动更新即将过期的证书</p><p>通过<code>crontab -l</code> 查看:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">18 18 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null<br></code></pre></td></tr></table></figure></li></ul><p>安装后目录</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">account.conf acme.sh acme.sh.env deploy dnsapi http.header notify<br></code></pre></td></tr></table></figure><p>具体命令可查看官网</p><h2 id="使用acme-sh配置ssl证书"><a href="#使用acme-sh配置ssl证书" class="headerlink" title="使用acme.sh配置ssl证书"></a>使用acme.sh配置ssl证书</h2><h3 id="直接指向项目"><a href="#直接指向项目" class="headerlink" title="直接指向项目"></a>直接指向项目</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">acme.sh --issue -d example.com -d test.com -w /var/www/project<br></code></pre></td></tr></table></figure><p>-d参数指定域名,多个域名使用多个-d参数,第一个-d参数指定的域名即证书的主体名称,其它-d参数指定的域名为证书的可选主体名称。</p><p>-w参数指定的是域名的webroot目录,以example.com为例,-w参数的值即是<a href="http://example.com对应的webroot目录.如果使用多个-d参数同时指定了多个域名,则所有这些域名必须对应同一个webroot目录;另外,当前系统用户必须具有webroot目录的写入权限./">http://example.com对应的webroot目录。如果使用多个-d参数同时指定了多个域名,则所有这些域名必须对应同一个webroot目录;另外,当前系统用户必须具有webroot目录的写入权限。</a></p><h3 id="DNS自动模式(建议)"><a href="#DNS自动模式(建议)" class="headerlink" title="DNS自动模式(建议)"></a>DNS自动模式(建议)</h3><p>此方法会向域名解析平台添加一个TXT记录值,需要提供对应平台的Key和Secret,具体参考<a href="https://github.com/acmesh-official/acme.sh/blob/master/dnsapi/dns_ali.sh">acme.sh/dnsapi/dns_ali.sh at master · acmesh-official/acme.sh (github.com)</a> 我使用的是dns_ali。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_">#</span><span class="language-bash">切换默认平台为letsencrypt 其他更换最后平台即可</span><br>acme.sh --set-default-ca --server letsencrypt<br></code></pre></td></tr></table></figure><blockquote><p>默认的签发平台是ZeroSSL,我使用的时候想着就用默认的平台,可是一直报错<code> et authz objec with invalid status, please try again later.</code> github上有人说是ZeroSSL的dns身份认证出问题了。<a href="https://github.com/acmesh-official/acme.sh/issues/4991">This domain won’t issue · Issue #4991 · acmesh-official/acme.sh (github.com)</a> 所以我换成了用letsencrypt</p></blockquote><p>获取阿里云的Key和Secret,添加到系统环境变量</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">export Ali_Key="*******************"<br>export Ali_Secret="*********************"<br></code></pre></td></tr></table></figure><p>生成证书</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">acme.sh --issue --dns dns_ali -d example.com -d www.example.com<br></code></pre></td></tr></table></figure><p>该命令从系统变量中读取aliyun的api授权ID和密码,并通过dns_ali参数指定DNS提供商为阿里云。该命令将通过api自动为指定域名添加txt记录,并在验证完毕后自动移除txt记录。</p><p>aliyun的api授权ID和密码将被保存在.acme.sh的账户配置文件中,以供将来自动更新证书时使用,存储位置为:</p><p><code> ~/.acme.sh/account.conf</code></p><p>通过<code> --install-cert</code>部署证书</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">acme.sh --install-cert -d *.example.com \<br>--key-file /etc/nginx/ssl/in/example.com.key \<br>--fullchain-file /etc/nginx/ssl/fullchain.cer \<br>--reloadcmd "nginx -s reload"<br></code></pre></td></tr></table></figure><p>使用<code> acme.sh --list</code>查看证书列表</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">Main_Domain KeyLength SAN_Domains CA Created Renew<br>*.ihuadz.top "ec-256" ihuadz.top LetsEncrypt.org 2024-02-18T04:06:07Z 2024-04-17T04:06:07Z<br></code></pre></td></tr></table></figure><h2 id="Nginx-部署"><a href="#Nginx-部署" class="headerlink" title="Nginx 部署"></a>Nginx 部署</h2><p>在项目对应的Nginx配置文件中添加</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs json">server <span class="hljs-punctuation">{</span><br> listen <span class="hljs-number">443</span> ssl;<br> server_name blog.ihuadz.top;<br> root /var/www/hexo;<br> <br> ssl_certificate <span class="hljs-string">"/etc/nginx/ssl/ihuadz.top/fullchain.cer"</span>;<br> ssl_certificate_key <span class="hljs-string">"/etc/nginx/ssl/ihuadz.top/*.ihuadz.top.key"</span>;<br> ssl_session_cache shared<span class="hljs-punctuation">:</span>SSL<span class="hljs-punctuation">:</span><span class="hljs-number">1</span>m;<br> ssl_session_timeout <span class="hljs-number">10</span>m;<br> ssl_ciphers HIGH<span class="hljs-punctuation">:</span>!aNULL<span class="hljs-punctuation">:</span>!MD5;<br> ssl_prefer_server_ciphers on;<br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><p>访问<a href="https://blog.ihuadz.top/">https://blog.ihuadz.top</a> ok。没问题</p><blockquote><p>不同的项目配置不同的域名和路径即可,使用泛域名的话就不用重新申请证书</p></blockquote>]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Aginx</tag>
<tag>Linux</tag>
<tag>SSL</tag>
</tags>
</entry>
<entry>
<title>EFCore概述</title>
<link href="/2024/02/01/ef_core/01-EFCore%E6%A6%82%E8%BF%B0/"/>
<url>/2024/02/01/ef_core/01-EFCore%E6%A6%82%E8%BF%B0/</url>
<content type="html"><![CDATA[<h1 id="EFCore概述"><a href="#EFCore概述" class="headerlink" title="EFCore概述"></a>EFCore概述</h1><p>本系列文章参考微软官方文档:<a href="https://learn.microsoft.com/zh-cn/ef/core/">Entity Framework Core | Microsoft Learn</a>;</p><p>Entity Framework(Ef) Core是轻量化、可扩展、开源和跨平台的常用Entity Framework数据访问技术。</p><p>EF Core可用作对象关系映射程序(O/RM),这可以实现以下两点:</p><ul><li>使.NET开发人员能够使用.NET对象处理数据库。</li><li>无需再像通常那样编写大部分数据访问代码。</li></ul><p>EF Core 支持多个数据库引擎。</p>]]></content>
<categories>
<category>.Net</category>
<category>EFCore</category>
</categories>
<tags>
<tag>.Net</tag>
<tag>EFCore</tag>
</tags>
</entry>
<entry>
<title>在Linux上使用Nginx部署ASP.NET Core应用</title>
<link href="/2024/01/26/dotnet/004-%E5%9C%A8Linux%E4%B8%8A%E9%83%A8%E7%BD%B2ASP.NET%20Core%E5%BA%94%E7%94%A8/"/>
<url>/2024/01/26/dotnet/004-%E5%9C%A8Linux%E4%B8%8A%E9%83%A8%E7%BD%B2ASP.NET%20Core%E5%BA%94%E7%94%A8/</url>
<content type="html"><![CDATA[<h1 id="在Linux上使用Nginx部署ASP-NET-Core应用"><a href="#在Linux上使用Nginx部署ASP-NET-Core应用" class="headerlink" title="在Linux上使用Nginx部署ASP.NET Core应用"></a>在Linux上使用Nginx部署ASP.NET Core应用</h1><p>本篇文章参考微软官方文章<a href="https://learn.microsoft.com/zh-cn/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-8.0&tabs=linux-ubuntu">使用 Nginx 在 Linux 上托管 ASP.NET Core</a> </p><h2 id="准备环境"><a href="#准备环境" class="headerlink" title="准备环境"></a>准备环境</h2><ul><li>Linux版本<code>Ubuntu22.04</code></li><li>.Net运行时<code>.NetRutime8.0</code></li><li>代理服务器<code>Nginx1.18.0</code></li></ul><h3 id="安装-Net"><a href="#安装-Net" class="headerlink" title="安装.Net"></a>安装.Net</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash">运行时</span><br>sudo apt-get update && \<br>sudo apt-get install -y dotnet-runtime-8.0 <br><span class="hljs-meta prompt_"></span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">Sdk</span><br>sudo apt install dotnet-sdk-8.0<br></code></pre></td></tr></table></figure><blockquote><p>安装sdk时可能会出现找不到包的情况,这时使用官方的安装脚本即可</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash">下载脚本</span><br>wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh<br><span class="hljs-meta prompt_"></span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">修改脚本权限</span><br>chmod +x ./dotnet-install.sh<br><span class="hljs-meta prompt_"></span><br><span class="hljs-meta prompt_"># </span><span class="language-bash">安装最新版本,若需要LTS删除--version latest</span><br>./dotnet-install.sh --version latest<br><span class="hljs-meta prompt_"></span><br><span class="hljs-meta prompt_">#</span><span class="language-bash">runtime也可以用脚本安装</span><br>./dotnet-install.sh --version latest --runtime aspnetcore<br></code></pre></td></tr></table></figure></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash">查看dotnet版本</span><br>dotnet --info<br></code></pre></td></tr></table></figure><p><img src="/../img/007/01.png" alt="shell"></p><h3 id="部署Asp-Net项目"><a href="#部署Asp-Net项目" class="headerlink" title="部署Asp.Net项目"></a>部署Asp.Net项目</h3><p>本地运行OK后发布上传到服务器,这里我使用的时<code>XFtp</code>,和XShell一套挺好用的;</p><p>测试应用:</p><blockquote><p>注意:当NETCORE的版本低于3.0时,对应的命令为<br><code>dotnet web.dll --server.urls="http://localhost:7102"</code><br>当NETCORE高于等于3.0版本时<br><code>--urls "http://localhost:7102"</code> </p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_"># </span><span class="language-bash">Linux进入文件目录运行应用</span><br>dotnet RazorPageDemo.dll --urls "http://localhost:7102"<br></code></pre></td></tr></table></figure><p><img src="/../img/007/02.png" alt="Alt text"></p><h3 id="配置nginx"><a href="#配置nginx" class="headerlink" title="配置nginx"></a>配置nginx</h3><p>nginx默认的配置路径<code>/etc/nginx/conf.d</code><br>新建文件<code>rdemo.conf</code>并添加内容</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs json">server<span class="hljs-punctuation">{</span><br> listen <span class="hljs-number">7102</span>;<br> server_name *.exmple.com;<br> location /<span class="hljs-punctuation">{</span><br> proxy_pass http<span class="hljs-punctuation">:</span><span class="hljs-comment">//127.0.0.1:7202/;</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><p>重新加载nginx配置文件<code>nginx -s reload</code></p><p>访问页面</p><p><img src="/../img/007/03.png" alt="Alt text"> </p><h3 id="启动后台守护程序"><a href="#启动后台守护程序" class="headerlink" title="启动后台守护程序"></a>启动后台守护程序</h3><p>ctrl+c停止程序运行<br>创建服务定义文件:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo nano /etc/systemd/system/kestrel-rdemo.service<br></code></pre></td></tr></table></figure><p>以下示例是应用的一个 .ini 服务文件:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs text">[Unit]<br>Description=Example .NET Web API App running on Linux<br><br>[Service]<br>WorkingDirectory=/var/www/razorpagedemo<br>ExecStart=/usr/bin/dotnet /var/www/razorpagedemo/RazorPageDemo.dll --urls "http://localhost:7202"<br>Restart=always<br># Restart service after 10 seconds if the dotnet service crashes:<br>RestartSec=10<br>KillSignal=SIGINT<br>SyslogIdentifier=razorpagedemo<br>User=www-data<br>Environment=ASPNETCORE_ENVIRONMENT=Production<br>Environment=DOTNET_NOLOGO=false<br><br>[Install]<br>WantedBy=multi-user.target<br></code></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_">#</span><span class="language-bash">启动服务</span><br>sudo systemctl enable kestrel-rdemo.service<br><span class="hljs-meta prompt_">#</span><span class="language-bash">运行</span><br>sudo systemctl start kestrel-rdemo.service<br><span class="hljs-meta prompt_">#</span><span class="language-bash">查看状态</span><br>sudo systemctl status kestrel-rdemo.service<br></code></pre></td></tr></table></figure><p>OK,访问没问题就可以了,云服务器的话记得打开端口</p>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
<tag>Aginx</tag>
</tags>
</entry>
<entry>
<title>一次购买服务器的经历</title>
<link href="/2024/01/26/essays/001-%E4%B8%80%E6%AC%A1%E8%B4%AD%E4%B9%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E7%BB%8F%E5%8E%86/"/>
<url>/2024/01/26/essays/001-%E4%B8%80%E6%AC%A1%E8%B4%AD%E4%B9%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E7%BB%8F%E5%8E%86/</url>
<content type="html"><![CDATA[<h1 id="一次购买服务器的经历"><a href="#一次购买服务器的经历" class="headerlink" title="一次购买服务器的经历"></a>一次购买服务器的经历</h1><h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>事情是这样的,收到一条阿里云的短信,说是云服务器99元一年,这配置得心动一下啊; </p><p><img src="/../img/006/01.png" alt="阿里云服务器"> </p><p>之前不是在国外域名商namesilo买了域名嘛,刚好买一台Linux拿来练练手。</p><h2 id="购买服务器"><a href="#购买服务器" class="headerlink" title="购买服务器"></a>购买服务器</h2><p>开开心心付了款,等待分配实例。OK,成功登录上熟练的<code>sudo apt update && sudo apt upgrade</code>;没问题,一切都正常。好了,开始配置<code>nginx</code>,把我的博客给上传,配置好域名。<br>不错,正常访问<br><img src="/../img/006/02.png" alt="ihuadz"></p><blockquote><p>关于博客搭建可以参看我的第一篇博客<a href="https://gblog.ihuadz.top/">https://gblog.ihuadz.top</a> </p></blockquote><h2 id="出问题了"><a href="#出问题了" class="headerlink" title="出问题了"></a>出问题了</h2><p>下班回家,想继续看一下还能不能正常访问,毕竟用的是国外域名商,果然:<br><img src="/../img/006/03.png" alt="ohps"><br>好了,那就备案呗;疯狂填信息,哦豁!需要实名域名。。。<br>咋整,namesilo又不提供实名服务。没办法,只能在阿里云重新买一个域名了 </p><blockquote><p>对了,这里用的都是<code>gblog.ihuadz.top</code>域名,部署到了<code>github page</code>上,<code>blog.ihuadz.top</code>暂时用不了是因为服务器需要等域名实名后2-3天才能备案 </p></blockquote><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><blockquote><p>服务器和域名,要么全国内,要么全国外<br>自己玩又有购买能力的话,全国外吧,毕竟实名认证挺麻烦<br>怕封ip又想向我一样贪小便宜就老老实实玩全国内吧</p></blockquote>]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title>英语语法架构</title>
<link href="/2023/10/30/english/001-%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95%E6%9E%B6%E6%9E%84/"/>
<url>/2023/10/30/english/001-%E8%8B%B1%E8%AF%AD%E8%AF%AD%E6%B3%95%E6%9E%B6%E6%9E%84/</url>
<content type="html"><![CDATA[<h2 id="语法架构"><a href="#语法架构" class="headerlink" title="语法架构"></a>语法架构</h2><p><img src="https://s2.loli.net/2024/01/22/DCzuriOFfW9wUIa.jpg" alt="EnglishGrammarStruc.jpg"></p>]]></content>
<categories>
<category>英语</category>
</categories>
<tags>
<tag>英语</tag>
</tags>
</entry>
<entry>
<title>英语动词时态例句</title>
<link href="/2023/08/02/english/002-%E5%8A%A8%E8%AF%8D%E6%97%B6%E6%80%81%E4%BE%8B%E5%8F%A5/"/>
<url>/2023/08/02/english/002-%E5%8A%A8%E8%AF%8D%E6%97%B6%E6%80%81%E4%BE%8B%E5%8F%A5/</url>
<content type="html"><![CDATA[<h2 id="英语动词时态例句"><a href="#英语动词时态例句" class="headerlink" title="英语动词时态例句"></a>英语动词时态例句</h2><table><thead><tr><th>时间\时态</th><th>简单时态</th><th>进行时态</th><th>完成时态</th><th>完成进行时态</th></tr></thead><tbody><tr><td>现在</td><td>She goes shopping every Saturday. (她每个星期六去购物。)</td><td>She is going shopping right now. (她正在去购物。)</td><td>She has already gone shopping. (她已经去购物了。)</td><td>She has been going shopping for two hours. (她已经去购物两个小时了。)</td></tr><tr><td>过去</td><td>She went shopping last Sunday. (她上个星期天去购物了。)</td><td>She was going shopping when I called. (我给她打电话时,她正在去购物。)</td><td>She had already gone shopping when her friends arrived. (她的朋友到达时,她已经去购物了。)</td><td>She had been going shopping for two hours before the mall closed. (购物中心关门前,她已经去购物两个小时了。)</td></tr><tr><td>将来</td><td>She will go shopping tomorrow. (她明天会去购物。)</td><td>She will be going shopping at this time tomorrow. (明天这个时候,她将在去购物的路上。)</td><td>She will have gone shopping by the time you arrive. (到你到达的时候,她会已经去购物了。)</td><td>She will have been going shopping for three hours by 5 PM. (到下午5点,她将已经去购物三个小时了。)</td></tr><tr><td>过去将来</td><td>She said she would go shopping last weekend, but she couldn’t. (她说上个周末会去购物,但她没去成。)</td><td>She said she would be going shopping at this time last Saturday. (她说上个星期六这个时候会去购物。)</td><td>She said she would have gone shopping before the store closed. (她说店关门前会去购物。)</td><td>She said she would have been going shopping for two hours by the time her friends arrived. (她说她的朋友到达时,她已经去购物两个小时了。)</td></tr></tbody></table>]]></content>
<categories>
<category>英语</category>
</categories>
<tags>
<tag>英语</tag>
</tags>
</entry>
<entry>
<title>.NET学习计划</title>
<link href="/2023/05/31/dotnet/001-DotNET%E5%AD%A6%E4%B9%A0%E8%AE%A1%E5%88%92/"/>
<url>/2023/05/31/dotnet/001-DotNET%E5%AD%A6%E4%B9%A0%E8%AE%A1%E5%88%92/</url>
<content type="html"><![CDATA[<h1 id="NET学习计划"><a href="#NET学习计划" class="headerlink" title=".NET学习计划"></a>.NET学习计划</h1><p>因为要上班,学习的时候总是东一榔头西一斧头的,导致啥啥都学不好,还经常忘记,本篇文章暂拟一个计划,深入学习DotNET。由于是空余时间学习,就按照这个计划推进吧,在学习过程中逐渐优化,加油吧!</p><h2 id="计划"><a href="#计划" class="headerlink" title="计划"></a>计划</h2><ol><li><p>确定学习目标:</p><ul><li><p><a href="https://hengyu.club/2023/05/30/DotNET-001.Net%E5%B9%B3%E5%8F%B0%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86/" title=".NET-001.Net平台的概念和组成部分">了解.Net平台的概念和组成部分</a> </p></li><li><p><a href="https://learn.microsoft.com/zh-cn/dotnet/csharp/" title="C#官方文档">学习 C# 编程语言。</a> </p></li><li><p><a href="https://learn.microsoft.com/zh-cn/aspnet/core/?view=aspnetcore-7.0" title="ASP.NET 文档 | Microsoft Learn">掌握 ASP.NET Core 开发。</a> </p></li><li><p><a href="https://learn.microsoft.com/zh-cn/ef/" title="实体框架文档中心 | Microsoft Learn">学习使用 Entity Framework Core 进行数据库开发。</a> </p></li><li><p><a href="https://learn.microsoft.com/zh-cn/visualstudio/?view=vs-2022" title="Visual Studio 产品系列文档 | Microsoft Learn">掌握常用的 .NET 开发工具和技术。</a></p></li></ul></li><li><p>学习基础知识:</p><ul><li><input checked="" disabled="" type="checkbox"> 学习 C# 编程语言基础,包括语法、数据类型、控制流等。</li><li><input checked="" disabled="" type="checkbox"> <a href="https://hengyu.club/2023/05/31/DotNET-002%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/">了解面向对象编程(OOP)的基本概念和原则。</a> </li><li><input checked="" disabled="" type="checkbox"> 学习使用 Visual Studio 或者 Visual Studio Code 进行 .NET 开发。</li></ul></li><li><p>深入学习 .NET 平台和核心概念:</p><ul><li><input checked="" disabled="" type="checkbox"> 了解 .NET 平台的历史和演变。</li><li><input checked="" disabled="" type="checkbox"> 学习 .NET 标准库和常用的命名空间。(太多了,持续学习中…)</li><li><input checked="" disabled="" type="checkbox"> 了解 .NET Core 和 .NET Framework 的区别和共同点。(最大区别,跨平台..)</li></ul></li><li><p>学习 ASP.NET Core 开发:</p><ul><li><input checked="" disabled="" type="checkbox"> 了解 ASP.NET Core 的基本概念和架构。</li><li><input checked="" disabled="" type="checkbox"> 学习使用 MVC(模型-视图-控制器)或者 Razor Pages 进行 Web 开发。</li><li><input checked="" disabled="" type="checkbox"> 掌握路由、中间件、模型绑定、身份验证和授权等核心功能。</li><li><input checked="" disabled="" type="checkbox"> 学习前端开发技术,如 HTML、CSS 和 JavaScript。</li></ul></li><li><p>数据库开发:</p><ul><li><input disabled="" type="checkbox"> 学习使用 Entity Framework Core 进行数据库访问和操作。</li><li><input disabled="" type="checkbox"> 掌握数据库迁移和代码优先开发的概念和实践。</li><li><input disabled="" type="checkbox"> 了解常见的数据库管理系统,如 SQL Server、MySQL 或者 PostgreSQL。</li></ul></li><li><p>学习资源和实践:</p><ul><li><input disabled="" type="checkbox"> 阅读官方文档和教程,如 Microsoft 的官方文档和 ASP.NET Core 文档。</li><li><input disabled="" type="checkbox"> 参加在线课程或者培训班,如 Microsoft Learn 或者 Pluralsight 提供的相关课程。</li><li><input disabled="" type="checkbox"> 参与开发社区和论坛,与其他开发者交流和分享经验。</li><li><input disabled="" type="checkbox"> 尝试编写小型项目或者参与开源项目,实践所学知识。</li></ul></li><li><p>学习开源框架研究源码</p><ul><li><input disabled="" type="checkbox"> 学习研究公司框架源码</li><li><input disabled="" type="checkbox"> 学习研究Furion框架</li><li><input disabled="" type="checkbox"> 学习研究FreeSql框架-与EFCore比较</li></ul></li><li><p>持续学习和更新:</p><ul><li><input disabled="" type="checkbox"> 订阅 .NET 相关的博客、新闻和邮件列表,了解最新的技术动态。</li><li><input disabled="" type="checkbox"> 参与技术会议和线下活动,与其他开发者面对面交流和学习。</li><li><input disabled="" type="checkbox"> 持续关注 .NET 社区的发展和新兴技术,不断扩展自己的知识面。</li></ul></li></ol>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
</tags>
</entry>
<entry>
<title>.Net平台的概念和组成部分</title>
<link href="/2023/05/30/dotnet/002-DotNET%E5%B9%B3%E5%8F%B0%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86/"/>
<url>/2023/05/30/dotnet/002-DotNET%E5%B9%B3%E5%8F%B0%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86/</url>
<content type="html"><![CDATA[<h1 id="Net平台的概念和组成部分"><a href="#Net平台的概念和组成部分" class="headerlink" title=".Net平台的概念和组成部分"></a>.Net平台的概念和组成部分</h1><p>.NET 平台是一个跨平台的软件开发平台,由微软公司开发和维护。它提供了一个统一的环境和工具集,用于开发和执行各种类型的应用程序,包括桌面应用程序、Web 应用程序、移动应用程序、云服务等。下面是.NET 平台的概念和组成部分的介绍:</p><h3 id="Common-Language-Runtime-CLR"><a href="#Common-Language-Runtime-CLR" class="headerlink" title="Common Language Runtime (CLR)"></a>Common Language Runtime (CLR)</h3><p>CLR 是.NET 平台的核心组件之一,它提供了应用程序的执行环境。CLR 负责将.NET 程序编译为中间语言(IL)并执行,同时处理内存管理、安全性、异常处理等运行时任务。</p><h3 id="NET-Framework"><a href="#NET-Framework" class="headerlink" title=".NET Framework"></a>.NET Framework</h3><p>.NET Framework 是最早引入的.NET 平台版本,它是一个用于构建 Windows 应用程序的完整开发框架。它包括了大量的类库、工具和运行时环境,支持多种编程语言(如C#、VB.NET 和 F#)。</p><h3 id="NET-Core"><a href="#NET-Core" class="headerlink" title=".NET Core"></a>.NET Core</h3><p>.NET Core 是.NET 平台的开源版本,它是跨平台的,可以在 Windows、Linux 和 macOS 等操作系统上运行。.NET Core 面向云和容器化应用开发,具有更轻量级的体积和更高的性能。</p><h3 id="ASP-NET"><a href="#ASP-NET" class="headerlink" title="ASP.NET"></a>ASP.NET</h3><p>ASP.NET 是.NET 平台的 Web 开发框架,用于构建动态的、可扩展的 Web 应用程序。它提供了一组强大的工具和功能,包括模型-视图-控制器(MVC)模式、Web API、身份验证、授权等。</p><h3 id="Entity-Framework"><a href="#Entity-Framework" class="headerlink" title="Entity Framework"></a>Entity Framework</h3><p>Entity Framework 是.NET 平台的对象关系映射(ORM)框架,用于简化与数据库的交互和数据持久化。它提供了一种面向对象的方式来操作数据库,支持多种数据库管理系统。</p><h3 id="编程语言"><a href="#编程语言" class="headerlink" title="编程语言"></a>编程语言</h3><p>.NET 平台支持多种编程语言,包括C#、VB.NET、F#等。C# 是.NET 平台的主要语言之一,它是一种现代、面向对象的编程语言,用于开发各种类型的应用程序。</p><h3 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h3><p>在.NET 平台上开发应用程序时,常用的开发工具包括 Visual Studio 和 Visual Studio Code。Visual Studio 是一个强大的集成开发环境(IDE),提供了丰富的功能和工具,简化开发过程。</p><h3 id="NuGet"><a href="#NuGet" class="headerlink" title="NuGet"></a>NuGet</h3><p>NuGet 是.NET 平台的软件包管理系统,用于方便地添加、更新和管理项目所依赖的第三方库和工具。</p>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
</tags>
</entry>
<entry>
<title>.NET面向对象编程</title>
<link href="/2023/05/30/dotnet/003-DotNET%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/"/>
<url>/2023/05/30/dotnet/003-DotNET%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/</url>
<content type="html"><![CDATA[<h1 id="面向对象编程"><a href="#面向对象编程" class="headerlink" title="面向对象编程"></a>面向对象编程</h1><p>面向对象编程(Object-Oriented Programming,简称OOP)是一种常用的编程范式,它以对象为基本单位,通过封装、继承和多态等概念来组织和构建程序。</p><p>在面向对象编程中,一个对象是由数据(属性)和操作(方法)组成的实体。对象可以互相通信和交互,通过调用彼此的方法来实现各种功能。以下是面向对象编程中的一些关键概念:</p><h3 id="类(Class)"><a href="#类(Class)" class="headerlink" title="类(Class)"></a>类(Class)</h3><p>类是对象的模板或蓝图,描述了对象的属性和方法。它定义了对象共享的特征和行为。类是创建对象的基础,可以看作是对象的类型。</p><h3 id="对象(Object)"><a href="#对象(Object)" class="headerlink" title="对象(Object)"></a>对象(Object)</h3><p>对象是类的实例,具体的实体。它具有类定义的属性和方法,并且可以进行特定的操作。每个对象都是独立的,拥有自己的状态。</p><h3 id="封装(Encapsulation)"><a href="#封装(Encapsulation)" class="headerlink" title="封装(Encapsulation)"></a>封装(Encapsulation)</h3><p>封装是将数据和方法组合在一个单元内,对外部隐藏对象的内部实现细节。通过封装,对象的内部状态和实现细节对外部是不可见的,只有通过公开的接口(方法)来访问和操作对象。</p><h3 id="继承(Inheritance)"><a href="#继承(Inheritance)" class="headerlink" title="继承(Inheritance)"></a>继承(Inheritance)</h3><p>继承是一种通过扩展现有类来创建新类的机制。子类可以继承父类的属性和方法,并可以新增或修改其行为。继承使得代码重用变得更加容易,同时可以建立类之间的层次关系。</p><h3 id="多态(Polymorphism)"><a href="#多态(Polymorphism)" class="headerlink" title="多态(Polymorphism)"></a>多态(Polymorphism)</h3><p>多态是指在父类的引用中使用子类的对象。多态允许使用统一的接口来处理不同的对象,通过动态绑定,可以在运行时确定要调用的方法。</p><h3 id="面向对象编程的优点"><a href="#面向对象编程的优点" class="headerlink" title="面向对象编程的优点"></a>面向对象编程的优点</h3><ul><li>模块化:通过封装和抽象,代码可以被组织成独立的模块,便于理解和维护。</li><li>代码重用:通过继承和多态,可以有效地重用已有的代码,减少重复编写相似功能的工作。</li><li>可扩展性:面向对象编程提供了良好的扩展性,可以通过新增类和修改现有类来扩展程序的功能。</li><li>更易于理解:面向对象编程提供了一种自然的、类似现实世界的抽象方式,使得代码更易于理解和交流。</li></ul>]]></content>
<categories>
<category>.Net</category>
</categories>
<tags>
<tag>.Net</tag>
</tags>
</entry>
<entry>
<title>我的第一篇博客</title>
<link href="/2023/05/19/essays/000-%E7%AC%AC%E4%B8%80%E7%AF%87BLOG/"/>
<url>/2023/05/19/essays/000-%E7%AC%AC%E4%B8%80%E7%AF%87BLOG/</url>
<content type="html"><![CDATA[<h1 id="我的第一篇博客"><a href="#我的第一篇博客" class="headerlink" title="我的第一篇博客"></a>我的第一篇博客</h1><p>第一篇博客也不知道写点啥,就先写一下如何建站的吧!</p><p>首先,为啥要弄这个博客呢?</p><ul><li><p>一个程序员的好奇心</p></li><li><p>真的想学点东西</p></li><li><p>装x</p></li></ul><p>就是这几点原因造就了这个站点,下面说一下技术吧。</p><h2 id="Hexo"><a href="#Hexo" class="headerlink" title="Hexo"></a>Hexo</h2><p>这就不用多说了,点击快速建站<a href="https://hexo.io/zh-cn/index.html" title="Hexo主页">Hexo</a>。这是我接触到的第一个博客框架,没用过其他的,感觉上手还是挺简单的,官网介绍的比较详细,轻松运行。</p><h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h2><p>我用的是Fluid,点击<a href="https://hexo.fluid-dev.com/docs/start/#%E6%90%AD%E5%BB%BA-hexo-%E5%8D%9A%E5%AE%A2">Fluid官方介绍</a> ,各主题应该大同小异可去Hexo官网选择。</p><h2 id="站点计数与评论"><a href="#站点计数与评论" class="headerlink" title="站点计数与评论"></a>站点计数与评论</h2><p>计数和评论放在一起是因为都用到了<a href="https://www.leancloud.cn/">LeanCloud</a>,一个基于Docker的云计算平台,分国内版和海外版,我用的是海外版,因为不需要实名。计数和评论都调用了此平台的API,网上有很多其他博主写的详细教程。</p><p>评论功能还用到了<a href="https://vercel.com/dashboard">Vercel</a>,一个网站托管服务,类似GitHub Pages,主要用它部署了<a href="https://waline.js.org/">Waline</a>,一款简洁安全的评论系统,挺牛的系统,登录、回复、表情、图片、管理评论啥啥都有。</p><h2 id="域名"><a href="#域名" class="headerlink" title="域名"></a>域名</h2><p>之前申请过阿里、腾讯的域名,那一个麻烦申请过的朋友应该都清楚,也是准备建站的时候才了解到<a href="https://namesilo-china.com/">NameSilo</a>,国外的一个域名服务网站,价格低,主要是续费也是差不多价格,学习使用域名的话,这个挺好的,还可以配置50个二级域名,自己玩够够的了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>第一次写博客,不知道写啥,慢慢学习吧。</p><p>上面说到的技术都是粗略介绍了一下,之后有时间或者有需求的话做个系列介绍。</p><p>学习的时间不多,逐渐优化完善吧。</p>]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
</search>