ABP vNext微服务架构详细教程(补充篇)——单层模板(中)

框架搭建

2

聚合服务

a397f833b8020deaad5eb313f26f8e74.png

这里我们将聚合服务命名为Domain.Core

e2b64a3ca28f8cf127b73262d7a2605b.gif

和基础服务层一致,我们先通过命令创建单层模板项目Domain.Core,这里我们删除wwwroot、Data、Entities、Localization、ObjectMapping文件夹及其所有子文件,并删除package.json文件和Services文件夹下的Dtos文件夹

fe893f40298110d9e3fcf6e8ee8adcbc.gif

在同级目录添加类库Domain.Core.Constracts并删除其中的Class1.cs文件

c2eb67e59dfae65ebc058a183d0db0e1.png

这里我们在聚合服务中暂时不需要提供动态客户端代理,暂时不创建.Client项目,如果需要,创建方式和基础服务层相同。

71cc44124fc4c51822b912cc5c43a240.gif

修改Demo.Core.csproj文件如下:

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net6.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Serilog.AspNetCore" Version="5.0.0" /><PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /></ItemGroup><ItemGroup><PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="5.3.4" /><PackageReference Include="Volo.Abp.Autofac" Version="5.3.4" /><PackageReference Include="Volo.Abp.Swashbuckle" Version="5.3.4" /><PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="5.3.4" /></ItemGroup><ItemGroup><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.5" /></ItemGroup><ItemGroup><Content Remove="Localization\Core\*.json" /><EmbeddedResource Include="Localization\Core\*.json" /><EmbeddedResource Remove="wwwroot\**" /><Content Remove="wwwroot\**" /><Content Remove="package.json" /></ItemGroup><ItemGroup><Compile Remove="Logs\**" /><Content Remove="Logs\**" /><EmbeddedResource Remove="Logs\**" /><None Remove="Logs\**" /><Compile Remove="wwwroot\**" /><None Remove="wwwroot\**" /></ItemGroup><ItemGroup><ProjectReference Include="..\..\..\service\notificationmanager\Demo.NotificationManager.Client\Demo.NotificationManager.Client.csproj" /><ProjectReference Include="..\Demo.Core.Contracts\Demo.Core.Contracts.csproj" /></ItemGroup>
</Project>

28c4648364d7fcd2f1e09a1cc48ad6ab.gif

修改CoreModule.cs类代码如下:

using Demo.Core.Contracts;
using Demo.NotificationManager.Client;
using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;namespace Demo.Core;[DependsOn(// ABP Framework packagestypeof(AbpAspNetCoreMvcModule),typeof(AbpAutofacModule),typeof(AbpSwashbuckleModule),typeof(AbpAspNetCoreSerilogModule),typeof(CoreContractsModule),typeof(NotificationManagerClientModule)
)]
public class CoreModule : AbpModule
{#region 私有方法#region 配置动态WebApiprivate void ConfigureAutoApiControllers(){Configure<AbpAspNetCoreMvcOptions>(options =>{options.ConventionalControllers.Create(typeof(CoreModule).Assembly);});}#endregion#region 配置swaggerprivate void ConfigureSwagger(IServiceCollection services){services.AddAbpSwaggerGen(options =>{options.SwaggerDoc("v1", new OpenApiInfo { Title = "Core API", Version = "v1" });options.DocInclusionPredicate((docName, description) => true);options.CustomSchemaIds(type => type.FullName);});}#endregion#endregionpublic override void ConfigureServices(ServiceConfigurationContext context){ConfigureSwagger(context.Services);ConfigureAutoApiControllers();}public override void OnApplicationInitialization(ApplicationInitializationContext context){var app = context.GetApplicationBuilder();app.UseRouting();app.UseUnitOfWork();app.UseSwagger();app.UseSwaggerUI(options =>{options.SwaggerEndpoint("/swagger/v1/swagger.json", "Core API");});app.UseAbpSerilogEnrichers();app.UseConfiguredEndpoints();}
}

9b2097b55a6f30e0391f6012b85090ca.gif

修改Program.cs文件内容如下:

