ABP vNext微服务架构详细教程——基础服务层

1

服务创建

713dbdfd23c3a5ef120db4ec0241c00f.png

在除身份管理相关服务以外的其他业务服务中,我们不需要包含用户角色权限管理功能模块,ABP vNext框架为我们提供了模块模式,其默认模板不包含身份管理相关模块,更适合用于搭建普通的业务微服务。

fa2015a87df233745b5059a36f54e5ce.gif

以产品管理服务为例,我们在解决方案目录中找到service目录,在其中创建productmanager目录,切换至该目录并启动cmd命令行。使用以下命令创建产品管理服务:

abp new Demo.ProductManager -t module --no-ui

56efa2b4ac4a432fc3680d037dda064a.png

其中

    -t module表示模块模式

    --no-ui表示不使用UI界面

a91d49c5e11681f8ea1819ad11adca00.gif

在ABP vNext框架Module模式下一直存在一个问题,创建时无法和Application一样使用-dbms参数设置数据库类型,而是使用默认的SQL Server数据库类型,这里我们的项目采用MySQL数据库,需要手动修改为MySQL,具体方法见下一章节。

f24af5a1e81b09264d2dbfa0a8a942d8.gif

因为我们身份认证服务采用统一的服务,所以我们在生成的模板中找到host目录下的ProductManager.IdentityServer项目文件夹并删除,数据库我们不使用MongoDB,所以可以将src目录下的ProductManager.MongoDB项目文件夹和test目录下的ProductManager.MongoDB.Tests项目文件夹删除。之后我们可以删除该项目根目录下database文件夹和除Demo.ProductManager.sln、common.props以外的所有文件,如果不需要对该项目进行单元测试,也可删除test文件夹。

1888979095115820a6fb9e7d6145e07b.gif

清理后,跳转到总解决方案所在目录,使用解决方案构建工具将产品管理服务所有项目添加到总解决方案,添加后效果如下:

2

切换为Mysql数据库

75a9446e7f194a69bde9a70d7fa468ca.gif

将Module模式项目从SQL Server数据库更改为MySQL数据库步骤如下:

1. 找到ProductManager.HttpApi.Host项目移除其Nuget引用中的Volo.Abp.EntityFrameworkCore.SqlServer,然后添加Nuget引用Volo.Abp.EntityFrameworkCore.MySQL,注意版本号和主项目ABP框架版本一致。

2. 找到ProductManager.HttpApi.Host项目中的模块类ProductManagerHttpApiHostModule,将其特性DependsOn特性中引用的 typeof(AbpEntityFrameworkCoreSqlServerModule) 更改为 typeof(AbpEntityFrameworkCoreMySQLModule) 并将其命名空间引用 using Volo.Abp.EntityFrameworkCore.SqlServer; 改为 using Volo.Abp.EntityFrameworkCore.MySQL; 。将ConfigureServices方法的

Configure<AbpDbContextOptions>(options => { options.UseSqlServer(); }); 改为 Configure<AbpDbContextOptions>(options => { options.UseMySQL(); });

3. 找到ProductManager.HttpApi.Host项目中的ProductManagerHttpApiHostMigrationsDbContextFactory类,将其方法CreateDbContext中的 var builder = new DbContextOptionsBuilder<ProductManagerHttpApiHostMigrationsDbContext>() .UseSqlServer(configuration.GetConnectionString("ProductManager")); 改为以下代码(注意我的MySQL版本为5.7,具体版本号请依据个人情况修改):

var builder = new DbContextOptionsBuilder<ProductManagerHttpApiHostMigrationsDbContext>().UseMySql(configuration.GetConnectionString("ProductManager"),ServerVersion.Parse("5.7.28-mysql"));

4. 修改Demo.ProductManager.HttpApi.Host项目的appsettings.json配置文件,和Application模式不同,我们会发现Module模式下ABP vNext框架提供的项目模板ConnectionStrings项会包含Default和ProductManager两个配置项。其中Default为ABP框架基础配置信息的数据库,身份管理服务已包含其所需的所有数据,所以我们将Default配置为和身份管理中心相同的数据库链接。ProductManger也就是和当前项目相同的数据库配置项,所指向的数据库为对当前模块领域实体持久化的数据库,需要在当前项目中配置和创建。

