Browse Source

Merge branch 'rel-4.0' into dev

pull/6352/head
Yunus Emre Kalkan 5 years ago
parent
commit
2b18e14dee
  1. 49
      docs/en/Domain-Driven-Design-Implementation-Guide.md
  2. BIN
      docs/en/images/domain-driven-design-web-request-flow.png
  3. 44
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
  4. 148
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs
  5. 30
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AbpAuditLoggingDomainModule.cs
  6. 16
      modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs
  7. 36
      modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
  8. 40
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs
  9. 22
      modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/AbpTenantManagementApplicationContractsModule.cs
  10. 16
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs
  11. 20
      modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs

49
docs/en/Domain-Driven-Design-Implementation-Guide.md

@ -92,6 +92,8 @@ The picture below shows a Visual Studio Solution created using the ABP's [applic
The solution name is `IssueTracking` and it consists of multiple projects. The solution is layered by considering **DDD principles** as well as **development** and **deployment** practicals. The sub sections below explains the projects in the solution;
> Your solution structure may be slightly different if you choose a different UI or Database provider. However, the Domain and Application layers will be same and this is the essential point for the DDD perspective. See the [Application Startup Template](Startup-Templates/Application.md) document if you want to know more about the solution structure.
#### The Domain Layer
The Domain Layer is splitted into two projects;
@ -169,8 +171,53 @@ This design decision potentially allows you to use Entities and EF Core objects
### Execution Flow a DDD Based Application
TODO
The figure below shows a typical request flow for a web application that has been developed based on DDD patterns.
![](images/domain-driven-design-web-request-flow.png)
* The request typically begins by a user interaction on the UI (a *use case*) that causes an HTTP request to the server.
* An MVC Controller or a Razor Page Handler in the Presentation Layer (or in the Distributed Services Layer) handles the request and can perform some cross cutting concerns in this stage ([Authorization](Authorization.md), [Validation](Validation.md), [Exception Handling](Exception-Handling.md), etc.). A Controller/Page injects the related Application Service interface and calls its method(s) by sending and receiving DTOs.
* The Application Service use the Domain Objects (Entities, Repository interfaces, Domain Services, etc.) to implement the *use case*. Application Layer implements some cross cutting concerns (Authorization, Validation, etc.). An Application Service method should be a [Unit Of Work](Unit-Of-Work.md). That means it should be atomic.
Most of the cross cutting concerns are **automatically and conventionally implemented by the ABP Framework** and you typically don't need to write code for them.
### Common Principles
Before going into details, let's see some overall DDD principles;
#### Database Provider / ORM Independence
The domain and application layers should be ORM / Database Provider agnostic. They only depends on the Repository interfaces and the Repository interfaces doesn't use any ORM specific objects.
Here, the main reasons of this principle;
1. To make your domain/application **infrastructure independent** since the infrastructure may change in the future or you may need to support a second database type later.
2. To make your domain/application **focus on the business code** by hiding the infrastructure details behind the repositories.
3. To make your **automated tests** easier since you can mock the repositories in this case.
> As a respect to this principle, none of the projects in the solution has reference to the `EntityFrameworkCore` project, except the startup application.
##### Discussion About the Database Independence Principle
Especially, the **reason 1** deeply effects your domain **object design** (especially, the entity relations) and **application code**. Assume that you are using [Entity Framework Core](Entity-Framework-Core.md) with a relational database. If you try to make your application so that it is possible to switch to [MongoDB](MongoDB.md) later, you can't use some very **useful EF Core features**. Examples;
* You can't assume [Change Tracking](https://docs.microsoft.com/en-us/ef/core/querying/tracking) since MongoDB provider can't do it. So, you always need to explicitly update the changed entities.
* You can't use [Navigation Properties](https://docs.microsoft.com/en-us/ef/core/modeling/relationships) (or Collections) to other Aggregates in your entities since this is not possible for a Document Database. See the "Rule: Reference Other Aggregates Only By Id" section for more info.
If you think such features are **important** for you and you **will never move away** from the EF Core, we believe that it is worth **relaxing this principle**. We still suggest to use the repository pattern to hide the infrastructure details. But you can assume that you are using EF Core while designing your entity relations and writing your application code. You can even reference to the EF Core NuGet Package from your application layer to be able to directly use the asynchronous LINQ extension methods, like `ToListAsync()` (see the *IQueryable & Async Operations* section in the [Repositories](Repositories.md) document for more info).
#### Presentation Technology Agnostic
The presentation technology (UI Framework) is one of the most changed parts of a real world application. It is very important to design the **Domain and Application Layers** to be completely **unaware** of the presentation technology/framework. This principle is relatively easy to implement and ABP's startup template makes it even easier.
In some cases, you may need to have **duplicate logic** in the application and presentation layers. For example, you may need to duplicate the **validation** and **authorization** checks in both layers. The checks in the UI layer is mostly for **user experience** while checks in the application and domain layers are for **security and data integrity**. That's perfectly normal and necessary.
#### Focus on the State Changes, Not Reporting
DDD focuses on how the domain objects **changes and interactions**; How to create an entity and change its properties by preserving the data **integrity/validity** and implementing the **business rules**.
DDD **ignores reporting** and mass querying. That doesn't mean they are not important. If your application doesn't have fancy dashboards and reports, who would use it? However, reporting is another topic. You typically want to use the full power of the SQL Server or even use a separate data source (like ElasticSearch) for reporting purpose. You will write optimized queries, create indexes and even stored procedures(!). You are free to do all as long as you don't mix all these into your business logic.
## Implementation: The Building Blocks
TODO

