首页 文章 精选 留言 我的

精选列表

搜索[asp.net],共1116篇文章
优秀的个人博客,低调大师

ASP.NET中使用三层架构事务的技巧实战

在我知道的.NET中,执行事务有两种方法,一种是自动事物,使用起来相当简单,但是需要配置服务器,如果你用的是web共享主机,即没有权限配置自己的服务器,那就没必要用这种了,接下来我讲下.net中最普通的事务SqlTransaction。 接触3层也有一段时间了,了解水平一般,前段时间在想在三层中怎么使用事务呢,放在哪呢?Sqlherper ? DAL? BLL?。然后我就疯狂的百度,一直未能如愿(因为做的都是小项目,不用事务也关系不大),今天我再次查时,好好的看了csdn上的以讨论,http://topic.csdn.net/u/20091101/19/f21697d7-8f0c-4eb3-8e59-d0fe2f0b04b0.html,结合前辈和高手们的意见,自己改了一个出来。我的想法是将事务逻辑写在业务逻辑层,数据库的处理还都是在SQLHELPER,BLL层通过事务SqlTransaction传值访问DAL,再访问Sqlhelper。接下来是分块的代码。 Sqlhelper: 1 public static SqlTransaction BeginTransaction() 2 { 3 SqlConnection myConnection = new SqlConnection(DbConfig.ConnectionString); 4 myConnection.Open(); 5 SqlTransaction tran = myConnection.BeginTransaction(); 6 return tran; 7 } 8 9 public int ExecutenQuery(string cmdtxt, SqlParameter[] paras, CommandType cmdtype, SqlTransaction tran) 10 { 11 int res; 12 try 13 { 14 Cmd = new SqlCommand(cmdtxt, tran.Connection); 15 Cmd.Transaction = tran; 16 Cmd.CommandType = cmdtype; 17 Cmd.Parameters.AddRange(paras); 18 res = Cmd.ExecuteNonQuery(); 19 } 20 catch (Exception ex) 21 { 22 FileHelper.WriteMyLog(ex); 23 throw ex; 24 } 25 return res; 26 } DAL: 1 public bool test(int i,SqlTransaction tran) 2 { 3 string sql = "insert into [test]([item]) values(@i)"; 4 SqlParameter[] paras=new SqlParameter[]{new SqlParameter("@i",i)}; 5 return sqlhelper.ExecutenQuery(sql, paras, CommandType.Text, tran)>0; 6 } BLL: 1 UserDAO userdao = new UserDAO(); 2 public bool test() 3 { 4 using (SqlTransaction tran = SQLHelper.BeginTransaction()) 5 { 6 try 7 { 8 userdao.test(2, tran); 9 userdao.test(256, tran); 10 tran.Commit(); return true; 11 } 12 catch 13 { 14 tran.Rollback(); 15 return false; 16 } 17 finally 18 { 19 tran.Connection.Close();//关闭数据库连接 20 } 21 } 22 } 上述代码在此次测试中通过,若要用于真实项目中,请修改后再使用,还有本人水平一般,写的不到之处请大家见谅。欢迎大家指导指正。 本文转自 wws5201985 51CTO博客,原文链接:http://blog.51cto.com/wws5201985/771636,如需转载请自行联系原作者

优秀的个人博客,低调大师

ASP.NET Core on K8S深入学习(6)Health Check

本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。 一、关于K8S中的Health Check 所谓Health Check,就是健康检查,即防微杜渐。K8S是一个编排引擎可以帮助我们快捷地部署容器集群,如果部署上错误的容器导致服务崩溃,通常情况下我们都会通过一些高可用机制进行故障转移。但是,前提条件是有健康检查。 K8S自然帮我们考虑到了这个问题,健康检查是K8S的重要特性之一,默认有健康检查机制,此外还可以主动设置一些自定义的健康检查。 默认情况下,每个容器启动时都会执行一个进程,由Dockerfile中的CMD或ENTRYPOINT指定。如果进程退出时的返回码不为0,则认为容器发生了故障,K8S会根据重启策略(restartPolicy)重启容器。 例如下面这个例子,它模拟了容器发生故障的场景,注意下面配置文件中的args选项的定义: apiVersion: v1 kind: Pod metadata: name: edc-healthcheck-demo labels: test: healthcheck spec: restartPolicy: OnFailure containers: - name: healthcheck image: busybox imagePullPolicy: IfNotPresent args: - /bin/sh - -c - sleep 10; exit 1 其中 sleep 10; exit 1代表启动10秒之后就非正常退出(返回码不为0),然后通过kubectl创建Pod: kubectl apply -f health-check.yaml 过一段时间后查看Pod的状态,如下图所示: 可以看到,该容器已经重启了2次。也可以看出,restartPolicy简单直接暴力有效,不由感叹重启大法好! 但是,也要正视一个问题:必须等到进程退出后的返回值是非零才会触发重启策略,不能直接监测容器是否是健康。 那么,K8S中有没有更好的机制能够实现智能一点的健康检查呢?答案就是使用Liveness与Readinesss。 二、Liveness探测 2.1 Liveness初体验 一句话Liveness:如果检测有问题(如果健康检查失败),重启pod!至于怎么检测,你说了算(自定义判断容器是否健康的条件)! Liveness提供了一些重要的参数: initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒,看运行的服务而定。 periodSeconds:执行探测的频率,默认是10秒,最小1秒。 timeoutSeconds:探测超时时间,默认1秒,最小1秒。 successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1。 failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1. 下面实践一个小例子创建一个Pod: #command自己定义,例子为 /tmp/healthy 不存在则认为pod有问题,大家根据实际业务来自定义。 apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-demo spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf/tmp/healthy; sleep 10 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5 这里启动pod后会创建文件夹 /tmp/healthy,30秒后删除,在我们的设置中,如果 /tmp/healthy 存在,则认为容器处于正常状态,否则认为发生故障。 需要注意的就是livenessProbe部分的定义了: (1)探测方法:通过cat命令查看/tmp/healthy是否存在;如果返回值为0,则探测成功;否则,探测失败; (2)initialDelaySeconds: 10 => 容器启动10秒之后开始执行liveness探测; (3)periodSeconds: 5 => 每5秒执行一次liveness探测;如果连续执行3次探测都失败,那么就会杀掉并重启容器; 下面快速地验证一下: (1)kubectl创建demo kubectl apply -f liveness-demo.yaml (2)查看pod日志 kubectl describe pod liveness-demo 结果如下图所示: 30秒之后,/tmp/healthy 被删除了,liveness探测失败,又过了几十秒,重复探测均失败后,开启了重启容器。 2.2 Liveness探针 上面的例子使用的是Liveness的exec探针,此外K8S还有几种其他类型的探针: exec:在容器中执行一个命令,如果命令退出码返回0则表示探测成功,否则表示失败 tcpSocket:对指定的容IP及端口执行一个TCP检查,如果端口是开放的则表示探测成功,否则表示失败 httpGet:对指定的容器IP、端口及路径执行一个HTTP Get请求,如果返回的状态码在 [200,400)之间则表示探测成功,否则表示失败 针对tcpSocket的例子:这里会检测80端口是否可以正常访问; #检测80端口是否联通 apiVersion: v1 kind: Pod metadata: labels: test: readiness name: readiness-tcp spec: containers: - name: readiness image: nginx readinessProbe: failureThreshold: 3 tcpSocket: port: 80 initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 针对httpGet的例子:这里会检测index.html文件是否可以正常访问; #访问80端口的index.html文件是否存在 apiVersion: v1 kind: Pod metadata: labels: test: readiness name: readiness-httpget spec: containers: - name: readiness image: nginx readinessProbe: failureThreshold: 3 httpGet: path: /index.html port: 80 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 三、Readiness探测 3.1 Readiness初体验 一句话Readiness:如果检查失败,K8S会将该Pod从服务代理的分发后端去除,不再让其接客(分发请求给该Pod)。如果检测成功,那么K8S就会将容器加入到分发后端,重新对外接客(对外提供服务)。 下面继续以上面Liveness的例子来实践一下: apiVersion: v1 kind: Pod metadata: labels: test: readiness name: readiness-demo spec: containers: - name: readiness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf/tmp/healthy; sleep 10 readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 10 periodSeconds: 5 readinessProbe的配置语法与livenessProbe完全一致,但执行后的效果却不一样,见下图所示: 可以看出: (1)刚被创建时,其READY状态为不可用; (2)15秒(initialDelaySeconds + periodSeconds = 10 + 5 = 15)之后,第一次进行Readiness探测成功,其READY状态变为可用。 (3)30秒之后,/tmp/healthy被删除,连续3次Readiness探测均失败后,其READY状态又变为了不可用。 此外,我们也可以通过kubectl describe pod readiness-demo 查看到更想起的日志信息。 3.2 与Liveness的对比 Liveness与Readiness都是K8S的Health Check机制,Liveness探测是重启容器,而Readiness探测则是将容器设置为不可用,不让其再接受Service转发的请求。 Liveness与Readiness是独立执行的,二者无依赖,可以单独使用也可以同时使用。 四、Health Check在K8S中的应用 4.1 在Scale Up中的应用 对于多副本应用,当执行Scale Up操作时,新的副本会作为后端服务加入到Service的负载均衡列表中。但是,很多时候应用的启动都需要一定的时间做准备(比如加载缓存、连接数据库等等),这时我们可以通过Readiness探测判断容器是否真正就绪,从而避免将请求发送到还未真正就绪的后端服务。 下面一个示例YAML配置文件定义了Readiness探测,重点关注readinessProbe部分: apiVersion: apps/v1 kind: Deployment metadata: name: edc-webapi-deployment namespace: aspnetcore spec: replicas: 2 selector: matchLabels: name: edc-webapi template: metadata: labels: name: edc-webapi spec: containers: - name: edc-webapi-container image: edisonsaonian/k8s-demo:1.2 ports: - containerPort: 80 imagePullPolicy: IfNotPresent readinessProbe: httpGet: scheme: HTTP path: /api/health port: 80 initialDelaySeconds: 10 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: edc-webapi-service namespace: aspnetcore spec: type: NodePort ports: - nodePort: 31000 port: 8080 targetPort: 80 selector: name: edc-webapi 对于readinessProbe部分: (1)schema指定了协议,这里是HTTP协议,也可以是HTTPS协议; (2)path指定访问路径,这里是我们自定义的一个Controller中的接口:简单地返回一个状态码为200的响应; [Produces("application/json")] [Route("api/Health")] public class HealthController : Controller { [HttpGet] public IActionResult Get() => Ok("ok"); } (3)port指定端口,这里是容器的端口80; (4)initialDelaySeconds和periodSeconds指定了容器启动10秒之后开始探测,然后每隔5秒执行探测,如果发生3次以上探测失败,则该容器会从Service的负载均衡中移除,直到下次探测成功后才会重新加入。 4.2 在Rolling Update中的应用 假设现在有一个正常运行的多副本应用,我们要对其进行滚动更新即Rolling Update,K8S会逐步用新Pod替换旧Pod,结果就有可能发生这样的一个场景:当所有旧副本被替换之后,而新的Pod由于人为配置错误一直无法启动,因此整个应用将无法处理请求,无法对外提供服务,后果很严重! 因此,Readiness探测还提供了用于避免滚动更新中出现这种情况的一些解决办法,比如maxSurge和maxUnavailable两个参数,用来控制副本替换的数量。 继续以上面的YAML配置文件为例,重点关注strategy部分: apiVersion: apps/v1 kind: Deployment metadata: name: edc-webapi-deployment namespace: aspnetcore spec: strategy: rollingupdate: maxSurge: 25% maxUnavailable: 25% replicas: 10 selector: matchLabels: name: edc-webapi template: metadata: labels: name: edc-webapi spec: containers: - name: edc-webapi-container image: edisonsaonian/k8s-demo:1.2 ports: - containerPort: 80 imagePullPolicy: IfNotPresent readinessProbe: httpGet: scheme: HTTP path: /api/health port: 80 initialDelaySeconds: 10 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: edc-webapi-service namespace: aspnetcore spec: type: NodePort ports: - nodePort: 31000 port: 8080 targetPort: 80 selector: name: edc-webapi (1)maxSurge : 25% => 控制滚动更新过程中副本总数超过预期(这里预期是10个副本 replicas: 10)的上限,可以是数值也可以是百分比,然后向上取整。这里写的百分比,默认值是25%; 如果预期副本数为10,那么副本总数的最大值为RoundUp(10 + 10 * 25%)=13个。 (2)maxUnavailable : 25% => 控制滚动更新过程中不可用的副本(这里预期是10个副本 replicas: 10)占预期的最大比例,可以是数值也可以是百分比,然后向下取整,同样地默认值也是25%; 如果预期副本总数为10,那么可用的副本数至少要为10-roundDown(10 * 25%)=10-2=8个。 综上看来,maxSurge的值越大,初始创建的新副本数量就越多;maxUnavaliable值越大,初始销毁的旧副本数量就越多; 五、小结 本文探索了K8S中的默认健康检查机制以及Liveness和Readiness两种各有特点的探测机制,并通过一些小例子进行了说明。不过由于笔者也是初学,对于这一块没有过多实践经验,因此也是讲的比较粗浅,也希望以后能够有更多的实际经验分享与各位。 参考资料 (1)CloudMan,《每天5分钟玩转Kubernetes》 (2)李振良,《一天入门Kubernets教程》 (3)马哥(马永亮),《Kubernetes快速入门》 (4)华仔,《[[译]Kubernetes最佳实践:使用Readiness和Liveness探测做Health Check](https://blog.csdn.net/cainiaofly/article/details/84324321)》 (5)benjanmin杨,《K8S中的Health Check》 (6)条子在洗澡,《K8S健康性检查-探测》

优秀的个人博客,低调大师

ASP.NET Core微服务之服务间的调用方式(REST and RPC)

Tip: 此篇已加入.NET Core微服务基础系列文章索引 一、REST or RPC ? 1.1 REST & RPC 微服务之间的接口调用通常包含两个部分,序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如dubbo,netty、mina、thrift。 REST:严格意义上说接口很规范,操作对象即为资源,对资源的四种操作(post、get、put、delete),并且参数都放在URL上,但是不严格的说Http+json、Http+xml,常见的http api都可以称为Rest接口。 RPC:即我们常说的远程过程调用,就是像调用本地方法一样调用远程方法,通信协议大多采用二进制方式。 1.2 HTTP vs 高性能二进制协议 HTTP相对更规范,更标准,更通用,无论哪种语言都支持HTTP协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,相应的,如果采用HTTP,无疑在你实现SDK之前,支持了所有语言,所以,现在开源中间件,基本最先支持的几个协议都包含RESTful。 RPC协议性能要高的多,例如Protobuf、Thrift、Kyro等,(如果算上序列化)吞吐量大概能达到http的二倍。响应时间也更为出色。千万不要小看这点性能损耗,公认的,微服务做的比较好的,例如,netflix、阿里,曾经都传出过为了提升性能而合并服务。如果是交付型的项目,性能更为重要,因为你卖给客户往往靠的就是性能上微弱的优势。 所以,最佳实践一般是对外REST,对内RPC,但是追求极致的性能会消耗很多额外的成本,所以一般情况下对内一般也REST,但对于个别性能要求较高的接口使用RPC。 二、案例结构 这里假设有两个服务,一个ClinetService和一个PaymentService,其中PaymentService有两部分,一部分是基于REST风格的WebApi部分,它主要是负责一些对性能没有要求的查询服务,另一部分是基于TCP的RPC Server,它主要是负责一些对性能要求高的服务,比如支付和支出等涉及到钱的接口。假设User在消费ClientService时需要调用PaymentService根据客户账户获取Payment History(走REST)以及进行交易事务操作(走RPC)。 三、REST调用 3.1 一个好用的REST Client : WebApiClient 使用过Java Feign Client的人都知道,一个好的声明式REST客户端可以帮我们省不少力。在.NET下,园子里的大大老九就写了一款类似于Feign Client的REST Client:WebApiClient。WebApiClient是开源在github上的一个httpClient客户端库,内部基于HttpClient开发,是一个只需要定义C#接口(interface),并打上相关特性,即可异步调用http-api的框架 ,支持.net framework4.5+、netcoreapp2.0和netstandard2.0。它的GitHub地址是:https://github.com/dotnetcore/WebApiClient 如何安装? NuGet>Install-Package WebApiClient-JIT 3.2 使用实例:走API Gateway Step1.定义HTTP接口 [HttpHost("http://yourgateway:5000")] public interface IPaymentWebApi: IHttpApi { // GET api/paymentservice/history/edisonzhou // Return 原始string内容 [HttpGet("/api/paymentservice/history/{account}")] ITask<IList<string>> GetPaymentHistoryByAccountAsync(string account); } 这里需要注意的是,由于我们要走API网关,所以这里定义的HttpHost地址是一个假的,后面具体调用时会覆盖掉,当然你也可以直接把地址写在这里,不过我更倾向于写到配置文件中,然后把这里的HttpHost设置注释掉。 Step2.在Controller中即可异步调用: [Route("api/[controller]")] public class PaymentController : Controller { private readonly string gatewayUrl;public PaymentController(IConfiguration _configuration) { gatewayUrl = _configuration["Gateway:Uri"]; } [HttpGet("{account}")] public async Task<IList<string>> Get(string account) { using (var client = HttpApiClient.Create<IPaymentWebApi>(gatewayUrl)) { var historyList = await client.GetPaymentHistoryByAccountAsync(account); // other business logic code here // ...... return historyList; } } } 当然你也可以在Service启动时注入一个单例的IPaymentServiceWebApi实例,然后直接在各个Controller中直接使用,这样更加类似于Feign Client的用法: (1)StartUp类注入 public void ConfigureServices(IServiceCollection services) { // IoC - WebApiClient services.AddSingleton(HttpApiClient.Create<IPaymentServiceWebApi>(Configuration["PaymentService:Url"])); } (2)Controller中直接使用 [HttpPost] public async Task<string> Post([FromBody]ModelType model, [FromServices]IPaymentServiceWebApi restClient) { ...... var result = await restClient.Save(model); ...... } 这里PaymentService的实现很简单,就是返回了一个String集合: // GET api/history/{account} [HttpGet("{account}")] public IList<string> Get(string account) { // some database logic // ...... IList<string> historyList = new List<string> { "2018-06-10,10000RMB,Chengdu", "2018-06-11,11000RMB,Chengdu", "2018-06-12,12000RMB,Beijing", "2018-06-13,10030RMB,Chengdu", "2018-06-20,10400RMB,HongKong" }; return historyList; } 最终调用结果如下: 3.3 使用实例:直接访问具体服务 在服务众多,且单个服务就部署了多个实例的情况下,我们可以通过API网关进行中转,但是当部分场景我们不需要通过API网关进行中转的时候,比如:性能要求较高,负载压力较小单个实例足够等,我们可以直接与要通信的服务进行联接,也就不用从API网关绕一圈。 Step1.改一下HTTP接口: [HttpHost("http://paymentservice:8880")] public interface IPaymentDirectWebApi: IHttpApi { // GET api/paymentservice/history/edisonzhou // Return 原始string内容 [HttpGet("/api/history/{account}")] ITask<IList<string>> GetPaymentHistoryByAccountAsync(string account); } 同理,这里的HttpHost也是后面需要被覆盖的,原因是我们将其配置到了配置文件中。 Step2.改一下调用代码: [Route("api/[controller]")] public class PaymentController : Controller { private readonly string gatewayUrl; private readonly string paymentServiceUrl; public PaymentController(IConfiguration _configuration) { gatewayUrl = _configuration["Gateway:Uri"]; paymentServiceUrl = _configuration["PaymentService:Uri"]; } [HttpGet("{account}")] public async Task<IList<string>> Get(string account) { #region v2 directly call PaymentService using (var client = HttpApiClient.Create<IPaymentDirectWebApi>(paymentServiceUrl)) { var historyList = await client.GetPaymentHistoryByAccountAsync(account); // other business logic code here // ...... return historyList; } #endregion } 最终调用结果如下: 四、RPC调用 4.1 Thrift简介 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。 当然,还有gRPC也可以选择,不过从网上的性能测试来看,Thrift性能应该优于gRPC 2倍以上,但是gRPC的文档方面要比Thrift友好很多。 4.2 Thrift的使用 (1)下载Thrift (这里选择Windows版) 下载完成后解压,这里我将其改名为thrift.exe(去掉了版本号),一会在命令行敲起来更方便一点。 (2)编写一个PaymentService.thrift,这是一个IDL中间语言 namespace csharp Manulife.DNC.MSAD.Contracts service PaymentService { TrxnResult Save(1:TrxnRecord trxn) } enum TrxnResult { SUCCESS = 0, FAILED = 1, } struct TrxnRecord { 1: required i64 TrxnId; 2: required string TrxnName; 3: required i32 TrxnAmount; 4: required string TrxnType; 5: optional string Remark; } (3)根据thrift语法规则生成C#代码 cmd>thrift.exe -gen csharp PaymentService.thrift (4)创建一个Contracts类库项目,将生成的C#代码放进去 4.3 增加RPC Server (1)新增一个控制台项目,作为我们的Payment Service RPC Server,并引用Contracts类库项目 (2)引入thrift-netcore包: NuGet>Install-Package apache-thrift-netcore (3)加入一个新增的PaymentService实现类 public class PaymentServiceImpl : Manulife.DNC.MSAD.Contracts.PaymentService.Iface { public TrxnResult Save(TrxnRecord trxn) { // some business logic here //Thread.Sleep(1000 * 1); Console.WriteLine("Log : TrxnName:{0}, TrxnAmount:{1}, Remark:{2}", trxn.TrxnName, trxn.TrxnAmount, trxn.Remark); return TrxnResult.SUCCESS; } } 这里输出日志仅仅是为了测试。 (4)编写启动RPC Server的主程序 public class Program { private const int port = 8885; public static void Main(string[] args) { Console.WriteLine("[Welcome] PaymentService RPC Server is lanuched..."); TServerTransport transport = new TServerSocket(port); var processor = new Manulife.DNC.MSAD.Contracts.PaymentService.Processor(new PaymentServiceImpl()); TServer server = new TThreadedServer(processor, transport); // lanuch server.Serve(); } } (5)如果是多个服务实现的话,也可以如下这样启动: public static void Main(string[] args) { Console.WriteLine("[Welcome] PaymentService RPC Server is lanuched..."); TServerTransport transport = new TServerSocket(port); var processor1 = new Manulife.DNC.MSAD.Contracts.PaymentService.Processor(new PaymentServiceImpl()); var processor2 = new Manulife.DNC.MSAD.Contracts.PayoutService.Processor(new PayoutServiceImpl()); var processorMulti = new Thrift.Protocol.TMultiplexedProcessor(); processorMulti.RegisterProcessor("Service1", processor1); processorMulti.RegisterProcessor("Service2", processor2); TServer server = new TThreadedServer(processorMulti, transport); // lanuch server.Serve(); } 4.4 调用RPC 在ClientService中也引入apache-thrift-netcore包,然后在调用的地方修改如下: [HttpPost] public string Post([FromBody]TrxnRecordDTO trxnRecordDto) { // RPC - use Thrift using (TTransport transport = new TSocket( configuration["PaymentService:RpcIP"], Convert.ToInt32(configuration["PaymentService:RpcPort"]))) { using (TProtocol protocol = new TBinaryProtocol(transport)) { using (var serviceClient = new PaymentService.Client(protocol)) { transport.Open(); TrxnRecord record = new TrxnRecord { TrxnId = GenerateTrxnId(), TrxnName = trxnRecordDto.TrxnName, TrxnAmount = trxnRecordDto.TrxnAmount, TrxnType = trxnRecordDto.TrxnType, Remark = trxnRecordDto.Remark }; var result = serviceClient.Save(record); return Convert.ToInt32(result) == 0 ? "Trxn Success" : "Trxn Failed"; } } } } private long GenerateTrxnId() { return 10000001; } 最终测试结果如下: 五、小结 本篇简单的介绍了下微服务架构下服务之间调用的两种常用方式:REST与RPC,另外前面介绍的基于消息队列的发布/订阅模式也是服务通信的方式之一。本篇基于WebApiClient这个开源库介绍了如何进行声明式的REST调用,以及Thrift这个RPC框架介绍了如何进行RPC的通信,最后通过一个小例子来结尾。最后,服务调用的最佳实践一般是对外REST,对内RPC,但是追求极致的性能会消耗很多额外的成本,所以一般情况下对内一般也REST,但对于个别性能要求较高的接口使用RPC。 参考资料 远方的行者,《微服务 RPC和REST》 杨中科,《.NET Core微服务课程:Thrift高效通讯》 醉眼识朦胧,《Thrift入门初探--thrift安装及java入门实例》 focus-lei,《.net core下使用Thrift》 宝哥在路上,《Thrift性能测试与分析》

优秀的个人博客,低调大师

1.2环境安装「深入浅出ASP.NET Core系列」

官网 在介绍安装环境之前,先介绍周边信息,比如微软net官网。 https://www.microsoft.com/net 这个网站是学习微软技术栈比较权威的地方,包括环境下载,学习,架构,文档,社区等等非常有价值的内容。 1.1下载.NET Core 下载网址:https://www.microsoft.com/net/download 微信支付 在逛这个网站的时候,偶然发现微信支付用的微服务就是基于.NET Core技术栈,视频里你还可以看到张善友本人(张善友是微软MVP,.NET Core社区推广大使),可以想见,未来的.NET Core的应用前景有多大…… 安装 接下来就是详细的安装过程了,官网以英文为主,如果你不想阅读二手的信息,请学好英文。 https://www.microsoft.com/net/learn/dotnet/hello-world-tutorial 这里我们看到跨平台的下载和安装方法,注意下载包默认是最新的版本,目前最新版本是2.1.403 我是.NET架构师张飞洪,入行10年有余,人不堪其忧,吾不改其乐,谢谢您关注我的头条号。

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册