5. 进入Demo.ProductManager.HttpApi.Host项目所在目录,执行数据迁移命令 dotnet-ef database update ,执行成功后查看数据库,发现已创建模块数据库,且仅包含__EFMigrationsHistory表,则数据库链接成功。

3

初始化运行

1671e6ce65ded084dd6b37254bb0ad77.gif

在Demo.ProductManager.Application、Demo.ProductManager.Application.Contracts、Demo.ProductManager.HttpApi三个项目中分别找到Samples文件夹并删除,这是ABP vNext提供的样例API,没有实际用途。

87bcef0e50f032f8c12192b34ec91dfd.gif

设置端口号为5010并允许IP地址访问,方式为在Demo.ProductManager.HttpApi.Host项目配置文件appsettings.json中添加配置项: "urls": "http://*:5010" 

647b122b97d0ad11f4ca1790d325044e.gif

上一章节我们已经配置了数据库链接字符串,我们继续编辑Demo.ProductManager.HttpApi.Host项目配置文件appsettings.json,设置Redis链接字符串。

8560792cfe5500e96c029325346ecb69.gif

启动Demo.ProductManager.HttpApi.Host项目并访问http://localhost:5010/swagger/index.html,可以正常显示Swagger页面,即启动成功。

4

产品管理API

01

领域层

f1ce05f9acbdc7c9e0d713151b18ac8c.gif

在Demo.ProductManager.Domain项目中添加Products文件夹(产品领域)并创建Product类(产品聚合根)代码如下:

using System;
using Volo.Abp.Domain.Entities;namespace Demo.ProductManager.Products;/// <summary>
/// 产品
/// </summary>
public class Product : AggregateRoot<Guid>
{/// <summary>/// 名称/// </summary>public string Name { get; set; }/// <summary>/// 价格/// </summary>public float Price { get; set; }
}

02

数据库创建

3f48a0682b0bd47cc1f63bb7e1b9785d.gif

在Demo.ProductManager.EntityFrameworkCore项目中找到IProductManagerDbContext接口和ProductManagerDbContext类,分别添加 DbSet<Product> Products { get; set; } 和 public DbSet<Product> Products { get; set; } 属性并添加相应引用。

8638c96284f5f51186f0b5787b3bf688.gif

在Demo.ProductManager.EntityFrameworkCore项目中找到ProductManagerDbContextModelCreatingExtensions类中的ConfigureProductManager方法内添加以下内容:

builder.Entity<Product>(b =>
{b.ToTable(ProductManagerDbProperties.DbTablePrefix+ "Products", ProductManagerDbProperties.DbSchema);b.ConfigureByConvention();
});

这里使用实体类默认设置,如果需要进行自定义修改,可自行编辑实体配置。

1e104b7f02dcd43a15f90ca71fb243ec.gif

在Demo.ProductManager.HttpApi.Host项目所在目录中执行创建数据迁移语句:

dotnet-ef migrations Add BuildProduct

创建成功后执行数据迁移:

dotnet-ef database update

000a0b982fcf9a530a29ea60689c67cf.gif

执行成功后,我们可以在ProductManager模块数据库中看到已新增数据库表Product,此表中除主键ID和我们自己定义的两个字段以外,如果Product继承自AggregateRoot,则会包含ExtraProperties和ConcurrencyStamp两个字段,分别为扩展属性和并发戳。若继承自Entity则默认不会包含这两个字段。

03

应用层

为方便演示,本实例采用CrudAppService,对Product提供增删改查接口,具体实现方式如下:

173687abcb5cf8fc53f9f7f0a8134da9.gif