BIN
docs/en/images/domain-driven-design-web-request-flow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

44
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs

@ -53,6 +53,12 @@ namespace Volo.Abp.Cli.Commands.Services
var zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null)
{
if (IsAngularTestFile(zipEntry.Name))
{
zipEntry = zipInputStream.GetNextEntry();
continue;
}
var fullZipToPath = Path.Combine(outputFolder, zipEntry.Name);
var directoryName = Path.GetDirectoryName(fullZipToPath);
@ -81,5 +87,43 @@ namespace Volo.Abp.Cli.Commands.Services
Logger.LogInformation($"'{moduleName}' has been successfully downloaded to '{outputFolder}'");
}
private bool IsAngularTestFile(string zipEntryName)
{
if (string.IsNullOrEmpty(zipEntryName))
{
return false;
}
if (zipEntryName.Contains(Path.Combine("angular/e2e")))
{
return true;
}
if (zipEntryName.Contains(Path.Combine("angular/src")))
{
return true;
}
if (zipEntryName.Contains(Path.Combine("angular/node_modules")))
{
return true;
}
if (zipEntryName.Contains(Path.Combine("angular/scripts")))
{
return true;
}
if (zipEntryName.Contains(Path.Combine("angular/source-code-requirements")))
{
return true;
}
var fileName = Path.GetFileName(zipEntryName);
if (!string.IsNullOrEmpty(fileName) && zipEntryName.Equals("angular/" + fileName))
{
return true;
}
return false;
}
}
}

148
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs

@ -33,17 +33,13 @@ namespace Volo.Abp.Cli.ProjectModification
return;
}
await ReplaceProjectNamesAndCopySourCodeRequirementsToProjectsAsync(angularProjectsPath, projects);
await RemoveRedundantFilesAsync(angularProjectsPath, projects);
await AddPathsToTsConfigAsync(angularPath, angularProjectsPath, projects);
await AddProjectToAngularJsonAsync(angularPath, projects);
}
catch (Exception e)
{
Logger.LogError( "Unable to add angular source code: " + e.Message);
Logger.LogError("Unable to add angular source code: " + e.Message);
}
}
@ -54,7 +50,7 @@ namespace Volo.Abp.Cli.ProjectModification
var json = JObject.Parse(fileContent);
var projectsJobject = (JObject)json["projects"];
var projectsJobject = (JObject) json["projects"];
foreach (var project in projects)
{
@ -62,126 +58,88 @@ namespace Volo.Abp.Cli.ProjectModification
new JProperty("projectType", "library"),
new JProperty("root", $"projects/{project}"),
new JProperty("sourceRoot", $"projects/{project}/src"),
new JProperty("prefix", "lib"),
new JProperty("prefix", "abp"),
new JProperty("architect", new JObject(
new JProperty("build", new JObject(
new JProperty("builder", "@angular-devkit/build-ng-package:build"),
new JProperty("builder", "@angular-devkit/build-ng-packagr:build"),
new JProperty("options", new JObject(
new JProperty("tsConfig", $"projects/{project}/tsconfig.lib.json"),
new JProperty("project", $"projects/{project}/ng-package.json")
)),
)),
new JProperty("configurations", new JObject(
new JProperty("production", new JObject(
new JProperty("tsConfig", $"projects/{project}/tsconfig.lib.prod.json")))
)))),
new JProperty("test", new JObject(
new JProperty("builder", "@angular-devkit/build-angular:karma"),
new JProperty("builder", "@angular-builders/jest:run"),
new JProperty("options", new JObject(
new JProperty("main", $"projects/{project}/src/test.ts"),
new JProperty("tsConfig", $"projects/{project}/tsconfig.spec.json"),
new JProperty("karmaConfig", $"projects/{project}/karma.conf.js")
new JProperty("coverage", true),
new JProperty("passWithNoTests", true)
)
))),
new JProperty("lint", new JObject(
new JProperty("builder", "@angular-devkit/build-angular:tslint"),
new JProperty("options", new JObject(
new JProperty("tsConfig", new JArray(new JValue($"projects/{project}/tsconfig.lib.json"), new JValue($"projects/{project}/tsconfig.spec.json"))),
new JProperty("tsConfig",
new JArray(new JValue($"projects/{project}/tsconfig.lib.json"),
new JValue($"projects/{project}/tsconfig.spec.json"))),
new JProperty("exclude", new JArray(new JValue("**/node_modules/**")))
))
))
))
));
))
));
}
File.WriteAllText(angularJsonFilePath, json.ToString(Formatting.Indented));
}
private async Task AddPathsToTsConfigAsync(string angularPath, string angularProjectsPath, List<string> projects)
private async Task AddPathsToTsConfigAsync(string angularPath, string angularProjectsPath,
List<string> projects)
{
var tsConfigPath = Path.Combine(angularPath, "tsconfig.json");
var fileContent = File.ReadAllText(tsConfigPath);
var tsConfigAsJson = JObject.Parse(fileContent);
var compilerOptions = (JObject)tsConfigAsJson["compilerOptions"];
var compilerOptions = (JObject) tsConfigAsJson["compilerOptions"];
foreach (var project in projects)
{
var projectPackageName = await GetProjectPackageNameAsync(angularProjectsPath, project);
var property = new JProperty($"{projectPackageName}",
new JArray(new object[] { $"projects/{project}/src/public-api.ts" })
);
var property2 = new JProperty($"{projectPackageName}/*",
new JArray(new object[] { $"projects/{project}/src/lib/*" })
);
var publicApis = Directory.GetFiles(Path.Combine(angularProjectsPath, project), "*public-api.ts", SearchOption.AllDirectories)
.Where(p => !p.Contains("\\node_modules\\"))
.Select(p => p.RemovePreFix(angularPath).Replace("\\", "/").RemovePreFix("/"));
if (compilerOptions["paths"] == null)
{
compilerOptions.Add("paths", new JObject());
}
((JObject)compilerOptions["paths"]).Add(property);
((JObject)compilerOptions["paths"]).Add(property2);
}
File.WriteAllText(tsConfigPath, tsConfigAsJson.ToString(Formatting.Indented));
}
private async Task<string> GetProjectPackageNameAsync(string angularProjectsPath, string project)
{
var packageJsonPath = Path.Combine(angularProjectsPath, project, "package.json");
var fileContent = File.ReadAllText(packageJsonPath);
return (string)JObject.Parse(fileContent)["name"];
}
private async Task RemoveRedundantFilesAsync(string angularProjectsPath, List<string> projects)
{
foreach (var project in projects)
{
var jestConfigPath = Path.Combine(angularProjectsPath, project, "jest.config.js");
if (File.Exists(jestConfigPath))
foreach (var publicApi in publicApis)
{
File.Delete(jestConfigPath);
}
var subFolderName = publicApi.RemovePreFix($"projects/{project}/").Split("/")[0];
var testPath = Path.Combine(angularProjectsPath, project, "src", "test.ts");
if (subFolderName == "src")
{
subFolderName = "";
}
else
{
subFolderName = $"/{subFolderName}";
}
if (File.Exists(testPath))
{
File.Delete(testPath);
((JObject) compilerOptions["paths"]).Add(
new JProperty($"{projectPackageName}{subFolderName}",
new JArray(new object[] {publicApi})
)
);
}
}
}
private async Task ReplaceProjectNamesAndCopySourCodeRequirementsToProjectsAsync(string angularProjectsPath, List<string> projects)
{
foreach (var project in projects)
{
var sourceCodeReqFolder = Path.Combine(angularProjectsPath, project, "source-code-requirements");
Directory.CreateDirectory(sourceCodeReqFolder);
var filesUnderSourceCodeReqFolder = Directory.GetFiles(sourceCodeReqFolder);
foreach (var fileUnderSourceCodeReqFolder in filesUnderSourceCodeReqFolder)
{
var newDest = Path.Combine(angularProjectsPath, project, Path.GetFileName(fileUnderSourceCodeReqFolder));
File.Move(fileUnderSourceCodeReqFolder, newDest);
var fileContent = File.ReadAllText(newDest);
fileContent = fileContent.Replace("{{project-name}}", project);
fileContent = fileContent.Replace("{{library-name-kebab-case}}", project);
File.WriteAllText(newDest, fileContent);
}
}
File.WriteAllText(tsConfigPath, tsConfigAsJson.ToString(Formatting.Indented));
}
private async Task<List<string>> CopyAndGetNamesOfAngularProjectsAsync(string solutionFilePath, string angularProjectsPath)
private async Task<List<string>> CopyAndGetNamesOfAngularProjectsAsync(string solutionFilePath,
string angularProjectsPath)
{
var projects = new List<string>();
@ -190,25 +148,40 @@ namespace Volo.Abp.Cli.ProjectModification
Directory.CreateDirectory(angularProjectsPath);
}
var angularPathsInDownloadedSourceCode = Directory.GetDirectories(Path.Combine(Path.Combine(Path.GetDirectoryName(solutionFilePath), "modules"))).Select(p => Path.Combine(p, "angular"))
var angularPathsInDownloadedSourceCode = Directory
.GetDirectories(Path.Combine(Path.Combine(Path.GetDirectoryName(solutionFilePath), "modules")))
.Select(p => Path.Combine(p, "angular"))
.Where(Directory.Exists);
foreach (var folder in angularPathsInDownloadedSourceCode)
{
var projectsInFolder = Directory.GetDirectories(folder);
if (projectsInFolder.Length == 1 && Path.GetFileName(projectsInFolder[0]) == "projects")
{
var foldersUnderProject = Directory.GetDirectories(Path.Combine(folder, "projects"));
foreach (var folderUnderProject in foldersUnderProject)
{
if (Directory.Exists(Path.Combine(folder, Path.GetFileName(folderUnderProject))))
{
continue;
}
Directory.Move(folderUnderProject, Path.Combine(folder, Path.GetFileName(folderUnderProject)));
}
projectsInFolder = Directory.GetDirectories(folder);
}
foreach (var projectInFolder in projectsInFolder)
{
var projectName = Path.GetFileName(projectInFolder.TrimEnd('\\').TrimEnd('/'));
var destDirName = Path.Combine(angularProjectsPath, projectName);
if (Directory.Exists(destDirName))
if (projectName == "projects" || Directory.Exists(destDirName))
{
Directory.Delete(projectInFolder, true);
continue;
}
projects.Add(projectName);
Directory.Move(projectInFolder, destDirName);
@ -217,5 +190,14 @@ namespace Volo.Abp.Cli.ProjectModification
return projects;
}
private async Task<string> GetProjectPackageNameAsync(string angularProjectsPath, string project)
{
var packageJsonPath = Path.Combine(angularProjectsPath, project, "package.json");
var fileContent = File.ReadAllText(packageJsonPath);
return (string) JObject.Parse(fileContent)["name"];
}
}
}

