澳门至尊网站-首页

您的位置:澳门至尊网站 > 搜索引擎 > Core中间件实现分布式,支付功能接入

Core中间件实现分布式,支付功能接入

2019-10-19 11:57

转自:

  • 1. ASP.NET Core中间件详解
    • 1.1. 中间件原理
      • 1.1.1. 怎么是中间件
      • 1.1.2. 中间件实行进度
      • 1.1.3. 中间件的布置
    • 1.2. 信任注入中间件
    • 1.3. Cookies和session中间件
      • 1.3.1. Session
      • 1.3.2. Session保存到Redis中
      • 1.3.3. 贯彻布满Session
    • 1.4. 总结

那篇小说将介绍ASP.NET Core中利用 开源项目 Payment,达成连通支付宝-Computer网页支付接口及一块跳转及异步公告成效。

1.1. 中间件原理

开辟条件:Win 10 x64、VS2017 15.6.4、.NET Core SDK 2.1.101、.NET Core Runtime 2.0.6

1.1.1. 什么是中间件

中间件是段代码用于拍卖央求和响应,平时多当中间件链接起来变成管道,由每个中间件自身来支配是或不是要调用下三个中间件。

图片 1

2017-10-10-21-47-00

1.新建"ASP.NET Core Web 应用程序"项目,笔者将它定名称为Alipay萨姆ple.

1.1.2. 中间件实施进程

举二个演示来演示中间件的进行进程(分别有五在那之中间件:日志记录、权限验证和路由):当呼吁步入应用程序时,施行实践日志记录的中间件,它记录央求属性并调用链中的下壹在那之中间件权限验证,要是权力验证通过则将调控权传递给下叁此中间件,不通过则设置401 HTTP代码并再次回到响应,响应传递给日志中间件举行再次回到。

图片 2

2017-10-10-22-47-32

图片 3

1.1.3. 中间件的布置

中间件配置重假诺用RunMapUse主意开展配置,三者的两样参见上篇ASP.NET Core 运营规律剖判;简单的中间件能够直接运用佚名格局就足以消除,如下代码:

app.Run(async (context,next) =>
        {
            await context.Response.WriteAsync("environment " + env);
            await next();
        });

倘使想援用中间件,就供给单独封装到一个类中开展调用。

图片 4

1.2. 依赖注入中间件

在实际项目中,中间件往往必要调用别的对象的章程。所以要成立对象之间的信任性,由于ASP.NET Core 内置的重视性注入系统,写程序的时候可以创造更文雅的代码。

第一须要要在IOC容器中注册类,正是Startup类中的ConfigureServices艺术中开展挂号,ConfigureServices方法会在Configure主意早先被施行。以便在用中间件时持有信赖都计划好了。

未来有二个Greeter类:

public class Greeter : IGreeter
{
    public string Greet()
    {
        return "Hello from Greeter!";
    }
}

public interface IGreeter
{
    string Greet();
}

第一步在ConfigureServices措施中开展注册

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IGreeter, Greeter>();
}

小编这里运用的是AddTransient实行挂号,该方法在每回哀告时创建该类的新实例。能够挑选此外措施:AddSingleton,AddScoped或简捷的Add(全部在私行前应用)。整个DI系统在官方文书档案中有所描述。

在登记了依据项后,就足以选用它们了。IApplicationBuilder实例允许在Configure艺术中有二个RequestServices特性用于获取Greeter实例。由于已经注册了这几个IGreeter接口,所以无需将中间件与具体的Greeter兑现相结合。

app.Use(async (ctx, next) =>
    {
        IGreeter greeter = ctx.RequestServices.GetService<IGreeter>();
        await ctx.Response.WriteAsync(greeter.Greet());
        await next();
    });

如果Greeter类有多少个参数化的构造函数,它的正视性关系也必得在个中注册ConfigureServices

中间件能够很轻松解决信任关系。能够向中间件构造函数增加其余参数:

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IGreeter _greeter;

    public MyMiddleware(RequestDelegate next, IGreeter greeter)
    {
        _next = next;
        greeter = greeter;
    }

    public async Task Invoke(HttpContext context)
    {
        await context.Response.WriteAsync(_greeter.Greet());
        await _next(context);
    }
}

要么,可以将此信任关系增多到Invoke方法中:

public async Task Invoke(HttpContext context, IGreeter greeter)
{
    await context.Response.WriteAsync(greeter.Greet());
    await _next(context);
}