using Demo.Core;
using Serilog;
using Serilog.Events;Log.Logger = new LoggerConfiguration()
#if DEBUG.MinimumLevel.Debug()
#else.MinimumLevel.Information()
#endif.MinimumLevel.Override("Microsoft", LogEventLevel.Information).Enrich.FromLogContext().WriteTo.Async(c => c.File("Logs/logs.txt"))
#if DEBUG.WriteTo.Async(c => c.Console())
#endif.CreateLogger();var builder = WebApplication.CreateBuilder(args);builder.Host.UseAutofac().UseSerilog();
builder.Services.ReplaceConfiguration(builder.Configuration);
builder.Services.AddApplication<CoreModule>();var app = builder.Build();
app.InitializeApplication();
app.Run();

a8dcacd6cd33398d897e461888ef26ed.gif

修改appsettings.json文件如下:

{"urls": "http://*:6003","RemoteServices": {"NitificationManager": {"BaseUrl": "http://localhost:5003/"}}
}

0dba3eb74b9ed7774f3c5aa2765bcfbb.gif

修改Demo.Core.Contracts.csproj文件:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net6.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="5.3.4" /></ItemGroup>
</Project>

514fc89985a44ebfbe4f32ae3f6f5b5f.gif

在Demo.Core.Contracts项目中创建CoreContractsModule.cs文件内容如下:

using Volo.Abp.Application;
using Volo.Abp.Modularity;namespace Demo.Core.Contracts;[DependsOn(typeof(AbpDddApplicationContractsModule)
)]
public class CoreContractsModule : AbpModule
{}

153d455b9d47f9cb9d23b2051d03ee82.png

启动Demo.Core项目可正常运行并显示swagger页面则聚合服务创建成功。

业务代码

1

基础服务

a887f1cb12fa154cbe22f37efe9e0323.gif

在Demo.NotificationManager项目Entities文件夹中按领域划分子文件夹,这里创建Notifications领域文件夹,并添加实体类Notification如下:

using System.ComponentModel.DataAnnotations;
using Volo.Abp.Domain.Entities.Auditing;namespace Demo.NotificationManager.Entities.Notifications;/// <summary>
/// 通知
/// </summary>
public class Notification : CreationAuditedEntity<Guid>
{/// <summary>/// 接受着用户ID/// </summary>public Guid ReceiverId { get; set; }/// <summary>/// 标题/// </summary>[StringLength(128)]public string Title { get; set; }/// <summary>/// 内容/// </summary>public string Content { get; set; }/// <summary>/// 是否已读/// </summary>public bool IsRead { get; set; }
}

f6c9688eaffd5e6aad93142b721fead8.gif

在Demo.NotificationManager项目Data文件夹下的NotificationManagerDbContext类中添加如下属性并引入相应依赖:

public DbSet<Notification> Notifications { get; set; }

a822c3d888def1eec2da0385984e98d5.gif

通过 dotnet-ef 的 migrations add 命令和 database update 命令创建数据库结构。

44427566c4a9d095cf4e1ee9691f49f6.png

这里我们未用到领域服务,如果需要,可在Demo.NotificationManager项目中添加Managers文件夹并按领域存放对应代码。

66e42c2e2b094c360a2c19a3820341a0.gif

在Demo.NotificationManager.Contracts项目中添加Services文件夹,DTO和应用服务接口的定义。这里添加子文件夹Notifications并在其中添加Dtos文件夹,用于存放DTO。

d62a2be487f4830c8a1991366413ef81.gif

我们添加以下两个DTO分别用于添加和查询通知:

using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos;namespace Demo.NotificationManager.Contracts.Services.Notifications.Dtos;public class NotificationCreateDto:EntityDto<Guid>
{/// <summary>/// 接受着用户ID/// </summary>public Guid ReceiverId { get; set; }/// <summary>/// 标题/// </summary>[StringLength(128)]public string Title { get; set; }/// <summary>/// 内容/// </summary>public string Content { get; set; }/// <summary>/// 是否已读/// </summary>public bool IsRead { get; set; }
}
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;namespace Demo.NotificationManager.Contracts.Services.Notifications.Dtos;public class NotificationDto:NotificationCreateDto,ICreationAuditedObject
{/// <summary>/// 创建时间/// </summary>public DateTime CreationTime { get; set; }/// <summary>/// 创建者/// </summary>public Guid? CreatorId { get; set; }
}

