Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into dev

pull/2531/head
mehmet-erim 7 years ago
parent
commit
334b7b5b0f
  1. 0
      docs/cs/Entity-Framework-Core-PostgreSQL.md
  2. 2
      docs/cs/docs-nav.json
  3. 2
      docs/en/Best-Practices/Index.md
  4. 67
      docs/en/Connection-Strings.md
  5. 12
      docs/en/Data-Access.md
  6. 58
      docs/en/Entity-Framework-Core-MySQL.md
  7. 16
      docs/en/Entity-Framework-Core-PostgreSQL.md
  8. 44
      docs/en/Entity-Framework-Core.md
  9. 3
      docs/en/Modules/IdentityServer.md
  10. 2
      docs/en/Modules/Index.md
  11. 41
      docs/en/docs-nav.json
  12. 2
      docs/pt-BR/docs-nav.json
  13. 0
      docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md
  14. 2
      docs/zh-Hans/docs-nav.json
  15. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs
  16. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs
  17. 34
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs
  18. 26
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs
  19. 3
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs
  20. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs
  21. 38
      modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs

0
docs/cs/EntityFrameworkCore-PostgreSQL-Integration.md → docs/cs/Entity-Framework-Core-PostgreSQL.md

2
docs/cs/docs-nav.json

@ -264,7 +264,7 @@
"items": [
{
"text": "PostgreSQL integrace",
"path": "EntityFrameworkCore-PostgreSQL-Integration.md"
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},

2
docs/en/Best-Practices/Index.md

@ -23,5 +23,5 @@ Also, this guide is mostly usable for general **application development**.
* [Data Transfer Objects](Data-Transfer-Objects.md)
* Data Access
* [Entity Framework Core Integration](Entity-Framework-Core-Integration.md)
* [MongoDB Integration](MongoDB-Integration.md)
* [MongoDB Integration](MongoDB-Integration.md)

67
docs/en/Connection-Strings.md

@ -1,11 +1,64 @@
# Data Access
# Connection Strings
ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions.
ABP Framework is designed to be [modular](Module-Development-Basics.md), [microservice compatible](Microservice-Architecture.md) and [multi-tenancy](Multi-Tenancy.md) aware. Connection string management is also designed to support these scenarios;
However, currently the following providers are implements:
* Allows to set separate connection strings for every module, so every module can have its own physical database. Modules even might be configured to use different DBMSs.
* Allows to set separate connection string and use a separate database per tenant (in a SaaS application).
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).)
* [MongoDB](MongoDB.md)
* [Dapper](Dapper.md)
It also supports hybrid scenarios;
More providers might be added in the next releases.
* Allows to group modules into databases (all modules into a single shared database, 2 modules to database A, 3 modules to database B, 1 module to database C and rest of the modules to database D... etc.)
* Allows to group tenants into databases, just like the modules.
* Allows to separate databases per tenant per module (which might be harder to maintain for you because of too many databases, but the ABP framework supports it).
All the [pre-built application modules](Modules/Index.md) are designed to be compatible these scenarios.
## Configure the Connection Strings
See the following configuration:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;",
"AbpIdentityServer": "Server=localhost;Database=MyIdsDb;Trusted_Connection=True;",
"AbpPermissionManagement": "Server=localhost;Database=MyPermissionDb;Trusted_Connection=True;"
}
````
> ABP uses the `IConfiguration` service to get the application configuration. While the simplest way to write configuration into the `appsettings.json` file, it is not limited to this file. You can use environment variables, user secrets, Azure Key Vault... etc. See the [configuration](Configuration.md) document for more.
This configuration defines three different connection strings:
* `MyMainDb` (the `Default` connection string) is the main connection string of the application. If you don't specify a connection string for a module, it fallbacks to the `Default` connection string. The [application startup template](Startup-Templates/Application.md) is configured to use a single connection string, so all the modules uses a single shared database.
* `MyIdsDb` is used by the [IdentityServer](Modules/IdentityServer.md) module.
* `MyPermissionDb` is used by the [Permission Management](Modules/Permission-Management.md) module.
[Pre-built application modules](Modules/Index.md) define constants for the connection string names. For example, the IdentityServer module defines a ` ConnectionStringName ` constant in the ` AbpIdentityServerDbProperties ` class (located in the ` Volo.Abp.IdentityServer ` namespace). Other modules similarly define constants, so you can investigate the connection string name.
## Set the Connection String Name
A module typically has a unique connection string name associated to its `DbContext` class using the `ConnectionStringName` attribute. Example:
````csharp
[ConnectionStringName("AbpIdentityServer")]
public class IdentityServerDbContext
: AbpDbContext<IdentityServerDbContext>, IIdentityServerDbContext
{
}
````
For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has).
> If you are developing a reusable, database provider independent module see also [the best practices guide](Best-Practices/Index.md).
## Database Migrations for the Entity Framework Core
Relational databases require to create the database and the database schema (tables, views... etc.) before using it.
The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore.DbMigrations` project that contains the migration files for that database. This project mainly defines a *YourProjectName*MigrationsDbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`.
Once you want to separate a module's database, you typically will need to create a second migration path. The easiest way to create a copy of the `.EntityFrameworkCore.DbMigrations` project with the `DbContext` inside it, change its content to only call the `Configure...()` methods of the modules needs to be stored in the second database and re-create the initial migration. In this case, you also need to change the `.DbMigrator` application to be able to work with these second database too. In this way, you will have a separate migrations DbContext per database.
## Multi-Tenancy
See [the multi-tenancy document](Multi-Tenancy.md) to learn how to use separate databases for tenants.