要是DI系统掌握这个参数的门类,则在类被实例化时,它们将被电动剖析。非常粗略!

  1. 引进安装Nuget包 "Essensoft.AspNetCore.Payment.Alipay". 目前(2018/03/29)版本为 1.2.1

1.3. Cookies和session中间件

图片 5

1.3.1. Session

HTTP是四个无状态合同,Web服务器将每多个伸手都视为独立央浼。并且不保留从前央求中客户的值。

Session 状态是ASP.NET Core提供的二个功效,它能够在客户通应用访谈网络服务器的时候保存和存储客商数据。由服务器上的字典和散列表组成,Session状态通过浏览器的伸手中获得,Session的数码保存到缓存中。

ASP.NET Core通过包罗Session ID的Cookie来保证会话状态,种种伏乞都会带走此Session ID。

Microsoft.AspNetCore.Session包中提供的中间件用来治本Session状态。要启用Session中间件,Startup类里面必要做以下多少个操作:

  • 选择其余贰个完结了IDistributedCache接口的服务来启用内部存款和储蓄器缓存,
  • 设置AddSession回调,由于AddSession是在Microsoft.AspNetCore.Session包内落成的,所以必需在Nuget中增多Microsoft.AspNetCore.Session
  • UseSession回调

现实示例代码如下:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        // 添加一个内存缓存
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // 设置10秒钟Session过期来测试
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseSession();
        app.UseMvcWithDefaultRoute();
    }
}

地点代码中IdleTimeout属性用来规定客商多长时间未有操作时废弃Session。此属性和Cookie超时非亲非故,通过Session中间件的种种央求都会重新载入参数超时时间。

图片 6

1.3.2. Session保存到Redis中

得以实现布满式Session方法官方提供有Redis、Sql Server等。可是Sql Server效能对于这种以key/value获取值的办法远远不及Redis效能高,所以那边小编选用Redis来作示例完成布满式Session。

准备Redis

出于近些日子Redis还不援救windows,所以大家在设置Redis的时候谋算一台linux操作系统,笔者这里的类别是ubuntu 16.04;下载及安装方式能够参谋官方示例。

设置成功之后运维Redis 服务,就算看见以下音信,就意味着Redis运维成功:

图片 7

2017-10-30-20-33-47

有关安插

先是供给用Nuget安装包Microsoft.Extensions.Caching.Redis,安装成功之后就足以在app.csproj文本中得以见到。

图片 8

2017-10-30-20-12-20

Configure方式中增加app.UseSession();然后再ConfigureServices添加Redis服务

public void ConfigureServices(IServiceCollection services){
    services.AddDistributedRedisCache(options=>{
        options.Configuration="127.0.0.1"; //多个redis服务器:{RedisIP}:{Redis端口},{RedisIP}:{Redis端口}
        options.InstanceName="sampleInstance";
    });
    services.AddMvc();
    services.AddSession();
}

上述代码中作者只用三个Redis服务器来作测量检验,实际项目中须求七个Redis服务器;配置格局如:options.Configuration="地址1:端口,地址2:端口";,这里小编并不曾给端口而是用的暗中认可端口6379

一体化代码

Startup.cs

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.Caching.Distributed;

namespace app{    
    public class Startup{        
        public Startup(IConfiguration configuration)        
        {            
            Configuration = configuration;        
        }
        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services){                     
            services.AddDistributedRedisCache(options =>{                
                options.Configuration = "127.0.0.1";                
                options.InstanceName = "sampleInstance";            
            });            
            services.AddMvc();            
            services.AddSession();        
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env){            
            if (env.IsDevelopment())
            {                
                app.UseDeveloperExceptionPage();            
            }            
            else            
            {                
                app.UseExceptionHandler("/Home/Error");            
            }
            app.UseSession();
            app.UseStaticFiles();
            app.UseMvc(routes =>{                
                routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");           
            });        
        }    
    }
}

HomeControler.cs

public class HomeController : Controller   
{        
    public IActionResult Index()       
    {            
        HttpContext.Session.Set("apptest",Encoding.UTF8.GetBytes("apptestvalue"));
        return View();        
    }
    public IActionResult ShowRedis()        
    {            
        byte[] temp;
        if(HttpContext.Session.TryGetValue("apptest",out temp))
        {                
            ViewData["Redis"]=Encoding.UTF8.GetString(temp);            
        }            
        return View();        
    }
}

Index页面只做一件事给Session设置值:"apptestvalue",ShowRedis页面显示Session值。

ShowRedis.cshtml

Redis Session Value:ViewData["Redis"]

演示结果

