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

第 5 章 创建数据服务

选择一种数据存储

由于我坚持要尽可能的跨平台,所以我决定选用 Postgres,而不用 SQL Server 以照顾 Linux 或 Mac 电脑的读者

构建 Postgres 仓储

在本节,我们要升级位置服务让它使用 Postgres

为了完成这一过程,需要创建一个新的仓储实现,以封装 PostgreSQL 的客户端通信

回顾一下位置仓库的接口

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);
}

接下来要做的就是创建一个数据库上下文

数据库上下文的使用方式是创建与特定模型相关的类型,并从数据库上下文继承

由于与位置数据打交道,所以要创建一个 LocationDbContext 类

using Microsoft.EntityFrameworkCore;
using StatlerWaldorfCorp.LocationService.Models;
using Npgsql.EntityFrameworkCore.PostgreSQL;namespace StatlerWaldorfCorp.LocationService.Persistence
{public class LocationDbContext : DbContext{public LocationDbContext(DbContextOptions<LocationDbContext> options) :base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.HasPostgresExtension("uuid-ossp");}public DbSet<LocationRecord> LocationRecords {get; set;}}
}

实现位置记录仓储接口

// using Microsoft.EntityFrameworkCore;using System;
using System.Linq;
using System.Collections.Generic;
using StatlerWaldorfCorp.LocationService.Models;
using Microsoft.EntityFrameworkCore;namespace StatlerWaldorfCorp.LocationService.Persistence
{public class LocationRecordRepository : ILocationRecordRepository{private LocationDbContext context;public LocationRecordRepository(LocationDbContext context){this.context = context;}public LocationRecord Add(LocationRecord locationRecord){this.context.Add(locationRecord);this.context.SaveChanges();return locationRecord;}public LocationRecord Update(LocationRecord locationRecord){this.context.Entry(locationRecord).State = EntityState.Modified;this.context.SaveChanges();return locationRecord;}public LocationRecord Get(Guid memberId, Guid recordId){return this.context.LocationRecords.FirstOrDefault(lr => lr.MemberID == memberId && lr.ID == recordId);}public LocationRecord Delete(Guid memberId, Guid recordId){LocationRecord locationRecord = this.Get(memberId, recordId);this.context.Remove(locationRecord);this.context.SaveChanges();return locationRecord;}public LocationRecord GetLatestForMember(Guid memberId){LocationRecord locationRecord = this.context.LocationRecords.Where(lr => lr.MemberID == memberId).OrderBy(lr => lr.Timestamp).Last();return locationRecord;}public ICollection<LocationRecord> AllForMember(Guid memberId){return this.context.LocationRecords.Where(lr => lr.MemberID == memberId).OrderBy(lr => lr.Timestamp).ToList();}}
}

为了实现以注入的方式获取 Postgres 数据库上下文,需要在 Startup 类的 ConfigureServices 方法里把仓储添加到依赖注入系统

public void ConfigureServices(IServiceCollection services)
{services.AddEntityFrameworkNpgsql().AddDbContext<LocationDbContext>(options =>options.UseNpgsql(Configuration));services.AddScoped<ILocationRecordRepository, LocationRecordRepository>();services.AddMvc();
}

数据库是一种后端服务

在本例中,我们准备用环境变量来覆盖由配置文件提供的默认配置

appsettings.json

{"transient": false,"postgres": {"cstr": "Host=localhost;Port=5432;Database=locationservice;Username=integrator;Password=inteword"}
}

前面实现的仓储需要一种数据库上下文才能运作,为了给位置模型创建数据库上下文,只需要创建一个类,并从 DbContext 继承

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using StatlerWaldorfCorp.LocationService.Models;
using Npgsql.EntityFrameworkCore.PostgreSQL;namespace StatlerWaldorfCorp.LocationService.Persistence
{public class LocationDbContext : DbContext{public LocationDbContext(DbContextOptions<LocationDbContext> options) :base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.HasPostgresExtension("uuid-ossp");}public DbSet<LocationRecord> LocationRecords {get; set;}}public class LocationDbContextFactory : IDbContextFactory<LocationDbContext>{public LocationDbContext Create(DbContextFactoryOptions options){var optionsBuilder = new DbContextOptionsBuilder<LocationDbContext>();var connectionString = Startup.Configuration.GetSection("postgres:cstr").Value;optionsBuilder.UseNpgsql(connectionString);return new LocationDbContext(optionsBuilder.Options);}}
}

创建了新的数据库上下文后,需要让它在依赖注入中可用,这样位置仓储才能使用它

public void ConfigureServices(IServiceCollection services)
{//var transient = Boolean.Parse(Configuration.GetSection("transient").Value);var transient = true;if (Configuration.GetSection("transient") != null) {transient = Boolean.Parse(Configuration.GetSection("transient").Value);}if (transient) {logger.LogInformation("Using transient location record repository.");services.AddScoped<ILocationRecordRepository, InMemoryLocationRecordRepository>();} else {var connectionString = Configuration.GetSection("postgres:cstr").Value;services.AddEntityFrameworkNpgsql().AddDbContext<LocationDbContext>(options =>options.UseNpgsql(connectionString));logger.LogInformation("Using '{0}' for DB connection string.", connectionString);services.AddScoped<ILocationRecordRepository, LocationRecordRepository>();}services.AddMvc();
}

让这些功能最终生效的奇妙之处在于对 AddEntityFrameworkNpgsql 以及 AddDbContext 两个方法的调用

对真实仓储进行集成测试

我们想要利用自动的构建流水线,每次运行构建时都启动一个新的、空白的 Postgres 实例

然后,让集成测试在这个新实例上运行,执行迁移以配置数据库结构

每次提交代码时,整个过程既要能在本地、团队成员的机器上运行,又要能在云上自动运行

这就是我喜欢搭配使用 Wercker 和 Docker 的原因

试运行数据服务

使用特定参数启动 Postgres

$ docker run -p 5432:5432 --name some-postgres \
-e POSTGRES_PASSWORD=inteword -e POSTGRES_USER=integrator \
-e POSTGRES_DB=locationservice -d postgres

这样就以 some-postgres 为名称启动一个 Postgres 的 Docker 镜像

为验证能够成功连接到 Postgres,可运行下面的 Docker 命令来启动 psql

$ docker run -it --rm --link some-postgres:postgres postgres \
psql -h postgres -U integrator -d locationservice

数据库启动后,还需要表结构,顺便设置了很快会用到的环境变量

$ exprot TRANSIENT=false
$ export POSTGRES__CSTR=“Host=localhost;Username=integrator; \
Password=inteword;Database=locationservice;Port=5432"
$ dotnet ef database update

我们期望位置服务能够访问到自己的容器之外,并进入 Postgres 容器之内

容器链接能够实现这项能力,不过需要在启动 Docker 镜像之前就完成环境变量的修改

$ export POSTGRES__CSTR=“Host=localhost;Username=integrator; \
Password=inteword;Database=locationservice;Port=5432"
$ docker run -p 5000:5000 --link some-postgres:psotgres \
-e TRANSIENT=false -e PORT=5000 \
-e POSTGRES__CSTR dotnetcoreservices/locationservice:latest

使用 psotgres 作为主机名链接 Postgres 容器后,位置服务就应该能够正确连接到数据库了

为亲自验证结果,可以提交一个位置记录

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

通过服务查询我们虚构的团队成员历史位置

$ curl http://localhost:5000/locations/63e7acf8-8fae-42ec-9349-3c8593ac8292

为了再次确认,查询 latest 端点并确保仍能获取到期望的输出

$ curl http://localhost:5000/locations/63e7acf8-8fae-42ec-9349-3c8593ac8292/latest

最后,为了证实确实在使用真实的数据库实例,可以使用 docker ps 以及 docker kill 找到位置服务所在的 Docker 进程并终止它

然后通过之前用过的命令重新启动服务

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

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

相关文章

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

去年的时候有同学在微信上问了我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) <…

向大厂看齐!为自己的程序增加自动转储的功能!

如果你还不清楚什么是转储文件&#xff0c;不知道什么时候需要转储文件&#xff0c;请参考转储文件系列文章的第一篇 —— 转储文件知多少。前言不知道各位小伙伴有没有遇到过 微信 或者 QQ 崩溃的情况。它们在崩溃的时候都会自动弹出一个对话框&#xff0c;提示用户上传相关文…