30
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AbpAuditLoggingDomainModule.cs

@ -3,6 +3,7 @@ using Volo.Abp.Domain;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.AuditLogging
{
@ -11,25 +12,30 @@ namespace Volo.Abp.AuditLogging
[DependsOn(typeof(AbpAuditLoggingDomainSharedModule))]
public class AbpAuditLoggingDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,
AuditLoggingModuleExtensionConsts.EntityNames.AuditLog,
typeof(AuditLog)
);
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,
AuditLoggingModuleExtensionConsts.EntityNames.AuditLogAction,
typeof(AuditLogAction)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,
AuditLoggingModuleExtensionConsts.EntityNames.AuditLogAction,
typeof(AuditLogAction)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,
AuditLoggingModuleExtensionConsts.EntityNames.EntityChange,
typeof(EntityChange)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
AuditLoggingModuleExtensionConsts.ModuleName,
AuditLoggingModuleExtensionConsts.EntityNames.EntityChange,
typeof(EntityChange)
);
});
}
}
}

16
modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs

@ -5,6 +5,7 @@ using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Users;
using Volo.Abp.Threading;
namespace Volo.Abp.Identity
{
@ -17,6 +18,8 @@ namespace Volo.Abp.Identity
)]
public class AbpIdentityApplicationContractsModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void ConfigureServices(ServiceConfigurationContext context)
{
@ -24,23 +27,24 @@ namespace Volo.Abp.Identity
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToApi(
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToApi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.Role,
getApiTypes: new[] { typeof(IdentityRoleDto) },
createApiTypes: new[] { typeof(IdentityRoleCreateDto) },
updateApiTypes: new[] { typeof(IdentityRoleUpdateDto) }
);
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToApi(
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToApi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.User,
getApiTypes: new[] { typeof(IdentityUserDto) },
createApiTypes: new[] { typeof(IdentityUserCreateDto) },
updateApiTypes: new[] { typeof(IdentityUserUpdateDto) }
);
});
}
}
}
}