现行开端运转页面,首先直接进去到ShowRedis页面,Session值突显为空

图片 9

2017-10-31-06-47-24

当点击SetSessionValue日后,重回ShowRedis页面,Session就值展现出来了

图片 10

2017-10-31-23-56-58

看到apptestvalue表示Session值已经存到Redis里面,怎么样注脚apptestvalue值是从Redis里面取到呢?接下去就表达给大家看。

  1. 在Startup.cs文件内 增多正视注入、设置参数(蚂蚁金服开放平台 - 账户管理 - 密钥管理 - 开放平台密钥)

1.3.3. 落实分布Session

前面已经将Session保存到Redis中,不过我们不清楚那么些值是或不是是真的保存到Redis里面去了或然在品种内部存款和储蓄器中;所以那边就贯彻在四个不的应用程序(或两台不相同的机器)中国共产党享Session,也便是兑现布满式Session,布满式即意味着了差别的机械不一致的应用程序,但每每有下边包车型客车一种进退维谷的图景,固然是每种HTTP乞请时都带领了同样的cookie值。

图片 11

2017-10-30-20-35-19

致使那一个的主题素材的来由是各类机器上面的ASP.NET Core的应用程序的密钥是分裂的,所以并没有主意获得前三个应用程序保存的Session数据;为了消除这些标题,.NET Core团队为提供了Microsoft.AspNetCore.DataProtection.AzureStorageMicrosoft.AspNetCore.DataProtection.Redis包将密钥保存到Azure或Redis中。这里选拔将密钥保存到Redis。

图片 12

分享密钥

利用Microsoft.AspNetCore.DataProtection.Redis包提供的PersistKeysToRedis重载方法将密钥保存到Redis里面去。所以那边需求在ConfigureServices办法中添AddDataProtection()

var redis = ConnectionMultiplexer.Connect("127.0.0.1:6379");
    services.AddDataProtection()
        .SetApplicationName("session_application_name")
        .PersistKeysToRedis(redis, "DataProtection-Keys");

上面演示怎样完毕布满式Session

安顿步骤

  • 再正是创立五个品种,分别为app1和app2
  • 添加Microsoft.AspNetCore.DataProtection.RedisStackExchange.Redis.StrongName

图片 13

2017-10-31-23-41-37

  • 鉴于在同样台机器上,ASP.NET Core程序私下认可运行的时候端口为5000,由于app1已经攻下了,所以将app2的启端口安装为5001

图片 14

2017-10-31-23-54-19

一体化代码

  • app1项目

Startup.cs

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.Caching.Distributed;

namespace app1{    
    public class Startup{        
        public Startup(IConfiguration configuration)        
        {            
            Configuration = configuration;        
        }
        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services){
            var redis = ConnectionMultiplexer.Connect("127.0.0.1:6379");
            services.AddDataProtection()
                .SetApplicationName("session_application_name")
                .PersistKeysToRedis(redis, "DataProtection-Keys");          
            services.AddDistributedRedisCache(options =>{                
                options.Configuration = "127.0.0.1";                
                options.InstanceName = "sampleInstance";            
            });            
            services.AddMvc();            
            services.AddSession();        
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env){            
            if (env.IsDevelopment())
            {                
                app.UseDeveloperExceptionPage();            
            }            
            else            
            {                
                app.UseExceptionHandler("/Home/Error");            
            }
            app.UseSession();
            app.UseStaticFiles();
            app.UseMvc(routes =>{                
                routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");           
            });        
        }    
    }
}

HomeControler.cs

public class HomeController : Controller   
{        
    public IActionResult Index()       
    {            
        HttpContext.Session.Set("app1test",Encoding.UTF8.GetBytes("app1testvalue"));
        return View();        
    }
    public IActionResult ShowRedis()        
    {            
        byte[] temp;
        if(HttpContext.Session.TryGetValue("app1test",out temp))
        {                
            ViewData["Redis"]=Encoding.UTF8.GetString(temp);            
        }            
        return View();        
    }
}

ShowRedis.cshtml

Redis Session Value:ViewData["Redis"]
  • app2项目

Startup.cs
计划同app1配置一样。

HomeControler.cs

public class HomeController : Controller   
{        
    public IActionResult Index()       
    {            
        byte[] temp;
        if(HttpContext.Session.TryGetValue("app1test",out temp))
        {                
            ViewData["Redis"]=Encoding.UTF8.GetString(temp);            
        }  
        return View();        
    }
}

Index.cshtml

ViewData["Redis"]

