ABP_Vnext_Microservice_Practice

2019/06/23 DotNetCore 共 7211 字,约 21 分钟

一些零碎的关于ABP整理的记录。automapper实体更新,

ABP_Vnext中实体的更新

参考官方文档:https://docs.abp.io/en/abp/4.4/Object-To-Object-Mapping 这个地方很容易忽视,造成实体对象无法更新写入数据库。

注意对比官方的使用,下面这里的代码写法是一种错误的写法。实体从数据库取出来之后,经过映射会自动跟踪,不需要再次赋值。否则会出现如下错误:

{"data":null,"succeed":false,"code":"500","msg":"The instance of entity type 'BgeInfo' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.","timeticks":1647597741807}

image-20220318180519469

AutoMapper正确更新Entity的步骤如下:先取出Entity实体,然后Dto映射实体,进行对实体的更新,映射的时候不再需要使用等号去赋值。

image-20220318175728940

ABP_Vnext微服务项目

ABP框架是基于规则和约定的,框架内部有非常多默认的规则和约定。

规则约定

Application层对外暴露的DTO会写在Application.Contracts中,而如果是Application层和Domain层交互使用的DTO则写在DomainShared中(内部交互)。

微服务

ABP_Vnext微服务架构,参考文档:ABP Framework微服务文档

IIS调试部署

参考:win10 IIS 托管DotNetCore

给windows添加IIS的时候,全部勾选上必要的选项;

然后win + R ,输入inetmgr 打开IIS管理面板。

win10_install_iis_2717.png

1.首先是在IIS中建立好一个Server,比如:Mywebsite,路径设置为C盘中的C:\inetpub\wwwroot\Mywebsite.然后把默认的APP池设置为No Managed Code。

defualt_pooling_2827.png

2.把项目属性中的debug环境设置Development改为Production,这是发布到IIS之前需要做的事情。

production_enviroment_18172.png

3.然后是发布到本地电脑的某个文件夹中:

publish_to_some_filepath_28271.png

4.这里设置Portable是为了让Dotnetcore程序可以运行在任何类型的操作系统环境中,是跨平台的,默认就是这么设置的。

deployment_settings_2827.png

5.如果是发布程序到C盘,那么请用administrator打开visual studio 2019并执行发布操作。

publish_visual_studio2019_18173.png

6.最后需要安装DotNetCore的Host模块。

参考微软官方文档:Host ASP.NET Core on Windows with IIS,直接下载最新版本的Hosting Bundle。

host_bundle_837.png

参考上面这个链接提供的信息,安装IIS的DotNet Host模块。安装完成之后,发布到IIS目录下面的项目就可以访问了。

iis_open_dotnetcore_2348.png

常见问题

IIS部署完微服务之后,访问本地微服务端口会报错,查看EventViewer能够发现更具体的报错信息,是因为我们把程序发布到C盘,系统盘没有访问权限导致的。

fabucuowu_873628.png

如果是发布DotNetCore程序到本地win10机器的C盘,会出现Access Denied 。需要配置文件夹访问权限。需要设置inetpub下面www文件夹的Everyone访问权限。参考资料 设置c盘inetpub_wwwroot目录权限

image-20211021063130600

image-20211021063215111

image-20211021063249095

给予全部访问权限即可,设置完成之后,发布到C盘inetpub/wwwroot目录下面的所有.net core程序访问权限就具备了。

生成Swagger文档没有注释

注意查看当前项目的Build设置,如果是处于Debug模式,则下图3个地方都要是Debug的路径和设置。如果是Release情况,则都要设置为Release的设置。必须一致,要不然不会生成带有注释的文档。

特别注意:如果频繁修改API接口的形参注释信息,最好是清空SwaggerXml路径下面的HttpApi.xml文件,重新生成。重新编译是不会生成的,一定要清理Clean项目,之后重新生成,会自动生成并刷新API备注那些信息。

gjNW9eOdi5

image-20211129140848556

