创建模块项目
一、使用模板创建项目
abp new Poi.RulesEngine -t module --no-ui
用这个模板,把多余的文件夹删掉,然后在 vs 中把对应的项目移除(这样就不会报错找不到项目)
如果用传统的方式,会议 DbMigrator
abp new Poi.RulesEngine -u none -d ef
使用app模板创建项目也行
需要将module中多余的部分删掉 应用层
<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>
Domain层
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
</ItemGroup>
删除domain层中的迁移代码,删除这个Data文件夹,移除DbMigrator项目。删除Domain层的openiddict文件夹
删掉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需要保留,那是配置使用本地化的代码,删了会报错。
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>
清除使用哪个数据库的代码
...DbContext
移除掉这些
删除migrator、factory、migrations
httpApi, 引用mvc的包
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(AbpVersion)" />
</ItemGroup>
httpApiClient层可以去掉
单元测试项目里也有很多需要删掉的!
1、移除HttpApi.Client.ConsoleTestApp项目
2、Domain
移除这个文件夹
3、Application、ef core移除sample
二、重命名相应文件
重命名是为了符合所集成进的项目的命名规则
删除不需要的类库后,重新构建报错
要把外面这个解决方案也重命名了,重命名名字并以文本形式打开重命名里面内部的内容
修改项目名称时,要改掉这个 RootNameSpace,否则创建文件还会是原来的命名空间
启动报错依赖问题(这个也是项目的特有问题,主项目把依赖抽象成了变量,且使用内部的依赖库)
然后把 csproj 中的版本号全改成变量
把 common.props 中添加上变量
efcore 层报错(这个是 reder 的问题)
这个在 VS 中不报错,关闭 rider 后,重新启动就不报错了
有个坑,这个项目结构abpHelper无法识别,需要手写
配置生成xml描述文档
只有配了这个,接口的注释才会在swagger上显示,默认的项目中没有这个
下面就是生成的xml描述文件,右键项目-属性-生成,可以看到
详细步骤
更改名称
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 层
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 类型的就允许为空了