运作效果

  • app1 项目

首次张开进去ShowRedis页面,Session值为空

图片 15

2017-10-31-06-47-24

点击SetSessionValue以后,再回到ShowRedis页面:

图片 16

2017-11-01-00-04-13

  • app2项目,间接在浏览器访谈:http://localhost:5001

图片 17

2017-11-01-00-00-30

以上是用Redis完成布满式Session示例。

代码:

1.4. 总结

本节教学了中间件的运作规律及配置进程,中间件之间对象正视关系的配置和平常项目中常用到Session的配备问题。并在事实上代码彰显了怎么利用中间件完成布满式Session。

转载评释出处 http://www.xdpie.com/2017/11/02/asp-net-core-distributed-session/

图片 18

图片 19

 1         public void ConfigureServices(IServiceCollection services)
 2         {
 3             services.AddMvc();
 4 
 5             // 添加支付宝客户端依赖注入
 6             services.AddAlipay();
 7 
 8             // 可在添加依赖注入时设置参数 一般设置 AppId、RsaPrivateKey、RsaPublicKey,其余默认即可.
 9             // 如:
10             //services.AddAlipay(opt =>
11             //{
12             //    //此处为蚂蚁金服开放平台上创建的APPID,而非老版本的商户号
13             //    opt.AppId = "";
14 
15             //    // 这里的公私钥 默认均为支付宝官方推荐使用的RSAWithSHA256.
16             //    // 商户私钥
17             //    opt.RsaPrivateKey = "";
18             //    // 支付宝公钥
19             //    opt.RsaPublicKey = "";
20             //});
21 
22             // 具体参数见 AlipayOptions
23 
24             // 注册配置实例
25             services.Configure<AlipayOptions>(Configuration.GetSection("Alipay"));
26 
27             // 两种方式设置注册配置实例参数
28 
29             // 1.默认配置文件(开发环境/正式环境):
30             // appsettings.Development.json / appsettings.json
31 
32             // 2.用户机密配置文件(VS2017 15.6.4 中,右键项目 => 管理用户机密):
33             // Windows: % APPDATA %microsoftUserSecrets< userSecretsId >secrets.json
34             // Linux: ~/.microsoft / usersecrets /< userSecretsId >/ secrets.json
35             // macOS: ~/.microsoft / usersecrets /< userSecretsId >/ secrets.json
36 
37             // 配置文件内容如下('...'为省略的项目其他配置内容,若有的情况下 -_-!):
38 
39             //{
40             // ...
41             // ...
42             //
43             //  "Alipay": {
44             //    "AppId": "",
45             //    "RsaPublicKey": "",
46             //    "RsaPrivateKey": ""
47             //  }
48             //}
49         }

图片 20

图片 21

  1. 加上贰个调控器, 小编将其取名字为 AlipayController.cs

代码:

图片 22