12
docs/en/Data-Access.md

@ -1,11 +1,15 @@
# Data Access
ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions.
## Database Providers
However, currently the following providers are implements:
ABP framework was designed as database agnostic. It can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions. However, currently the following providers are implemented:
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).)
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/).)
* [MongoDB](MongoDB.md)
* [Dapper](Dapper.md)
More providers might be added in the next releases.
More providers will be added in the future.
## See Also
* [Connection Strings](Connection-Strings.md)

58
docs/en/Entity-Framework-Core-MySQL.md

@ -0,0 +1,58 @@
# Switch to EF Core MySQL Provider
This document explains how to switch to the **MySQL** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured.
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package
`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.MySQL](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL) package.
## Replace the Module Dependency
Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreMySQLModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.MySQL;`).
## UseMySQL()
Find `UseSqlServer()` calls in your solution, replace with `UseMySQL()`. Check the following files:
* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project.
* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project.
> Depending on your solution structure, you may find more code files need to be changed.
## Change the Connection Strings
MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/mysql/ ) for details of MySQL connection string options.
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Change the Migrations DbContext
MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS.
The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables.
Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations.
## Re-Generate the Migrations
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails.
* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution.
* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in de Package Manager Console).
This will create a database migration with all database objects (tables) configured.
Run the `.DbMigrator` project to create the database and seed the initial data.
## Run the Application
It is ready. Just run the application and enjoy coding.

16
docs/en/EntityFrameworkCore-PostgreSQL-Integration.md → docs/en/Entity-Framework-Core-PostgreSQL.md