T9dRff2kmu

在httpApi解决方案中配置:

..\GDBS.ProjectService.HttpApi.Hosting\SwaggerXml\GDBS.ProjectService.HttpApi.xml

image-20211130142730103

SwaggerXml文件不更新

image-20220124030121105

如果发现微服务中其他项目不能正确生成最新的xml Swagger文件,可以Edit Project file,来手动修复此问题。下面是一段关键的xml配置参考代码:

 <ItemGroup>
    <None Update="Dockerfile">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\ApplicationContracts.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\DomainShared.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\GDBS.BridgeService.Application.Contracts.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\GDBS.BridgeService.Domain.Shared.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\GDBS.BridgeService.HttpApi.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="SwaggerXml\HttpApi.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

架构中间件

网关这块目前使用的是Ocelot,据说微软官方开源的yarp性能更强。

wAfnnqPp5h

手动控制uow

手动控制uow(unitofwork): 首先是注入类:

 private readonly IUnitOfWorkManager _unitOfWorkManager;

然后是:

 using var uow = _unitOfWorkManager.Begin(requiresNew:true,isTransactional:true,timeout:15000);
//中间是数据库操作
await uow.CompleteAsync();

ABP切换其他数据库

在实际开发中经常会有要临时切换到其他的数据库,操作完成之后再切换回来的这种场景。也就是说我们想要临时去修改我们DbContext的链接字符串,怎么做呢?就是如下的做法:

可以参考ABP源码中 UnitOfWorkDbContextProvider.cs中的代码: DbContextCreationContext