图片 23

  1 using Essensoft.AspNetCore.Payment.Alipay;
  2 using Essensoft.AspNetCore.Payment.Alipay.Domain;
  3 using Essensoft.AspNetCore.Payment.Alipay.Notify;
  4 using Essensoft.AspNetCore.Payment.Alipay.Request;
  5 using Microsoft.AspNetCore.Mvc;
  6 using System.Threading.Tasks;
  7 
  8 namespace AlipaySample.Controllers
  9 {
 10     public class AlipayController : Controller
 11     {
 12         // 支付宝请求客户端(用于处理请求与其响应)
 13         private readonly AlipayClient _client = null;
 14 
 15         // 支付宝通知客户端(用于解析异步通知或同步跳转)
 16         private readonly AlipayNotifyClient _notifyClient = null;
 17 
 18         // 赋值依赖注入对象
 19         public AlipayController(AlipayClient client, AlipayNotifyClient notifyClient)
 20         {
 21             _client = client;
 22             _notifyClient = notifyClient;
 23         }
 24 
 25         [HttpPost]
 26         public async Task<IActionResult> PagePay(string out_trade_no, string subject, string total_amount, string body, string product_code, string notify_url, string return_url)
 27         {
 28             // 组装模型
 29             var model = new AlipayTradePagePayModel()
 30             {
 31                 Body = body,
 32                 Subject = subject,
 33                 TotalAmount = total_amount,
 34                 OutTradeNo = out_trade_no,
 35                 ProductCode = product_code,
 36             };
 37 
 38             var req = new AlipayTradePagePayRequest();
 39 
 40             // 设置请求参数
 41             req.SetBizModel(model);
 42 
 43             // 设置异步通知URL
 44             req.SetNotifyUrl(notify_url);
 45 
 46             // 设置同步跳转URL
 47             req.SetReturnUrl(return_url);
 48 
 49             // 页面请求处理 传入 'GET' 返回的 response.Body 为 URL, 'POST' 返回的 response.Body 为 HTML.
 50             var response = await _client.PageExecuteAsync(req, null, "GET");
 51 
 52             // 重定向到支付宝电脑网页支付页面.
 53             return Redirect(response.Body);
 54         }
 55 
 56         /// <summary>
 57         /// 电脑网页支付-同步跳转
 58         /// 常用于展示订单支付状态页,建议在异步通知统一做业务处理,而不是在此处.
 59         /// </summary>
 60         /// <returns></returns>
 61         [HttpGet]
 62         public async Task<IActionResult> PagePayReturn()
 63         {
 64             try
 65             {
 66                 // 以 AlipayTradePagePayReturnResponse 类型 解析
 67                 var notify = await _notifyClient.ExecuteAsync<AlipayTradePagePayReturnResponse>(Request);
 68                 return Content("成功:" + notify.OutTradeNo);
 69             }
 70             catch
 71             {
 72                 return Content("参数异常/验签失败");
 73             }
 74         }
 75 
 76         /// <summary>
 77         /// 电脑网页支付-异步通知
 78         /// 常用于订单业务处理
 79         /// </summary>
 80         /// <returns></returns>
 81         [HttpPost]
 82         public async Task<IActionResult> PagePayNotify()
 83         {
 84             try
 85             {
 86                 // 以 AlipayTradePagePayNotifyResponse 类型 解析
 87                 var notify = await _notifyClient.ExecuteAsync<AlipayTradePagePayNotifyResponse>(Request);
 88                 if ("TRADE_SUCCESS" == notify.TradeStatus) // 订单是否交易完成
 89                 {
 90                     // 业务代码
 91                     // ...
 92                     // ...
 93 
 94                     //返回给支付宝成功内容,停止继续通知
 95                     return Content("success", "text/plain");
 96                 }
 97                 // 订单其他状态均返回给支付宝空内容.
 98                 return NoContent();
 99             }
100             catch
101             {
102                 // 参数异常/验签失败均返回给支付宝空内容.
103                 return NoContent();
104             }
105         }
106     }
107 }

图片 24

图片 25

 5. 修改 Views/Home/Index 页面,用于网站提交支付要求.

代码:

图片 26

图片 27

 1 @{
 2     ViewData["Title"] = "Home Page";
 3 }
 4 
 5 <div style="padding:24px 0">
 6     <h3>支付宝 电脑网站支付 - <a href="https://docs.open.alipay.com/270/alipay.trade.page.pay" target="_blank">API文档</a></h3>
 7     <hr />
 8     <form asp-controller="Alipay" asp-action="PagePay" target="_blank">
 9         <div class="form-group">
10             <label>body:</label>
11             <input type="text" class="form-control" name="body" value="支付宝网站支付测试详情">
12         </div>
13         <div class="form-group">
14             <label>subject:</label>
15             <input type="text" class="form-control" name="subject" value="支付宝网站支付测试">
16         </div>
17         <div class="form-group">
18             <label>total_amount:</label>
19             <input type="text" class="form-control" name="total_amount" value="0.01">
20         </div>
21         <div class="form-group">
22             <label>out_trade_no:</label>
23             <input type="text" class="form-control" name="out_trade_no" value="@DateTime.Now.ToString("yyyyMMddHHmmssfff")">
24         </div>
25         <div class="form-group">
26             <label>product_code:</label>
27             <input type="text" class="form-control" name="product_code" value="FAST_INSTANT_TRADE_PAY">
28         </div>
29         <div class="form-group">
30             <label>notify_url(通知Url需外网环境可访问):</label>
31             <input type="text" class="form-control" name="notify_url" value="http://xxx.com/alipay/pagepaynotify">
32         </div>
33         <div class="form-group">
34             <label>return_url:</label>
35             <input type="text" class="form-control" name="return_url" value="http://xxx.com/alipay/pagepayreturn">
36         </div>
37         <button type="submit" class="btn btn-primary">提交</button>
38     </form>
39 </div>

图片 28

图片 29

 达成页面如下:

图片 30

本篇小提及此停止,具体效果可自行测量试验。多谢各位旁观。

本文由澳门至尊网站发布于搜索引擎,转载请注明出处:Core中间件实现分布式,支付功能接入

关键词: