Browse Source

Merge remote-tracking branch 'abpframework/dev' into Translate

pull/2946/head
liangshiwei 6 years ago
parent
commit
eb37ec067d
  1. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  2. 664
      docs/en/Entity-Framework-Core-Migrations.md
  3. BIN
      docs/en/_resources/Diagrams.docx
  4. 4
      docs/en/docs-nav.json
  5. BIN
      docs/en/images/bookstore-second-database.png
  6. BIN
      docs/en/images/multiple-database-usage.png
  7. BIN
      docs/en/images/pmc-add-migration-initial-update-database.png
  8. BIN
      docs/en/images/pmc-add-migration-role-title.png
  9. 61
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/ButtonsDemo/ButtonsDemoViewComponent.cs
  10. 47
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/ButtonsDemo/Default.cshtml
  11. 105
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/TagHelpers/AbpComponentDemoSectionTagHelper.cs
  12. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/_ViewImports.cshtml
  13. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs
  14. 27
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
  15. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/AbpNuGetIndexUrlService.cs
  16. 25
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/MobileApp.cs
  17. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
  18. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs
  19. 7
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs
  20. 20
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/TemplateRandomSslPortStep.cs
  21. 36
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml
  22. 34
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs
  23. 28
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/BasicThemeDemoMenuContributor.cs
  24. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Components/Buttons/Index.cshtml
  25. 3
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Index.cshtml
  26. 12
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Index.cshtml.cs
  27. 9
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj
  28. 29
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/demo/styles/main.css
  29. 45
      npm/ng-packs/angular.json
  30. 8
      npm/ng-packs/apps/dev-app/src/app/app.component.ts
  31. 43
      npm/ng-packs/package.json
  32. 5
      npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts
  33. 2
      npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts
  34. 1
      npm/ng-packs/packages/core/ng-package.json
  35. 7
      npm/ng-packs/packages/core/package.json
  36. 21
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts
  37. 21
      npm/ng-packs/packages/core/src/lib/guards/auth.guard.ts
  38. 2
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  39. 2
      npm/ng-packs/packages/core/src/lib/states/profile.state.ts
  40. 2
      npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts
  41. 2
      npm/ng-packs/packages/core/src/lib/states/session.state.ts
  42. 2
      npm/ng-packs/packages/feature-management/src/lib/states/feature-management.state.ts
  43. 20
      npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts
  44. 2
      npm/ng-packs/packages/identity/src/lib/states/identity.state.ts
  45. 7
      npm/ng-packs/packages/permission-management/src/lib/states/permission-management.state.ts
  46. 12
      npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts
  47. 16
      npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts
  48. 7
      npm/ng-packs/packages/setting-management/src/lib/states/setting-management.state.ts
  49. 2
      npm/ng-packs/packages/tenant-management/src/lib/states/tenant-management.state.ts
  50. 4
      npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html
  51. 4
      npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts
  52. 2
      npm/ng-packs/packages/theme-basic/src/lib/states/layout.state.ts
  53. 3
      npm/ng-packs/packages/theme-shared/ng-package.json
  54. 12
      npm/ng-packs/packages/theme-shared/package.json
  55. 3
      npm/ng-packs/packages/theme-shared/src/lib/components/pagination/pagination.component.ts
  56. 17
      npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.html
  57. 339
      npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.scss
  58. 18
      npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.ts
  59. 3
      npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts
  60. 63
      npm/ng-packs/packages/theme-shared/src/lib/tests/pagination.component.spec.ts
  61. 2
      npm/ng-packs/packages/theme-shared/src/lib/tests/table-sort.directive.spec.ts
  62. 2
      npm/ng-packs/packages/theme-shared/src/lib/tests/table.component.spec.ts
  63. 4
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  64. 59
      npm/ng-packs/scripts/yarn.lock
  65. 3098
      npm/ng-packs/yarn.lock
  66. 1
      samples/EfCoreMigrationDemo/.gitattributes
  67. 259
      samples/EfCoreMigrationDemo/.gitignore
  68. 144
      samples/EfCoreMigrationDemo/Acme.BookStore.sln
  69. 23
      samples/EfCoreMigrationDemo/Acme.BookStore.sln.DotSettings
  70. 7
      samples/EfCoreMigrationDemo/common.props
  71. 22
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Acme.BookStore.Application.Contracts.csproj
  72. 22
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/BookStoreApplicationContractsModule.cs
  73. 22
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissionDefinitionProvider.cs
  74. 10
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissions.cs
  75. 12
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Roles/AppRoleDto.cs
  76. 14
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Roles/IAppRoleAppService.cs
  77. 23
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj
  78. 18
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreAppService.cs
  79. 14
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
  80. 30
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreApplicationModule.cs
  81. 42
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/Roles/AppRoleAppService.cs
  82. 35
      samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/Acme.BookStore.DbMigrator.csproj
  83. 22
      samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/BookStoreDbMigratorModule.cs
  84. 34
      samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/DbMigratorHostedService.cs
  85. 38
      samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/Program.cs
  86. 21
      samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/appsettings.json
  87. 26
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Acme.BookStore.Domain.Shared.csproj
  88. 7
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/BookStoreDomainErrorCodes.cs
  89. 45
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/BookStoreDomainSharedModule.cs
  90. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/cs.json
  91. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
  92. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/pl.json
  93. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/pt-BR.json
  94. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/tr.json
  95. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/vi.json
  96. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/zh-Hans.json
  97. 8
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/zh-Hant.json
  98. 10
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStoreResource.cs
  99. 11
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/MultiTenancy/MultiTenancyConsts.cs
  100. 27
      samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj

4
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -154,6 +154,8 @@
"SeeTheDocumentForMoreInformation": "See the <a href=\"{1}\">{0} document</a> for more information",
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>open source</strong></span><span class=\"second-line text-uppercase\">Web Application<br />Framework </span><span class=\"third-line shine2\"><strong>for asp.net core</strong></span>",
"UiFramework": "UI Framework",
"EmailAddress": "Email address"
"EmailAddress": "Email address",
"Mobile": "Mobile",
"ReactNative": "React Native"
}
}

664
docs/en/Entity-Framework-Core-Migrations.md

