
ABP Framework 在架构上有四大目标:模块化、DDD、多租户和微服务。从 7.0 更新的功能来看,其侧重点转向微服务场景的实现,比如:Dapr 集成、动态权限和功能、外部本地化、分布式实体缓存服务,都是对微服务和分布式架构所提出的解决方案。
ABP Framework 已然在成为优雅的 .NET 微服务基础设施道路上开始狂奔!
欢迎加入 ABP Framework 研习社,千人学习群(QQ群:726299208),问题解答、经验分享、示例源码、电子书共享,欢迎入住!
转载出处:https://www.cnblogs.com/YGYH/p/16921860.html (编程悟道)
本版本中的重要特性
7.04.07.0紧跟 .NET 升级步伐,ABP Framework 解决方案升级到 .NET 7.0 。
4.0OpenIddict 4.0 预览版于2022年6月22日发布,在 ABP 7.0 中 OpenIddict Nuget包引用升级到 4.0-preview。一旦 OpenIddict 4.0 最终版本发布,也会立即同步升级到稳定版本,并计划使 ABP 7.0 最终版使用 OpenIddict 4.0 稳定版本。
阅读 OpenIddict 4.0 preview1 is out 了解 OpenIddict 4.0 新功能。
Dapr,分布式应用程序运行时,提供API简化微服务开发。ABP 和 Dapr 有一些相互交叉的功能和特性,如服务对服务通信、分布式消息总线和分布式锁定。需要注意的是:ABP 和 Dapr 目的是不同的。ABP 目标是提升端到端开发体验,例如:框架提供的客户端与服务器端动静态代理、服务器端远程服务调用,极大地提升了开发体验;而 Dapr 目的是提供一个运行时,将常见的微服务通信模式与应用程序逻辑进行解耦。
ABP 7.0 提供了一些包,可以更好地与 Dapper 集成。我将在下面介绍一些重要的集成注意事项,但如果您想获得 ABP Dapr 集成的全面概述,请参阅ABP Dapr集成文档。
ABP 分布式事件总线系统允许应用程序通过事件进行异步通信,系统提供了抽象层,扩展友好可以基于不同的通信技术来实现,前面的版本已经提供基于 RabbitMQ、Kafka、Rebus、Azure Service Bus 的实现。
本版本新增 Volo.Abp.EventBus.Dapr 和 Volo.Abp.AspNetCore.Mvc.Dapr.EventBus 包,使 ABP 分布式事件总线有了基于 Dapr 基础设施的实现。Volo.Abp.EventBus.Dapr包用于发布事件,Volo.Abp.AspNetCore.Mvc.Dapr.EventBus 包用于订阅事件。
ABP可以生成动态或静态代理类,实现从 .NET 客户端应用程序调用 HTTP API。
Volo.Abp.Http.Client.Dapr 包用于配置客户端代理系统,以方便地使用 Dapr 服务来调用构建块,实现应用程序之间的通信。
ABP 提供分布式锁定来控制多个应用程序对共享资源的访问。Volo.Abp.DistributedLocking.Dapr 包使 ABP 使用 Dapr 分布式锁构建块。
ABP 7.0 提供选项类
AbpDistributedLockOptions来配置分布式锁,可以指定任何名称作为锁前缀。
集成服务用来将为模块间(或微服务间)通信而构建的应用服务与为用户界面或客户端应用程序使用的应用程序服务进行区分。
在 ABP 7.0 中,可以使用 [IntegrationService] 特性(在 Volo.Abp.Application.Services 命名空间中定义)将应用服务标记为集成服务。例子:
[IntegrationService]
public class ProductAppService : ApplicationService, IProductAppService
{
// ...
}
如果对应用服务定义了接口,比如 IProductService,还可以在服务接口上使用:
[IntegrationService]
public interface IProductAppService : IApplicationService
{
// ...
}
使用特性标记的服务,ABP 将按照约定执行以下操作:
/integration-api/ 而不是 /api/。通过这种方式,就可以在微服务系统中阻止 API网关 对集成服务 API 的调用,并且不授权这些服务。在自动创建API控制器时,还可以使用 ConventionalControllerSetting 对象 ApplicationServiceTypes 选项设置是否包含集成服务。AbpAuditingOptions 选项类中将 IsEnabledForIntegrationServices 设置为true,为集成服务启用审计日志记录。在 ABP Framework 中,权限和功能在项目中通过代码定义。基于此设计,在不同微服务中定义权限(或功能)以及在单独应用中对所有权限进行集中管理,变得很困难。为了实现权限管理,需要一个单独的微服务,并添加所有微服务的服务契约项目引用,以知道所有微服务的权限(和功能)并管理它们。因此,只要任何一个微服务的权限发生变化,就需要重新部署权限管理微服务。
在 7.0 中,我们引入动态授权和动态功能系统。参看如下图:

