diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
index 7c8af93c47..aaebfafe6f 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs
index 19c707bfad..37541b4d4c 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs
@@ -8,13 +8,14 @@ using AbpIoLocalization.Support.Localization;
using AbpIoLocalization.Www;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
-using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.Modularity;
+using Volo.Abp.Validation;
+using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace AbpIoLocalization
{
- [DependsOn(typeof(AbpLocalizationModule))]
+ [DependsOn(typeof(AbpValidationModule))]
public class AbpIoLocalizationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
diff --git a/docs/cs/EntityFrameworkCore-PostgreSQL-Integration.md b/docs/cs/Entity-Framework-Core-PostgreSQL.md
similarity index 100%
rename from docs/cs/EntityFrameworkCore-PostgreSQL-Integration.md
rename to docs/cs/Entity-Framework-Core-PostgreSQL.md
diff --git a/docs/cs/docs-nav.json b/docs/cs/docs-nav.json
index 85cbf43c9d..2854966a10 100644
--- a/docs/cs/docs-nav.json
+++ b/docs/cs/docs-nav.json
@@ -264,7 +264,7 @@
"items": [
{
"text": "PostgreSQL integrace",
- "path": "EntityFrameworkCore-PostgreSQL-Integration.md"
+ "path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},
diff --git a/docs/en/Best-Practices/Index.md b/docs/en/Best-Practices/Index.md
index 1a48c6b46b..f3f626ca63 100644
--- a/docs/en/Best-Practices/Index.md
+++ b/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)
diff --git a/docs/en/Connection-Strings.md b/docs/en/Connection-Strings.md
index 36103011e1..a080e10dea 100644
--- a/docs/en/Connection-Strings.md
+++ b/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.
\ No newline at end of file
+* 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, 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.
\ No newline at end of file
diff --git a/docs/en/Data-Access.md b/docs/en/Data-Access.md
index 36103011e1..a37f77eb65 100644
--- a/docs/en/Data-Access.md
+++ b/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.
\ No newline at end of file
+More providers will be added in the future.
+
+## See Also
+
+* [Connection Strings](Connection-Strings.md)
\ No newline at end of file
diff --git a/docs/en/Entity-Framework-Core-MySQL.md b/docs/en/Entity-Framework-Core-MySQL.md
new file mode 100644
index 0000000000..d1fa66e1a4
--- /dev/null
+++ b/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 the 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.
\ No newline at end of file
diff --git a/docs/en/Entity-Framework-Core-PostgreSQL.md b/docs/en/Entity-Framework-Core-PostgreSQL.md
new file mode 100644
index 0000000000..85ce3197f2
--- /dev/null
+++ b/docs/en/Entity-Framework-Core-PostgreSQL.md
@@ -0,0 +1,41 @@
+# Switch to EF Core PostgreSQL Provider
+
+This document explains how to switch to the **PostgreSQL** 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.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) package.
+
+## Replace the Module Dependency
+
+Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.PostgreSql;`).
+
+## UsePostgreSql()
+
+Find `UseSqlServer()` calls in your solution, replace with `UsePostgreSql()`. 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
+
+PostgreSql 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/postgresql/ ) for details of PostgreSql connection string options.
+
+You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
+
+## 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 the 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.
\ No newline at end of file
diff --git a/docs/en/Entity-Framework-Core-SQLite.md b/docs/en/Entity-Framework-Core-SQLite.md
new file mode 100644
index 0000000000..62a8ef815d
--- /dev/null
+++ b/docs/en/Entity-Framework-Core-SQLite.md
@@ -0,0 +1,41 @@
+# Switch to EF Core SQLite Provider
+
+This document explains how to switch to the **SQLite** 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.Sqlite](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Sqlite) package.
+
+## Replace the Module Dependency
+
+Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreSqliteModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.Sqlite;`).
+
+## UseSqlite()
+
+Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. 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
+
+SQLite 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/sqlite/ ) for details of SQLite connection string options.
+
+You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
+
+## 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 the 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.
\ No newline at end of file
diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md
index e608736bcd..b73e16a3e5 100644
--- a/docs/en/Entity-Framework-Core.md
+++ b/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` as shown below:
@@ -62,7 +73,7 @@ public class MyDbContext : AbpDbContext
}
```
-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 _bookRepository;
- public BookManager(IRepository bookRepository) //inject default repository
+ //inject default repository to the constructor
+ public BookManager(IRepository 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
@@ -187,21 +200,23 @@ public class BookRepository : EfCoreRepository,
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` 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(options =>
{
options.AddDefaultRepositories();
- options.AddRepository(); //Replaces IRepository
+
+ //Replaces IRepository
+ options.AddRepository();
});
````
-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
@@ -271,7 +286,7 @@ public class MyRepositoryBase
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(options =>
typeof(MyRepositoryBase<,>),
typeof(MyRepositoryBase<>)
);
+
//...
});
```
@@ -316,7 +332,7 @@ public class BookRepository : EfCoreRepository,
}
````
-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
diff --git a/docs/en/EntityFrameworkCore-PostgreSQL-Integration.md b/docs/en/EntityFrameworkCore-PostgreSQL-Integration.md
deleted file mode 100644
index 2f6dd03be7..0000000000
--- a/docs/en/EntityFrameworkCore-PostgreSQL-Integration.md
+++ /dev/null
@@ -1,73 +0,0 @@
-## Entity Framework Core PostgreSQL Integration
-
-> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration.
-
-### 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`
- - Replace the `AbpEntityFrameworkCoreSqlServerModule` with the `AbpEntityFrameworkCorePostgreSqlModule`
- - Replace the `options.UseSqlServer()` with the `options.UsePostgreSql()`
-- 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
-- Update to use PostgreSQL in `XXXMigrationsDbContextFactory`
- - Replace the `new DbContextOptionsBuilder().UseSqlServer()` with the `new DbContextOptionsBuilder().UseNpgsql()`
-
-### Delete Existing Migrations
-
-Delete all existing migration files (including `DbContextModelSnapshot`)
-
-
-
-### Regenerate Initial Migration
-
-Set the correct startup project (usually a web project)
-
-
-
-Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command:
-
-Run `Add-Migration` command.
-````
-PM> Add-Migration Initial
-````
-
-### Update the Database
-
-You have two options to create the database.
-
-#### 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.
-
-> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
-
-Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
-
-
-
-Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below:
-
-
-
-#### Using EF Core Update-Database Command
-
-Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations.
-
-Set the correct startup project (usually a web project)
-
-
-
-Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command:
-
-````
-PM> Update-Database
-````
-
-This will create a new database based on the configured connection string.
-
-
-
-> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.
diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md
index 0a74d7ebde..dbafe910da 100644
--- a/docs/en/Modules/Docs.md
+++ b/docs/en/Modules/Docs.md
@@ -501,6 +501,10 @@ You can also use variables in a text, adding **_Value** postfix to its key:
This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider.
````
+Also, **Document_Language_Code** and **Document_Version** keys are pre-defined if you want to get the language code or the version of the current document (This may be useful for creating links that redirects to another documentation system in another domain).
+
+------
+
**IMPORTANT NOTICE**: Scriban uses "{{" and "}}" for syntax. Therefore, you must use escape blocks if you are going to use those in your document (an Angular document, for example). See [Scriban docs]( ) for more information.
### 8- Creating the Navigation Document
diff --git a/docs/en/Modules/IdentityServer.md b/docs/en/Modules/IdentityServer.md
new file mode 100644
index 0000000000..0d2ab35c21
--- /dev/null
+++ b/docs/en/Modules/IdentityServer.md
@@ -0,0 +1,3 @@
+# IdentityServer Module
+
+TODO
\ No newline at end of file
diff --git a/docs/en/Modules/Index.md b/docs/en/Modules/Index.md
index 9d1c1d301f..8616ed2281 100644
--- a/docs/en/Modules/Index.md
+++ b/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.
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index db194177a9..9943c3b6af 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -257,25 +257,42 @@
},
{
"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": "Switch to SQLite",
+ "path": "Entity-Framework-Core-SQLite.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"
}
]
},
diff --git a/docs/pt-BR/docs-nav.json b/docs/pt-BR/docs-nav.json
index 8e7eaf62af..a189b83c09 100644
--- a/docs/pt-BR/docs-nav.json
+++ b/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"
}
]
},
diff --git a/docs/zh-Hans/EntityFrameworkCore-PostgreSQL-Integration.md b/docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md
similarity index 100%
rename from docs/zh-Hans/EntityFrameworkCore-PostgreSQL-Integration.md
rename to docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md
diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json
index dd740f6c3b..301af0fd6a 100644
--- a/docs/zh-Hans/docs-nav.json
+++ b/docs/zh-Hans/docs-nav.json
@@ -254,7 +254,7 @@
"items": [
{
"text": "PostgreSQL 集成",
- "path": "EntityFrameworkCore-PostgreSQL-Integration.md"
+ "path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs
index 4ff54f39bf..e93f558afd 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs
@@ -11,14 +11,14 @@ namespace Microsoft.AspNetCore.Builder
{
if (ctx.User.Identity?.IsAuthenticated != true)
{
- var result = await ctx.AuthenticateAsync(schema);
+ var result = await ctx.AuthenticateAsync(schema).ConfigureAwait(false);
if (result.Succeeded && result.Principal != null)
{
ctx.User = result.Principal;
}
}
- await next();
+ await next().ConfigureAwait(false);
});
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs
index ba8802a80e..b260df4247 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs
+++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs
@@ -33,7 +33,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
TenantConfiguration tenant = null;
if (resolveResult.TenantIdOrName != null)
{
- tenant = await FindTenantAsync(resolveResult.TenantIdOrName);
+ tenant = await FindTenantAsync(resolveResult.TenantIdOrName).ConfigureAwait(false);
if (tenant == null)
{
//TODO: A better exception?
@@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
using (_currentTenant.Change(tenant?.Id, tenant?.Name))
{
- await next(context);
+ await next(context).ConfigureAwait(false);
}
}
@@ -53,11 +53,11 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
if (Guid.TryParse(tenantIdOrName, out var parsedTenantId))
{
- return await _tenantStore.FindAsync(parsedTenantId);
+ return await _tenantStore.FindAsync(parsedTenantId).ConfigureAwait(false);
}
else
{
- return await _tenantStore.FindAsync(tenantIdOrName);
+ return await _tenantStore.FindAsync(tenantIdOrName).ConfigureAwait(false);
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
index 1fbb72bb3e..a4f7eb0567 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
@@ -43,12 +43,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
configuration = await Cache.GetOrAddAsync(
cacheKey,
- async () => await Proxy.Service.GetAsync(),
+ async () => await Proxy.Service.GetAsync().ConfigureAwait(false),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(120) //TODO: Should be configurable. Default value should be higher (5 mins would be good).
}
- );
+ ).ConfigureAwait(false);
if (httpContext != null)
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs
index f769f512a5..9671703db8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs
@@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
public override async Task GetOrNullAsync(string name)
{
- var configuration = await ConfigurationClient.GetAsync();
+ var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false);
return configuration.Features.Values.GetOrDefault(name);
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs
index 02c97c0598..42b6eeb543 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs
@@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
public async Task> GetLanguagesAsync()
{
- var configuration = await ConfigurationClient.GetAsync();
+ var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false);
return configuration.Localization.Languages;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs
index 18f5272e7b..553160029b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs
@@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
public async Task IsGrantedAsync(string name)
{
- var configuration = await ConfigurationClient.GetAsync();
+ var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false);
return configuration.Auth.GrantedPolicies.ContainsKey(name);
}
@@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
public async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name)
{
/* This provider always works for the current principal. */
- return await IsGrantedAsync(name);
+ return await IsGrantedAsync(name).ConfigureAwait(false);
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs
index db3ea6e9a6..d6526a0b7b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs
@@ -17,13 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
public async Task GetOrNullAsync(string name)
{
- var configuration = await ConfigurationClient.GetAsync();
+ var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false);
return configuration.Setting.Values.GetOrDefault(name);
}
public async Task> GetAllAsync()
{
- var configuration = await ConfigurationClient.GetAsync();
+ var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false);
return configuration
.Setting.Values
.Select(s => new SettingValue(s.Key, s.Value))
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs
index 236387823c..8e95376663 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs
@@ -39,13 +39,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
tenantConfiguration = await Cache.GetOrAddAsync(
cacheKey,
- async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name)),
+ async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name).ConfigureAwait(false)),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMinutes(5) //TODO: Should be configurable.
}
- );
+ ).ConfigureAwait(false);
if (httpContext != null)
{
@@ -67,13 +67,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
tenantConfiguration = await Cache.GetOrAddAsync(
cacheKey,
- async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id)),
+ async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id).ConfigureAwait(false)),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMinutes(5) //TODO: Should be configurable.
}
- );
+ ).ConfigureAwait(false);
if (httpContext != null)
{
@@ -95,7 +95,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
tenantConfiguration = Cache.GetOrAdd(
cacheKey,
- () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name))),
+ () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name).ConfigureAwait(false))),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
@@ -123,7 +123,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
tenantConfiguration = Cache.GetOrAdd(
cacheKey,
- () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id))),
+ () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id).ConfigureAwait(false))),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs
index 8eeeb1e929..4b3a4dd471 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs
@@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
{
var list = InitilizeFormGroupContentsContext(context, output);
- await output.GetChildContentAsync();
+ await output.GetChildContentAsync().ConfigureAwait(false);
SetInnerOlTag(context, output);
SetInnerList(context, output, list);
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
index ffba80fb6f..65cffd8cb6 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
@@ -19,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
var itemList = InitilizeCarouselItemsContentsContext(context, output);
- await output.GetChildContentAsync();
+ await output.GetChildContentAsync().ConfigureAwait(false);
SetOneItemAsActive(context, output, itemList);
SetItems(context, output, itemList);
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
index 9dc279334b..509b801ba9 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
@@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
SetRandomIdIfNotProvided();
- var innerContent = (await output.GetChildContentAsync()).GetContent();
+ var innerContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent();
var html = GetAccordionHeaderItem(context, output) + GetAccordionContentItem(context, output, innerContent);
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
index 20e62604a9..c6c5c2eb5e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
@@ -20,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
var items = InitilizeFormGroupContentsContext(context, output);
- await output.GetChildContentAsync();
+ await output.GetChildContentAsync().ConfigureAwait(false);
var content = GetContent(items);
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
index 10e49b92a7..2b81961f67 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
@@ -22,7 +22,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
output.Attributes.AddClass("multi-collapse");
}
- var innerContent = (await output.GetChildContentAsync()).GetContent();
+ var innerContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent();
output.Content.SetHtmlContent(innerContent);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
index 673204b302..459a7be318 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
@@ -26,9 +26,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
- var content = await output.GetChildContentAsync();
+ var content = await output.GetChildContentAsync().ConfigureAwait(false);
- var buttonsAsHtml = await GetButtonsAsHtmlAsync(context, output, content);
+ var buttonsAsHtml = await GetButtonsAsHtmlAsync(context, output, content).ConfigureAwait(false);
output.PreElement.SetHtmlContent(buttonsAsHtml);
@@ -43,13 +43,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{
var buttonBuilder = new StringBuilder("");
- var mainButton = await GetMainButtonAsync(context, output, content);
+ var mainButton = await GetMainButtonAsync(context, output, content).ConfigureAwait(false);
buttonBuilder.AppendLine(mainButton);
if (TagHelper.DropdownStyle == DropdownStyle.Split)
{
- var splitButton = await GetSplitButtonAsync(context, output);
+ var splitButton = await GetSplitButtonAsync(context, output).ConfigureAwait(false);
buttonBuilder.AppendLine(splitButton);
}
@@ -68,7 +68,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForMainButton(context, output);
- var buttonTag = await abpButtonTagHelper.ProcessAndGetOutputAsync(attributes, context, "button", TagMode.StartTagAndEndTag);
+ var buttonTag = await abpButtonTagHelper.ProcessAndGetOutputAsync(attributes, context, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false);
buttonTag.PreContent.SetHtmlContent(content.GetContent());
@@ -89,7 +89,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForSplitButton(context, output);
- return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
+ return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual TagHelperAttributeList GetAttributesForMainButton(TagHelperContext context, TagHelperOutput output)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs
index d925fd11e8..6767e2bf1d 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs
@@ -19,14 +19,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
tagHelper.Init(context);
- await tagHelper.ProcessAsync(innerContext, innerOutput);
+ await tagHelper.ProcessAsync(innerContext, innerOutput).ConfigureAwait(false);
return innerOutput;
}
public static async Task RenderAsync(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing)
{
- var innerOutput = await tagHelper.ProcessAndGetOutputAsync(attributeList, context, tagName, tagMode);
+ var innerOutput = await tagHelper.ProcessAndGetOutputAsync(attributeList, context, tagName, tagMode).ConfigureAwait(false);
return innerOutput.Render(htmlEncoder);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
index ee2a920980..5fb439b6f7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
@@ -37,11 +37,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
NormalizeTagMode(context, output);
- var childContent = (await output.GetChildContentAsync()).GetContent();
+ var childContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent();
- await ConvertToMvcForm(context, output);
+ await ConvertToMvcForm(context, output).ConfigureAwait(false);
- await ProcessFieldsAsync(context, output);
+ await ProcessFieldsAsync(context, output).ConfigureAwait(false);
SetContent(context, output, list, childContent);
@@ -67,9 +67,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
- var formTagOutput = await formTagHelper.ProcessAndGetOutputAsync(output.Attributes, context, "form", TagMode.StartTagAndEndTag);
+ var formTagOutput = await formTagHelper.ProcessAndGetOutputAsync(output.Attributes, context, "form", TagMode.StartTagAndEndTag).ConfigureAwait(false);
- await formTagOutput.GetChildContentAsync();
+ await formTagOutput.GetChildContentAsync().ConfigureAwait(false);
output.PostContent.SetHtmlContent(output.PostContent.GetContent() + formTagOutput.PostContent.GetContent());
output.PreContent.SetHtmlContent(output.PreContent.GetContent() + formTagOutput.PreContent.GetContent());
@@ -134,11 +134,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
if (IsSelectGroup(context, model))
{
- await ProcessSelectGroupAsync(context, output, model);
+ await ProcessSelectGroupAsync(context, output, model).ConfigureAwait(false);
}
else
{
- await ProcessInputGroupAsync(context, output, model);
+ await ProcessInputGroupAsync(context, output, model).ConfigureAwait(false);
}
}
}
@@ -147,7 +147,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var abpSelectTagHelper = GetSelectGroupTagHelper(context, output, model);
- await abpSelectTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
+ await abpSelectTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual AbpTagHelper GetSelectGroupTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@@ -185,7 +185,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpButtonTagHelper.Text = "Submit";
abpButtonTagHelper.ButtonType = AbpButtonType.Primary;
- return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
+ return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual async Task ProcessInputGroupAsync(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@@ -195,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpInputTagHelper.ViewContext = TagHelper.ViewContext;
abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true;
- await abpInputTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
+ await abpInputTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual List GetModels(TagHelperContext context, TagHelperOutput output)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
index 75fe4f23e7..b1195b729e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
@@ -27,7 +27,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
- var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output);
+ var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output).ConfigureAwait(false);
var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
@@ -57,12 +57,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual async Task<(string, bool)> GetFormInputGroupAsHtmlAsync(TagHelperContext context, TagHelperOutput output)
{
- var (inputTag, isCheckBox) = await GetInputTagHelperOutputAsync(context, output);
+ var (inputTag, isCheckBox) = await GetInputTagHelperOutputAsync(context, output).ConfigureAwait(false);
var inputHtml = inputTag.Render(_encoder);
- var label = await GetLabelAsHtmlAsync(context, output, inputTag, isCheckBox);
+ var label = await GetLabelAsHtmlAsync(context, output, inputTag, isCheckBox).ConfigureAwait(false);
var info = GetInfoAsHtml(context, output, inputTag, isCheckBox);
- var validation = isCheckBox ? "" : await GetValidationAsHtmlAsync(context, output, inputTag);
+ var validation = isCheckBox ? "" : await GetValidationAsHtmlAsync(context, output, inputTag).ConfigureAwait(false);
return (GetContent(context, output, label, inputHtml, validation, info, isCheckBox), isCheckBox);
}
@@ -82,7 +82,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
- return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag);
+ return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox)
@@ -125,7 +125,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var tagHelper = GetInputTagHelper(context, output);
- var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input");
+ var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input").ConfigureAwait(false);
ConvertToTextAreaIfTextArea(inputTagHelperOutput);
AddDisabledAttribute(inputTagHelperOutput);
@@ -227,7 +227,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
if (string.IsNullOrEmpty(TagHelper.Label))
{
- return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox) + GetRequiredSymbol(context, output);
+ return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox).ConfigureAwait(false) + GetRequiredSymbol(context, output);
}
var checkboxClass = isCheckbox ? "class=\"custom-control-label\" " : "";
@@ -301,7 +301,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
attributeList.AddClass("custom-control-label");
}
- return await labelTagHelper.RenderAsync(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag);
+ return await labelTagHelper.RenderAsync(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual void ConvertToTextAreaIfTextArea(TagHelperOutput tagHelperOutput)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
index b18bc6ed75..f1260883ef 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
@@ -30,7 +30,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
- var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output);
+ var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output).ConfigureAwait(false);
var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
@@ -52,10 +52,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual async Task GetFormInputGroupAsHtmlAsync(TagHelperContext context, TagHelperOutput output)
{
- var selectTag = await GetSelectTagAsync(context, output);
+ var selectTag = await GetSelectTagAsync(context, output).ConfigureAwait(false);
var selectAsHtml = selectTag.Render(_encoder);
- var label = await GetLabelAsHtmlAsync(context, output, selectTag);
- var validation = await GetValidationAsHtmlAsync(context, output, selectTag);
+ var label = await GetLabelAsHtmlAsync(context, output, selectTag).ConfigureAwait(false);
+ var validation = await GetValidationAsHtmlAsync(context, output, selectTag).ConfigureAwait(false);
var infoText = GetInfoAsHtml(context, output, selectTag);
return label + Environment.NewLine + selectAsHtml + Environment.NewLine + infoText + Environment.NewLine + validation;
@@ -75,7 +75,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
- var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag);
+ var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag).ConfigureAwait(false);
selectTagHelperOutput.Attributes.AddClass("form-control");
selectTagHelperOutput.Attributes.AddClass(GetSize(context, output));
@@ -123,7 +123,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return "" + GetRequiredSymbol(context, output);
}
- return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output);
+ return await GetLabelAsHtmlUsingTagHelperAsync(context, output).ConfigureAwait(false) + GetRequiredSymbol(context, output);
}
protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output)
@@ -242,7 +242,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext
};
- return await labelTagHelper.RenderAsync(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag);
+ return await labelTagHelper.RenderAsync(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual async Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
@@ -255,7 +255,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
- return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag);
+ return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag).ConfigureAwait(false);
}
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
index 25307c3fee..f1d2f5c02f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
@@ -31,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
}
ProcessMainTag(context, output);
- await SetContentAsHtmlAsync(context, output);
+ await SetContentAsHtmlAsync(context, output).ConfigureAwait(false);
}
protected virtual async Task SetContentAsHtmlAsync(TagHelperContext context, TagHelperOutput output)
@@ -39,9 +39,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
var html = new StringBuilder("");
html.AppendLine(GetOpeningTags(context, output));
- html.AppendLine(await GetPreviousButtonAsync(context, output));
- html.AppendLine(await GetPagesAsync(context, output));
- html.AppendLine(await GetNextButton(context, output));
+ html.AppendLine(await GetPreviousButtonAsync(context, output).ConfigureAwait(false));
+ html.AppendLine(await GetPagesAsync(context, output).ConfigureAwait(false));
+ html.AppendLine(await GetNextButton(context, output).ConfigureAwait(false));
html.AppendLine(GetClosingTags(context, output));
output.Content.SetHtmlContent(html.ToString());
@@ -61,7 +61,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
foreach (var page in TagHelper.Model.Pages)
{
- pagesHtml.AppendLine(await GetPageAsync(context, output, page));
+ pagesHtml.AppendLine(await GetPageAsync(context, output, page).ConfigureAwait(false));
}
return pagesHtml.ToString();
@@ -86,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
}
else
{
- pageHtml.AppendLine(await RenderAnchorTagHelperLinkHtmlAsync(context, output, page.Index.ToString(), page.Index.ToString()));
+ pageHtml.AppendLine(await RenderAnchorTagHelperLinkHtmlAsync(context, output, page.Index.ToString(), page.Index.ToString()).ConfigureAwait(false));
}
pageHtml.AppendLine("");
@@ -102,7 +102,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
: (TagHelper.Model.CurrentPage - 1).ToString();
return
"