@ -1,9 +1,13 @@
# EF Core Advanced Database Migrations
# EF Core Database Migrations
This document begins by **introducing the default structure** provided by [the application startup template](Startup-Templates/Application.md) and **discusses various scenarios** you may want to implement for your own application.
> This document is for who want to fully understand and customize the database structure comes with [the application startup template](Startup-Templates/Application.md). If you simply want to create entities and manage your code first migrations, just follow [the startup tutorials](Tutorials/Index.md).
### Source Code
You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp/tree/dev/samples/EfCoreMigrationDemo). However, you need to read and understand this document in order to understand the example project's source code.
## About the EF Core Code First Migrations
Entity Framework Core provides an easy to use and powerful [database migration system](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). ABP Framework [startup templates](Startup-Templates/Index.md) take the advantage of this system to allow you to develop your application in a standard way.
@ -20,17 +24,19 @@ When you [create a new web application](https://abp.io/get-started) (with EF Cor
![bookstore-visual-studio-solution-v3](images/bookstore-visual-studio-solution-v3.png)
> Actual solution structure may be a bit different based on your preferences, but the database part will be same.
Actual solution structure may be a bit different based on your preferences, but the database part will be same.
> This document will use the `Acme.BookStore` example project name to refer the projects and classes. You need to find the corresponding class/project in your solution.
### The Database Structure
The startup template has some [application modules](Modules/Index.md) pre-installed. Each layer of the solution has corresponding module package references. So, the `.EntityFrameworkCore` project has the NuGet references for the `.EntityFrameworkCore` packages of the used modules:
The startup template has some [application modules](Modules/Index.md) pre-installed. Each layer of the solution has corresponding module **package references**. So, the `.EntityFrameworkCore` project has the NuGet references for the `.EntityFrameworkCore` packages of the used modules:
![bookstore-efcore-dependencies](images/bookstore-efcore-dependencies.png)
In this way, you collect all the EF Core dependencies under the `.EntityFrameworkCore` project.
In this way, you collect all the **EF Core dependencies** under the `.EntityFrameworkCore` project.
> In addition to the module references, it references to the `Volo.Abp.EntityFrameworkCore.SqlServer` package since the startup template is pre-configured for the SQL Server. See the documentation if you want to [switch to another DBMS](Entity-Framework-Core-Other-DBMS.md).
> In addition to the module references, it references to the `Volo.Abp.EntityFrameworkCore.SqlServer` package since the startup template is pre-configured for the **SQL Server**. See the documentation if you want to [switch to another DBMS](Entity-Framework-Core-Other-DBMS.md).
While every module has its own `DbContext` class by design and can use its **own physical database**, the solution is configured to use a **single shared database** as shown in the figure below:
@ -57,25 +63,25 @@ ABP Framework's [connection string](Connection-Strings.md) system allows you to
The example configuration about tells to the ABP Framework to use the second connection string for the [Audit Logging module](Modules/Audit-Logging.md).
However, this is just the beginning. You also need to create the second database, create audit log tables inside it and maintain the database tables using the code first approach. One of the main purposes of this document is to guide you on such database separation scenarios.
**However, this is just the beginning**. You also need to create the second database, create audit log tables inside it and maintain the database tables using the code first migrations approach. One of the main purposes of this document is to guide you on such **database separation** scenarios.
#### Module Tables
Every module uses its own databases tables. For example, the [Identity Module](Modules/Identity.md) has some tables to manage the users and roles in the system.
Every module uses its **own databases tables**. For example, the [Identity Module](Modules/Identity.md) has some tables to manage the users and roles in the system.
#### Table Prefixes
##### Table Prefixes
Since it is allowed to share a single database by all modules (it is the default configuration), a module typically uses a prefix to group its own tables.
Since it is allowed to share a single database by all modules (it is the default configuration), a module typically uses a **table name prefix** to group its own tables.
The fundamental modules, like [Identity](Modules/Identity.md), [Tenant Management](Modules/Tenant-Management.md) and [Audit Logs](Modules/Audit-Logging.md), use the `Abp` prefix, while some other modules use their own prefixes. [Identity Server](Modules/IdentityServer.md) module uses the `IdentityServer` prefix for example.
If you want, you can change the database table name prefix for a module for your application. Example:
If you want, you can **change the database table name prefix** for a module for your application. Example:
````csharp
Volo.Abp.IdentityServer.AbpIdentityServerDbProperties.DbTablePrefix = "Ids";
````
This code changes the prefix of the [Identity Server](Modules/IdentityServer.md) module. Write this code at the very beginning in your application.
This code changes the prefix of the [Identity Server](Modules/IdentityServer.md) module. Write this code **at the very beginning** in your application.
> Every module also defines `DbSchema` property (near to `DbTablePrefix`), so you can set it for the databases support the schema usage.
@ -87,7 +93,7 @@ From the database point of view, there are three important projects those will b
This project has the `DbContext` class (`BookStoreDbContext` for this sample) of your application.
Every module uses its own `DbContext` class to access to the database. Likewise, your application has its own `DbContext`. You typically use this `DbContext` in your application code (in your custom [repositories](Repositories.md) if you follow the best practices). It is almost an empty `DbContext` since your application don't have any entities at the beginning, except the pre-defined `AppUser` entity:
**Every module uses its own `DbContext` class** to access to the database. Likewise, your application has its own `DbContext`. You typically use this `DbContext` in your application code (in your custom [repositories](Repositories.md) if you follow the best practices). It is almost an empty `DbContext` since your application don't have any entities at the beginning, except the pre-defined `AppUser` entity:
````csharp
[ConnectionStringName("Default")]
@ -196,9 +202,9 @@ public class BookStoreMigrationsDbContext : AbpDbContext<BookStoreMigrationsDbCo
##### Sharing the Mapping Code
First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `MigrationsDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely don't want to duplicate the mapping code.
First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `MigrationsDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely **don't want to duplicate** the mapping code.
The solution is to define an extension method (on the `ModelBuilder`) that can be called by both `DbContext` classes. So, every module defines such an extension method.
The solution is to define an **extension method** (on the `ModelBuilder`) that can be called by both `DbContext` classes. So, all modules define such extension methods.
For example, the `builder.ConfigureBackgroundJobs()` method call configures the database tables for the [Background Jobs module](Modules/Background-Jobs.md). The definition of this extension method is something like that:
@ -235,9 +241,9 @@ public static class BackgroundJobsDbContextModelCreatingExtensions
This extension method also gets options to change the database table prefix and schema for this module, but it is not important here.
The final application calls the extension methods inside the `MigrationsDbContext` class, so it can decide which modules are included to the database maintained by this `MigrationsDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `MigrationsDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections.
The final application calls the extension methods inside the `MigrationsDbContext` class, so it can decide which modules are included in the database maintained by this `MigrationsDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `MigrationsDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections.
The same `ConfigureBackgroundJobs` method is also called the `DbContext` of the Background Jobs module:
The same `ConfigureBackgroundJobs` method is also called in the `DbContext` of the Background Jobs module:
````csharp
[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)]
@ -262,14 +268,14 @@ public class BackgroundJobsDbContext
}
````
In this way, the mapping configuration of a module can be shared between `DbContext` classes.
In this way, the mapping configuration of a module can be shared between `DbContext` classes. The code above is inside the related module NuGet package, so you don't care about it.
##### Reusing a Table of a Module
You may want to reuse a table of a depended module in your application. In this case, you have two options:
You may want to **reuse a table** of a depended module in your application. In this case, you have two options:
1. You can directly use the entity defined by the module.
2. You can create a new entity mapping to the same database table.
1. You can **directly use the entity** defined by the module.
2. You can **create a new entity** mapping to the same database table.
###### Use the Entity Defined by a Module
@ -304,12 +310,622 @@ namespace Acme.BookStore
This example injects the `IRepository<IdentityUser, Guid>` (default repository) which defines the standard repository methods and implements the `IQueryable` interface.
In addition, Identity module defines the `IIdentityUserRepository` (custom repository) that can also be injected and used by your application. `IIdentityUserRepository` provides additional custom methods for the `IdentityUser` entity while it does not implement the `IQueryable`.
> In addition, Identity module defines the `IIdentityUserRepository` (custom repository) that can also be injected and used by your application. `IIdentityUserRepository` provides additional custom methods for the `IdentityUser` entity while it does not implement the `IQueryable` interface.
###### Create a New Entity
TODO
Working with an entity of a module is easy if you want to use the entity as is. However, you may want to define your own entity class and map to the same database table in the following cases;
* You want to **add a new field** to the table and map it to a property in the entity. You can't use the module's entity since it doesn't have the related property.
* You want to **use a subset of the table fields**. You don't want to access to all properties of the entity and hide the unrelated properties (from a security perspective or just by design).
* You don't want to directly **depend on** a module entity class.
In any case, the progress is same. Assume that you want to create an entity, named `AppRole`, mapped to the same table of the `IdentityRole` entity of the [Identity module](Modules/Identity.md).
Here, we will show the implementation, then **will discuss the limitations** of this approach.
First, create a new `AppRole` class in your `.Domain` project:
````csharp
using System;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace Acme.BookStore.Roles
{
public class AppRole : AggregateRoot<Guid>, IMultiTenant
{
// Properties shared with the IdentityRole class
public Guid? TenantId { get; private set; }
public string Name { get; private set; }
//Additional properties
public string Title { get; set; }
private AppRole()
{
}
}
}
````
* It's inherited from [the `AggregateRoot<Guid>` class](Entities.md) and implements [the `IMultiTenant` interface](Multi-Tenancy.md) because the `IdentityRole` also does the same.
* You can add any properties defined by the `IdentityRole` entity. This examples add only the `TenantId` and `Name` properties since we only need them here. You can make the setters private (like in this example) to prevent changing Identity module's properties accidently.
* You can add custom (additional) properties. This example adds the `Title` property.
* The **constructor is private**, so it is not allowed to directly create a new `AppRole` entity. Creating a role is a responsibility of the Identity module. You can query roles, set/update your custom properties, but you should not create or delete a role in your code, as a best practice (while there is nothing restricts you).
Now, it is time to define the EF Core mappings. Open the `DbContext` of your application (`BookStoreDbContext` in this sample) and add the following property:
````csharp
public DbSet<AppRole> Roles { get; set; }
````
Then configure the mapping inside the `OnModelCreating` method (after calling the `base.OnModelCreating(builder)`):
````csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Configure the shared tables (with included modules) here */
//CONFIGURE THE AppRole ENTITY
builder.Entity<AppRole>(b =>
{
b.ToTable("AbpRoles");
b.ConfigureByConvention();
b.ConfigureCustomRoleProperties();
});
...
/* Configure your own tables/entities inside the ConfigureBookStore method */
builder.ConfigureBookStore();
}
````
We added the following lines:
````csharp
builder.Entity<AppRole>(b =>
{
b.ToTable("AbpRoles");
b.ConfigureByConvention();
b.ConfigureCustomRoleProperties();
});
````
* It maps to the same `AbpRoles` table shared with the `IdentityRole` entity.
* `ConfigureByConvention()` configures the standard/base properties (like `TenantId`) and recommended to always call it.
`ConfigureCustomRoleProperties()` has not exists yet. Define it inside the `BookStoreDbContextModelCreatingExtensions` class (near to your `DbContext` in the `.EntityFrameworkCore` project):
````csharp
public static void ConfigureCustomRoleProperties<TRole>(this EntityTypeBuilder<TRole> b)
where TRole : class, IEntity<Guid>
{
b.Property<string>(nameof(AppRole.Title)).HasMaxLength(128);
}
````
* This method only defines the **custom properties** of your entity.
* Unfortunately, we can not utilize the fully **type safety** here (by referencing the `AppRole` entity). The best we can do is to use the `Title` name as type safe. This is because of EF Core migration system can not map two unrelated entity classes to the same database table.
You've configured the custom property for your `DbContext` used by your application on the runtime. We also need to configure the `MigrationsDbContext`.
Open the `MigrationsDbContext` (`BookStoreMigrationsDbContext` for this example) and change as shown below:
````csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
...
/* Configure customizations for entities from the modules included */
//CONFIGURE THE CUSTOM ROLE PROPERTIES
builder.Entity<IdentityRole>(b =>
{
b.ConfigureCustomRoleProperties();
});
...
/* Configure your own tables/entities inside the ConfigureBookStore method */
builder.ConfigureBookStore();
}
````
Only added the following lines:
````csharp
builder.Entity<IdentityRole>(b =>
{
b.ConfigureCustomRoleProperties();
});
````
In this way, we re-used the extension method that is used to configure custom property mappings for the role. But, this time, did the same customization for the `IdentityRole` entity.
Now, you can add a new EF Core database migration using the standard `Add-Migration` command in the Package Manager Console (remember to select `.EntityFrameworkCore.DbMigrations` as the Default Project in the PMC and make sure that the `.Web` project is still the startup project):
![pmc-add-migration-role-title](images/pmc-add-migration-role-title.png)
This command will create a new code first migration class as shown below:
````csharp
public partial class Added_Title_To_Roles : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Title",
table: "AbpRoles",
maxLength: 128,
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Title",
table: "AbpRoles");
}
}
````
All done! Just run the `Update-Database` command in the PMC or run the `.DbMigrator` project in your solution to apply changes to database.
Now, you can work with the `AppRole` entity just like any other entity of your application. An example [application service](Application-Services.md) that queries and updates roles:
````csharp
public class AppRoleAppService : ApplicationService, IAppRoleAppService
{
private readonly IRepository<AppRole, Guid> _appRoleRepository;
public AppRoleAppService(IRepository<AppRole, Guid> appRoleRepository)
{
_appRoleRepository = appRoleRepository;
}
public async Task<List<AppRoleDto>> GetListAsync()
{
var roles = await _appRoleRepository.GetListAsync();
return roles
.Select(r => new AppRoleDto
{
Id = r.Id,
Name = r.Name,
Title = r.Title
})
.ToList();
}
public async Task UpdateTitleAsync(Guid id, string title)
{
var role = await _appRoleRepository.GetAsync(id);
role.Title = title;
await _appRoleRepository.UpdateAsync(role);
}
}
````
There are some **limitations** of creating a new entity and mapping it to a table of a depended module:
* Your **custom properties must be nullable**. For example, `AppRole.Title` was nullable here. Otherwise, Identity module throws exception because it doesn't know and can not fill the Title when it inserts a new role to the database.
* As a good practice, you should not update the **properties defined by the module**, especially if it requires a business logic. You typically want to manage your own properties.
##### Alternative Approaches
Instead of creating a new entity class to add a custom property, you can use the following approaches.
###### Using the ExtraProperties
All entities derived from the `AggregateRoot ` class can store name-value pairs in their `ExtraProperties` property, which is a `Dictionary<string, object>` serialized to JSON in the database table. So, you can add values to this dictionary and query again without changing the entity.
For example, you can store query the title Property inside an `IdentityRole` instead of creating a new entity. Example:
````csharp
public class IdentityRoleExtendingService : ITransientDependency
{
private readonly IIdentityRoleRepository _identityRoleRepository;
public IdentityRoleExtendingService(IIdentityRoleRepository identityRoleRepository)
{
_identityRoleRepository = identityRoleRepository;
}
public async Task<string> GetTitleAsync(Guid id)
{
var role = await _identityRoleRepository.GetAsync(id);
return role.GetProperty<string>("Title");
}
public async Task SetTitleAsync(Guid id, string newTitle)
{
var role = await _identityRoleRepository.GetAsync(id);
role.SetProperty("Title", newTitle);
await _identityRoleRepository.UpdateAsync(role);
}
}
````
* `GetProperty` and `SetProperty` methods are shortcuts to get and set a value in the `role.ExtraProperties` dictionary and they are the recommended way to work with the extra properties.
In this way, you can easily attach any type of value to an entity of a depended module. However, there are some drawbacks of this usage:
* All the extra properties are stored as **a single JSON object** in the database. They are not stored as new table fields, as you may expect. Creating database table indexes and using SQL queries against these properties will be harder compared to simple table fields.
* Property names are strings, so they are **not type safe**. It is recommended to define constants for these kind of properties to prevent typo errors.
###### Creating a New Table
Instead of creating a new entity and mapping to the same table, you can also create **your own table** to store your properties. You typically duplicate some values of the original entity. For example, you can add `Name` field to your own table which is a duplication of the `Name` field in the original table.
In this case, you don't deal with migration problems, however you need to deal with the problems of data duplication. When the duplicated value changes, you should reflect the same change in your table. You can use local or distributed [event bus](Event-Bus.md) to subscribe to the change events for the original entity. This is the recommended way of depending on a microservice's data from another microservice, especially if they have separate physical databases (you can search on the web on data sharing on a microservice design, it is a wide topic to cover here).
#### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path
As mentioned before, `.EntityFrameworkCore.DbMigrations` merges all the database mappings of all the modules (plus your application's mappings) to create a unified migration path.
An alternative approach would be to allow each module to have its own migrations to maintain its database tables. While it seems more module in the beginning, it has some important drawbacks:
* **EF Core migration system depends on the DBMS provider**. For example, if a module has created migrations for SQL Server, then you can not use this migration code for MySQL. It is not practical for a module to maintain migrations for all available DBMS providers. Leaving the migration to the application code (as explained in this document) allows you to **choose the DBMS in the application** code.
* It would be harder or impossible to **share a table** between modules or **re-use a table** of a module in your application. Because EF Core migration system can not handle it and will throw exceptions like "Table XXX is already exists in the database".
* It would be harder to **customize/enhance** the mapping and the resulting migration code.
* It would be harder to track and **apply changes** to database when you use multiple modules.
## Using Multiple Databases
The default startup template is organized to use a single database used by all the modules and by your application. However, the ABP Framework and all the pre-built modules are designed so that **they can use multiple databases**. Each module can use its own database or you can group modules into a few databases.
This section will explain how to move Audit Logging, Setting Management and Permission Management module tables to a **second database** while the remaining modules continue to use the main ("Default") database.
The resulting structure will be like the figure below:
![single-database-usage](images/multiple-database-usage.png)
### Change the Connection Strings Section
First step is to change the connection string section inside all the `appsettings.json` files. Initially, it is like that:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true"
}
````
Change it as shown below:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
````
Added **three more connection strings** for the related module to target the `BookStore_SecondDb` database (they are all same). For example, `AbpPermissionManagement` is the connection string for the permission management module.
The `AbpPermissionManagement` is a constant [defined](https://github.com/abpframework/abp/blob/97eaa6ff5a044f503465455c86332e5a277b077a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDbProperties.cs#L11) by the permission management module. ABP Framework [connection string selection system](Connection-Strings.md) selects this connection string for the permission management module if you define. If you don't define, it fallbacks to the `Default` connection string.
### Create a Second Migration Project
Defining the connection strings as explained above is enough **on runtime**. However, `BookStore_SecondDb` database doesn't exist yet. You need to create the database and the tables for the related modules.
Just like the main database, we want to use the EF Core Code First migration system to create and maintain the second database.
An easy way is to create a second project (`.csproj`) for the second migration `DbContext`.
So, create a new **class library project** in your solution named `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` (or name it better if you didn't like it).
The `.csproj` content should be something like that:
````xml
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Acme.BookStore.DbMigrationsForSecondDb</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Acme.BookStore.EntityFrameworkCore\Acme.BookStore.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.0" />
</ItemGroup>
</Project>
````
You can just copy & modify the content of the original `.DbMigrations` project. This project references to the `.EntityFrameworkCore` project. **Only difference** is the `RootNamespace` value.
**Add a reference** to this project from the `.Web` project (otherwise, EF Core tooling doesn't allow to use the `Add-Migration` command).
### Create the Second DbMigrationDbContext
Create a new `DbContext` for the migrations and call the **extension methods** of the modules to configure the database tables for the related modules:
````csharp
[ConnectionStringName("AbpPermissionManagement")]
public class BookStoreSecondMigrationsDbContext :
AbpDbContext<BookStoreSecondMigrationsDbContext>
{
public BookStoreSecondMigrationsDbContext(
DbContextOptions<BookStoreSecondMigrationsDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureAuditLogging();
}
}
````
> `[ConnectionStringName(...)]` attribute is important here and tells to the ABP Framework which connection string should be used for this `DbContext`. We've used `AbpPermissionManagement`, but all are the same.
Create a **Design Time Db Factory** class, that is used by the EF Core tooling (by `Add-Migration` and `Update-Database` PCM commands for example):
````csharp
/* This class is needed for EF Core console commands
* (like Add-Migration and Update-Database commands) */
public class BookStoreSecondMigrationsDbContextFactory
: IDesignTimeDbContextFactory<BookStoreSecondMigrationsDbContext>
{
public BookStoreSecondMigrationsDbContext CreateDbContext(string[] args)
{
var configuration = BuildConfiguration();
var builder = new DbContextOptionsBuilder<BookStoreSecondMigrationsDbContext>()
.UseSqlServer(configuration.GetConnectionString("AbpPermissionManagement"));
return new BookStoreSecondMigrationsDbContext(builder.Options);
}
private static IConfigurationRoot BuildConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);
return builder.Build();
}
}
````
This is similar to the class inside the `.EntityFrameworCore.DbMigrations` project, except this one uses the `AbpPermissionManagement` connection string.
Now, you can open the Package Manager Console, select the `.EntityFrameworkCore.DbMigrationsForSecondDb` project as the default project (make sure the `.Web` project is still the startup project) and run the `Add-Migration "Initial"` and `Update-Database` commands as shown below:
![pmc-add-migration-initial-update-database](images/pmc-add-migration-initial-update-database.png)
Now, you should have a new database contains only the tables needed by the related modules:
![bookstore-second-database](images/bookstore-second-database.png)
### Remove Modules from the Main Database
We've **created a second database** contains tables for the Audit Logging, Permission Management and Setting Management modules. So, we should **delete these tables from the main database**. It is pretty easy.
First, remove the following lines from the `MigrationsDbContext` class (`BookStoreMigrationsDbContext` for this example):
````csharp
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureAuditLogging();
````
Open the Package Manager Console, select the `.EntityFrameworkCore.DbMigrations` as the Default project (make sure that the `.Web` project is still the startup project) and run the following command:
````
Add-Migration "Removed_Audit_Setting_Permission_Modules"
````
This command will create a new migration class as shown below:
````csharp
public partial class Removed_Audit_Setting_Permission_Modules : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpAuditLogActions");
migrationBuilder.DropTable(
name: "AbpEntityPropertyChanges");
migrationBuilder.DropTable(
name: "AbpPermissionGrants");
migrationBuilder.DropTable(
name: "AbpSettings");
migrationBuilder.DropTable(
name: "AbpEntityChanges");
migrationBuilder.DropTable(
name: "AbpAuditLogs");
}
...
}
````
Be careful in this step:
* If you have a **live system**, then you should care about the **data loss**. You need to move the table contents to the second database before deleting the tables.
* If you **haven't started** your project yet, you can consider to **remove all the migrations** and re-create the initial one to have a cleaner migration history.
Run the `Update-Database` command to delete the tables from your main database.
Notice that you've also **deleted some initial seed data** (for example, permission grants for the admin role) if you haven't copied it to the new database. If you run the application, you may not login anymore. The solution is simple: **Re-run the `.DbMigrator` console application** in your solution, it will seed the new database.
### Automate the Second Database Schema Migration
`.DbMigrator` console application can run the database seed code across multiple databases, without any additional configuration. However, it can not run the EF Core Code First Migrations inside the second database migration project. Now, you will see how to configure the console migration application to handle both databases.
#### Implementing the IBookStoreDbSchemaMigrator
`EntityFrameworkCoreBookStoreDbSchemaMigrator` class inside the `Acme.BookStore.EntityFrameworkCore.DbMigrations` project is responsible to migrate the database schema for the `BookStoreMigrationsDbContext`. It should be like that:
````csharp
[Dependency(ReplaceServices = true)]
public class EntityFrameworkCoreBookStoreDbSchemaMigrator
: IBookStoreDbSchemaMigrator, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public EntityFrameworkCoreBookStoreDbSchemaMigrator(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task MigrateAsync()
{
/* We are intentionally resolving the BookStoreMigrationsDbContext
* from IServiceProvider (instead of directly injecting it)
* to properly get the connection string of the current tenant in the
* current scope.
*/
await _serviceProvider
.GetRequiredService<BookStoreMigrationsDbContext>()
.Database
.MigrateAsync();
}
}
````
It implements the `IBookStoreDbSchemaMigrator` and **replaces existing services** (see the first line).
Remove the `[Dependency(ReplaceServices = true)]` line, because we will have two implementations of this interface and we want to use both. We don't want to replace one of them.
Create a copy of this class inside the new migration project (`Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb`), but use the `BookStoreSecondMigrationsDbContext`. Example implementation:
````csharp
public class EntityFrameworkCoreSecondBookStoreDbSchemaMigrator
: IBookStoreDbSchemaMigrator, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public EntityFrameworkCoreSecondBookStoreDbSchemaMigrator(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task MigrateAsync()
{
/* We are intentionally resolving the BookStoreSecondMigrationsDbContext
* from IServiceProvider (instead of directly injecting it)
* to properly get the connection string of the current tenant in the
* current scope.
*/
await _serviceProvider
.GetRequiredService<BookStoreSecondMigrationsDbContext>()
.Database
.MigrateAsync();
}
}
````
> Name of this class is important for [dependency injection](Dependency-Injection.md). It should end with `BookStoreDbSchemaMigrator` to be injectable by `IBookStoreDbSchemaMigrator` reference.
We, now, have two implementations of the `IBookStoreDbSchemaMigrator` interface, each one responsible to migrate the related database schema.
#### Define a Module Class for the Second Migration Project
It is time to define the [module](Module-Development-Basics.md) class for this second migrations (`Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb`) project:
````csharp
[DependsOn(
typeof(BookStoreEntityFrameworkCoreModule)
)]
public class BookStoreEntityFrameworkCoreSecondDbMigrationsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<BookStoreSecondMigrationsDbContext>();
}
}
````
Now, reference `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` project from the `Acme.BookStore.DbMigrator` project and `typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule)` to the dependency list of the `BookStoreDbMigratorModule`. `BookStoreDbMigratorModule` class should be something like that:
````csharp
[DependsOn(
typeof(AbpAutofacModule),
typeof(BookStoreEntityFrameworkCoreDbMigrationsModule),
typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule), // ADDED THIS!
typeof(BookStoreApplicationContractsModule)
)]
public class BookStoreDbMigratorModule : AbpModule
{
...
}
````
We had a reference to the `Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb` project from the `Acme.BookStore.Web` project, but hadn't added module dependency since we hadn't created it before. But, now we have it and we need to add `typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule)` to the dependency list of the `BookStoreWebModule` class.
#### BookStoreDbMigrationService
You need one final touch to the `BookStoreDbMigrationService` inside the `Acme.BookStore.Domain` project. It is currently designed to work with a single `IBookStoreDbSchemaMigrator` implementation, but now we have two.
It injects `IBookStoreDbSchemaMigrator`. Replace it with an `IEnumerable<IBookStoreDbSchemaMigrator>` injection ([Dependency Injection System](Dependency-Injection.md) allows to inject multiple implementations of an interface just like that).
Now, you have **a collection of schema migrators** instead of a single one. Find the lines like:
````csharp
await _dbSchemaMigrators.MigrateAsync();
````
change them to:
````csharp
foreach (var migrator in _dbSchemaMigrators)
{
await migrator.MigrateAsync();
}
````
You can run the `.DbMigrator` application to migrate & seed the databases. To test, you can delete both databases and run the `.DbMigrator` application again to see if it creates both of the databases.
## Conclusion
This document explains how to split your databases and manage your database migrations of your solution for Entity Framework Core. In brief, you need to have a separate migration project per different databases.
##### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path
## Source Code
TODO
You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp/tree/dev/samples/EfCoreMigrationDemo). However, you need to read and understand this document in order to understand the example project's source code.