1d1140cf896ea59dd9b68864495d98a4.gif

添加INotificationAppService应用服务接口,内容如下:

using Demo.NotificationManager.Contracts.Services.Notifications.Dtos;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;namespace Demo.NotificationManager.Contracts.Services.Notifications;public interfaceINotificationAppService : ICrudAppService<NotificationDto, Guid, PagedResultRequestDto, NotificationCreateDto>
{}

49f0ce48db65eb06ca4916094df5efca.gif

在Demo.NotificationManger中Services文件夹中添加应用服务实现类,这里添加Notifications子文件夹并创建NotificationAppService类如下:

using Demo.Abp.Extension;
using Demo.NotificationManager.Contracts.Services.Notifications;
using Demo.NotificationManager.Contracts.Services.Notifications.Dtos;
using Demo.NotificationManager.Entities.Notifications;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;namespace Demo.NotificationManager.Services.Notifications;public class NotificationAppService : CustomCrudAppService<Notification, NotificationDto, Guid,PagedResultRequestDto,NotificationCreateDto>, INotificationAppService
{public NotificationAppService(IRepository<Notification, Guid> repository) : base(repository){}
}

c7ed3ec6ee29053be72fd3a3969a829e.png

此处,我引入了Mapster框架替代原来的AutoMapper框架,所以我们看到CustomCrudAppService类替代了默认增删改查类CrudAppService。

620f6317d2f0030a68a5fe427adaa76a.gif

CrudAppService类被存放在Demo.Abp.Extension类库中作为通用基类使用,代码如下:

using Mapster;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;namespace Demo.Abp.Extension;#region 重载
public abstract class CustomCrudAppService<TEntity, TEntityDto, TKey>: CustomCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CustomCrudAppService(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CustomCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>: CustomCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CustomCrudAppService(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CustomCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>: CustomCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CustomCrudAppService(IRepository<TEntity, TKey> repository): base(repository){}
}public abstract class CustomCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>: CustomCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>where TEntity : class, IEntity<TKey>where TEntityDto : IEntityDto<TKey>
{protected CustomCrudAppService(IRepository<TEntity, TKey> repository): base(repository){}protected override Task<TEntityDto> MapToGetListOutputDtoAsync(TEntity entity){return MapToGetOutputDtoAsync(entity);}protected override TEntityDto MapToGetListOutputDto(TEntity entity){return MapToGetOutputDto(entity);}
}
#endregionpublic class CustomCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput,TUpdateInput>: CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>where TEntity : class, IEntity<TKey>where TGetOutputDto : IEntityDto<TKey>where TGetListOutputDto : IEntityDto<TKey>
{public CustomCrudAppService(IRepository<TEntity, TKey> repository) : base(repository){}#region Mapsterprotected override TEntity MapToEntity(TCreateInput createInput){var entity = createInput.Adapt<TEntity>();SetIdForGuids(entity);return entity;}protected override void MapToEntity(TUpdateInput updateInput, TEntity entity){if (updateInput is IEntityDto<TKey> entityDto){entityDto.Id = entity.Id;}entity = updateInput.Adapt(entity);}protected override TGetOutputDto MapToGetOutputDto(TEntity entity){return entity.Adapt<TGetOutputDto>(); //ObjectMapper.Map<TEntity, TGetOutputDto>(entity);}protected override TGetListOutputDto MapToGetListOutputDto(TEntity entity){return entity.Adapt<TGetListOutputDto>(); //ObjectMapper.Map<TEntity, TGetListOutputDto>(entity);}#endregion
}

0b760975cc56ab9a5e2736b30524c9ec.png

此类我继承自原有的CrudAppService类,并重写了对象转换方法。

31d92ef53bfcbdc94c6819813cbecc7b.png

使用Mapster,比AutoMapper效率更高,而且不需要提前声明默认的对象映射关系,如果需要额外定义映射关系或操作,可通过添加MapConfig类实现。具体用法参考其官方文档:https://github.com/rivenfx/Mapster-docs

bc4c51300601d072ca8019ca51cddcc5.png

如果我们需要定义领域通用配置、枚举等原属于Domain.Share项目中的内容,可创建并存放在Demo.NotificationManager.Contracts项目下Share文件夹中。

86c30f763a8b05646422fef42f2c675d.png

完成以上步骤,并可成功运行Demo.NotificationManager项目,则基础服务代码运行成功。

e9246de82a733964a451446af7168f16.png

未完待续

3d465c4ef30fbb5e8470b6749e9403a2.jpeg

03618cecdcc73e8c939e838d022114b2.png

关注我获得

更多精彩

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

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

相关文章

谈一谈synchronized关键词

1.使用 java中的每一个对象都可以作为synchronized的锁进行代码同步&#xff0c;常见的形式 同步代码块锁是synchronized括号内的对象普通成员方法上&#xff0c;锁是当前的对象&#xff0c;synchronized(this)静态方法上&#xff0c;锁是当前类的Class对象2. 原理 synchronize…

系统学习redis之二——redis集群搭建

redis单点部署&#xff1a; 安装命令&#xff1a; # cd /usr/local/ # wget http://download.redis.io/releases/redis-4.0.1.tar.gz #下载安装包 # yum -y install gcc psmisc #安装依赖包 # tar xf redis-4.0.1.tar.gz # cd /usr/lo…

业务技术协同线上化的研发管理实战

摘要&#xff1a;2017年1月13日举办的【云栖计算之旅】线下沙龙第4期研发管理专场&#xff0c;阿里巴巴B2B事业群产品专家代平为大家带来了题为业务技术协同线上化的研发管理实战的演讲。本文主要从管理产品研发的理念开始谈起&#xff0c;着重说明了云效指挥部的六大步骤&…

Linux中写脚本,同时去开启我们自己设定的多个服务(含定时脚本实现)

场景介绍&#xff1a; 在Linux中&#xff0c;我们通常开启服务需要使用systemctl start 服务名 命令&#xff0c;这样&#xff0c;如果开启一个服务还好&#xff0c;但是如果同时开启多个服务&#xff0c;难免会感到麻烦&#xff0c;这时&#xff0c;我们可以自定义一个脚本&a…

负载均衡环境搭建实战之nginx和tomcat

Linux基本环境负载均衡的环境需要在linux下搭建完成&#xff0c;所以有一个基础的linux系统是必须的&#xff0c;这里建议大家按照http://edu.51cto.com/course/10209.html中的基础linux环境来安装&#xff0c;这样能少走弯路。JDK安装1、 下载对应版本的Java1.7&#xff0c;a)…

桌面应用如何判断win11操作系统

背景Windows 11 操作系统已经正式发布快有一年了&#xff0c;在 .Net 开发中&#xff0c;我们获取操作系统版本&#xff0c;经常使用 Environment.OSVersion.Version.Major 和 Minor&#xff08;6.1 Windows 7, 10.0 Windows 10&#xff09;&#xff0c;但是当 Win11 出现以后…

Nginx 网站定义自己的错误页面

场景&#xff1a; 为了给用户较好的交互和感官&#xff0c;我们通常需要对错误页面进行友好提示。 环境介绍&#xff1a; LNMP&#xff08;linux&#xff08;centos7.4&#xff09;Nginx Mysql5.6 php7.0&#xff09;实现&#xff1a; 这里&#xff0c;我直接对nginx的子配置文…

车辆调度

为什么80%的码农都做不了架构师&#xff1f;>>> 车辆调度系统 大体上分为4个部分吧 1.调度车辆&#xff1a;你调度的时候需要的车辆&#xff0c;方便给你运输啥的 2.调度任务&#xff1a;你为啥会调度车辆&#xff0c;肯定要有一个任务 3.客户&#xff1a;那这个…

Nginx 设置,设置已经解析的域名,在nginx中没有定义相应server时的默认访问

场景介绍&#xff1a; 因为业务需求&#xff0c;我们需要对域名进行解析&#xff0c;这里我对域名进行了如下解析但是&#xff0c;因为业务需求&#xff0c;我可能在nginx中只定义了kuman.xiaobudiu.top 和 www.xiaobudiu.top 的相应server的子配置文件&#xff0c;如图那么问题…

第一次作业--四则运算题目生成程序

功能简介&#xff1a; 1.获取用户所要生成算术的个数 2.随机生成算式和式子的答案 3.生成算式和答案的txt文件来保存算式和答案 思路&#xff1a; 生成里的运算数分为三个部分&#xff0c;整数&#xff0c;如果是分数就再分为分子和分母&#xff0c;然后为这三个部分创建数组&a…

ABP vNext微服务架构详细教程(补充篇)——单层模板(上)订正篇

简介在之前的《ABP vNext微服务架构详细教程》系列中&#xff0c;我们已经构建了完整的微服务架构实例&#xff0c;但是在开发过程中&#xff0c;我们会发现每个基础服务都包含10个类库&#xff0c;这是给予DDD四层架构下ABP的实现方案&#xff0c;但是实际使用中我们会发现&am…

javascript基础修炼(4)——UMD规范的代码推演

javascript基础修炼(4)——UMD规范的代码推演 1. UMD规范 地址&#xff1a;https://github.com/umdjs/umd UMD规范&#xff0c;就是所有规范里长得最丑的那个&#xff0c;没有之一&#xff01;&#xff01;&#xff01;它是为了让模块同时兼容AMD和CommonJs规范而出现的&#x…

Missing artifact log4j:log4j:bundle:1.2.17

为什么80%的码农都做不了架构师&#xff1f;>>> maven引入log4jjar包出现Missing artifact log4j:log4j:bundle:1.2.17&#xff0c;解决方法是去掉bundle&#xff0c;其他的解决方案可以参考maven log4j.jar问题 Maven使用log4j可能会有协议上的问题 如果log4j的版…

PHPStorm 配置远程服务器文件夹在本地windows镜像,实现代码自动同步(类似于Samba架构文件同步功能)

场景介绍&#xff1a; 这是一种类似samba架构&#xff0c;也和 filezillaxshell 模式相类似的代码文件同步的模式&#xff0c;但是却更加优雅&#xff0c;也更加方便简洁。环境介绍&#xff1a; 本地windows端&#xff1a;编辑器phpstorm 远程Linux端&#xff1a;centos&#x…

反向ajax实现

在过去的几年中&#xff0c;web开发已经发生了很大的变化。现如今&#xff0c;我们期望的是能够通过web快速、动态地访问应用。在这一新的文章系列中&#xff0c;我们学习如何使用反 向Ajax&#xff08;Reverse Ajax&#xff09;技术来开发事件驱动的web应用&#xff0c;以此来…

linux系统启动流程及常见问题的解决

一、前言计算机开机是一个神秘的过程。我们只是按了开机键&#xff0c;就看到屏幕上的进度条或者一行行的输出&#xff0c;直到我们到达登录界面。然而&#xff0c;计算机开机又是个异常脆弱的过程&#xff0c;我们满心期望的登录界面可能并不会出现&#xff0c;而是一个命令行…

使用.NET开发一个屏幕OCR工具

本文将介绍使用.NET开发的一款桌面截图 OCR 工具&#xff0c;软件已开源&#xff0c;地址&#xff1a;https://github.com/sangyuxiaowu/Snipping_OCR背景因为不同地方人们的使用习惯不同&#xff0c;国内可能截图更多的是使用QQ&#xff0c;微信等即时聊天工具提供的截图功能。…

Linux开启fileinfo扩展

在项目初始部署环境的时候&#xff0c;可能考虑的并不全面&#xff0c;就会少装一些扩展&#xff0c;这里讲解如何添加fileinfo扩展1、找到php安装的压缩包2、将压缩包cp到 /data目录下&#xff0c;并解压 cp php-7.0.30.tar.gz /data cd /data tar -zxvf php-7.0.30.tar.gz…

Layui版本的WPF开源控件库-Layui-WPF

大家好&#xff0c;我是沙漠尽头的狼。今天介绍一款Layui风格的WPF开源控件库&#xff0c;仓库信息如下&#xff1a;仓库地址&#xff1a;https://github.com/Layui-WPF-Team/Layui-WPF仓库截图&#xff1a;Layui-WPF关于Layui请点击此链接[1]了解&#xff0c;本文不做介绍&…

Mycat 之 通过Keepalived 实现高可用

一、系统拓扑图 一、操作方法 参考本博客的Nginx Keepalived 实现高可用转载于:https://blog.51cto.com/12965094/2164485