在Demo.ProductManager.Application.Contracts项目中创建Products文件夹并在其中创建Dto文件夹。在Dto文件夹中存放产品管理的数据传输对象,这里增删改查接口统一使用ProductDto,代码如下:

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;namespace Demo.ProductManager.Products.Dto;/// <summary>
/// 产品DTO
/// </summary>
public class ProductDto : EntityDto<Guid>, IHasConcurrencyStamp
{/// <summary>/// 名称/// </summary>public string Name { get; set; }/// <summary>/// 价格/// </summary>public float Price { get; set; }/// <summary>/// 并发戳/// </summary>public string ConcurrencyStamp { get; set; }
}

这里因为我们使用聚合根,修改数据时需要提供并发戳ConcurrencyStamp,但EntityDto中并未提供该字段,所以需继承IHasConcurrencyStamp接口。

213d71f05a0fbee58e19622f79ab2f09.gif

在Demo.ProductManager.Application.Contracts项目Products文件夹下添加产品管理应用服务接口IProductAppService如下:

using System;
using Demo.ProductManager.Products.Dto;
using Volo.Abp.Application.Services;namespace Demo.ProductManager.Products;/// <summary>
/// 产品管理应用服务接口
/// </summary>
public interface IProductAppService : ICrudAppService<ProductDto, Guid>
{}

58dc6b36fae0eeced609fbc0ee7eb9dc.gif

在Demo.ProductManager.Application项目中添加Products文件夹,添加应用服务类ProductAppService如下:

using System;
using Demo.ProductManager.Products.Dto;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;namespace Demo.ProductManager.Products;/// <summary>
/// 产品管理应用服务
/// </summary>
public class ProductAppService:CrudAppService<Product,ProductDto,Guid>,IProductAppService
{public ProductAppService(IRepository<Product, Guid> repository) : base(repository){}
}

9d5f751484ef7860c24384783987e673.gif

为方便多个领域下AutoMapper映射关系的管理,我在每个领域单独创建一个静态类,以扩展方法的方式编写当前领域的对象映射关系。例如在当前Products领域中,在Demo.ProductManager.Application项目中Products文件夹下添加静态类ProductAutoMapperProfile如下:

using Demo.ProductManager.Products.Dto;namespace Demo.ProductManager.Products;public static class ProductAutoMapperProfile
{public static void CreatProductMapper(this ProductManagerApplicationAutoMapperProfile profile){profile.CreateMap<Product, ProductDto>();profile.CreateMap<ProductDto, Product>();}
}

之后,就可以在ProductManagerApplicationAutoMapperProfile类的ProductManagerApplicationAutoMapperProfile方法中增加以下代码:

this.CreatProductMapper();

bc1736034a4eb25cfb806d8012891021.gif

通常情况,DTO和实体的字段并非完全一一对应,我们需要再映射过程中忽略映射关系的校验,具体方法为将ProductManagerApplicationModule类中ConfigureServices方法下  Configure<AbpAutoMapperOptions>(options => { options.AddMaps<ProductManagerApplicationModule>(validate: true); }); 这一句validate参数值改为false

04

其他处理

05af90f0ce3f9bf1443b8d313afdb928.gif

ABP vNext框架Module模式模板默认未开启动态WebAPI,需要我们手动启用动态WebAPI,具体方式为在Demo.ProductManager.HttpApi.Host项目的ProductManagerHttpApiHostModule类ConfigureServices方法中添加以下代码:

Configure<AbpAspNetCoreMvcOptions>(options =>{   options     .ConventionalControllers     .Create(typeof(ProductManagerApplicationModule).Assembly); });

5d6ccd812583e434738ae7a96e077077.gif