BIN
docs/en/_resources/Diagrams.docx

Binary file not shown.

4
docs/en/docs-nav.json

@ -295,6 +295,10 @@
"text": "Entity Framework Core",
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "Database Migrations",
"path": "Entity-Framework-Core-Migrations.md"
},
{
"text": "Switch DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md",

BIN
docs/en/images/bookstore-second-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/en/images/multiple-database-usage.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/en/images/pmc-add-migration-initial-update-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/en/images/pmc-add-migration-role-title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

61
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/ButtonsDemo/ButtonsDemoViewComponent.cs

@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.Shared.Demos.ButtonsDemo
{
@ -13,61 +8,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.S
{
public const string ViewPath = "/Views/Components/Themes/Shared/Demos/ButtonsDemo/Default.cshtml";
private const string DemoSectionOpeningTag = "<DemoSection:";
private const string DemoSectionClosingTag = "</DemoSection:";
private readonly IVirtualFileProvider _virtualFileProvider;
public ButtonsDemoViewComponent(IVirtualFileProvider virtualFileProvider)
{
_virtualFileProvider = virtualFileProvider;
}
public IViewComponentResult Invoke()
{
var model = new DemoViewModel();
var viewFileInfo = _virtualFileProvider.GetFileInfo(ViewPath);
var viewFileContent = viewFileInfo.ReadAsString();
var lines = viewFileContent.SplitToLines();
StringBuilder sb = null;
foreach (var line in lines)
{
if (line.Contains(DemoSectionOpeningTag))
{
sb = new StringBuilder();
}
else if (line.Contains(DemoSectionClosingTag, StringComparison.InvariantCultureIgnoreCase))
{
var demoName = line.Substring(line.IndexOf(DemoSectionClosingTag, StringComparison.InvariantCultureIgnoreCase) + DemoSectionClosingTag.Length);
if (demoName.Contains(">"))
{
demoName = demoName.Left(demoName.IndexOf(">", StringComparison.InvariantCultureIgnoreCase));
}
model.SourceCodes[demoName] = sb.ToString();
sb = new StringBuilder();
}
else if(sb != null)
{
sb.AppendLine(line);
}
}
return View(ViewPath, model);
}
}
public class DemoViewModel
{
public Dictionary<string, string> SourceCodes { get; set; }
public DemoViewModel()
{
SourceCodes = new Dictionary<string, string>();
return View(ViewPath);
}
}
}

47
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/ButtonsDemo/Default.cshtml

@ -1,17 +1,30 @@
@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.Shared.Demos.ButtonsDemo.DemoViewModel
<div class="abp-theme-demo-section">
<h2>
Basic Buttons
</h2>
<div class="abp-theme-demo-section-body">
<!-- <DemoSection:Buttons.Basic> -->
<abp-button button-type="Primary" text="Primary button" />
<abp-button button-type="Secondary" text="Secondary button" />
<!-- </DemoSection:Buttons.Basic> -->
</div>
<div>
<pre>
@Model.SourceCodes["Buttons.Basic"]
</pre>
</div>
</div>
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.Shared.Demos.ButtonsDemo
<abp-component-demo-section title="Basics" view-path="@ButtonsDemoViewComponent.ViewPath">
<abp-button text="Default" />
<abp-button button-type="Primary" text="Primary" />
<abp-button button-type="Secondary">Secondary</abp-button>
<abp-button button-type="Success">Success</abp-button>
<abp-button button-type="Danger">Danger</abp-button>
<abp-button button-type="Warning">Warning</abp-button>
<abp-button button-type="Info">Info</abp-button>
<abp-button button-type="Light">Light</abp-button>
<abp-button button-type="Dark">Dark</abp-button>
<abp-button button-type="Link">Link</abp-button>
</abp-component-demo-section>
<abp-component-demo-section title="Outline" view-path="@ButtonsDemoViewComponent.ViewPath">
<abp-button button-type="Outline_Primary">Primary</abp-button>
<abp-button button-type="Outline_Secondary">Secondary</abp-button>
<abp-button button-type="Outline_Success">Success</abp-button>
<abp-button button-type="Outline_Danger">Danger</abp-button>
<abp-button button-type="Outline_Warning">Warning</abp-button>
<abp-button button-type="Outline_Info">Info</abp-button>
<abp-button button-type="Outline_Light">Light</abp-button>
<abp-button button-type="Outline_Dark">Dark</abp-button>
</abp-component-demo-section>
<abp-component-demo-section title="Icons" view-path="@ButtonsDemoViewComponent.ViewPath">
<abp-button button-type="Warning" icon="pencil" text="Edit" />
<abp-button button-type="Info" icon-type="FontAwesome" icon="info" text="Information" />
</abp-component-demo-section>

105
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/TagHelpers/AbpComponentDemoSectionTagHelper.cs

@ -0,0 +1,105 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.Shared.TagHelpers
{
public class AbpComponentDemoSectionTagHelper : AbpTagHelper
{
private const string DemoSectionOpeningTag = "<abp-component-demo-section";
private const string DemoSectionClosingTag = "</abp-component-demo-section";
public string ViewPath { get; set; }
public string Title { get; set; }
private readonly IVirtualFileProvider _virtualFileProvider;
public AbpComponentDemoSectionTagHelper(IVirtualFileProvider virtualFileProvider)
{
_virtualFileProvider = virtualFileProvider;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
var content = await output.GetChildContentAsync();
output.PreContent.AppendHtml("<div class=\"abp-component-demo-section\">");
output.PreContent.AppendHtml($"<h2>{Title}</h2>");
output.PreContent.AppendHtml("<div class=\"abp-component-demo-section-body\">");
/* component rendering here */
output.PostContent.AppendHtml("</div>"); //abp-component-demo-section-body
AppendRawSource(output);
AppendBootstrapSource(output, content);
output.PostContent.AppendHtml("</div>"); //abp-component-demo-section
}
private static void AppendBootstrapSource(TagHelperOutput output, TagHelperContent content)
{
output.PostContent.AppendHtml("<div class=\"abp-component-demo-section-bs-source\">");
output.PostContent.AppendHtml("<h3>Bootstrap</h3>");
output.PostContent.AppendHtml("<pre>");
output.PostContent.Append(content.GetContent());
output.PostContent.AppendHtml("</pre>");
output.PostContent.AppendHtml("</div>");
}
private void AppendRawSource(TagHelperOutput output)
{
output.PostContent.AppendHtml("<div class=\"abp-component-demo-section-raw-source\">");
output.PostContent.AppendHtml("<h3>ABP Tag Helpers</h3>");
output.PostContent.AppendHtml("<pre>");
output.PostContent.Append(GetRawDemoSource());
output.PostContent.AppendHtml("</pre>");
output.PostContent.AppendHtml("</div>");
}
private string GetRawDemoSource()
{
StringBuilder sourceBuilder = null;
var lines = GetFileContent().SplitToLines();
foreach (var line in lines)
{
if (line.Contains(DemoSectionOpeningTag) && GetName(line) == Title)
{
sourceBuilder = new StringBuilder();
}
else if (line.Contains(DemoSectionClosingTag, StringComparison.InvariantCultureIgnoreCase))
{
if (sourceBuilder == null)
{
continue;
}
return sourceBuilder.ToString();
}
else if (sourceBuilder != null)
{
sourceBuilder.AppendLine(line);
}
}
throw new AbpException($"Could not find {Title} demo section inside {ViewPath}");
}
private string GetFileContent()
{
var viewFileInfo = _virtualFileProvider.GetFileInfo(ViewPath);
return viewFileInfo.ReadAsString();
}
private string GetName(string line)
{
var str = line.Substring(line.IndexOf("title=\"", StringComparison.OrdinalIgnoreCase) + "title=\"".Length);
str = str.Left(str.IndexOf("\"", StringComparison.OrdinalIgnoreCase));
return str;
}
}
}

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/_ViewImports.cshtml → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/_ViewImports.cshtml

@ -1,4 +1,5 @@
@using System.Globalization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo

1
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs

@ -76,6 +76,7 @@ namespace Volo.Abp.Cli.Commands
version,
DatabaseProvider.NotSpecified,
UiFramework.NotSpecified,
MobileApp.None,
gitHubLocalRepositoryPath,
commandLineArgs.Options
)