@ -1,8 +1,8 @@
## Entity Framework Core PostgreSQL Integration
# Switch to EF Core PostgreSQL Provider
> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration.
### EntityFrameworkCore Project Update
## EntityFrameworkCore Project Update
- In `Acme.BookStore.EntityFrameworkCore` project replace package `Volo.Abp.EntityFrameworkCore.SqlServer` with `Volo.Abp.EntityFrameworkCore.PostgreSql`
- Update to use PostgreSQL in `BookStoreEntityFrameworkCoreModule`
@ -11,17 +11,17 @@
- In other projects update the PostgreSQL connection string in necessary `appsettings.json` files
- more info of [PostgreSQL connection strings](https://www.connectionstrings.com/postgresql/),You need to pay attention to `Npgsql` in this document
### EntityFrameworkCore.DbMigrations Project Update
## EntityFrameworkCore.DbMigrations Project Update
- Update to use PostgreSQL in `XXXMigrationsDbContextFactory`
- Replace the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseSqlServer()` with the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseNpgsql()`
### Delete Existing Migrations
## Delete Existing Migrations
Delete all existing migration files (including `DbContextModelSnapshot`)
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
### Regenerate Initial Migration
## Regenerate Initial Migration
Set the correct startup project (usually a web project)
@ -34,11 +34,11 @@ Run `Add-Migration` command.
PM> Add-Migration Initial
````
### Update the Database
## Update the Database
You have two options to create the database.
#### Using the DbMigrator Application
## Using the DbMigrator Application
The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment.
@ -52,7 +52,7 @@ Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown be
![set-as-startup-project](../images/db-migrator-app.png)
#### Using EF Core Update-Database Command
### Using EF Core Update-Database Command
Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations.

44
docs/en/Entity-Framework-Core.md

@ -28,6 +28,17 @@ namespace MyCompany.MyProject
> Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed.
### Database Management System Selection
Entity Framework Core supports various database management systems ([see all](https://docs.microsoft.com/en-us/ef/core/providers/)). ABP framework and this document doesn't depend on any specific DBMS.
If you are creating a reusable library, avoid to depend on a specific DBMS package. However, in a final application you eventually will select a DBMS.
ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier. [The startup templates](Startup-Templates/Index.md) come with **SQL Server (localdb) pre-configured**. See the following documents to learn how to configure for the other DBMS providers:
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
## Creating DbContext
You can create your DbContext as you normally do. It should be derived from `AbpDbContext<T>` as shown below:
@ -62,7 +73,7 @@ public class MyDbContext : AbpDbContext<MyDbContext>
}
```
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string.
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string (see [the connection strings document](Connection-Strings.md) for more information).
## Registering DbContext To Dependency Injection
@ -126,7 +137,8 @@ public class BookManager : DomainService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookManager(IRepository<Book, Guid> bookRepository) //inject default repository
//inject default repository to the constructor
public BookManager(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
@ -142,7 +154,8 @@ public class BookManager : DomainService
Type = type
};
await _bookRepository.InsertAsync(book); //Use a standard repository method
//Use a standard repository method
await _bookRepository.InsertAsync(book);
return book;
}
@ -153,9 +166,9 @@ This sample uses `InsertAsync` method to insert a new entity to the database.
### Add Custom Repositories
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods.
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. Assume that you want to delete all books by type.
Assume that you want to delete all books by type. It's suggested to define an interface for your custom repository:
It's suggested to define an interface for your custom repository:
````csharp
public interface IBookRepository : IRepository<Book, Guid>
@ -187,21 +200,23 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed.
#### Override Default Generic Repository
#### Override the Default Generic Repository
Even if you create a custom repository, you can still inject the default generic repository (`IRepository<Book, Guid>` for this example). Default repository implementation will not use the class you have created.
If you want to replace default repository implementation with your custom repository, do it inside `AddAbpDbContext` options:
If you want to replace default repository implementation with your custom repository, do it inside the `AddAbpDbContext` options:
````csharp
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.AddDefaultRepositories();
options.AddRepository<Book, BookRepository>(); //Replaces IRepository<Book, Guid>
//Replaces IRepository<Book, Guid>
options.AddRepository<Book, BookRepository>();
});
````
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete an entity in a more efficient way:
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete a specific entity in a more efficient way:
````csharp
public override async Task DeleteAsync(
@ -215,7 +230,7 @@ public override async Task DeleteAsync(
### Access to the EF Core API
In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository). However, if you want to access the DbContext instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example:
In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository pattern). However, if you want to access the `DbContext` instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example:
````csharp
public class BookService
@ -243,9 +258,9 @@ public class BookService
#### Set Default Repository Classes
Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for default repository implementation.
Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for all the default repository implementations.
First, define your repository classes like that:
First, define your default repository classes like that:
```csharp
public class MyRepositoryBase<TEntity>
@ -271,7 +286,7 @@ public class MyRepositoryBase<TEntity, TKey>
First one is for [entities with composite keys](Entities.md), second one is for entities with single primary key.
It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all standard repository methods manually.
It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all the standard repository methods manually.
Now, you can use `SetDefaultRepositoryClasses` option:
@ -282,6 +297,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
typeof(MyRepositoryBase<,>),
typeof(MyRepositoryBase<>)
);
//...
});
```
@ -316,7 +332,7 @@ public class BookRepository : EfCoreRepository<IBookStoreDbContext, Book, Guid>,
}
````
One advantage of using interface for a DbContext is then it becomes replaceable by another implementation.
One advantage of using an interface for a DbContext is then it will be replaceable by another implementation.
#### Replace Other DbContextes

3
docs/en/Modules/IdentityServer.md

@ -0,0 +1,3 @@
# IdentityServer Module
TODO

2
docs/en/Modules/Index.md

@ -17,7 +17,7 @@ There are some **free and open source** application modules developed and mainta
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://docs.abp.io) already using this module.
* **Identity**: Used to manage roles, users and their permissions.
* **Identity Server**: Integrates to IdentityServer4.
* **IdentityServer**: Integrates to IdentityServer4.
* **Permission Management**: Used to persist permissions.
* **[Setting Management](Setting-Management.md)**: Used to persist and manage the [settings](../Settings.md).
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.

41
docs/en/docs-nav.json

@ -257,25 +257,38 @@
},
{
"text": "Data Access",
"path": "Data-Access.md",
"path": "Data-Access.md",
"items": [
{
"text": "Entity Framework Core Integration",
"path": "Entity-Framework-Core.md",
"items": [
"text": "Connection Strings",
"path": "Connection-Strings.md"
},
{
"text": "Database Providers",
"items": [
{
"text": "Entity Framework Core",
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "Switch to MySQL",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "Switch to PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},
{
"text": "PostgreSQL Integration",
"path": "EntityFrameworkCore-PostgreSQL-Integration.md"
"text": "MongoDB",
"path": "MongoDB.md"
},
{
"text": "Dapper",
"path": "Dapper.md"
}
]
},
{
"text": "MongoDB Integration",
"path": "MongoDB.md"
},
{
"text": "Dapper Integration",
"path": "Dapper.md"
}
]
},

2
docs/pt-BR/docs-nav.json

@ -249,7 +249,7 @@
"items": [
{
"text": "Integração do PostgreSQL",
"path": "EntityFrameworkCore-PostgreSQL-Integration.md"
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},

0
docs/zh-Hans/EntityFrameworkCore-PostgreSQL-Integration.md → docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md

2
docs/zh-Hans/docs-nav.json

@ -254,7 +254,7 @@
"items": [
{
"text": "PostgreSQL 集成",
"path": "EntityFrameworkCore-PostgreSQL-Integration.md"
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},

2
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features
public async Task Should_Allow_Enabled_Features()
{
await GetResponseAsStringAsync(
"/api/feature-test/allowed-feature"
"/api/feature-test/allowed-feature", HttpStatusCode.NoContent
).ConfigureAwait(false);
}

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs

@ -1,8 +1,10 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement
{
[Serializable]
[IgnoreMultiTenancy]
public class FeatureValueCacheItem
{
public string Value { get; set; }

34
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs

@ -1,6 +1,8 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
using Xunit;
namespace Volo.Abp.FeatureManagement
@ -8,10 +10,14 @@ namespace Volo.Abp.FeatureManagement
public class FeatureManager_Tests : FeatureManagementDomainTestBase
{
private readonly IFeatureManager _featureManager;
private readonly ICurrentTenant _currentTenant;
private readonly IFeatureChecker _featureChecker;
public FeatureManager_Tests()
{
_featureManager = GetRequiredService<IFeatureManager>();
_featureChecker = GetRequiredService<IFeatureChecker>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
[Fact]
@ -79,5 +85,31 @@ namespace Volo.Abp.FeatureManagement
TestEditionIds.Ultimate
).ConfigureAwait(false)).ShouldBe("10");
}
[Fact]
public async Task Should_Change_Feature_Value_And_Refresh_Cache()
{
var tenantId = Guid.NewGuid();
//It is "False" at the beginning
using (_currentTenant.Change(tenantId))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
}
//Set to "True" by host for the tenant
using (_currentTenant.Change(null))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
await _featureManager.SetForTenantAsync(tenantId, TestFeatureDefinitionProvider.SocialLogins, "True");
(await _featureManager.GetOrNullForTenantAsync(TestFeatureDefinitionProvider.SocialLogins, tenantId)).ShouldBe("True");
}
//Now, it should be "True"
using (_currentTenant.Change(tenantId))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeTrue();
}
}
}
}

26
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs

@ -26,21 +26,31 @@ namespace Volo.Abp.FeatureManagement
public async Task Cache_Should_Invalidator_WhenFeatureChanged()
{
// Arrange cache feature.
await _featureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()).ConfigureAwait(false);
(await _featureManagementStore.GetOrNullAsync(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
).ConfigureAwait(false)
).ShouldNotBeNull();
var feature = await _featureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
var feature = await _featureValueRepository.FindAsync(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()).ConfigureAwait(false);
TestEditionIds.Regular.ToString()
).ConfigureAwait(false);
// Act
await _featureValueRepository.DeleteAsync(feature).ConfigureAwait(false);
// Assert
(await _cache.GetAsync(FeatureValueCacheItem.CalculateCacheKey(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ConfigureAwait(false)).ShouldBeNull();
(await _cache.GetAsync(
FeatureValueCacheItem.CalculateCacheKey(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
).ConfigureAwait(false)
).ShouldBeNull();
}
}

3
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs

@ -246,6 +246,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
apiSecret.HasKey(x => new { x.ApiResourceId, x.Type, x.Value });
apiSecret.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired();
apiSecret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql)
{
@ -255,8 +256,6 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
{
apiSecret.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired();
}
apiSecret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength);
});
builder.Entity<ApiResourceClaim>(apiClaim =>

2
modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs

@ -1,8 +1,10 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.SettingManagement
{
[Serializable]
[IgnoreMultiTenancy]
public class SettingCacheItem
{
public string Value { get; set; }

38
modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System;
using System.Threading.Tasks;
using Castle.DynamicProxy.Generators;
using Shouldly;
using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
using Xunit;
@ -16,6 +14,7 @@ namespace Volo.Abp.SettingManagement
private readonly ISettingManagementStore _settingManagementStore;
private readonly ISettingRepository _settingRepository;
private readonly SettingTestData _testData;
private readonly ICurrentTenant _currentTenant;
public SettingCacheItemInvalidator_Tests()
{
@ -23,6 +22,7 @@ namespace Volo.Abp.SettingManagement
_cache = GetRequiredService<IDistributedCache<SettingCacheItem>>();
_settingRepository = GetRequiredService<ISettingRepository>();
_testData = GetRequiredService<SettingTestData>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
[Fact]
@ -49,5 +49,35 @@ namespace Volo.Abp.SettingManagement
(await _cache.GetAsync(
SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString())).ConfigureAwait(false)).ShouldBeNull();
}
[Fact]
public async Task Cache_Should_Invalidator_WhenSettingChanged_Between_Tenant_And_Host()
{
var tenantId = Guid.NewGuid();
using (_currentTenant.Change(tenantId))
{
// GetOrNullAsync will cache language.
await _settingManagementStore
.GetOrNullAsync("MySetting2", GlobalSettingValueProvider.ProviderName, null)
.ConfigureAwait(false);
}
using (_currentTenant.Change(null))
{
// SetAsync will make cache invalid.
await _settingManagementStore
.SetAsync("MySetting2", "MySetting2Value", GlobalSettingValueProvider.ProviderName, null)
.ConfigureAwait(false);
}
using (_currentTenant.Change(tenantId))
{
// Assert
(await _cache.GetAsync(
SettingCacheItem.CalculateCacheKey("MySetting2", GlobalSettingValueProvider.ProviderName, null))
.ConfigureAwait(false)).ShouldBeNull();
}
}
}
}

Loading…
Cancel
Save