在 微服务1中定义权限 A 和 B,在微服务2中定义权限C D E ,在微服务中通过引用权限类库,直接将权限信息写入到授权管理数据库中。通过权限管理微服务提供权限管理UI管理用户的所有权限。
在 ABP 7.0 的解决方案中,所有微服务都序列化自己的权限定义,并在应用程序启动时将它们写入权限管理共享数据库(使用高度优化的算法)。另一方面,权限管理服务可以动态地从数据库获取这些权限定义(也经过了高度优化,以减少数据库的使用),并允许UI为用户或角色显示和管理它们。这些操作都是在框架内自动工作的。
如果你想知道为什么做出这些决定以及解决了什么问题,可以参看 分布式和微服务系统的授权解决方案 。
本地化是微服务系统中的另一个问题,当每个微服务定义了自己的本地化文本,在构建一个统一的UI应用程序时,实现 IExternalLocalizationStore 来获得其他服务的本地化。
目前 ABP Framework 没有提供动态本地化的模块 。如果我们从社区得到大量的请求,后面可能会添加到的开源计划中,大家一起来投票 #13953 ,推动早点实现。
在 7.0 中 ABP 引入了分布式实体缓存服务。假设有一个 Product 实体,实际上是一个聚合根:
public class Product : AggregateRoot<Guid>
{
public string Name { get; set; }
public string Description { get; set; }
public float Price { get; set; }
public int StockCount { get; set; }
}
希望使用缓存来提高访问产品的速度。首先应该在模块类的 ConfigureServices 方法中配置依赖注入来注册 IEntityCache服务:
context.Services.AddEntityCache<Product, Guid>();
然后,只需要注入 IEntityCache<Product, Guid> 服务即可。
public class ProductAppService : ApplicationService
{
private readonly IEntityCache<Product, Guid> _productCache;
public ProductAppService(IEntityCache<Product, Guid> productCache)
{
_productCache = productCache;
}
public async Task<ProductDto> GetAsync(Guid id)
{
var product = await _productCache.GetAsync(id);
return ObjectMapper.Map<Product, ProductDto>(product);
}
}
示例代码中,假设将对象映射配置为从 Product 映射到 ProductDto 。
在这里,直接缓存了 Product 对象。在这种情况下,Product 类必须是可序列化的,因为在分布式缓存中被序列化为JSON格式保存。
在某些情况下,可能希望使用另一个类来存储缓存数据。例如,对于缓存对象,可能希望使用 ProductDto 类而不是 Product 类。在这种情况下,更改依赖注入配置如下:
context.Services.AddEntityCache<Product, ProductDto, Guid>();
会注入 IEntityCache<ProductDto, Guid> 服务代替 IEntityCache<Product, Guid> 服务。
可以通过将 DistributedCacheEntryOptions 对象传递给 AddEntityCache 方法来配置缓存的持续时间:
context.Services.AddEntityCache<Product, ProductDto, Guid>(
new DistributedCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(30)
}
);
默认的缓存持续时间是2分钟,使用 AbsoluteExpirationRelativeToNow 配置。
该 PR 中包含关于分布式实体缓存的附加说明。
布局钩子系统允许你向布局的某些特定部分添加代码,ABP 框架提供的所有主题布局都实现了布局钩子。
如果你想在Blazor应用程序中使用布局钩子,可以阅读 Blazor UI: Layout Hooks 文档,并查看所需的配置。
在这个版本中,eShopOnAbp 项目进行了以下改进:
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建
在我的一些Controller中,我有一个before_filter检查用户是否登录?用于CRUD操作。application.rbdeflogged_in?unlesscurrent_userredirect_toroot_pathendendprivatedefcurrent_user_sessionreturn@current_user_sessionifdefined?(@current_user_session)@current_user_session=UserSession.findenddefcurrent_userreturn@current_userifdefine
require'pp'p*1..10这会打印出1-10。为什么这么简洁?您还可以用它做什么? 最佳答案 它是“splat”运算符。它可用于分解数组和范围并在赋值期间收集值。这里收集赋值中的值:a,*b=1,2,3,4=>a=1b=[2,3,4]在此示例中,内部数组([3,4])中的值被分解并收集到包含数组中:a=[1,2,*[3,4]]=>a=[1,2,3,4]您可以定义将参数收集到数组中的函数:deffoo(*args)pargsendfoo(1,2,"three",4)=>[1,2,"three",4]
我正在使用最新版本的Rails,启动一个我将在3.1发布后部署的新应用程序,但我无法让omniauth工作。如果我只是将omniauth添加到我的Gemfile,它会bundle起来,但是当我运行rake、railss或几乎所有命令时,它会出错:nosuchfiletoload--omniauth/password有什么想法吗?是否有适用于Rails3.1的分支或分支?还是只有我遇到这个问题? 最佳答案 实际问题是bundler选择了旧版本的omniauth。为了帮助bundler选择正确的版本,请使用:gem'omniauth',
我读过的关于Ruby符号的每一篇文章都在谈论符号相对于字符串的效率。但是,这不是1970年代。我的电脑可以处理一些额外的垃圾收集。我错了吗?我拥有最新最好的奔腾双核处理器和4GBRAM。我认为这应该足以处理一些字符串。 最佳答案 您的计算机可能能够处理“一点点额外的垃圾收集”,但是当“一点点”发生在运行数百万次的内部循环中时呢?如果它在内存有限的嵌入式系统上运行呢?有很多地方你可以随意使用字符串,但在某些地方你不能。这完全取决于上下文。 关于ruby-现代计算机的功能是否不足以处理字符串
我正在使用Windows并尝试运行一个现有的功能包,该功能包最初是在MacOS上构建的,这允许他们通过使用带空格的"\"来解决问题。我正在使用Ruby2.2.3和Cucumber。功能名称包含空格,我无法更改它。我尝试使用""和''来绕过空白,但每次都有同样的问题。这是问题的一个例子。如果我运行:cucumberfeatures/'Namecontainingwhitespaces.feature'它工作正常。但是当我运行时:cucumber-pmy_profile和cucumber.yml包含:my_profile:features/'Namecontainingwhitespace
单元测试的好方法是测试脚本在执行之间保持正确数据的能力——在使用Ctrl-C终止脚本然后重新运行之后?是否有针对执行类似操作的现有模块或脚本的任何测试可以针对最佳实践进行审查? 最佳答案 像http://avdi.org/devblog/2010/07/19/greenletters-painless-automation-and-testing-for-command-line-applications/一样使用库或者期望、运行、终止并重新运行您的程序,并检查它是否运行正确。好的做法是将程序设计为独立的模块,每个模块都经过良好测试
昨晚看到IDEA官推宣布IntelliJIDEA2023.1正式发布了。简单看了一下,发现这次的新版本包含了许多改进,进一步优化了用户体验,提高了便捷性。至于是否升级最新版本完全是个人意愿,如果觉得新版本没有让自己感兴趣的改进,完全就不用升级,影响不大。软件的版本迭代非常正常,正确看待即可,不持续改进就会慢慢被淘汰!根据官方介绍:IntelliJIDEA2023.1针对新的用户界面进行了大量重构,这些改进都是基于收到的宝贵反馈而实现的。官方还实施了性能增强措施,使得Maven导入更快,并且在打开项目时IDE功能更早地可用。由于后台提交检查,新版本提供了简化的提交流程。IntelliJIDEA