27
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs

@ -67,6 +67,12 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation("UI Framework: " + uiFramework);
}
var mobileApp = GetMobilePreference(commandLineArgs);
if (mobileApp != MobileApp.None)
{
Logger.LogInformation("Mobile App: " + mobileApp);
}
var gitHubLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubLocalRepositoryPath.Long);
if (gitHubLocalRepositoryPath != null)
{
@ -94,6 +100,7 @@ namespace Volo.Abp.Cli.Commands
version,
databaseProvider,
uiFramework,
mobileApp,
gitHubLocalRepositoryPath,
commandLineArgs.Options
)
@ -208,6 +215,20 @@ namespace Volo.Abp.Cli.Commands
}
}
private MobileApp GetMobilePreference(CommandLineArgs commandLineArgs)
{
var optionValue = commandLineArgs.Options.GetOrNull(Options.Mobile.Short, Options.Mobile.Long);
switch (optionValue)
{
case "none":
return MobileApp.None;
case "react-native":
return MobileApp.ReactNative;
default:
return MobileApp.ReactNative;
}
}
public static class Options
{
public static class Template
@ -244,6 +265,12 @@ namespace Volo.Abp.Cli.Commands
public const string Short = "u";
public const string Long = "ui";
}
public static class Mobile
{
public const string Short = "m";
public const string Long = "mobile";
}
}
}
}

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/AbpNuGetIndexUrlService.cs

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Licensing;

25
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/MobileApp.cs

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.Cli.ProjectBuilding.Building
{
public enum MobileApp
{
None,
ReactNative
}
public static class MobileAppExtensions{
public static string GetFolderName(this MobileApp mobileApp)
{
switch (mobileApp)
{
case MobileApp.ReactNative:
return "react-native";
default:
return null;
}
}
}
}

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs

@ -19,6 +19,8 @@ namespace Volo.Abp.Cli.ProjectBuilding
public UiFramework UiFramework { get; set; }
public MobileApp MobileApp { get; set; }
[CanBeNull]
public string AbpGitHubLocalRepositoryPath { get; set; }
@ -31,6 +33,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
[CanBeNull] string version = null,
DatabaseProvider databaseProvider = DatabaseProvider.NotSpecified,
UiFramework uiFramework = UiFramework.NotSpecified,
MobileApp mobileApp = MobileApp.ReactNative,
[CanBeNull] string abpGitHubLocalRepositoryPath = null,
Dictionary<string, string> extraProperties = null)
{
@ -39,6 +42,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
Version = version;
DatabaseProvider = databaseProvider;
UiFramework = uiFramework;
MobileApp = mobileApp;
AbpGitHubLocalRepositoryPath = abpGitHubLocalRepositoryPath;
ExtraProperties = extraProperties ?? new Dictionary<string, string>();
}

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs

@ -88,6 +88,8 @@ namespace Volo.Abp.Cli.ProjectBuilding
!x.Key.Equals(NewCommand.Options.OutputFolder.Short, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.UiFramework.Long, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.UiFramework.Short, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.Mobile.Long, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.Mobile.Short, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.Version.Long, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.Version.Short, StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Key).ToList();

7
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs

@ -74,6 +74,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
steps.Add(new RemoveFolderStep("/angular"));
}
if (context.BuildArgs.MobileApp != MobileApp.ReactNative)
{
steps.Add(new RemoveFolderStep(MobileApp.ReactNative.GetFolderName()?.EnsureStartsWith('/')));
}
}
private static void ConfigureWithoutUi(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
@ -156,7 +161,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
private static void CleanupFolderHierarchy(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
if (context.BuildArgs.UiFramework == UiFramework.Mvc)
if (context.BuildArgs.UiFramework == UiFramework.Mvc && context.BuildArgs.MobileApp == MobileApp.None)
{
steps.Add(new MoveFolderStep("/aspnet-core/", "/"));
}

20
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/TemplateRandomSslPortStep.cs

@ -44,6 +44,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates
)
.ToList();
var reactNativeEnvironments = context.Files.Where(x =>
!x.IsDirectory &&
x.Name.EndsWith($"{MobileApp.ReactNative.GetFolderName()}/Environment.js", StringComparison.InvariantCultureIgnoreCase)
)
.ToList();
if (AppTemplateBase.IsAppTemplate(context.Template.Name))
{
// no tiered
@ -127,6 +133,20 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates
environment.SetLines(environmentLines);
}
foreach (var environment in reactNativeEnvironments)
{
environment.NormalizeLineEndings();
var environmentLines = environment.GetLines();
for (var i = 0; i < environmentLines.Length; i++)
{
if (environmentLines[i].Contains(buildInUrl))
{
environmentLines[i] = environmentLines[i].Replace(buildInUrl, $"{buildInUrlWithoutPort}:{newPort}");
}
}
environment.SetLines(environmentLines);
}
}
}
}

36
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml

@ -31,16 +31,16 @@
<div class="demo-with-code">
<div class="demo-area">
<abp-button text="Default" />
<abp-button button-type="Primary" text="Primary" />
<abp-button button-type="Secondary">Secondary</abp-button>
<abp-button button-type="Success">Success</abp-button>
<abp-button button-type="Danger">Danger</abp-button>
<abp-button button-type="Warning">Warning</abp-button>
<abp-button button-type="Info">Info</abp-button>
<abp-button button-type="Light">Light</abp-button>
<abp-button button-type="Dark">Dark</abp-button>
<abp-button button-type="Link">Link</abp-button>
<abp-button text="Default" />
<abp-button button-type="Primary" text="Primary" />
<abp-button button-type="Secondary">Secondary</abp-button>
<abp-button button-type="Success">Success</abp-button>
<abp-button button-type="Danger">Danger</abp-button>
<abp-button button-type="Warning">Warning</abp-button>
<abp-button button-type="Info">Info</abp-button>
<abp-button button-type="Light">Light</abp-button>
<abp-button button-type="Dark">Dark</abp-button>
<abp-button button-type="Link">Link</abp-button>
</div>
<div class="code-area">
<abp-tabs>
@ -116,14 +116,14 @@
<div class="demo-with-code">
<div class="demo-area">
<abp-button button-type="Outline_Primary">Primary</abp-button>
<abp-button button-type="Outline_Secondary">Secondary</abp-button>
<abp-button button-type="Outline_Success">Success</abp-button>
<abp-button button-type="Outline_Danger">Danger</abp-button>
<abp-button button-type="Outline_Warning">Warning</abp-button>
<abp-button button-type="Outline_Info">Info</abp-button>
<abp-button button-type="Outline_Light">Light</abp-button>
<abp-button button-type="Outline_Dark">Dark</abp-button>
<abp-button button-type="Outline_Primary">Primary</abp-button>
<abp-button button-type="Outline_Secondary">Secondary</abp-button>
<abp-button button-type="Outline_Success">Success</abp-button>
<abp-button button-type="Outline_Danger">Danger</abp-button>
<abp-button button-type="Outline_Warning">Warning</abp-button>
<abp-button button-type="Outline_Info">Info</abp-button>
<abp-button button-type="Outline_Light">Light</abp-button>
<abp-button button-type="Outline_Dark">Dark</abp-button>
</div>
<div class="code-area">
<abp-tabs>

34
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs

@ -1,8 +1,15 @@
using Microsoft.AspNetCore.Builder;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
using Volo.Abp.UI;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo
{
@ -13,6 +20,31 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo
)]
public class AbpAspNetCoreMvcUiThemeBasicDemoModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var env = context.Services.GetHostingEnvironment();
if (env.IsDevelopment())
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.ReplaceEmbeddedByPhysical<AbpAspNetCoreMvcUiThemeSharedDemoModule>(Path.Combine(env.ContentRootPath, string.Format("..{0}..{0}src{0}Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo", Path.DirectorySeparatorChar)));
});
}
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles
.Get(StandardBundles.Styles.Global)
.AddFiles("/demo/styles/main.css");
});
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new BasicThemeDemoMenuContributor());
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();

28
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/BasicThemeDemoMenuContributor.cs

@ -0,0 +1,28 @@
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo
{
public class BasicThemeDemoMenuContributor : IMenuContributor
{
public Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if(context.Menu.Name == StandardMenus.Main)
{
AddMainMenuItems(context);
}
return Task.CompletedTask;
}
private void AddMainMenuItems(MenuConfigurationContext context)
{
context.Menu.AddItem(
new ApplicationMenuItem("BasicThemeDemo.Components", "Components")
.AddItem(
new ApplicationMenuItem("BasicThemeDemo.Components.Buttons", "Buttons", url: "/Components/Buttons")
)
);
}
}
}

2
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Components/Buttons/Index.cshtml

@ -1,6 +1,6 @@
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.Shared.Demos.ButtonsDemo
@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.Pages.Components.Buttons.IndexModel
<h1>Buttons Page</h1>
<h1>Buttons</h1>
@await Component.InvokeAsync(typeof(ButtonsDemoViewComponent))

3
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Index.cshtml

@ -0,0 +1,3 @@
@page
@model Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.Pages.IndexModel
<h1>Basic Theme Demo</h1>

12
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Pages/Index.cshtml.cs

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}

9
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj

@ -8,11 +8,10 @@
</PropertyGroup>
<ItemGroup>
<Content Remove="Pages\_ViewImports.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Pages\_ViewImports.cshtml" />
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup>
<ItemGroup>

29
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/wwwroot/demo/styles/main.css

@ -0,0 +1,29 @@
.abp-component-demo-section {
border: 1px solid #999;
padding: 10px;
}
.abp-component-demo-section-body {
padding-bottom: 10px;
}
.abp-component-demo-section-raw-source {
background-color: #eee;
padding: 5px;
}
.abp-component-demo-section-raw-source pre {
border: 1px solid #999;
margin: 5px;
}
.abp-component-demo-section-bs-source {
background-color: #ddd;
padding: 5px;
}
.abp-component-demo-section-bs-source pre {
border: 1px solid #999;
margin: 5px;
}

45
npm/ng-packs/angular.json

@ -56,7 +56,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/theme-shared/tsconfig.lib.json", "packages/theme-shared/tsconfig.spec.json"],
"tsConfig": [
"packages/theme-shared/tsconfig.lib.json",
"packages/theme-shared/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -86,7 +89,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/theme-basic/tsconfig.lib.json", "packages/theme-basic/tsconfig.spec.json"],
"tsConfig": [
"packages/theme-basic/tsconfig.lib.json",
"packages/theme-basic/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -115,7 +121,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/account/tsconfig.lib.json", "packages/account/tsconfig.spec.json"],
"tsConfig": [
"packages/account/tsconfig.lib.json",
"packages/account/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -176,7 +185,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/identity/tsconfig.lib.json", "packages/identity/tsconfig.spec.json"],
"tsConfig": [
"packages/identity/tsconfig.lib.json",
"packages/identity/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -333,7 +345,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/identity-config/tsconfig.lib.json", "packages/identity-config/tsconfig.spec.json"],
"tsConfig": [
"packages/identity-config/tsconfig.lib.json",
"packages/identity-config/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -362,7 +377,10 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["packages/account-config/tsconfig.lib.json", "packages/account-config/tsconfig.spec.json"],
"tsConfig": [
"packages/account-config/tsconfig.lib.json",
"packages/account-config/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
@ -434,21 +452,6 @@
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
"lazy": true,
"bundleName": "fontawesome-v4-shims.min"
},
{
"input": "node_modules/primeng/resources/themes/nova-light/theme.css",
"lazy": true,
"bundleName": "primeng-nova-light-theme"
},
{
"input": "node_modules/primeicons/primeicons.css",
"lazy": true,
"bundleName": "primeicons"
},
{
"input": "node_modules/primeng/resources/primeng.min.css",
"lazy": true,
"bundleName": "primeng.min"
}
],
"scripts": []

8
npm/ng-packs/apps/dev-app/src/app/app.component.ts

