《ASP.NET Core 微服务实战》-- 读书笔记(第4章)

第 4 章 后端服务

现实中的服务不可能处于真空之中,大多数服务都需要与其他服务通信才能完成功能。

我们将这些支持性服务称为后端服务,接下来我们将通过创建一个新的服务并修改之前的团队服务与这个服务通信,以探索如何创建并消费后端服务。

微服务生态系统

后端服务是通过某种机制绑定到应用上的,而这种机制又可以由云设施(PaaS)管理。与打开一个文件不同,我们与泛化的存储服务通信。

资源绑定的概念其实是一种抽象,而具体的实现可能根据应用托管所在的云平台而有所差异。服务的绑定信息可能直接来自从平台注入的环境变量,或者来自外部的配置提供设施。

微服务是单一职责 SRP 和 里氏替换原则 LSP 的集中体现。对单个微服务的修改,不应该对任何其他服务产生任何影响。对服务内部模型的修改不应该破坏服务公开的 API 和外部模型。

开发位置服务

GitHub 链接:https://github.com/microservices-aspnetcore/locationservice.git

首先创建一个模型表示位置记录

public class LocationRecord {public Guid ID { get; set; }public float Latitude { get; set; }public float Longitude { get; set; }public float Altitude { get; set; }public long Timestamp { get; set; }public Guid MemberID { get; set; }
}

接下来,我们需要一个接口来表示位置信息仓储的契约

public interface ILocationRecordRepository {LocationRecord Add(LocationRecord locationRecord);LocationRecord Update(LocationRecord locationRecord);LocationRecord Get(Guid memberId, Guid recordId);LocationRecord Delete(Guid memberId, Guid recordId);LocationRecord GetLatestForMember(Guid memberId);ICollection<LocationRecord> AllForMember(Guid memberId);
}

控制器通过构造器注入的方式接收一个 ILocationRecordRepository 实例

[Route("locations/{memberId}")]
public class LocationRecordController : Controller {private ILocationRecordRepository locationRepository;public LocationRecordController(ILocationRecordRepository repository) {this.locationRepository = repository;}[HttpPost]public IActionResult AddLocation(Guid memberId, [FromBody]LocationRecord locationRecord) {locationRepository.Add(locationRecord);return this.Created($"/locations/{memberId}/{locationRecord.ID}", locationRecord);}[HttpGet]public IActionResult GetLocationsForMember(Guid memberId) {return this.Ok(locationRepository.AllForMember(memberId));}[HttpGet("latest")]public IActionResult GetLatestForMember(Guid memberId) {return this.Ok(locationRepository.GetLatestForMember(memberId));}
}

要让依赖注入能够提供仓储,只需要在启动期间把它添加为具有特定生命周期的服务,在 Stattup.cs 中

public void ConfigureServices(IServiceCollection services)
{services.AddScoped<ILocationRecordRepository, InMemoryLocationRecordRepository>();services.AddMvc();
}

优化团队服务

我们希望在查询特定团队成员的详细信息时,要包含他们最新的位置以及签入时间。实现这一功能,有两个主要步骤:

  • 将位置服务的 URL 绑定到团队的服务

  • 使用 URL 消费位置服务

使用环境变量配置服务的 URL

这个过程中要记住最重要的一点就是这些信息必须来自运行环境,而不是签入的代码。

消费 RESTful 服务

由于需要对团队服务终端控制器方法进行单元测试,并且在测试过程中不发出 HTTP 请求,我们要先为位置服务的客户端创建接口

将 teamservice 的分支切换为 location

public interface ILocationClient
{Task<LocationRecord> GetLatestForMember(Guid memberId);
}

位置服务客户端的实现

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using StatlerWaldorfCorp.TeamService.Models;
using Newtonsoft.Json;
using Microsoft.Extensions.Configuration;
using System.Text;namespace StatlerWaldorfCorp.TeamService.LocationClient
{public class HttpLocationClient : ILocationClient{public String URL { get; set; }public HttpLocationClient(string url){this.URL = url;}public async Task<LocationRecord> GetLatestForMember(Guid memberId){LocationRecord locationRecord = null;using (var httpClient = new HttpClient()){httpClient.BaseAddress = new Uri(this.URL);httpClient.DefaultRequestHeaders.Accept.Clear();httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));HttpResponseMessage response = await httpClient.GetAsync(String.Format("/locations/{0}/latest", memberId));if (response.IsSuccessStatusCode){string json = await response.Content.ReadAsStringAsync();locationRecord = JsonConvert.DeserializeObject<LocationRecord>(json);}}return locationRecord;}public async Task<LocationRecord> AddLocation(Guid memberId, LocationRecord locationRecord){using (var httpClient = new HttpClient()){httpClient.BaseAddress = new Uri(this.URL);httpClient.DefaultRequestHeaders.Accept.Clear();httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));var jsonString = JsonConvert.SerializeObject(locationRecord);var uri = String.Format("/locations/{0}", memberId);HttpResponseMessage response =await httpClient.PostAsync(uri, new StringContent(jsonString, Encoding.UTF8, "application/json"));if (response.IsSuccessStatusCode){string json = await response.Content.ReadAsStringAsync();}}return locationRecord;}}
}

接着,修改控制器 MembersController,调用位置服务客户端,将团队成员的最新位置添加到响应中

[HttpGet]
[Route("/teams/{teamId}/[controller]/{memberId}")]
public async virtual Task<IActionResult> GetMember(Guid teamID, Guid memberId)
{Team team = repository.Get(teamID);if(team == null) {return this.NotFound();} else {var q = team.Members.Where(m => m.ID == memberId);if(q.Count() < 1) {return this.NotFound();} else {Member member = (Member)q.First();return this.Ok(new LocatedMember {ID = member.ID,FirstName = member.FirstName,LastName = member.LastName,LastLocation = await this.locationClient.GetLatestForMember(member.ID)});}}
}

我们用的 LocationRecord 模型类是团队服务所私有的。

团队服务和位置服务并不共用模型,团队服务一直只依赖于位置服务公共的 API, 而不依赖于内部实现。

接下来我们希望增加一种能力,为使用应用的每个人维护签到过的历史位置信息,创建一个位置服务用于单独管理位置数据,它公开一个方便的端点来检索团队成员的最新位置。

  • 团队服务:microservices-aspnetcore/teamservice:location

  • 位置服务:microservices-aspnetcore/locationservice:nodb

首先启动团队服务

$ docker run -p 5000:5000 -e PORT=5000 \
-e LOCATION__URL=http://localhost:5001 \
dotnetcoreservices/teamservice:location

这样就能在 5000 端口启动团队服务,把容器内的 5000 端口映射到 localhost 的 5000 端口,并让团队服务从 http://localhost:5001 调用位置服务

团队服务启动完成后再启动位置服务

$ docker run -p 5001:5001 -e PORT=5001 \
dotnetcoreservices/locationservice:nodb

两个服务启动完成后,可通过 docker ps 命令查看各个服务的 Docker 配置。

接下来,运行一系列命令确保一切工作正常。

创建一个新的团队

$ curl -H "Content-Type:application/json" -X POST -d \
'{"id":"e52baa63-d511-417e-9e54-7aab04286281", \
"name":"Team Zombie"}' http://localhost:5000/teams

通过向 /teams/{id}/members 资源发送 POST 请求添加新的成员

$ curl -H "Content-Type:application/json" -X POST -d \
'{"id":"63e7acf8-8fae-42ec-9349-3c8593ac8292", \
"firstName":"Al", \
"lastName":"Foo"}' \
http://localhost:5000/teams/e52baa63-d511-417e-9e54-7aab04286281/members

尝试查询团队详情,确保一切工作正常

$ curl http://localhost:5000/teams/e52baa63-d511-417e-9e54-7aab04286281

往位置服务添加新的位置信息

$ curl -H "Content-Type:application/json" -X POST -d \
'{"id":"64c3e69f-1580-4b2f-a9ff-2c5f3b8f0elf", \
"latitude":12.0,"longitude":12.0,"altitude":10.0, \
"timestamp":0, \
"memberId":"63e7acf8-8fae-42ec-9349-3c8593ac8292"}' \
http://localhost:5001/locations/63e7acf8-8fae-42ec-9349-3c8593ac8292

现在可以真正测试团队服务和位置服务之间的集成了,从 teams/{id}/members/{id} 资源查询团队成员的详细信息

$ curl http://localhost:5000/teams/e52baa63-d511-417e-9e54-7aab04286281 \
/members/63e7acf8-8fae-42ec-9349-3c8593ac8292

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WordList02

WordList 2 如果存在什么问题欢迎批评指正&#xff01;谢谢&#xff01;

CentOS7 安装 Jenkins( 构建 Vue 和 dotNET Core )

之前的自动构建工具 Jenkins 是部署在公司内网的 Windows 服务器上&#xff0c;现在武汉处于非常时期&#xff0c;兄弟们都在家自我隔离&#xff0c;为了远程提交的代码能自动构建&#xff0c;需要在外网的 CentOS 服务器上搭建 Jenkins 环境来进行构建工作。目的产品采用前后端…

shell(希尔排序)

shell&#xff08;希尔排序&#xff09; 原理:参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> void shellInsert(int b[],int dk,int length) {//希尔排序以dk的增量插入int j;for (int i 1 dk; i < length-1; i) {b[0] b[i];//哨…

[蓝桥杯2019初赛]等差数列-数列

解题思路: 给你n个数&#xff0c;是某个等差数列的一部分&#xff0c;问该等差数列最小有几项&#xff1f;&#xff1a;((最大数−最小数)/d)1((最大数-最小数)/d)1((最大数−最小数)/d)1,其中d是该等差数列所有&#xff08;所有已知数与最小数差值&#xff09;的最大公因数&am…

Dynatrace成功扩展kubernetes全栈可观察性

软件情报公司Dynatrace&#xff08;NYSE&#xff1a;DT&#xff09;在Perform 2020会议上宣布了对Kubernetes支持的新增强功能。Dynatrace可解释的AI引擎DavisTM现在自动获取其他Kubernetes事件和指标&#xff0c;使其能够在整个Kubernetes集群&#xff0c;容器和工作负载的堆栈…

wordList3

wordList3 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

[蓝桥杯2019初赛]矩形切割-找规律

代码如下&#xff1a; #include <iostream> using namespace std;int main() {int a, b;int ans 1;cin >> a >> b;while (1) {if (a 1 && b 1 || a b)break;if ( a > b) {int c b;b a;a c;}b b - a;ans;}cout << ans << end…

K8S水平伸缩器 - 自动伸缩微服务实例数量

作者&#xff1a;justmine头条号&#xff1a;大数据达摩院微信公众号&#xff1a;大数据处理系统创作不易&#xff0c;在满足创作共用版权协议的基础上可以转载&#xff0c;但请以超链接形式注明出处。为了方便大家阅读&#xff0c;可以关注头条号或微信公众号&#xff0c;后续…

[蓝桥杯2019初赛]质数-质数筛or 水题

法一&#xff1a; 代码如下&#xff1a; #include <iostream> #include <cmath> using namespace std;bool check(int x) {for (int i 2; i < sqrt(x); i)if (x % i 0)return false;return true; }int main() {int n;int ans 0;for (int i 2; i; i) {if (c…

SqlServer 利用游标批量更新数据

SqlServer 利用游标批量更新数据Intro游标在有时候会很有用&#xff0c;在更新一部分不多的数据时&#xff0c;可以很方便的更新数据&#xff0c;不需要再写一个小工具来做了&#xff0c;直接写 SQL 就可以了Sample下面来看一个实际示例&#xff1a;-- 声明字段变量 DECLARE Re…

math:线性代数之行列式

math&#xff1a;线性代数之行列式 提供解题的方法总结 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢!

[蓝桥杯2019初赛]旋转-找规律

代码如下&#xff1a; #include <iostream> using namespace std; const int N 110; int a[N][N];int main() {int n, m;cin >> n >> m;for (int i 1; i < n; i)for (int j 1; j < m; j)cin >> a[i][j];for (int i 1; i < m; i){for (in…

《ASP.NET Core 微服务实战》-- 读书笔记(第5章)

第 5 章 创建数据服务选择一种数据存储由于我坚持要尽可能的跨平台&#xff0c;所以我决定选用 Postgres&#xff0c;而不用 SQL Server 以照顾 Linux 或 Mac 电脑的读者构建 Postgres 仓储在本节&#xff0c;我们要升级位置服务让它使用 Postgres为了完成这一过程&#xff0c;…

腾飞答不忘初心的三个问题

去年的时候有同学在微信上问了我3个问题&#xff0c;我觉得非常有代表性&#xff0c;当时没有回答。主要是通过简短的语言无法全面表述可能会产生歧义&#xff0c;所以决定专门写一篇文章来表达一下我的想法&#xff0c;需要说明的是以下内容只是以我个人的经验给大家一些参考。…

wordList04

wordList04 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

用 C# 写一个 Redis 数据同步小工具

用 C# 写一个 Redis 数据同步小工具Intro为了实现 redis 的数据迁移而写的一个小工具&#xff0c;将一个实例中的 redis 数据同步到另外一个实例中。(原本打算找一个已有的工具去做&#xff0c;找了一个 nodejs 的小工具&#xff0c;结果折腾了好久都没装上。。。于是就自己写了…

数据结构----冒泡排序

数据结构----冒泡排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> void bubbleSort(int a[], int length) {//冒泡排序for (int i 0; i < length - 1; i) {//趟数for (int j 0; j < length - i - 1; j) {if…

C#如何安全、高效地玩转任何种类的内存之Span的本质(一)。

前言作为.net程序员&#xff0c;使用过指针&#xff0c;写过不安全代码吗&#xff1f;为什么要使用指针&#xff0c;什么时候需要使用它&#xff0c;以及如何安全、高效地使用它&#xff1f;如果能很好地回答这几个问题&#xff0c;那么就能很好地理解今天了主题了。C#构建了一…

数据结构------选择排序

数据结构------选择排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> void simpleSelectSort(int a[], int length) {//选择排序int j;for (int i 0; i < length - 1; i) {int k i;//每趟排序中找到最小的元素…

[蓝桥杯2018初赛]第几个幸运数-数论+枚举

代码如下&#xff1a; #include <iostream> #include <cmath> using namespace std; typedef long long LL; LL n 59084709587505; LL ans 0;int main() {for (int i 0; pow(3, i) < n; i)for (int j 0; pow(5, j) < n; j)for (int k 0; pow(7, k) <…