ABP框架创建模块项目并集成现有项目的步骤

408 阅读4分钟

创建模块项目

一、使用模板创建项目

abp new Poi.RulesEngine -t module --no-ui

用这个模板,把多余的文件夹删掉,然后在 vs 中把对应的项目移除(这样就不会报错找不到项目)

如果用传统的方式,会议 DbMigrator

abp new Poi.RulesEngine -u none -d ef

使用app模板创建项目也行

需要将module中多余的部分删掉 应用层

image.png

 <ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
 </ItemGroup>

contracts层

 <ItemGroup>
   <PackageReference Include="Volo.Abp.Authorization" Version="$(AbpVersion)" />
   <PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="$(AbpVersion)" />
 </ItemGroup>

image.png Domain层

  <ItemGroup>
	<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
	<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
  </ItemGroup>

image.png 删除domain层中的迁移代码,删除这个Data文件夹,移除DbMigrator项目。删除Domain层的openiddict文件夹

image.png

删掉DomianModule中的这些代码,保留一个空的ConfigureServices。

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpLocalizationOptions>(options =>
        {
            options.Languages.Add(new LanguageInfo("ar", "ar", "العربية", "ae"));
            options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
            options.Languages.Add(new LanguageInfo("en", "en", "English", "gb"));
            options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));
            options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
            options.Languages.Add(new LanguageInfo("hr", "hr", "Croatian"));
            options.Languages.Add(new LanguageInfo("fi", "fi", "Finnish", "fi"));
            options.Languages.Add(new LanguageInfo("fr", "fr", "Français", "fr"));
            options.Languages.Add(new LanguageInfo("hi", "hi", "Hindi", "in"));
            options.Languages.Add(new LanguageInfo("it", "it", "Italiano", "it"));
            options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
            options.Languages.Add(new LanguageInfo("ru", "ru", "Русский", "ru"));
            options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak", "sk"));
            options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe", "tr"));
            options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
            options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
            options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
            options.Languages.Add(new LanguageInfo("es", "es", "Español"));
        });

        Configure<AbpMultiTenancyOptions>(options =>
        {
            options.IsEnabled = MultiTenancyConsts.IsEnabled;
        });

#if DEBUG
        context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());
#endif
    }

DomainShared层,DomainSharedModule中的ConfigureServices需要保留,那是配置使用本地化的代码,删了会报错。

image.png efcore层 注意,引用了公共的share层

  <ItemGroup>
	<ProjectReference Include="..\..\..\..\shared\Arim.Poi.Shared.EntityFrameworkCore\Arim.Poi.Shared.EntityFrameworkCore.csproj" />
    <ProjectReference Include="..\Arim.Poi.Ladle.Domain\Arim.Poi.Ladle.Domain.csproj" />
  </ItemGroup>

image.png 清除使用哪个数据库的代码 image.png ...DbContext 移除掉这些

image.png

image.png 删除migrator、factory、migrations

image.png

image.png

image.png

httpApi, 引用mvc的包

  <ItemGroup>
	<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(AbpVersion)" />
  </ItemGroup>

image.png

httpApiClient层可以去掉

单元测试项目里也有很多需要删掉的!

1、移除HttpApi.Client.ConsoleTestApp项目

2、Domain 移除这个文件夹 image.png

3、Application、ef core移除sample

image.png

二、重命名相应文件

重命名是为了符合所集成进的项目的命名规则

删除不需要的类库后,重新构建报错

要把外面这个解决方案也重命名了,重命名名字并以文本形式打开重命名里面内部的内容

修改项目名称时,要改掉这个 RootNameSpace,否则创建文件还会是原来的命名空间

启动报错依赖问题(这个也是项目的特有问题,主项目把依赖抽象成了变量,且使用内部的依赖库)

然后把 csproj 中的版本号全改成变量

把 common.props 中添加上变量

efcore 层报错(这个是 reder 的问题)

这个在 VS 中不报错,关闭 rider 后,重新启动就不报错了

有个坑,这个项目结构abpHelper无法识别,需要手写

image.png

配置生成xml描述文档

只有配了这个,接口的注释才会在swagger上显示,默认的项目中没有这个

image.png 下面就是生成的xml描述文件,右键项目-属性-生成,可以看到 image.png

详细步骤

更改名称

1、文件系统中

首先,关闭Visual Studio,然后在文件系统中将项目的文件夹名称从DynamicExpression改为Formula。

2、更改.sln 和.csproj 文件

重命名解决方案(.sln)和项目(.csproj)文件。你可以使用文件资源管理器来完成这个任务。

使用文本编辑器(如Notepad++或VS Code)打开解决方案(.sln)文件,将里面所有提到DynamicExpression的地方改为Formula。

使用文本编辑器打开项目文件(.csproj),将文件中所有的DynamicExpression引用更新为Formula。同时,将不正确的引用名称修改掉

3、把 common.props 文件也移动过来

4、替换命名空间