@ -14,13 +14,7 @@ export class AppComponent implements OnInit {
ngOnInit() {
this.lazyLoadService
.load(
[
'primeng.min.css',
'primeicons.css',
'primeng-nova-light-theme.css',
'fontawesome-all.min.css',
'fontawesome-v4-shims.min.css',
],
['fontawesome-all.min.css', 'fontawesome-v4-shims.min.css'],
'style',
null,
'head',

43
npm/ng-packs/package.json

@ -21,24 +21,23 @@
"generate:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"devDependencies": {
"@abp/ng.account": "^2.0.1",
"@abp/ng.account.config": "^2.0.1",
"@abp/ng.core": "^2.0.1",
"@abp/ng.feature-management": "^2.0.1",
"@abp/ng.identity": "^2.0.1",
"@abp/ng.identity.config": "^2.0.1",
"@abp/ng.permission-management": "^2.0.1",
"@abp/ng.setting-management": "^2.0.1",
"@abp/ng.setting-management.config": "^2.0.1",
"@abp/ng.tenant-management": "^2.0.1",
"@abp/ng.tenant-management.config": "^2.0.1",
"@abp/ng.theme.basic": "^2.0.1",
"@abp/ng.theme.shared": "^2.0.1",
"@abp/ng.account": "^2.1.0",
"@abp/ng.account.config": "^2.1.0",
"@abp/ng.core": "^2.1.0",
"@abp/ng.feature-management": "^2.1.0",
"@abp/ng.identity": "^2.1.0",
"@abp/ng.identity.config": "^2.1.0",
"@abp/ng.permission-management": "^2.1.0",
"@abp/ng.setting-management": "^2.1.0",
"@abp/ng.setting-management.config": "^2.1.0",
"@abp/ng.tenant-management": "^2.1.0",
"@abp/ng.tenant-management.config": "^2.1.0",
"@abp/ng.theme.basic": "^2.1.0",
"@abp/ng.theme.shared": "^2.1.0",
"@angular-builders/jest": "^8.2.0",
"@angular-devkit/build-angular": "~0.803.21",
"@angular-devkit/build-ng-packagr": "~0.803.21",
"@angular/animations": "~8.2.14",
"@angular/cdk": "^8.2.3",
"@angular/cli": "~8.3.21",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
@ -46,23 +45,24 @@
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@angular/localize": "~9.0.2",
"@angular/platform-browser": "~8.2.14",
"@angular/platform-browser-dynamic": "~8.2.14",
"@angular/router": "~8.2.14",
"@fortawesome/fontawesome-free": "^5.11.2",
"@ng-bootstrap/ng-bootstrap": "^5.1.4",
"@fortawesome/fontawesome-free": "^5.12.1",
"@ng-bootstrap/ng-bootstrap": "^5.3.0",
"@ngneat/spectator": "^4.5.0",
"@ngx-validate/core": "^0.0.7",
"@ngxs/devtools-plugin": "^3.5.1",
"@ngxs/logger-plugin": "^3.5.1",
"@ngxs/router-plugin": "^3.5.1",
"@ngxs/storage-plugin": "^3.5.1",
"@ngxs/store": "^3.5.1",
"@ngxs/router-plugin": "^3.6.2",
"@ngxs/storage-plugin": "^3.6.2",
"@ngxs/store": "^3.6.2",
"@types/jest": "^24.0.18",
"@types/node": "~8.9.4",
"angular-oauth2-oidc": "^8.0.4",
"bootstrap": "^4.3.1",
"chart.js": "^2.9.2",
"bootstrap": "^4.4.1",
"chart.js": "^2.9.3",
"codelyzer": "^5.1.2",
"conventional-changelog-cli": "^2.0.31",
"cz-conventional-changelog": "3.0.2",
@ -78,7 +78,6 @@
"ngxs-schematic": "^1.1.9",
"prettier": "^1.18.2",
"primeicons": "^2.0.0",
"primeng": "^8.1.1",
"protractor": "~5.4.0",
"rxjs": "~6.4.0",
"snq": "^1.0.3",

5
npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts

@ -1,12 +1,11 @@
import { eLayoutType, RestService, addAbpRoutes } from '@abp/ng.core';
import { addAbpRoutes, eLayoutType } from '@abp/ng.core';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AccountConfigService {
constructor(private router: Router, private restService: RestService) {
constructor() {
addAbpRoutes({
name: 'AbpAccount::Menu:Account',
path: 'account',

2
npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts

@ -24,7 +24,7 @@ export class ChangePasswordComponent
inProgress: boolean;
mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => {
if (PASSWORD_FIELDS.indexOf(control.name) < 0) return errors;
if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors;
return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch'));
};

1
npm/ng-packs/packages/core/ng-package.json

@ -6,6 +6,7 @@
},
"deleteDestPath": false,
"whitelistedNonPeerDependencies": [
"@angular/localize",
"@ngxs/router-plugin",
"@ngxs/storage-plugin",
"@ngxs/store",

7
npm/ng-packs/packages/core/package.json

@ -7,9 +7,10 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@ngxs/router-plugin": "^3.5.1",
"@ngxs/storage-plugin": "^3.5.1",
"@ngxs/store": "^3.5.1",
"@angular/localize": "~9.0.2",
"@ngxs/router-plugin": "^3.6.2",
"@ngxs/storage-plugin": "^3.6.2",
"@ngxs/store": "^3.6.2",
"angular-oauth2-oidc": "^8.0.4",
"just-clone": "3.1.0",
"just-compare": "^1.3.0",

21
npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

@ -1,4 +1,4 @@
import { Component, Input, OnDestroy, Type } from '@angular/core';
import { Component, Input, OnDestroy, Type, Injector } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router, UrlSegment } from '@angular/router';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
@ -14,8 +14,10 @@ import { takeUntilDestroy } from '../utils/rxjs-utils';
template: `
<ng-container *ngTemplateOutlet="layout ? componentOutlet : routerOutlet"></ng-container>
<ng-template #routerOutlet><router-outlet></router-outlet></ng-template>
<ng-template #componentOutlet><ng-container *ngComponentOutlet="layout"></ng-container></ng-template>
`
<ng-template #componentOutlet
><ng-container *ngComponentOutlet="layout"></ng-container
></ng-template>
`,
})
export class DynamicLayoutComponent implements OnDestroy {
@Select(ConfigState.getOne('requirements')) requirements$: Observable<Config.Requirements>;
@ -25,18 +27,23 @@ export class DynamicLayoutComponent implements OnDestroy {
constructor(private router: Router, private route: ActivatedRoute, private store: Store) {
const {
requirements: { layouts },
routes
routes,
} = this.store.selectSnapshot(ConfigState.getAll);
if ((this.route.snapshot.data || {}).layout) {
this.layout = layouts
.filter(l => !!l)
.find((l: any) => snq(() => l.type.toLowerCase().indexOf(this.route.snapshot.data.layout), -1) > -1);
.find(
(l: any) =>
snq(() => l.type.toLowerCase().indexOf(this.route.snapshot.data.layout), -1) > -1,
);
}
this.router.events.pipe(takeUntilDestroy(this)).subscribe(event => {
router.events.pipe(takeUntilDestroy(this)).subscribe(event => {
if (event instanceof NavigationEnd) {
const { segments } = this.router.parseUrl(event.url).root.children.primary;
const segments = snq(() => router.parseUrl(event.url).root.children.primary.segments, [
{ path: router.url.replace('/', '') },
] as any);
const layout = (this.route.snapshot.data || {}).layout || findLayout(segments, routes);

21
npm/ng-packs/packages/core/src/lib/guards/auth.guard.ts

@ -1,5 +1,11 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Injectable, Injector } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc';
import { Observable } from 'rxjs';
@ -7,14 +13,19 @@ import { Observable } from 'rxjs';
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private oauthService: OAuthService, private router: Router) {}
constructor(private oauthService: OAuthService, private injector: Injector) {}
canActivate(
_: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> | boolean | UrlTree {
const router = this.injector.get(Router);
canActivate(_: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean | UrlTree {
const hasValidAccessToken = this.oauthService.hasValidAccessToken();
if (hasValidAccessToken) {
return hasValidAccessToken;
}
return this.router.createUrlTree(['/account/login'], { state: { redirectUrl: state.url } });
return router.createUrlTree(['/account/login'], { state: { redirectUrl: state.url } });
}
}

2
npm/ng-packs/packages/core/src/lib/states/config.state.ts

@ -14,11 +14,13 @@ import { Config } from '../models/config';
import { ApplicationConfigurationService } from '../services/application-configuration.service';
import { organizeRoutes } from '../utils/route-utils';
import { SessionState } from './session.state';
import { Injectable } from '@angular/core';
@State<Config.State>({
name: 'ConfigState',
defaults: {} as Config.State,
})
@Injectable()
export class ConfigState {
@Selector()
static getAll(state: Config.State) {

2
npm/ng-packs/packages/core/src/lib/states/profile.state.ts

@ -3,11 +3,13 @@ import { tap } from 'rxjs/operators';
import { ChangePassword, GetProfile, UpdateProfile } from '../actions/profile.actions';
import { Profile } from '../models/profile';
import { ProfileService } from '../services/profile.service';
import { Injectable } from '@angular/core';
@State<Profile.State>({
name: 'ProfileState',
defaults: {} as Profile.State,
})
@Injectable()
export class ProfileState {
@Selector()
static getProfile({ profile }: Profile.State): Profile.Response {

2
npm/ng-packs/packages/core/src/lib/states/replaceable-components.state.ts

@ -2,11 +2,13 @@ import { State, Action, StateContext, Selector, createSelector } from '@ngxs/sto
import { AddReplaceableComponent } from '../actions/replaceable-components.actions';
import { ReplaceableComponents } from '../models/replaceable-components';
import snq from 'snq';
import { Injectable } from '@angular/core';
@State<ReplaceableComponents.State>({
name: 'ReplaceableComponentsState',
defaults: { replaceableComponents: [] } as ReplaceableComponents.State,
})
@Injectable()
export class ReplaceableComponentsState {
@Selector()
static getAll({

2
npm/ng-packs/packages/core/src/lib/states/session.state.ts

@ -20,11 +20,13 @@ import {
import { ABP, Session } from '../models';
import { LocalizationService } from '../services/localization.service';
import { OAuthService } from 'angular-oauth2-oidc';
import { Injectable } from '@angular/core';
@State<Session.State>({
name: 'SessionState',
defaults: { sessionDetail: { openedTabCount: 0 } } as Session.State,
})
@Injectable()
export class SessionState {
@Selector()
static getLanguage({ language }: Session.State): string {

2
npm/ng-packs/packages/feature-management/src/lib/states/feature-management.state.ts

@ -3,11 +3,13 @@ import { tap } from 'rxjs/operators';
import { GetFeatures, UpdateFeatures } from '../actions/feature-management.actions';
import { FeatureManagement } from '../models/feature-management';
import { FeatureManagementService } from '../services/feature-management.service';
import { Injectable } from '@angular/core';
@State<FeatureManagement.State>({
name: 'FeatureManagementState',
defaults: { features: {} } as FeatureManagement.State,
})
@Injectable()
export class FeatureManagementState {
@Selector()
static getFeatures({ features }: FeatureManagement.State) {

20
npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts

@ -1,13 +1,11 @@
import { addAbpRoutes, eLayoutType, RestService } from '@abp/ng.core';
import { addAbpRoutes, eLayoutType } from '@abp/ng.core';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class IdentityConfigService {
constructor(private router: Router, private restService: RestService) {
constructor() {
addAbpRoutes([
{
name: 'AbpUiNavigation::Menu:Administration',
@ -24,8 +22,18 @@ export class IdentityConfigService {
layout: eLayoutType.application,
iconClass: 'fa fa-id-card-o',
children: [
{ path: 'roles', name: 'AbpIdentity::Roles', order: 1, requiredPolicy: 'AbpIdentity.Roles' },
{ path: 'users', name: 'AbpIdentity::Users', order: 2, requiredPolicy: 'AbpIdentity.Users' },
{
path: 'roles',
name: 'AbpIdentity::Roles',
order: 1,
requiredPolicy: 'AbpIdentity.Roles',
},
{
path: 'users',
name: 'AbpIdentity::Users',
order: 2,
requiredPolicy: 'AbpIdentity.Users',
},
],
},
]);

2
npm/ng-packs/packages/identity/src/lib/states/identity.state.ts

@ -15,11 +15,13 @@ import {
} from '../actions/identity.actions';
import { Identity } from '../models/identity';
import { IdentityService } from '../services/identity.service';
import { Injectable } from '@angular/core';
@State<Identity.State>({
name: 'IdentityState',
defaults: { roles: {}, selectedRole: {}, users: {}, selectedUser: {} } as Identity.State,
})
@Injectable()
export class IdentityState {
@Selector()
static getRoles({ roles }: Identity.State): Identity.RoleItem[] {

7
npm/ng-packs/packages/permission-management/src/lib/states/permission-management.state.ts

@ -3,11 +3,13 @@ import { GetPermissions, UpdatePermissions } from '../actions/permission-managem
import { PermissionManagement } from '../models/permission-management';
import { PermissionManagementService } from '../services/permission-management.service';
import { tap } from 'rxjs/operators';
import { Injectable } from '@angular/core';
@State<PermissionManagement.State>({
name: 'PermissionManagementState',
defaults: { permissionRes: {} } as PermissionManagement.State,
})
@Injectable()
export class PermissionManagementState {
@Selector()
static getPermissionGroups({ permissionRes }: PermissionManagement.State) {
@ -22,7 +24,10 @@ export class PermissionManagementState {
constructor(private permissionManagementService: PermissionManagementService) {}
@Action(GetPermissions)
permissionManagementGet({ patchState }: StateContext<PermissionManagement.State>, { payload }: GetPermissions) {
permissionManagementGet(
{ patchState }: StateContext<PermissionManagement.State>,
{ payload }: GetPermissions,
) {
return this.permissionManagementService.getPermissions(payload).pipe(
tap(permissionResponse =>
patchState({

12
npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, Injector } from '@angular/core';
import { addAbpRoutes, eLayoutType, PatchRouteByName, ABP } from '@abp/ng.core';
import { getSettingTabs } from '@abp/ng.theme.shared';
import { Store } from '@ngxs/store';
@ -7,7 +7,11 @@ import { Store } from '@ngxs/store';
providedIn: 'root',
})
export class SettingManagementConfigService {
constructor(private store: Store) {
get store(): Store {
return this.injector.get(Store);
}
constructor(private injector: Injector) {
const route = {
name: 'AbpSettingManagement::Settings',
path: 'setting-management',
@ -23,7 +27,9 @@ export class SettingManagementConfigService {
setTimeout(() => {
const tabs = getSettingTabs();
if (!tabs || !tabs.length) {
this.store.dispatch(new PatchRouteByName('AbpSettingManagement::Settings', { ...route, invisible: true }));
this.store.dispatch(
new PatchRouteByName('AbpSettingManagement::Settings', { ...route, invisible: true }),
);
}
});
}

16
npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts

@ -1,11 +1,9 @@
import { Component, TrackByFunction, OnInit } from '@angular/core';
import { SettingTab, getSettingTabs } from '@abp/ng.theme.shared';
import { Router } from '@angular/router';
import { Store } from '@ngxs/store';
import { ConfigState } from '@abp/ng.core';
import { SettingManagementState } from '../states/setting-management.state';
import { getSettingTabs, SettingTab } from '@abp/ng.theme.shared';
import { Component, OnInit, TrackByFunction } from '@angular/core';
import { Store } from '@ngxs/store';
import { SetSelectedSettingTab } from '../actions/setting-management.actions';
import { RouterState } from '@ngxs/router-plugin';
import { SettingManagementState } from '../states/setting-management.state';
@Component({
selector: 'abp-setting-management',
@ -29,11 +27,13 @@ export class SettingManagementComponent implements OnInit {
trackByFn: TrackByFunction<SettingTab> = (_, item) => item.name;
constructor(private router: Router, private store: Store) {}
constructor(private store: Store) {}
ngOnInit() {
this.settings = getSettingTabs()
.filter(setting => this.store.selectSnapshot(ConfigState.getGrantedPolicy(setting.requiredPolicy)))
.filter(setting =>
this.store.selectSnapshot(ConfigState.getGrantedPolicy(setting.requiredPolicy)),
)
.sort((a, b) => a.order - b.order);
if (!this.selected && this.settings.length) {

7
npm/ng-packs/packages/setting-management/src/lib/states/setting-management.state.ts

@ -1,11 +1,13 @@
import { Action, Selector, State, StateContext } from '@ngxs/store';
import { SetSelectedSettingTab } from '../actions/setting-management.actions';
import { SettingManagement } from '../models/setting-management';
import { Injectable } from '@angular/core';
@State<SettingManagement.State>({
name: 'SettingManagementState',
defaults: { selectedTab: {} } as SettingManagement.State,
})
@Injectable()
export class SettingManagementState {
@Selector()
static getSelectedTab({ selectedTab }: SettingManagement.State) {
@ -13,7 +15,10 @@ export class SettingManagementState {
}
@Action(SetSelectedSettingTab)
settingManagementAction({ patchState }: StateContext<SettingManagement.State>, { payload }: SetSelectedSettingTab) {
settingManagementAction(
{ patchState }: StateContext<SettingManagement.State>,
{ payload }: SetSelectedSettingTab,
) {
patchState({
selectedTab: payload,
});

2
npm/ng-packs/packages/tenant-management/src/lib/states/tenant-management.state.ts

@ -10,11 +10,13 @@ import {
} from '../actions/tenant-management.actions';
import { TenantManagement } from '../models/tenant-management';
import { TenantManagementService } from '../services/tenant-management.service';
import { Injectable } from '@angular/core';
@State<TenantManagement.State>({
name: 'TenantManagementState',
defaults: { result: {}, selectedItem: {} } as TenantManagement.State,
})
@Injectable()
export class TenantManagementState {
@Selector()
static get({ result }: TenantManagement.State): ABP.BasicItem[] {

4
npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.html

@ -147,7 +147,9 @@
</nav>
<div
[@slideFromBottom]="outlet && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path"
[@slideFromBottom]="
outlet && outlet.isActivated && outlet.activatedRoute && outlet.activatedRoute.routeConfig.path
"
class="container"
>
<router-outlet #outlet="outlet"></router-outlet>

4
npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

@ -123,4 +123,8 @@ background-color: rgba(0, 0, 0, 0.6);
.confirmation .confirmation-dialog .footer .confirmation-button--confirm:hover {
background-color: #2e819b;
}
.ui-table .pagination-wrapper {
background-color: #f4f4f4;
border: 1px solid #c8c8c8;
}
`;

2
npm/ng-packs/packages/theme-basic/src/lib/states/layout.state.ts

@ -2,11 +2,13 @@ import { Action, Selector, State, StateContext } from '@ngxs/store';
import snq from 'snq';
import { AddNavigationElement, RemoveNavigationElementByName } from '../actions/layout.actions';
import { Layout } from '../models/layout';
import { Injectable } from '@angular/core';
@State<Layout.State>({
name: 'LayoutState',
defaults: { navigationElements: [] } as Layout.State,
})
@Injectable()
export class LayoutState {
@Selector()
static getNavigationElements({ navigationElements }: Layout.State): Layout.NavigationElement[] {

3
npm/ng-packs/packages/theme-shared/ng-package.json

@ -6,14 +6,11 @@
},
"whitelistedNonPeerDependencies": [
"@abp/ng.core",
"@angular/cdk",
"@fortawesome/fontawesome-free",
"@ng-bootstrap/ng-bootstrap",
"@ngx-validate/core",
"bootstrap",
"font-awesome",
"primeicons",
"primeng",
"chart.js"
]
}

12
npm/ng-packs/packages/theme-shared/package.json

@ -8,15 +8,11 @@
},
"dependencies": {
"@abp/ng.core": "^2.1.0",
"@angular/cdk": "^8.2.3",
"@fortawesome/fontawesome-free": "^5.11.2",
"@ng-bootstrap/ng-bootstrap": "^5.1.4",
"@fortawesome/fontawesome-free": "^5.12.1",
"@ng-bootstrap/ng-bootstrap": "^5.3.0",
"@ngx-validate/core": "^0.0.7",
"bootstrap": "^4.3.1",
"chart.js": "^2.9.2",
"font-awesome": "^4.7.0",
"primeicons": "^2.0.0",
"primeng": "^8.1.1"
"bootstrap": "^4.4.1",
"chart.js": "^2.9.3"
},
"publishConfig": {
"access": "public"

3
npm/ng-packs/packages/theme-shared/src/lib/components/pagination/pagination.component.ts

@ -4,6 +4,9 @@ import { Component, Input, OnInit, Output, EventEmitter, TrackByFunction } from
selector: 'abp-pagination',
templateUrl: 'pagination.component.html',
})
/**
* @deprecated
*/
export class PaginationComponent implements OnInit {
private _value = 1;
@Input()

17
npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.html

@ -3,12 +3,17 @@
<ng-container
*ngTemplateOutlet="scrollable ? scrollableTemplate : defaultTemplate"
></ng-container>
<abp-pagination
*ngIf="rows"
[totalPages]="totalPages"
[(value)]="page"
(valueChange)="pageChange.emit($event)"
></abp-pagination>
<div class="pagination-wrapper">
<ngb-pagination
[class.op-0]="!totalPages"
[collectionSize]="totalPages"
[pageSize]="1"
[page]="page"
(pageChange)="pageChange.emit($event)"
[maxSize]="3"
[rotate]="true"
></ngb-pagination>
</div>
</div>
</div>

339
npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.scss

@ -0,0 +1,339 @@
.ui-table {
position: relative;
.ui-table-tbody > tr:nth-child(even):hover,
.ui-table-tbody > tr:hover {
filter: brightness(90%);
}
.ui-table-tbody > tr.empty-row:hover {
filter: none;
}
.ui-table-tbody > tr.empty-row > div.empty-row-content {
padding: 10px;
text-align: center;
}
.ui-table-caption,
.ui-table-summary {
background-color: #f4f4f4;
color: #333333;
border: 1px solid #c8c8c8;
padding: 0.571em 1em;
text-align: center;
}
.ui-table-caption {
border-bottom: 0 none;
font-weight: 700;
}
.ui-table-summary {
border-top: 0 none;
font-weight: 700;
}
.ui-table-thead > tr > th {
padding: 0.571em 0.857em;
border: 1px solid #c8c8c8;
font-weight: 700;
color: #333333;
background-color: #f4f4f4;
}
.ui-table-tbody > tr > td {
padding: 0.571em 0.857em;
}
.ui-table-tfoot > tr > td {
padding: 0.571em 0.857em;
border: 1px solid #c8c8c8;
font-weight: 700;
color: #333333;
background-color: #ffffff;
}
.ui-sortable-column {
-moz-transition: box-shadow 0.2s;
-o-transition: box-shadow 0.2s;
-webkit-transition: box-shadow 0.2s;
transition: box-shadow 0.2s;
}
.ui-sortable-column:focus {
outline: 0 none;
outline-offset: 0;
-webkit-box-shadow: inset 0 0 0 0.2em #8dcdff;
-moz-box-shadow: inset 0 0 0 0.2em #8dcdff;
box-shadow: inset 0 0 0 0.2em #8dcdff;
}
.ui-sortable-column .ui-sortable-column-icon {
color: #848484;
}
.ui-sortable-column:not(.ui-state-highlight):hover {
background-color: #e0e0e0;
color: #333333;
}
.ui-sortable-column:not(.ui-state-highlight):hover .ui-sortable-column-icon {
color: #333333;
}
.ui-sortable-column.ui-state-highlight {
background-color: #007ad9;
color: #ffffff;
}
.ui-sortable-column.ui-state-highlight .ui-sortable-column-icon {
color: #ffffff;
}
.ui-editable-column input {
font-size: 14px;
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
}
.ui-editable-column input:focus {
outline: 1px solid #007ad9;
outline-offset: 2px;
}
.ui-table-tbody > tr {
background-color: #ffffff;
color: #333333;
}
.ui-table-tbody > tr > td {
background-color: inherit;
border: 1px solid #c8c8c8;
}
.ui-table-tbody > tr.ui-state-highlight {
background-color: #007ad9;
color: #ffffff;
}
.ui-table-tbody > tr.ui-state-highlight a {
color: #ffffff;
}
.ui-table-tbody > tr.ui-contextmenu-selected {
background-color: #007ad9;
color: #ffffff;
}
.ui-table-tbody > tr.ui-table-dragpoint-top > td {
-webkit-box-shadow: inset 0 2px 0 0 #007ad9;
-moz-box-shadow: inset 0 2px 0 0 #007ad9;
box-shadow: inset 0 2px 0 0 #007ad9;
}
.ui-table-tbody > tr.ui-table-dragpoint-bottom > td {
-webkit-box-shadow: inset 0 -2px 0 0 #007ad9;
-moz-box-shadow: inset 0 -2px 0 0 #007ad9;
box-shadow: inset 0 -2px 0 0 #007ad9;
}
.ui-table-tbody > tr:nth-child(even) {
background-color: #f9f9f9;
}
.ui-table-tbody > tr:nth-child(even).ui-state-highlight {
background-color: #007ad9;
color: #ffffff;
}
.ui-table-tbody > tr:nth-child(even).ui-state-highlight a {
color: #ffffff;
}
.ui-table-tbody > tr:nth-child(even).ui-contextmenu-selected {
background-color: #007ad9;
color: #ffffff;
}
&.ui-table-hoverable-rows
.ui-table-tbody
> tr.ui-selectable-row:not(.ui-state-highlight):not(.ui-contextmenu-selected):hover {
cursor: pointer;
background-color: #eaeaea;
color: #333333;
}
.ui-column-resizer-helper {
background-color: #007ad9;
}
@media screen and (max-width: 40em) {
&.ui-table-responsive .ui-table-tbody > tr > td {
border: 0 none;
}
}
table {
border-collapse: collapse;
width: 100%;
table-layout: fixed;
}
.ui-table-tbody > tr > td,
.ui-table-tfoot > tr > td,
.ui-table-thead > tr > th {
padding: 0.571em 0.857em;
}
.ui-sortable-column {
cursor: pointer;
}
p-sorticon {
vertical-align: middle;
}
.ui-table-auto-layout > .ui-table-wrapper {
overflow-x: auto;
}
.ui-table-auto-layout > .ui-table-wrapper > table {
table-layout: auto;
}
.ui-table-caption,
.ui-table-summary {
padding: 0.25em 0.5em;
text-align: center;
font-weight: 700;
}
.ui-table-caption {
border-bottom: 0;
}
.ui-table-summary {
border-top: 0;
}
.ui-table-scrollable-wrapper {
position: relative;
}
.ui-table-scrollable-footer,
.ui-table-scrollable-header {
overflow: hidden;
border: 0;
}
.ui-table-scrollable-body {
overflow: auto;
position: relative;
}
.ui-table-virtual-table {
position: absolute;
}
.ui-table-loading-virtual-table {
display: none;
}
.ui-table-frozen-view .ui-table-scrollable-body {
overflow: hidden;
}
.ui-table-frozen-view > .ui-table-scrollable-body > table > .ui-table-tbody > tr > td:last-child {
border-right: 0;
}
.ui-table-unfrozen-view {
position: absolute;
top: 0;
}
.ui-table-resizable > .ui-table-wrapper {
overflow-x: auto;
}
.ui-table-resizable .ui-table-tbody > tr > td,
.ui-table-resizable .ui-table-tfoot > tr > td,
.ui-table-resizable .ui-table-thead > tr > th {
overflow: hidden;
}
.ui-table-resizable .ui-resizable-column {
background-clip: padding-box;
position: relative;
}
.ui-table-resizable-fit .ui-resizable-column:last-child .ui-column-resizer {
display: none;
}
.ui-column-resizer {
display: block;
position: absolute !important;
top: 0;
right: 0;
margin: 0;
width: 0.5em;
height: 100%;
padding: 0;
cursor: col-resize;
border: 1px solid rgba(0, 0, 0, 0);
}
.ui-column-resizer-helper {
width: 1px;
position: absolute;
z-index: 10;
display: none;
}
.ui-table-tbody > tr > td.ui-editing-cell {
padding: 0;
}
.ui-table-tbody > tr > td.ui-editing-cell p-celleditor > * {
width: 100%;
}
.ui-table-reorder-indicator-down,
.ui-table-reorder-indicator-up {
position: absolute;
display: none;
}
.ui-table-responsive .ui-table-tbody > tr > td .ui-column-title {
display: none;
}
@media screen and (max-width: 40em) {
.ui-table-responsive .ui-table-tfoot > tr > td,
.ui-table-responsive .ui-table-thead > tr > th,
.ui-table-responsive colgroup {
display: none !important;
}
.ui-table-responsive .ui-table-tbody > tr > td {
text-align: left;
display: block;
border: 0;
width: 100% !important;
box-sizing: border-box;
float: left;
clear: left;
}
.ui-table-responsive .ui-table-tbody > tr > td .ui-column-title {
padding: 0.4em;
min-width: 30%;
display: inline-block;
margin: -0.4em 1em -0.4em -0.4em;
font-weight: 700;
}
}
.ui-widget {
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 14px;
text-decoration: none;
}
.page-item.disabled .page-link,
.page-link {
background-color: transparent;
border: none;
}
.page-item.disabled .page-link {
box-shadow: none;
}
.pagination {
margin-bottom: 0;
}
.pagination-wrapper {
display: flex;
justify-content: center;
border-top: 0;
padding: 0;
}
.op-0 {
opacity: 0;
}
}

18
npm/ng-packs/packages/theme-shared/src/lib/components/table/table.component.ts

@ -14,23 +14,7 @@ import {
@Component({
selector: 'abp-table',
templateUrl: 'table.component.html',
styles: [
`
.ui-table .ui-table-tbody > tr:nth-child(even):hover,
.ui-table .ui-table-tbody > tr:hover {
filter: brightness(90%);
}
.ui-table .ui-table-tbody > tr.empty-row:hover {
filter: none;
}
.ui-table .ui-table-tbody > tr.empty-row > div.empty-row-content {
padding: 10px;
text-align: center;
}
`,
],
styleUrls: ['table.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class TableComponent {

3
npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts

@ -220,11 +220,12 @@ export class ErrorHandler {
.resolveComponentFactory(HttpErrorWrapperComponent)
.create(this.injector);
for (const key in this.componentRef.instance) {
for (const key in instance) {
if (this.componentRef.instance.hasOwnProperty(key)) {
this.componentRef.instance[key] = instance[key];
}
}
this.componentRef.instance.hideCloseIcon = this.httpErrorConfig.errorScreen.hideCloseIcon;
if (this.canCreateCustomError(instance.status as ErrorScreenErrorCodes)) {
this.componentRef.instance.cfRes = this.cfRes;

63
npm/ng-packs/packages/theme-shared/src/lib/tests/pagination.component.spec.ts

@ -1,63 +0,0 @@
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { PaginationComponent } from '../components';
describe('PaginationComponent', () => {
let spectator: SpectatorHost<PaginationComponent>;
const createHost = createHostFactory({
component: PaginationComponent,
});
beforeEach(() => {
spectator = createHost(
'<abp-pagination [totalPages]="totalPages" [value]="value"></abp-pagination>',
{
hostProps: {
value: 5,
totalPages: 12,
},
},
);
});
it('should add ui-state-active class to current page', () => {
expect(spectator.query('.ui-state-active').textContent).toBe('5');
});
it('should display the correct pages', () => {
expect(spectator.queryAll('.ui-paginator-page').map(node => node.textContent)).toEqual([
'3',
'4',
'5',
'6',
'7',
]);
spectator.click('.ui-paginator-first');
expect(spectator.queryAll('.ui-paginator-page').map(node => node.textContent)).toEqual([
'1',
'2',
'3',
'4',
'5',
]);
spectator.setHostInput({ value: 12 });
expect(spectator.queryAll('.ui-paginator-page').map(node => node.textContent)).toEqual([
'8',
'9',
'10',
'11',
'12',
]);
spectator.setHostInput({ value: 1, totalPages: 3 });
expect(spectator.queryAll('.ui-paginator-page').map(node => node.textContent)).toEqual([
'1',
'2',
'3',
]);
});
});

2
npm/ng-packs/packages/theme-shared/src/lib/tests/table-sort.directive.spec.ts

@ -3,6 +3,7 @@ import { TableSortDirective } from '../directives/table-sort.directive';
import { TableComponent } from '../components/table/table.component';
import { DummyLocalizationPipe } from './table.component.spec';
import { PaginationComponent } from '../components';
import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
describe('TableSortDirective', () => {
let spectator: SpectatorDirective<TableSortDirective>;
@ -10,6 +11,7 @@ describe('TableSortDirective', () => {
const createDirective = createDirectiveFactory({
directive: TableSortDirective,
declarations: [TableComponent, DummyLocalizationPipe, PaginationComponent],
imports: [NgbPaginationModule],
});
beforeEach(() => {

2
npm/ng-packs/packages/theme-shared/src/lib/tests/table.component.spec.ts

@ -2,6 +2,7 @@ import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { PaginationComponent, TableComponent } from '../components';
import { Pipe, PipeTransform } from '@angular/core';
import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
@Pipe({
name: 'abpLocalization',
@ -17,6 +18,7 @@ describe('TableComponent', () => {
const createHost = createHostFactory({
component: TableComponent,
declarations: [PaginationComponent, DummyLocalizationPipe],
imports: [NgbPaginationModule],
});
describe('without value', () => {

4
npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

@ -1,7 +1,7 @@
import { CoreModule, LazyLoadService } from '@abp/ng.core';
import { DatePipe } from '@angular/common';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { NgbDateParserFormatter, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
import { ButtonComponent } from './components/button/button.component';
@ -38,7 +38,7 @@ export function appendScript(injector: Injector) {
}
@NgModule({
imports: [CoreModule, NgxValidateCoreModule],
imports: [CoreModule, NgxValidateCoreModule, NgbPaginationModule],
declarations: [
BreadcrumbComponent,
ButtonComponent,

59
npm/ng-packs/scripts/yarn.lock

@ -3,9 +3,9 @@
"@types/fs-extra@^8.0.1":
version "8.0.1"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686"
integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==
version "8.1.0"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.0.tgz#1114834b53c3914806cd03b3304b37b3bd221a4d"
integrity sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==
dependencies:
"@types/node" "*"
@ -14,15 +14,10 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/node@*":
version "13.7.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
"@types/node@^13.1.2":
version "13.1.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.2.tgz#fe94285bf5e0782e1a9e5a8c482b1c34465fa385"
integrity sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ==
"@types/node@*", "@types/node@^13.1.2":
version "13.7.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113"
integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==
ansi-bgblack@^0.1.1:
version "0.1.1"
@ -260,9 +255,9 @@ ansi-yellow@^0.1.1:
ansi-wrap "0.1.0"
arg@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.2.tgz#e70c90579e02c63d80e3ad4e31d8bfdb8bd50064"
integrity sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
arr-flatten@^1.1.0:
version "1.1.0"
@ -490,9 +485,9 @@ define-property@^2.0.2:
isobject "^3.0.1"
diff@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
end-of-stream@^1.1.0:
version "1.4.4"
@ -742,9 +737,9 @@ kind-of@^5.0.0, kind-of@^5.0.2:
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
koalas@^1.0.2:
version "1.0.2"
@ -792,9 +787,9 @@ loose-envify@^1.0.0:
js-tokens "^3.0.0 || ^4.0.0"
make-error@^1.1.1:
version "1.3.5"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
map-visit@^1.0.0:
version "1.0.0"
@ -1154,15 +1149,15 @@ toggle-array@^1.0.1:
isobject "^3.0.0"
ts-node@^8.5.4:
version "8.5.4"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.5.4.tgz#a152add11fa19c221d0b48962c210cf467262ab2"
integrity sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==
version "8.6.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35"
integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==
dependencies:
arg "^4.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.6"
yn "^3.0.0"
yn "3.1.1"
tsconfig-paths@^3.9.0:
version "3.9.0"
@ -1175,9 +1170,9 @@ tsconfig-paths@^3.9.0:
strip-bom "^3.0.0"
typescript@^3.7.4:
version "3.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
version "3.8.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a"
integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==
universalify@^0.1.0:
version "0.1.2"
@ -1209,7 +1204,7 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
yn@^3.0.0:
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==

3098
npm/ng-packs/yarn.lock

File diff suppressed because it is too large

1
samples/EfCoreMigrationDemo/.gitattributes

@ -0,0 +1 @@
**/wwwroot/libs/** linguist-vendored

259
samples/EfCoreMigrationDemo/.gitignore

@ -0,0 +1,259 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# BookStore
src/Acme.BookStore.Web/Logs/*
src/Acme.BookStore.Web.Host/Logs/*
src/Acme.BookStore.IdentityServer/Logs/*
src/Acme.BookStore.HttpApi.Host/Logs/*
src/Acme.BookStore.HttpApi.HostWithIds/Logs/*

144
samples/EfCoreMigrationDemo/Acme.BookStore.sln

@ -0,0 +1,144 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29020.237
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain", "src\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj", "{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application", "src\Acme.BookStore.Application\Acme.BookStore.Application.csproj", "{1A94A50E-06DC-43C1-80B5-B662820EC3EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.EntityFrameworkCore", "src\Acme.BookStore.EntityFrameworkCore\Acme.BookStore.EntityFrameworkCore.csproj", "{C956DD76-69C8-4A9C-83EA-D17DF83340FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Web", "src\Acme.BookStore.Web\Acme.BookStore.Web.csproj", "{068855E8-9240-4F1A-910B-CF825794513B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CA9AC87F-097E-4F15-8393-4BC07735A5B0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{04DBDB01-70F4-4E06-B468-8F87850B22BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Tests", "test\Acme.BookStore.Application.Tests\Acme.BookStore.Application.Tests.csproj", "{50B2631D-129C-47B3-A587-029CCD6099BC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Web.Tests", "test\Acme.BookStore.Web.Tests\Acme.BookStore.Web.Tests.csproj", "{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.EntityFrameworkCore.DbMigrations", "src\Acme.BookStore.EntityFrameworkCore.DbMigrations\Acme.BookStore.EntityFrameworkCore.DbMigrations.csproj", "{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Shared", "src\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj", "{42F719ED-8413-4895-B5B4-5AB56079BC66}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Contracts", "src\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj", "{520659C8-C734-4298-A3DA-B539DB9DFC0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi", "src\Acme.BookStore.HttpApi\Acme.BookStore.HttpApi.csproj", "{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi.Client", "src\Acme.BookStore.HttpApi.Client\Acme.BookStore.HttpApi.Client.csproj", "{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.EntityFrameworkCore.Tests", "test\Acme.BookStore.EntityFrameworkCore.Tests\Acme.BookStore.EntityFrameworkCore.Tests.csproj", "{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.TestBase", "test\Acme.BookStore.TestBase\Acme.BookStore.TestBase.csproj", "{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Tests", "test\Acme.BookStore.Domain.Tests\Acme.BookStore.Domain.Tests.csproj", "{E512F4D9-9375-480F-A2F6-A46509F9D824}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi.Client.ConsoleTestApp", "test\Acme.BookStore.HttpApi.Client.ConsoleTestApp\Acme.BookStore.HttpApi.Client.ConsoleTestApp.csproj", "{EF480016-9127-4916-8735-D2466BDBC582}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.DbMigrator", "src\Acme.BookStore.DbMigrator\Acme.BookStore.DbMigrator.csproj", "{AA94D832-1CCC-4715-95A9-A483F23A1A5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb", "src\Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb\Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb.csproj", "{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.Build.0 = Release|Any CPU
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.Build.0 = Release|Any CPU
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.Build.0 = Release|Any CPU
{068855E8-9240-4F1A-910B-CF825794513B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{068855E8-9240-4F1A-910B-CF825794513B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{068855E8-9240-4F1A-910B-CF825794513B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{068855E8-9240-4F1A-910B-CF825794513B}.Release|Any CPU.Build.0 = Release|Any CPU
{50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.Build.0 = Release|Any CPU
{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.Build.0 = Release|Any CPU
{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Release|Any CPU.Build.0 = Release|Any CPU
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Release|Any CPU.Build.0 = Release|Any CPU
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Release|Any CPU.Build.0 = Release|Any CPU
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Release|Any CPU.Build.0 = Release|Any CPU
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Release|Any CPU.Build.0 = Release|Any CPU
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Release|Any CPU.Build.0 = Release|Any CPU
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Release|Any CPU.Build.0 = Release|Any CPU
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Release|Any CPU.Build.0 = Release|Any CPU
{EF480016-9127-4916-8735-D2466BDBC582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF480016-9127-4916-8735-D2466BDBC582}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF480016-9127-4916-8735-D2466BDBC582}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF480016-9127-4916-8735-D2466BDBC582}.Release|Any CPU.Build.0 = Release|Any CPU
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Release|Any CPU.Build.0 = Release|Any CPU
{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{1A94A50E-06DC-43C1-80B5-B662820EC3EB} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{C956DD76-69C8-4A9C-83EA-D17DF83340FD} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{068855E8-9240-4F1A-910B-CF825794513B} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{50B2631D-129C-47B3-A587-029CCD6099BC} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{5F1B28C6-8D0C-4155-92D0-252F7EA5F674} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{42F719ED-8413-4895-B5B4-5AB56079BC66} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{520659C8-C734-4298-A3DA-B539DB9DFC0B} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{E512F4D9-9375-480F-A2F6-A46509F9D824} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{EF480016-9127-4916-8735-D2466BDBC582} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
{AA94D832-1CCC-4715-95A9-A483F23A1A5D} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
{9F050D17-3D9E-4A0F-B8F9-D90460ABDC76} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
EndGlobalSection
EndGlobal

23
samples/EfCoreMigrationDemo/Acme.BookStore.sln.DotSettings

@ -0,0 +1,23 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceIfStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceLockStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String>
</wpf:ResourceDictionary>

7
samples/EfCoreMigrationDemo/common.props

@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>1.0.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>
</Project>

22
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Acme.BookStore.Application.Contracts.csproj

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Acme.BookStore</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Account.Application.Contracts" Version="2.1.1" />
<PackageReference Include="Volo.Abp.Identity.Application.Contracts" Version="2.1.1" />
<PackageReference Include="Volo.Abp.PermissionManagement.Application.Contracts" Version="2.1.1" />
<PackageReference Include="Volo.Abp.TenantManagement.Application.Contracts" Version="2.1.1" />
<PackageReference Include="Volo.Abp.FeatureManagement.Application.Contracts" Version="2.1.1" />
</ItemGroup>
</Project>

22
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/BookStoreApplicationContractsModule.cs

@ -0,0 +1,22 @@
using Volo.Abp.Account;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.TenantManagement;
namespace Acme.BookStore
{
[DependsOn(
typeof(BookStoreDomainSharedModule),
typeof(AbpAccountApplicationContractsModule),
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpIdentityApplicationContractsModule),
typeof(AbpPermissionManagementApplicationContractsModule),
typeof(AbpTenantManagementApplicationContractsModule)
)]
public class BookStoreApplicationContractsModule : AbpModule
{
}
}

22
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissionDefinitionProvider.cs

@ -0,0 +1,22 @@
using Acme.BookStore.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
namespace Acme.BookStore.Permissions
{
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup(BookStorePermissions.GroupName);
//Define your own permissions here. Example:
//myGroup.AddPermission(BookStorePermissions.MyPermission1, L("Permission:MyPermission1"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<BookStoreResource>(name);
}
}
}

10
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissions.cs

@ -0,0 +1,10 @@
namespace Acme.BookStore.Permissions
{
public static class BookStorePermissions
{
public const string GroupName = "BookStore";
//Add your own permission names. Example:
//public const string MyPermission1 = GroupName + ".MyPermission1";
}
}

12
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Roles/AppRoleDto.cs

@ -0,0 +1,12 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Roles
{
public class AppRoleDto : EntityDto<Guid>
{
public string Name { get; set; }
public string Title { get; set; }
}
}

14
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application.Contracts/Roles/IAppRoleAppService.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Roles
{
public interface IAppRoleAppService : IApplicationService
{
Task<List<AppRoleDto>> GetListAsync();
Task UpdateTitleAsync(Guid id, string title);
}
}

23
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Acme.BookStore</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj" />
<ProjectReference Include="..\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Account.Application" Version="2.1.1" />
<PackageReference Include="Volo.Abp.Identity.Application" Version="2.1.1" />
<PackageReference Include="Volo.Abp.PermissionManagement.Application" Version="2.1.1" />
<PackageReference Include="Volo.Abp.TenantManagement.Application" Version="2.1.1" />
<PackageReference Include="Volo.Abp.FeatureManagement.Application" Version="2.1.1" />
</ItemGroup>
</Project>

18
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreAppService.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using Acme.BookStore.Localization;
using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
/* Inherit your application services from this class.
*/
public abstract class BookStoreAppService : ApplicationService
{
protected BookStoreAppService()
{
LocalizationResource = typeof(BookStoreResource);
}
}
}

14
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs

@ -0,0 +1,14 @@
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
}
}
}

30
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/BookStoreApplicationModule.cs

@ -0,0 +1,30 @@
using Volo.Abp.Account;
using Volo.Abp.AutoMapper;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.TenantManagement;
namespace Acme.BookStore
{
[DependsOn(
typeof(BookStoreDomainModule),
typeof(AbpAccountApplicationModule),
typeof(BookStoreApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpFeatureManagementApplicationModule)
)]
public class BookStoreApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<BookStoreApplicationModule>();
});
}
}
}

42
samples/EfCoreMigrationDemo/src/Acme.BookStore.Application/Roles/AppRoleAppService.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Roles
{
public class AppRoleAppService : ApplicationService, IAppRoleAppService
{
private readonly IRepository<AppRole, Guid> _appRoleRepository;
public AppRoleAppService(IRepository<AppRole, Guid> appRoleRepository)
{
_appRoleRepository = appRoleRepository;
}
public async Task<List<AppRoleDto>> GetListAsync()
{
var roles = await _appRoleRepository.GetListAsync();
return roles
.Select(r => new AppRoleDto
{
Id = r.Id,
Name = r.Name,
Title = r.Title
})
.ToList();
}
public async Task UpdateTitleAsync(Guid id, string title)
{
var role = await _appRoleRepository.GetAsync(id);
role.Title = title;
await _appRoleRepository.UpdateAsync(role);
}
}
}

35
samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/Acme.BookStore.DbMigrator.csproj

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Autofac" Version="2.1.1" />
<ProjectReference Include="..\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj" />
<ProjectReference Include="..\Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb\Acme.BookStore.EntityFrameworkCore.DbMigrationsForSecondDb.csproj" />
<ProjectReference Include="..\Acme.BookStore.EntityFrameworkCore.DbMigrations\Acme.BookStore.EntityFrameworkCore.DbMigrations.csproj" />
</ItemGroup>
</Project>

22
samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/BookStoreDbMigratorModule.cs

@ -0,0 +1,22 @@
using Acme.BookStore.DbMigrationsForSecondDb.EntityFrameworkCore;
using Acme.BookStore.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Modularity;
namespace Acme.BookStore.DbMigrator
{
[DependsOn(
typeof(AbpAutofacModule),
typeof(BookStoreEntityFrameworkCoreDbMigrationsModule),
typeof(BookStoreEntityFrameworkCoreSecondDbMigrationsModule),
typeof(BookStoreApplicationContractsModule)
)]
public class BookStoreDbMigratorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobOptions>(options => options.IsJobExecutionEnabled = false);
}
}
}

34
samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/DbMigratorHostedService.cs

@ -0,0 +1,34 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Acme.BookStore.Data;
using Serilog;
using Volo.Abp;
namespace Acme.BookStore.DbMigrator
{
public class DbMigratorHostedService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
using (var application = AbpApplicationFactory.Create<BookStoreDbMigratorModule>(options =>
{
options.UseAutofac();
options.Services.AddLogging(c => c.AddSerilog());
}))
{
application.Initialize();
await application
.ServiceProvider
.GetRequiredService<BookStoreDbMigrationService>()
.MigrateAsync();
application.Shutdown();
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}

38
samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/Program.cs

@ -0,0 +1,38 @@
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
namespace Acme.BookStore.DbMigrator
{
class Program
{
static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
#if DEBUG
.MinimumLevel.Override("Acme.BookStore", LogEventLevel.Debug)
#else
.MinimumLevel.Override("Acme.BookStore", LogEventLevel.Information)
#endif
.Enrich.FromLogContext()
.WriteTo.File(Path.Combine(Directory.GetCurrentDirectory(), "Logs/logs.txt"))
.WriteTo.Console()
.CreateLogger();
await CreateHostBuilder(args).RunConsoleAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<DbMigratorHostedService>();
});
}
}

21
samples/EfCoreMigrationDemo/src/Acme.BookStore.DbMigrator/appsettings.json

@ -0,0 +1,21 @@
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"IdentityServer": {
"Clients": {
"BookStore_Web": {
"ClientId": "BookStore_Web",
"ClientSecret": "1q2w3e*",
"RootUrl": "https://localhost:44312"
},
"BookStore_App": {
"ClientId": "BookStore_App",
"ClientSecret": "1q2w3e*"
}
}
}
}

26
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Acme.BookStore.Domain.Shared.csproj

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Acme.BookStore</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Identity.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.IdentityServer.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.BackgroundJobs.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.AuditLogging.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.TenantManagement.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.FeatureManagement.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.Shared" Version="2.1.1" />
<PackageReference Include="Volo.Abp.SettingManagement.Domain.Shared" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\BookStore\*.json" />
<Content Remove="Localization\BookStore\*.json" />
</ItemGroup>
</Project>

7
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/BookStoreDomainErrorCodes.cs

@ -0,0 +1,7 @@
namespace Acme.BookStore
{
public static class BookStoreDomainErrorCodes
{
/* You can add your business exception error codes here, as constants */
}
}

45
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/BookStoreDomainSharedModule.cs

@ -0,0 +1,45 @@
using Acme.BookStore.Localization;
using Volo.Abp.AuditLogging;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement;
using Volo.Abp.SettingManagement;
using Volo.Abp.TenantManagement;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace Acme.BookStore
{
[DependsOn(
typeof(AbpAuditLoggingDomainSharedModule),
typeof(AbpBackgroundJobsDomainSharedModule),
typeof(AbpFeatureManagementDomainSharedModule),
typeof(AbpIdentityDomainSharedModule),
typeof(AbpIdentityServerDomainSharedModule),
typeof(AbpPermissionManagementDomainSharedModule),
typeof(AbpSettingManagementDomainSharedModule),
typeof(AbpTenantManagementDomainSharedModule)
)]
public class BookStoreDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<BookStoreDomainSharedModule>("Acme.BookStore");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<BookStoreResource>("en")
.AddBaseTypes(typeof(AbpValidationResource))
.AddVirtualJson("/Localization/BookStore");
});
}
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/cs.json

@ -0,0 +1,8 @@
{
"culture": "cs",
"texts": {
"Menu:Home": "Úvod",
"Welcome": "Vítejte",
"LongWelcomeMessage": "Vítejte v aplikaci. Toto je startovací projekt založený na ABP frameworku. Pro více informací, navštivte abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json

@ -0,0 +1,8 @@
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/pl.json

@ -0,0 +1,8 @@
{
"culture": "pl",
"texts": {
"Menu:Home": "Home",
"Welcome": "Witaj",
"LongWelcomeMessage": "Witaj w aplikacji. To jest inicjalny projekt bazujący na ABP framework. Po więcej informacji odwiedź stronę abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/pt-BR.json

@ -0,0 +1,8 @@
{
"culture": "pt-BR",
"texts": {
"Menu:Home": "Principal",
"Welcome": "Seja bem-vindo!",
"LongWelcomeMessage": "Bem-vindo a esta aplicação. Este é um projeto inicial baseado no ABP framework. Para mais informações, visite abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/tr.json

@ -0,0 +1,8 @@
{
"culture": "tr",
"texts": {
"Menu:Home": "Ana sayfa",
"Welcome": "Hoşgeldiniz",
"LongWelcomeMessage": "Uygulamaya hoşgeldiniz. Bu, ABP framework'ü üzerine bina edilmiş bir başlangıç projesidir. Daha fazla bilgi için abp.io adresini ziyaret edebilirsiniz."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/vi.json

@ -0,0 +1,8 @@
{
"culture": "vi",
"texts": {
"Menu:Home": "Trang chủ",
"Welcome": "Chào mừng bạn",
"LongWelcomeMessage": "Chào mừng bạn đến ứng dụng. Đây là một dự án khởi nghiệp dựa trên khung ABP. Để biết thêm thông tin, hãy truy cập abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/zh-Hans.json

@ -0,0 +1,8 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Home": "首页",
"Welcome": "欢迎",
"LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 abp.io."
}
}

8
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStore/zh-Hant.json

@ -0,0 +1,8 @@
{
"culture": "zh-Hant",
"texts": {
"Menu:Home": "首頁",
"Welcome": "歡迎",
"LongWelcomeMessage": "歡迎來到此應用程式. 這是一個基於ABP框架的起始專案. 有關更多訊息, 請瀏覽 abp.io."
}
}

10
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/Localization/BookStoreResource.cs

@ -0,0 +1,10 @@
using Volo.Abp.Localization;
namespace Acme.BookStore.Localization
{
[LocalizationResourceName("BookStore")]
public class BookStoreResource
{
}
}

11
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain.Shared/MultiTenancy/MultiTenancyConsts.cs

@ -0,0 +1,11 @@
namespace Acme.BookStore.MultiTenancy
{
public static class MultiTenancyConsts
{
/* Enable/disable multi-tenancy easily in a single point.
* If you will never need to multi-tenancy, you can remove
* related modules and code parts, including this file.
*/
public const bool IsEnabled = true;
}
}

27
samples/EfCoreMigrationDemo/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Acme.BookStore</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.DataAnnotations" Version="2.2.0" />
<PackageReference Include="Volo.Abp.Identity.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.Identity" Version="2.1.1" />
<PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.IdentityServer" Version="2.1.1" />
<PackageReference Include="Volo.Abp.BackgroundJobs.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.AuditLogging.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.TenantManagement.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.FeatureManagement.Domain" Version="2.1.1" />
<PackageReference Include="Volo.Abp.SettingManagement.Domain" Version="2.1.1" />
</ItemGroup>
</Project>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save