通常情况,我们使用的仓储为ABP vNext框架提供的默认仓储实现,我们需要一次性添加所有默认仓储,具体方法为在Demo.ProductManager.EntityFrameworkCore项目中ProductManagerEntityFrameworkCoreModule类的ConfigureServices方法中,找到 context.Services.AddAbpDbContext<ProductManagerDbContext>(…… ,在其中添加options.AddDefaultRepositories();修改为:

context.Services.AddAbpDbContext<ProductManagerDbContext>(options =>{    /* Add custom repositories here. Example:     * options.AddRepository<Question, EfCoreQuestionRepository>();    */    options.AddDefaultRepositories(); });

f0f709359d01d0c5bb34ad818ecf4e7c.png

完成以上修改后,运行Demo.ProductManager.HttpApi.Host项目并打开http://localhost:5010/swagger/index.html,可显示Swagger页面并包含,Product相关增删改查接口,可通过Swagger页面完成测试。

371bf6eb5a376496211037456e8f23e8.png

end

b8475dcb95a06323ef4a3cec6df5b505.png

9db6a99457704006d79a5835b1b4e9db.png

f23a6edbbb5d11bb4f7d8df08fed920d.png

更多精彩

关注我获得

c659f24332281c143b3b5818362949f3.png

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

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

相关文章

linux c之main(int argc, char *argv[], char *envp[])参数意义

1、问题 我们常见的int main(int argc, char *argv[], char *envp[]) 各个参数的意义 2、代码 #include<stdio.h> #include<unistd.h>int main(int argc, char *argv[], char *envp[]) {printf("argc ###\n%d\n",argc);puts("argc end ************…

salt-ssh的使用(不需要安装客户端)

什么情况下才使用salt-ssh&#xff0c;有一些比较老的红帽服务器&#xff0c;也有一些不方便安装salt-minion客户端。总会有一些服务器比较难安装上salt-minion的。好了&#xff0c;下面来说说简单配置默认使用roster配置文件vim /etc/salt/roster # Sample salt-ssh config fi…

bzoj 3232 01分数规划+最大权封闭子图判定

我们的目标是使v/c最小化&#xff0c;所以构造函数g(x)v-x*c&#xff0c;那么 二分一个X&#xff0c;判断当时的v-x*c的值是多少&#xff0c;然后根据g(x)函数的 单调递减性来二分&#xff0c;判断&#xff0c;直到g(x)0的时候当前的X就是答案。 然后我直接写的tle了&#xff0…

python设置cookie_Python中cookie的设置方法

学习目标:掌握 Cookie 的定义和使用Cookie 定义Cookie&#xff0c;有时也用其复数形式Cookies。指的是由服务端生成, 保存在客户端的一种数据存储形式&#xff0c;内部以 key-value 键值对形式存储&#xff0c; value大小有限制(最大为4kb)&#xff0c; 数据不安全。背景:Cooki…

中国第一个发《Nature》的竟然是清朝人!被皇帝夸天下第一,他却觉得羞耻..........

全世界只有3.14 % 的人关注了爆炸吧知识大清亡了&#xff01;这事在今天讲&#xff0c;算不得惊天动地&#xff0c;你听了之后&#xff0c;还可能微微一笑。作为中国最后一个封建王朝&#xff0c;它先闭关锁国&#xff0c;后又丧权辱国&#xff0c;造成百年前的中国在科学技术方…

【清北学堂】 死亡(death)

M个位置可以打sif&#xff0c;N1个人等着打sif&#xff0c;已知前N个人的时间&#xff0c;问第N1个人什么时候才能打sif&#xff08;不能插队&#xff0c;即必须按顺序来打sif&#xff09; 输入N,M以及每个人所需要的时间&#xff1b;输出第N1个人所需的时间 用优先队列用优先…

码农与UI沟通的日常

事情是这样的&#xff0c;这是一个兴趣群组的效果图。 我看了一眼没有帖子时的提示&#xff0c;觉得这样的提示 不走心 不能展现出我们团队对于人生及世界的深度理解和高尚的品格。 于是&#xff0c;我选择了表达内心的真实感受。 我觉得这完美表达了用户使用时的心声&#xff…

如何实现二次抛异常时保存第一次异常的详细信息?

咨询区 skolima我用反射来尝试调用一个可能会引发异常的方法&#xff0c;我如何将这个异常信息传递给调用者&#xff0c;而不需要通过反射包装器包装它。我目前的是再 throw 一次异常&#xff0c;但这种做法会销毁第一次异常的栈信息&#xff0c;参考如下代码&#xff1a;publi…

linux之cut命令使用和总结

cut是一个选取命令: 就是将一段数据经过分析,取出我们想要的。一般来说,选取信息通常是针对“行”来进行分析的,并不是整篇信息分析的。 (1)其语法格式为:cut [-bn] [file] 或 cut [-c] [file] 或 cut [-df] [file] 使用说明 cut 命令从文件的每一行剪切字节、字符…

flash builder 4.7 debug via usb device iPhone 4s - device not found

http://forums.adobe.com/message/4865192 Please provide more info on the above issue: 1.What is the message shown when you try to debug the application via USB on iOS device ? 2.Are you able to debug on other iOS devices ? Run this below command from comm…

贝叶斯分类器_Sklearn 中的朴素贝叶斯分类器

(给Python开发者加星标&#xff0c;提升Python技能)作者&#xff1a;Martin Mller&#xff0c;翻译&#xff1a;github-sisibelovedhttps://github.com/xitu/gold-miner/blob/master/TODO1/naive-bayes-classifier-sklearn-python-example-tips.md用豆机实现的高斯分布这篇教程…

linux之tr命令使用和总结

1、tr命令介绍 用来从标准输入中通过替换或删除操作进行字符转换。tr主要用于删除文件中控制字符或进行字符转换。使用tr时要转换两个字符串:字符串1用于查询,字符串2用于处理各种转换。tr刚执行时,字符串1中的字符被映射到字符串2中的字符,然后转换操作开始。 带有最常用…

美少女什么味??竟然还有美少女风味泡面......

1 毕业后第一次参加聚餐&#xff08;via&#xff1a;刘燕铭&#xff09;▼2 建议使用摩斯密码&#xff0c;谢谢▼3 隆马戏&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 真的很谢谢▼5 啊&#xff0c;哪里买呢&#xff08;via&#xff1a;Zero 浅忆&#xff09;…

ABP vNext微服务架构详细教程——身份管理服务

1框架搭建ABP vNext创建包含app和module两种模板&#xff0c;其中app方式所创建的模板包含用户、角色、权限管理&#xff0c;ABP基础配置IdentityServer的基础配置数据等功能。module模式是一个比较干净的服务&#xff0c;里面不包含默认业务功能。ABP vNext创建包含app和modul…

ubuntu安装时发现GPT分区表,无法安装问题

光盘安装时&#xff0c;先试用ubuntu&#xff0c;输入命令&#xff1a; sudo dd if/dev/zero of/dev/sda bs1 count8 seek512再用光盘引导安装即可。转载于:https://www.cnblogs.com/chengliu/p/3636343.html

双网卡上网冲突解决_【技术文章】局域网IP地址冲突罪魁祸首是什么?这几点要注意!(附高手处理方法)...

现如今&#xff0c;人们的生活处处离不开网络。单位办公信息化对网络的依赖则更大。为了提升安全管理和信息化水平&#xff0c;很多单位不仅建设了完善的办公信息系统&#xff0c;还部署了视频监控。但由于缺乏整体规划&#xff0c;或选择网络产品时考虑欠周&#xff0c;导致网…

异常分析

一、请阅读并运行AboutException.java示例&#xff0c;然后通过后面的几页PPT了解Java中实现异常处理的基础知识。 &#xff08;1&#xff09;源代码;import javax.swing.*; class AboutException { public static void main(String[] a) { int i1, j0, k; ki/j; try { k i/j…

linux c之wait和waitpid函数的用法和总结

1、wait和waitpid函数的介绍 1) wait()函数用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()函数就会立即返回。 2) waitpid()的作用和wait()一样,但它并不一…

微软开发者的年度回顾

2021 年 .NET 和 Microsoft 开发人员的技术都发生了什么&#xff1f;很难从 2021 年只选择一个主题。安静的进化&#xff1f;开源的争议&#xff1f;一个让开发人员疑惑的操作系统更新&#xff1f;当我回头看时, 发现一年发生了很多事情, 2021 年的发展是稳步向前的&#xff0c…

我是永远不可能出轨的,除非......

1 当爸妈学会了抠图&#xff08;素材来源豆瓣&#xff0c;侵删&#xff09;▼2 帮我带瓶我平时常喝的水&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 我们是被资本凑在一起的联姻&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 我是不会出轨的&…