sqlite3 c++ VS编译生成静态库

官网 https://www.sqlite.org/download.html 下载sqlite-amalgamation和x86版本下载sqlite-dll-win32-x86、x64位版本sqlite-dll-win64-x64 解压 SQLITE-AMALGAMATION包含 shell.csqlite3.csqlite3.hsqlite3ext.hsqlite-dll-win32-x86包含 sqlite3.def sqlite3.dll建立一个空…

数据结构----单源最短路径Dijkstra

数据结构----单源最短路径Dijkstra 原理&#xff1a;参考趣学数据结构 代码&#xff1a; stack.h 栈代码 #pragma once #include<stdio.h> #define maxSize 100 typedef struct stack {int * base;int * top; }stack; bool init(stack & Stack) {//栈的初始化Stack.b…

在.NET中执行Async/Await的两种错误方法

微信公众号&#xff1a;架构师高级俱乐部关注可了解更多的编程&#xff0c;架构知识。问题或建议&#xff0c;请公众号留言;如果你觉得此文对你有帮助&#xff0c;欢迎转发在.NET中执行异步/等待的两种错误方法 在应用开发中&#xff0c;我们为了提高应用程序的吞吐能力或者异步…

C#如何安全、高效地玩转任何种类的内存之Span的秉性特点(二)

前言读完上篇《C#如何安全、高效地玩转任何种类的内存之Span的本质(一)》&#xff0c;相信大家对span的本质应该非常清楚了。含着金钥匙出生的它&#xff0c;从小就被寄予厚望要成为.NET下编写高性能应用程序的重要积木&#xff0c;而且很多老前辈为了接纳它&#xff0c;都纷纷…

word List 05

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

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

第 6 章 事件溯源与 CQRS在本章&#xff0c;我们来了解一下随着云平台一同出现的设计模式我们先探讨事件溯源和命令查询职责分离&#xff08;CQRS&#xff09;背后的动机与哲学事件溯源简介事实由事件溯源而来我们大脑就是一种事件溯源系统&#xff0c;接收感官多种形式刺激&am…

数据结构----快速排序

数据结构----快速排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> int quickSort(int a[], int l, int h) {//快速排序int i l, j h, p a[l];while (i < j) {while (i<j&&a[j]>p) {//从右往左…

编译调试 .NET Core 5.0 Preview 并分析 Span 的实现原理

很久没有写过 .NET Core 相关的文章了&#xff0c;目前关店在家休息所以有些时间写一篇新的????。这次的文章主要介绍如何在 Linux 上编译调试最新的 .NET Core 5.0 Preview 与简单分析 Span 的实现原理。微软从 .NET Core 5.0 开始把 GIT 仓库 coreclr 与 corefx 合并移动…

数据结构----归并排序

数据结构----归并排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> #define N 100 void guiBingSort(int a[], int l, int h,int length) {//归并排序int mid (l h) / 2;int* b (int *)malloc(N*sizeof(int));i…

利用obfuscar对.NET应用进行混淆

背景发布客户端程序产品时&#xff0c;免不了会遇到一些怀有恶意或有强烈学习欲望的用户尝试对程序进行反编译。对于一些编译成本地指令的程序&#xff08;如C、C&#xff09;&#xff0c;编译后可读性低&#xff0c;反编译和破解成本较高&#xff0c;不需要对代码进行太高强度…

数据结构---基数排序

数据结构—基数排序 原理&#xff1a;参考趣学数据结构 代码&#xff1a; #include<stdio.h> #include<stdlib.h> int getNumberBit(int number) {//获取数字的位数int x number,count0;if (x 0)return 1;while (x ! 0) {count;x / 10;}return count; } int g…

C# 版本 疫情传播仿真程序

前言前一阵子看到有人制作了《疫情传播仿真程序》&#xff0c;是用 Java做的。里面根据多种实际情况&#xff0c;如居民移动意愿、医护能力、病毒传播能力&#xff0c;来模拟疫情的发展。看完之后&#xff0c;我暗暗称奇&#xff0c;特别是结合一些视频和照片&#xff0c;确实做…