36
modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs

@ -11,6 +11,7 @@ using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.PermissionManagement.Web;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.Threading;
namespace Volo.Abp.Identity.Web
{
@ -20,6 +21,8 @@ namespace Volo.Abp.Identity.Web
[DependsOn(typeof(AbpAspNetCoreMvcUiThemeSharedModule))]
public class AbpIdentityWebModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
@ -65,21 +68,24 @@ namespace Volo.Abp.Identity.Web
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.Role,
createFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.CreateModalModel.RoleInfoModel) },
editFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.EditModalModel.RoleInfoModel) }
);
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.User,
createFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel.UserInfoViewModel) },
editFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.EditModalModel.UserInfoViewModel) }
);
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.Role,
createFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.CreateModalModel.RoleInfoModel) },
editFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.EditModalModel.RoleInfoModel) }
);
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
IdentityModuleExtensionConsts.ModuleName,
IdentityModuleExtensionConsts.EntityNames.User,
createFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel.UserInfoViewModel) },
editFormTypes: new[] { typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.EditModalModel.UserInfoViewModel) }
);
});
}
}
}

40
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs

@ -20,6 +20,7 @@ using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.Security;
using Volo.Abp.Validation;
using Volo.Abp.Threading;
namespace Volo.Abp.IdentityServer
{
@ -34,6 +35,8 @@ namespace Volo.Abp.IdentityServer
)]
public class AbpIdentityServerDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpIdentityServerDomainModule>();
@ -102,23 +105,26 @@ namespace Volo.Abp.IdentityServer
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.Client,
typeof(Client)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.IdentityResource,
typeof(IdentityResource)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.ApiResource,
typeof(ApiResource)
);
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.Client,
typeof(Client)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.IdentityResource,
typeof(IdentityResource)
);
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
IdentityServerModuleExtensionConsts.ModuleName,
IdentityServerModuleExtensionConsts.EntityNames.ApiResource,
typeof(ApiResource)
);
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)

22
modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/AbpTenantManagementApplicationContractsModule.cs

@ -2,6 +2,7 @@
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.TenantManagement
{
@ -10,16 +11,21 @@ namespace Volo.Abp.TenantManagement
typeof(AbpTenantManagementDomainSharedModule))]
public class AbpTenantManagementApplicationContractsModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToApi(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
getApiTypes: new[] { typeof(TenantDto) },
createApiTypes: new[] { typeof(TenantCreateDto) },
updateApiTypes: new[] { typeof(TenantUpdateDto) }
);
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToApi(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
getApiTypes: new[] { typeof(TenantDto) },
createApiTypes: new[] { typeof(TenantCreateDto) },
updateApiTypes: new[] { typeof(TenantUpdateDto) }
);
});
}
}
}

16
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs

@ -7,6 +7,7 @@ using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectExtending.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.TenantManagement
{
@ -17,6 +18,8 @@ namespace Volo.Abp.TenantManagement
[DependsOn(typeof(AbpAutoMapperModule))]
public class AbpTenantManagementDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpTenantManagementDomainModule>();
@ -34,11 +37,14 @@ namespace Volo.Abp.TenantManagement
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
typeof(Tenant)
);
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
typeof(Tenant)
);
});
}
}
}

20
modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs

@ -11,6 +11,7 @@ using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.TenantManagement.Web.Navigation;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.Threading;
namespace Volo.Abp.TenantManagement.Web
{
@ -20,6 +21,8 @@ namespace Volo.Abp.TenantManagement.Web
[DependsOn(typeof(AbpAutoMapperModule))]
public class AbpTenantManagementWebModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
@ -62,13 +65,16 @@ namespace Volo.Abp.TenantManagement.Web
public override void PostConfigureServices(ServiceConfigurationContext context)
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
createFormTypes: new[] { typeof(Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants.CreateModalModel.TenantInfoModel) },
editFormTypes: new[] { typeof(Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants.EditModalModel.TenantInfoModel) }
);
OneTimeRunner.Run(() =>
{
ModuleExtensionConfigurationHelper
.ApplyEntityConfigurationToUi(
TenantManagementModuleExtensionConsts.ModuleName,
TenantManagementModuleExtensionConsts.EntityNames.Tenant,
createFormTypes: new[] { typeof(Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants.CreateModalModel.TenantInfoModel) },
editFormTypes: new[] { typeof(Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants.EditModalModel.TenantInfoModel) }
);
});
}
}
}
Loading…
Cancel
Save