private TDbContext CreateDbContext(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
        {
            var creationContext = new DbContextCreationContext(connectionStringName, connectionString);
            using (DbContextCreationContext.Use(creationContext))
            {
                var dbContext = CreateDbContext(unitOfWork);

                if (dbContext is IAbpEfCoreDbContext abpEfCoreDbContext)
                {
                    abpEfCoreDbContext.Initialize(
                        new AbpEfCoreDbContextInitializationContext(
                            unitOfWork
                        )
                    );
                }

                return dbContext;
            }
        }

上面的代码,实际上是用当前临时的connectionString去替代我们的DbContext中的那个连接字符串,使用完毕之后在dispose掉之后替换回原来的connectionString .替换成临时connectionString之后,再利用DbContextProvider去get到DbContext,得到的就是临时connectionstring对应的数据库,而不是confugure里面配置的原有DbContext. 以上方法来源于 :

 namespace Volo.Abp.Uow.EntityFrameworkCore
{
     public class UnitOfWorkDbContextProvider<TDbContext> : IDbContextProvider<TDbContext>
        where TDbContext : IEfCoreDbContext
    {
            private TDbContext CreateDbContext(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
        {    
            
        }
     }
 }

注意:要创建自己的DbContext需要再using里面创建,再using外面创建是没有用的。

Ocelot文档

参考:https://ocelot.readthedocs.io/en/latest/features/servicediscovery.html

用户名密码验证

ABP中主要是通过ResourceOwnerPasswordValidationContext 来验证用户UserNanem和Password。

ABP框架源码: TokenRequestValidator.cs 这个文件下面包括了主要的grantType验证方式。

如果是我们自己实现用户名和密码验证方式,我们需要自己实现IResourceOwnerPasswordValidator这个接口。

如果是web端走跳转的方式,一般是使用OIDC方式,也就是OpenIdConnect.

第三方验证登陆

在ABP框架源码的’abp-3.3.0\modules\identityserver’中,这个模块就是IdentityServer4相关的;

Volo.Abp.IdentityServer.AbpIdentityServerDomainModule文件中,76行代码开始的地方,

\abp-3.3.0\modules\identityserver\src\Volo.Abp.IdentityServer.Domain\Volo\Abp\IdentityServer\AbpIdentityServerDomainModule.cs
    
services.ExecutePreConfiguredActions(identityServerBuilder);

            if (!services.IsAdded<IPersistedGrantService>())
            {
                services.TryAddSingleton<IPersistedGrantStore, InMemoryPersistedGrantStore>();//保存登陆页信息的,GrantStore就是我们授权的信息,跳转到登陆页的时候,勾选的scope信息就是保存在这里
            }

            if (!services.IsAdded<IDeviceFlowStore>())
            {
                services.TryAddSingleton<IDeviceFlowStore, InMemoryDeviceFlowStore>();//设备信息
            }

            if (!services.IsAdded<IClientStore>())
            {
                identityServerBuilder.AddInMemoryClients(configuration.GetSection("IdentityServer:Clients"));
            }

            if (!services.IsAdded<IResourceStore>())
            {
                identityServerBuilder.AddInMemoryApiResources(configuration.GetSection("IdentityServer:ApiResources"));
                identityServerBuilder.AddInMemoryIdentityResources(configuration.GetSection("IdentityServer:IdentityResources"));
            }

//identityServerBuilder.AddExtensionGrantValidator<LinkLoginExtensionGrantValidator>();
//最后这句代码,是根据自己的需要在模块源码中自定义的,用来对接第三方登陆。比如对接第三方twitter或者google登陆到我们自己的系统。

公司的源码是基于ABP3.0.5的,如果要支持这个module扩展,可能需要升级。

Volo.Abp.IdentiyServer.EntityFrameworkCore这个是做持久化的,如果没有安装这个依赖,则会放到内存里面。

以下7个依赖项就可以搭建出自己的IdentityServer:

Volo.Abp.Identity.Application;
Volo.Abp.Identity.EntityFrameworkCore;
Volo.Abp.Identity.Web
Volo.Abp.IdentityServer.EntityFrameworkCore;
Volo.Abp.Account.Application;
Volo.Abp.Account.Web.IdentityServer;//这个是必选项
Volo.Abp.AspNetCore.Authentication.Jwtbearer//如果需要对外公开API就需要安装这个

基于IdentityServer4的管理后台

参考:https://github.com/skoruba/IdentityServer4.Admin

ABP Vnext中常见坑

微服务的时候最常见的就是注入的报错。

image-20211130111052131

上面这种Parameter’source’报错,一般都是注入的报错。

DbContext中的Service要和Application里面的一致

image-20211130152755250

要不然会发生某些Entity实体类注入的问题。

微服务接口调用的时候 400错误

在微服务之间Post调用接口的时候,被调用方的参数类型如果不能为空,没有打上问号,而调用方这边没有给默认值,那么缺省值就会是Null,导致被调用方参数检测的时候,直接报错,但是这个错误并不会反馈给调用者,调用者这边看到的只是400或者403错误。一般这种情况下,要约定好参数DTO,防止躺坑。

IIS不支持DELETE ,PUT谓词

解决办法参考:https://www.bbsmax.com/A/o75NxLwMzW/, 因为是本地调试,所以直接修改IIS,去掉WebDAV发布模块。重启win10即可搞定。如下:

image-20211214104435235

线上发布的是Linux服务器,用的是自托管,而windows调试的时候用的是iis托管,已经允许了所有谓词的情况下,还会出现某些API请求被拒绝的问题。

image-20211214104714603

如上,同样的两个方法,一个是在Linux上面部署,一个是本地localhost调试iis托管,出现DELETE操作405的情况。

image-20211214104823084

重启之后,在我们本地的API执行DELETE接口就成功了。

image-20211214105728787

前端配置注意事项

image-20211214163856253

原型设计

image-20211214193750720

DotNetCore进阶

Dapr + K8s的部署, CI/CD环境搭建。

ABP Vnext的SAAS模式开发。

跨服务调用报URI格式不正确

这种情况一般发生在API调用地址从qq里面传送的时候,编码发生变化,然后复制粘贴到visual studio里面,调试的时候肉眼是看不出来的,提交url给到同事的时候最好是确保url地址的编码格式正确。

文档信息

Search

    Table of Contents