5、替换文件所有文件名称中的DynamaicExpression为Formula

Get-ChildItem -Recurse | Where-Object { $_.Name -match 'DynamicExpression' } | Rename-Item -NewName { $_.Name -replace 'DynamicExpression','Formula' }

集成进主项目

一、集成文件进项目

将源代码复制到对应的位置

1、创建两个解决方案文件夹

2、添加项目,选择 csproj 文件

3、挨个修改项目名称

至于这个文件,可以删掉,或者重命名其及其内部的文本(用记事本打开)

然后执行清理、重新构建操作

二、依赖相应模块

引用对应的层的模块即可

以审计日志为例

1、主项目 host 层 这里依赖的是官方模块的代码,不是依赖引入项目的模块的代码,引入一个新的模块,可不用配这层

加上筛选如何添加审计日志的选项

Configure<AbpAuditingOptions>(options =>
{
    options.IsEnabled = true;
    options.IsEnabledForAnonymousUsers = false;
    options.IsEnabledForIntegrationServices = false;
    options.ApplicationName = "Arim.Poi";
    options.DisableLogActionInfo = true;

    options.EntityHistorySelectors.Add(
        new NamedTypeSelector(
            "MySelectorName",
            type =>
                typeof(IAuditedObject).IsAssignableFrom(type) &&
                type.Namespace?.StartsWith("Arim.Poi.SteelLadle") == true
        )
    );
});

Configure<AbpAspNetCoreAuditingOptions>(options =>
    {
        options.IgnoredUrls.Add("/api/base");
        options.IgnoredUrls.Add("/api/def");
        options.IgnoredUrls.Add("/api/data-dictionary");
        options.IgnoredUrls.Add("/api/audit-logging");
    }
);

2、httpApi 层

经测试,不依赖这个 httpApiModule 也行,也能生成接口,但是是先依赖后报错又注释掉的

还是依赖了这个项目,难道这样也能生成 Api?

ProjectReference Include="......\modules\steel-ladle\src\Arim.Poi.SteelLadle.HttpApi\Arim.Poi.SteelLadle.HttpApi.csproj" />

3、ef core 层

image.png

EF Core 的 DbContext 集成

需要创建一个I...DbContext,将 DbSet 都放进来,然后模块的 DbContext 继承这个 I..DbContext

[ConnectionStringName(SteelLadleConsts.ConnectionStringName)]
public interface ISteelLadleDbContext : IEfCoreDbContext
{
    public DbSet<LadleState> LadleStates { get; set; }
    public DbSet<LadleRunPlan> LadleRunPlans { get; set; }
    public DbSet<LadleEvent> LadleEvents { get; set; }
    public DbSet<LadleEventPlan> LadleEventPlans { get; set; }
    
}
[ReplaceDbContext(typeof(IAuditLoggingDbContext))]

public class PoiDbContext :
    AbpDbContext<PoiDbContext>,
    IAuditLoggingDbContext,
    //...
{
    //把模块的DbContext中的东西搬过来
    public DbSet<AuditLog> AuditLogs { get; set; }
    public DbSet<EntityChange> EntityChanges { get; set; }

    protected override void OnModelCreating(ModelBuilder builder){
        //审计日志...
        builder.ConfigureAuditLogging();
    }
}

大坑、大坑、大坑!!!

要修改仓储的实现

  • 下面应该使用 DbContext 的抽象,而不是实现!!!否则使用这个仓储时,又跑到模块内部的Context实现了,而不是最外层的Context!!!
public class FormulaDefinitionRepository : EfCoreRepository<IDynamicExpressionDbContext, FormulaDefinition, Guid>, IFormulaDefinitionRepository
{
    private readonly IDbContextProvider<IDynamicExpressionDbContext> _dbContextProvider;
    public FormulaDefinitionRepository(IDbContextProvider<IDynamicExpressionDbContext> dbContextProvider) : base(dbContextProvider)
    {
        _dbContextProvider = dbContextProvider;
    }

}

4、应用层

需要引用 ApplicationModule 模块,否则会报错应用服务 I...Service 在控制器中无法依赖注入

三、暴露模块中的控制器的方法

在 httpApi 层新建一个 Controller

[Area(AuditLoggingRemoteServiceConsts.ModuleName)]
[RemoteService(Name = AuditLoggingRemoteServiceConsts.RemoteServiceName)]
[Route("api/audit-logging")]
public class AuditLoggingController( IAuditLogAppService auditLogAppService) : AuditLoggingBaseController
{
    /// <summary>
    /// 获取访问日志
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet("audit-logs")]
    public async Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogQueryDto input)
    {
        return await auditLogAppService.GetListAsync(input);
    }

}

禁用 Nullable 检查

在 application、application.contract、httpApi 层,删掉

<Nullable>enable</Nullable>

否则 string、object类型的不允许为空,在EF Core层映射到数据库的字段也不允许为空。删掉后string 类型的就允许为空了