Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into feature/angular-9

pull/2927/head
mehmet-erim 7 years ago
parent
commit
2d97e89cd0
  1. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  2. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  3. 7
      docs/en/CLI.md
  4. 315
      docs/en/Entity-Framework-Core-Migrations.md
  5. 14
      docs/en/Entity-Framework-Core-Other-DBMS.md
  6. 9
      docs/en/Entity-Framework-Core.md
  7. 4
      docs/en/Exception-Handling.md
  8. 4
      docs/en/Modules/Identity.md
  9. 3
      docs/en/Modules/Tenant-Management.md
  10. 6
      docs/en/Tutorials/Index.md
  11. BIN
      docs/en/_resources/Diagrams.docx
  12. 31
      docs/en/docs-nav.json
  13. BIN
      docs/en/images/bookstore-efcore-dependencies.png
  14. BIN
      docs/en/images/single-database-usage.png
  15. 20
      docs/zh-Hans/CLI.md
  16. 160
      docs/zh-Hans/Entities.md
  17. 8
      docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md
  18. 9
      docs/zh-Hans/Entity-Framework-Core.md
  19. 2
      docs/zh-Hans/Exception-Handling.md
  20. 3
      docs/zh-Hans/Tutorials/Angular/Part-I.md
  21. 26
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-I.md
  22. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-II.md
  23. 2
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-III.md
  24. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png
  25. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-edit-dialog.png
  26. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png
  27. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-appservice-tests.png
  28. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-book-list-2.png
  29. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-book-list.png
  30. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-books-table-actions.png
  31. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-books-table.png
  32. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-dialog-2.png
  33. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-dialog.png
  34. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-template.png
  35. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-homepage.png
  36. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png
  37. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-localization-files-v2.png
  38. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-menu-items.png
  39. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-new-book-button.png
  40. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png
  41. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration.png
  42. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-swagger.png
  43. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist-network.png
  44. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist.png
  45. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-projects-v2.png
  46. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-user-management.png
  47. 0
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png
  48. 6
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Index.md
  49. 31
      docs/zh-Hans/docs-nav.json
  50. 1
      framework/src/Volo.Abp.Authorization/Microsoft/Extensions/DependencyInjection/AbpAuthorizationServiceCollectionExtensions.cs
  51. 12
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AlwaysAllowMethodInvocationAuthorizationService.cs
  52. 48
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/AbpNuGetIndexUrlService.cs
  53. 38
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs
  54. 4
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs
  55. 4
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs
  56. 8
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs
  57. 12
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs
  58. 3
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs
  59. 6
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml
  60. 2
      modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs

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

@ -53,6 +53,7 @@
"CreateANugetPackage": "Create a Nuget package",
"AddNew": "Add new",
"PackageAlreadyExist{0}": "\"{0}\" package is already added.",
"ModuleAlreadyExist{0}": "\"{0}\" module is already added.",
"ClearCache": "Clear cache",
"SuccessfullyCleared": "Successfully cleared",
"Menu:NpmPackages": "NPM Packages",
@ -83,6 +84,7 @@
"This{0}AlreadyExistInThisOrganization": "This {0} already exist in this organization",
"AreYouSureYouWantToDeleteAllComputers": "Are you sure you want to delete all computers?",
"DeleteAll": "Delete all",
"DoYouWantToCreateNewUser": "Do you want to create new user?"
"DoYouWantToCreateNewUser": "Do you want to create new user?",
"MasterModules": "Master Modules"
}
}

7
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -5,8 +5,9 @@
"OrganizationList": "Organization list",
"Volo.AbpIo.Commercial:010003": "You are not owner of this organization!",
"OrganizationNotFoundMessage": "No organization found!",
"DeveloperCount": "Developer count",
"QuestionCount": "Question count",
"DeveloperCount": "Allocated / total developers",
"QuestionCount": "Remaining / total questions",
"Unlimited": "Unlimited",
"Owners": "Owners",
"AddMember": "Add member",
"AddOwner": "Add owner",
@ -30,5 +31,5 @@
"SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!",
"ManageProfile": "Manage your profile",
"EmailNotValid": "Please enter a valid email address."
}
}
}

7
docs/en/CLI.md

@ -51,8 +51,8 @@ abp new Acme.BookStore
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `module`: [Module template](Startup-Templates/Module.md). Additional options:
* `--no-ui`: Specifies to not include the UI. This makes possible to create service-only modules (a.k.a. microservices - without UI).
* `module`: [Module template](Startup-Templates/Module.md). Additional options:
* `--no-ui`: Specifies to not include the UI. This makes possible to create service-only modules (a.k.a. microservices - without UI).
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
* `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version.
@ -161,5 +161,4 @@ Examples:
````bash
abp help # Shows a general help.
abp help new # Shows help about the "new" command.
````
````

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

@ -0,0 +1,315 @@
# EF Core Advanced Database Migrations
This document begins by **introducing the default structure** provided by [the application startup template](Startup-Templates/Application.md) and **discusses various scenarios** you may want to implement for your own application.
> This document is for who want to fully understand and customize the database structure comes with [the application startup template](Startup-Templates/Application.md). If you simply want to create entities and manage your code first migrations, just follow [the startup tutorials](Tutorials/Index.md).
## About the EF Core Code First Migrations
Entity Framework Core provides an easy to use and powerful [database migration system](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). ABP Framework [startup templates](Startup-Templates/Index.md) take the advantage of this system to allow you to develop your application in a standard way.
However, EF Core migration system is **not so good in a modular environment** where each module maintains its **own database schema** while two or more modules may **share a single database** in practical.
Since ABP Framework cares about modularity in all aspects, it provides a **solution** to this problem. It is important to understand this solution if you need to **customize your database structure**.
> See [EF Core's own documentation](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) to fully learn the EF Core Code First Migrations and why you need to such a system.
## The Default Solution & Database Configuration
When you [create a new web application](https://abp.io/get-started) (with EF Core, which is the default database provider), your solution structure will be similar to the picture below:
![bookstore-visual-studio-solution-v3](images/bookstore-visual-studio-solution-v3.png)
> Actual solution structure may be a bit different based on your preferences, but the database part will be same.
### The Database Structure
The startup template has some [application modules](Modules/Index.md) pre-installed. Each layer of the solution has corresponding module package references. So, the `.EntityFrameworkCore` project has the NuGet references for the `.EntityFrameworkCore` packages of the used modules:
![bookstore-efcore-dependencies](images/bookstore-efcore-dependencies.png)
In this way, you collect all the EF Core dependencies under the `.EntityFrameworkCore` project.
> In addition to the module references, it references to the `Volo.Abp.EntityFrameworkCore.SqlServer` package since the startup template is pre-configured for the SQL Server. See the documentation if you want to [switch to another DBMS](Entity-Framework-Core-Other-DBMS.md).
While every module has its own `DbContext` class by design and can use its **own physical database**, the solution is configured to use a **single shared database** as shown in the figure below:
![single-database-usage](images/single-database-usage.png)
This is **the simplest configuration** and suitable for most of the applications. `appsettings.json` file has a **single connection string**, named `Default`:
````json
"ConnectionStrings": {
"Default": "..."
}
````
So, you have a **single database schema** which contains all the tables of the modules **sharing** this database.
ABP Framework's [connection string](Connection-Strings.md) system allows you to easily **set a different connection string** for a desired module:
````json
"ConnectionStrings": {
"Default": "...",
"AbpAuditLogging": "..."
}
````
The example configuration about tells to the ABP Framework to use the second connection string for the [Audit Logging module](Modules/Audit-Logging.md).
However, this is just the beginning. You also need to create the second database, create audit log tables inside it and maintain the database tables using the code first approach. One of the main purposes of this document is to guide you on such database separation scenarios.
#### Module Tables
Every module uses its own databases tables. For example, the [Identity Module](Modules/Identity.md) has some tables to manage the users and roles in the system.
#### Table Prefixes
Since it is allowed to share a single database by all modules (it is the default configuration), a module typically uses a prefix to group its own tables.
The fundamental modules, like [Identity](Modules/Identity.md), [Tenant Management](Modules/Tenant-Management.md) and [Audit Logs](Modules/Audit-Logging.md), use the `Abp` prefix, while some other modules use their own prefixes. [Identity Server](Modules/IdentityServer.md) module uses the `IdentityServer` prefix for example.
If you want, you can change the database table name prefix for a module for your application. Example:
````csharp
Volo.Abp.IdentityServer.AbpIdentityServerDbProperties.DbTablePrefix = "Ids";
````
This code changes the prefix of the [Identity Server](Modules/IdentityServer.md) module. Write this code at the very beginning in your application.
> Every module also defines `DbSchema` property (near to `DbTablePrefix`), so you can set it for the databases support the schema usage.
### The Projects
From the database point of view, there are three important projects those will be explained in the next sections.
#### .EntityFrameworkCore Project
This project has the `DbContext` class (`BookStoreDbContext` for this sample) of your application.
Every module uses its own `DbContext` class to access to the database. Likewise, your application has its own `DbContext`. You typically use this `DbContext` in your application code (in your custom [repositories](Repositories.md) if you follow the best practices). It is almost an empty `DbContext` since your application don't have any entities at the beginning, except the pre-defined `AppUser` entity:
````csharp
[ConnectionStringName("Default")]
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<AppUser> Users { get; set; }
/* Add DbSet properties for your Aggregate Roots / Entities here. */
public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Configure the shared tables (with included modules) here */
builder.Entity<AppUser>(b =>
{
//Sharing the same table "AbpUsers" with the IdentityUser
b.ToTable("AbpUsers");
//Configure base properties
b.ConfigureByConvention();
b.ConfigureAbpUser();
//Moved customization of the "AbpUsers" table to an extension method
b.ConfigureCustomUserProperties();
});
/* Configure your own tables/entities inside the ConfigureBookStore method */
builder.ConfigureBookStore();
}
}
````
This simple `DbContext` class still needs some explanations:
* It defines a `[ConnectionStringName]` attribute which tells ABP to always use the `Default` connection string for this `Dbcontext`.
* It inherits from the `AbpDbContext<T>` instead of the standard `DbContext` class. You can see the [EF Core integration](Entity-Framework-Core.md) document for more. For now, know that the `AbpDbContext<T>` base class implements some conventions of the ABP Framework to automate some common tasks for you.
* It declares a `DbSet` property for the `AppUser` entity. `AppUser` shares the same table (named `AbpUsers` by default) with the `IdentityUser` entity of the [Identity module](Modules/Identity.md). The startup template provides this entity inside the application since we think that the User entity is generally needs to be customized in your application.
* The constructor takes a `DbContextOptions<T>` instance.
* It overrides the `OnModelCreating` method to define the EF Core mappings.
* It first calls the the `base.OnModelCreating` method to let the ABP Framework to implement the base mappings for us.
* It then configures the mapping for the `AppUser` entity. There is a special case for this entity (it shares a table with the Identity module), which will be explained in the next sections.
* It finally calls the `builder.ConfigureBookStore()` extension method to configure other entities of your application.
This design will be explained in more details after introducing the other database related projects.
#### .EntityFrameworkCore.DbMigrations Project
As mentioned in the previous section, every module (and your application) have **their own** separate `DbContext` classes. Each `DbContext` class only defines the entity to table mappings related to its own module and each module (and your application) use the related `DbContext` class **on runtime**.
As you know, EF Core Code First migration system relies on a `DbContext` class **to track and generate** the code first migrations. So, which `DbContext` we should use for the migrations? The answer is *none of them*. There is another `DbContext` defined in the `.EntityFrameworkCore.DbMigrations` project (which is the `BookStoreMigrationsDbContext` for this example solution).
##### The MigrationsDbContext
The `MigrationsDbContext` is only used to create and apply the database migrations. It is **not used on runtime**. It **merges** all the entity to table mappings of all the used modules plus the application's mappings.
In this way, you create and maintain a **single database migration path**. However, there are some difficulties of this approach and the next sections explains how ABP Framework overcomes these difficulties. But first, see the `BookStoreMigrationsDbContext` class as an example:
````csharp
/* This DbContext is only used for database migrations.
* It is not used on runtime. See BookStoreDbContext for the runtime DbContext.
* It is a unified model that includes configuration for
* all used modules and your application.
*/
public class BookStoreMigrationsDbContext : AbpDbContext<BookStoreMigrationsDbContext>
{
public BookStoreMigrationsDbContext(
DbContextOptions<BookStoreMigrationsDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentity();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement();
/* Configure customizations for entities from the modules included */
builder.Entity<IdentityUser>(b =>
{
b.ConfigureCustomUserProperties();
});
/* Configure your own tables/entities inside the ConfigureBookStore method */
builder.ConfigureBookStore();
}
}
````
##### Sharing the Mapping Code
First problem is that: A module uses its own `DbContext` which needs to the database mappings. The `MigrationsDbContext` also needs to the same mapping in order to create the database tables for this module. We definitely don't want to duplicate the mapping code.
The solution is to define an extension method (on the `ModelBuilder`) that can be called by both `DbContext` classes. So, every module defines such an extension method.
For example, the `builder.ConfigureBackgroundJobs()` method call configures the database tables for the [Background Jobs module](Modules/Background-Jobs.md). The definition of this extension method is something like that:
````csharp
public static class BackgroundJobsDbContextModelCreatingExtensions
{
public static void ConfigureBackgroundJobs(
this ModelBuilder builder,
Action<BackgroundJobsModelBuilderConfigurationOptions> optionsAction = null)
{
var options = new BackgroundJobsModelBuilderConfigurationOptions(
BackgroundJobsDbProperties.DbTablePrefix,
BackgroundJobsDbProperties.DbSchema
);
optionsAction?.Invoke(options);
builder.Entity<BackgroundJobRecord>(b =>
{
b.ToTable(options.TablePrefix + "BackgroundJobs", options.Schema);
b.ConfigureCreationTime();
b.ConfigureExtraProperties();
b.Property(x => x.JobName)
.IsRequired()
.HasMaxLength(BackgroundJobRecordConsts.MaxJobNameLength);
//...
});
}
}
````
This extension method also gets options to change the database table prefix and schema for this module, but it is not important here.
The final application calls the extension methods inside the `MigrationsDbContext` class, so it can decide which modules are included to the database maintained by this `MigrationsDbContext`. If you want to create a second database and move some module tables to the second database, then you need to have a second `MigrationsDbContext` class which only calls the extension methods of the related modules. This topic will be detailed in the next sections.
The same `ConfigureBackgroundJobs` method is also called the `DbContext` of the Background Jobs module:
````csharp
[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)]
public class BackgroundJobsDbContext
: AbpDbContext<BackgroundJobsDbContext>, IBackgroundJobsDbContext
{
public DbSet<BackgroundJobRecord> BackgroundJobs { get; set; }
public BackgroundJobsDbContext(DbContextOptions<BackgroundJobsDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
//Reuse the same extension method!
builder.ConfigureBackgroundJobs();
}
}
````
In this way, the mapping configuration of a module can be shared between `DbContext` classes.
##### Reusing a Table of a Module
You may want to reuse a table of a depended module in your application. In this case, you have two options:
1. You can directly use the entity defined by the module.
2. You can create a new entity mapping to the same database table.
###### Use the Entity Defined by a Module
Using an entity defined a module is pretty easy and standard. For example, Identity module defines the `IdentityUser` entity. You can inject the [repository](Repositories.md) for the `IdentityUser` and perform the standard repository operations for this entity. Example:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
namespace Acme.BookStore
{
public class MyService : ITransientDependency
{
private readonly IRepository<IdentityUser, Guid> _identityUserRepository;
public MyService(IRepository<IdentityUser, Guid> identityUserRepository)
{
_identityUserRepository = identityUserRepository;
}
public async Task DoItAsync()
{
//Get all users
var users = await _identityUserRepository.GetListAsync();
}
}
}
````
This example injects the `IRepository<IdentityUser, Guid>` (default repository) which defines the standard repository methods and implements the `IQueryable` interface.
In addition, Identity module defines the `IIdentityUserRepository` (custom repository) that can also be injected and used by your application. `IIdentityUserRepository` provides additional custom methods for the `IdentityUser` entity while it does not implement the `IQueryable`.
###### Create a New Entity
TODO
##### Discussion of an Alternative Scenario: Every Module Manages Its Own Migration Path
TODO

14
docs/en/Entity-Framework-Core-Other-DBMS.md

@ -1,12 +1,16 @@
# Switch to another DBMS for Entity Framework Core
# Switch to Another DBMS for Entity Framework Core
**[The application startup template](Startup-Templates/Application.md)** comes with SQL Server provider pre-configured for the Entity Framework Core. Entity Framework Core supports [many other DBMSs](https://docs.microsoft.com/en-us/ef/core/providers/) and you can use any of them with your ABP based applications.
**[The application startup template](Startup-Templates/Application.md)** comes with **SQL Server provider pre-configured** for the Entity Framework Core. However, EF Core supports [many other DBMSs](https://docs.microsoft.com/en-us/ef/core/providers/) and you can use any of them within your ABP based applications.
ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier (see the [entity framework core document](Entity-Framework-Core.md) for a list of available integration packages). However, you can configure your DBMS provider without these integration packages.
ABP framework provides **integration packages** for some common DBMSs to make the configuration a bit easier. You can use the following documents to learn how to **switch to your favorite DBMS**:
While using the integration package is always recommended (it also makes standard for the depended version across different modules), you can do it manually if there is no integration package for your DBMS provider.
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
* [SQLite](Entity-Framework-Core-SQLite.md)
This document explains how to switch to MySQL without using [the MySQL integration package](Entity-Framework-Core-MySQL.md).
However, you can configure your DBMS provider **without** these integration packages. While using the integration package is always recommended (it also makes standard for the depended version across different modules), you can do it manually if there is no integration package for your DBMS provider.
For an example, this document explains how to switch to MySQL without using [the MySQL integration package](Entity-Framework-Core-MySQL.md).
## Replace the SQL Server Dependency

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

@ -32,14 +32,9 @@ namespace MyCompany.MyProject
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.
If you are creating a [reusable application module](Modules/Index.md), 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)
* [SQLite](Entity-Framework-Core-SQLite.md)
* [Others](Entity-Framework-Core-Other-DBMS.md)
See [Switch to Another DBMS for Entity Framework Core](Entity-Framework-Core-Other-DBMS.md) document to learn how to switch the DBMS.
## Creating DbContext

4
docs/en/Exception-Handling.md

@ -204,7 +204,7 @@ Instead of localizing the message while throwing the exception, you can separate
First, define the **code-namespace** to **localization resource** mapping in the module configuration:
````C#
services.Configure<ExceptionLocalizationOptions>(options =>
services.Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Qa", typeof(QaResource));
});
@ -285,7 +285,7 @@ The `IHttpExceptionStatusCodeFinder` is used to automatically determine the HTTP
Automatic HTTP status code determination can be overrided by custom mappings. For example:
````C#
services.Configure<ExceptionHttpStatusCodeOptions>(options =>
services.Configure<AbpExceptionHttpStatusCodeOptions>(options =>
{
options.Map("Volo.Qa:010002", HttpStatusCode.Conflict);
});

4
docs/en/Modules/Identity.md

@ -0,0 +1,4 @@
# Identity Management Module
See [the source code](https://github.com/abpframework/abp/tree/dev/modules/identity). Documentation will come soon...

3
docs/en/Modules/Tenant-Management.md

@ -0,0 +1,3 @@
# Tenant Management Module
TODO

6
docs/en/Tutorials/Index.md

@ -0,0 +1,6 @@
# Tutorials
## Application Development
* [With ASP.NET Core MVC / Razor Pages UI](AspNetCore-Mvc/Part-I.md)
* [With Angular UI](Angular/Part-I.md)

BIN
docs/en/_resources/Diagrams.docx

Binary file not shown.

31
docs/en/docs-nav.json

@ -33,6 +33,7 @@
},
{
"text": "Tutorials",
"path": "Tutorials/Index.md",
"items": [
{
"text": "Application Development",
@ -295,20 +296,22 @@
"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": "Switch to another DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md"
"text": "Switch DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md",
"items": [
{
"text": "To MySQL",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "To PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": "To SQLite",
"path": "Entity-Framework-Core-SQLite.md"
}
]
}
]
},

BIN
docs/en/images/bookstore-efcore-dependencies.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

20
docs/zh-Hans/CLI.md

@ -125,6 +125,26 @@ abp update [options]
#### Options
* `--include-previews` 或 `-p`: 将预览版, 测试版本 和 rc 包 同时更新到最新版本.
* `--npm`: 仅更新NPM包
* `--nuget`: 仅更新的NuGet包
### login
CLI的一些功能需要登录到abp.io平台. 使用你的用户名登录
```bash
abp login <username>
```
请注意,新的登录将终止先前的会话并创建一个新的会话.
### logout
通过从计算机中删除会话令牌来注销.
```
abp logout
```
### help

160
docs/zh-Hans/Entities.md

@ -1,34 +1,80 @@
## 实体
# 实体
实体是DDD(Domain Driven Design)中核心概念.Eric Evans是这样描述实体的 "一个没有从其属性,而是通过连续性和身份的线索来定义的对象"
实体通常映射到关系型数据库的表中.
### 实体类
## 实体类
实体都继承自`Entity<TKey>`类,如下所示:
```C#
public class Person : Entity<int>
public class Book : Entity<Guid>
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public float Price { get; set; }
}
```
> 如果你不想继承基类`Entity<TKey>`,也可以直接实现`IEntity<TKey>`接口
`Entity<TKey>`类只是用给定的主 **键类型** 定义了一个`Id`属性,在上面的示例中是`Guid`类型.可以是其他类型如`string`, `int`, `long`或其他你需要的类型.
### Guid主键的实体
如果你的实体Id类型为 `Guid`,有一些好的实践可以实现:
public Person()
* 创建一个构造函数,获取ID作为参数传递给基类.
* 如果没有为GUID Id斌值,ABP框架会在保存时设置它,但是在将实体保存到数据库之前最好在实体上有一个有效的Id.
* 如果使用带参数的构造函数创建实体,那么还要创建一个 `protected` 构造函数. 当数据库提供程序从数据库读取你的实体时(反序列化时)将使用它.
* 不要使用 `Guid.NewGuid()` 来设置Id! 在创建实体的代码中使用[`IGuidGenerator`服务](Guid-Generation.md)传递Id参数. `IGuidGenerator`经过优化可以产生连续的GUID.这对于关系数据库中的聚集索引非常重要.
示例实体:
````csharp
public class Book : Entity<Guid>
{
public string Name { get; set; }
public float Price { get; set; }
protected Book()
{
}
public Book(Guid id)
: base(id)
{
CreationTime = DateTime.Now;
}
}
```
````
> 如果你不想继承基类`Entity<TKey>`,也可以直接实现`IEntity<TKey>`接口
在[应用服务](Application-Services.md)中使用示例:
`Entity<TKey>`类只是用给定的主 **键类型** 定义了一个`Id`属性,在上面的示例中是`int`类型.可以是其他类型如`string`, `Guid`, `long`或其他你需要的类型.
````csharp
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book> _bookRepository;
public BookAppService(IRepository<Book> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task CreateAsync(CreateBookDto input)
{
await _bookRepository.InsertAsync(
new Book(GuidGenerator.Create())
{
Name = input.Name,
Price = input.Price
}
);
}
}
````
实体类还重写了 **equality** 运算符(==),以方便地检查两个实体是否相等(如果它们是相同的类型并且它们的Id相等,则它们是相等的).
* `BookAppService` 注入图书实体的默认[仓库](Repositories.md),使用`InsertAsync`方法插入 `Book` 到数据库中.
* `GuidGenerator`类型是 `IGuidGenerator`,它是在`ApplicationService`基类中定义的属性. ABP将这样常用属性预注入,所以不需要手动[注入](Dependency-Injection.md).
* 如果您想遵循DDD最佳实践,请参阅下面的*聚合示例*部分.
#### 具有复合键的实体
### 具有复合键的实体
有些实体可能需要 **复合键** .在这种情况下,可以从非泛型`Entity`类派生实体.如:
@ -53,30 +99,30 @@ public class UserRole : Entity
}
````
上面的例子中,复合键由`UserId`和`RoleId`组成.在关系数据库中,它是相关表的复合主键.
上面的例子中,复合键由`UserId`和`RoleId`组成.在关系数据库中,它是相关表的复合主键. 具有复合键的实体应当实现上面代码中所示的`GetKeys()`方法.
具有复合键的实体应当实现上面代码中所示的`GetKeys()`方法.
> 你还需要在**对象关系映射**(ORM)中配置实体的键. 参阅[Entity Framework Core](Entity-Framework-Core.md)集成文档查看示例.
你还需要在 **object-to-relational mapping**(ORM)中配置实体的键.
> 需要注意,复合主键实体不可以使用 `IRepository<TEntity, TKey>` 接口,因为它需要一个唯一的Id属性. 但你可以使用 `IRepository<TEntity>`.更多信息请参见[仓储](Repositories.md)的文档.
> 复合主键在仓储中有限制.由于不知道Id属性,所以对于这些实体,不能使用`IRepository<TEntity, TKey>`.但是,可以使用`IRepository<TEntity>`.更多信息请参见[仓储](Repositories.md)的文档.
### 聚合根
## 聚合根
"*聚合是域驱动设计中的一种模式.DDD的聚合是一组可以作为一个单元处理的域对象.例如,订单及订单系列的商品,这些是独立的对象,但将订单(连同订单系列的商品)视为一个聚合通常是很有用的*"( [查看详细介绍](http://martinfowler.com/bliki/DDD_Aggregate.html))
`AggregateRoot`类继承自`Entity`类,所以默认有`Id`这个属性
`AggregateRoot<TKey>`类继承自`Entity<TKey>`类,所以默认有`Id`这个属性
> 值得注意的是 ABP 会默认为聚合根创建仓储,当然,ABP也可以为所有的实体创建仓储,详情参见[仓储](Repositories.md).
ABP不强制你使用聚合根,实际上你可以使用上面定义的`Entity`类,当然,如果你想实现DDD并且创建聚合根,这里有一些最佳实践仅供参考:
ABP不强制你使用聚合根,实际上你可以使用上面定义的`Entity`类,当然,如果你想实现[领域驱动设计](Domain-Driven-Design.md)并且创建聚合根,这里有一些最佳实践仅供参考:
* 聚合根需要维护自身的完整性,所有的实体也是这样.但是聚合根也要维护子实体的完整性.所以,聚合根必须一直有效.
* 使用Id引用聚合根,而不使用导航属性
* 聚合根被视为一个单元.它是作为一个单元检索和更新的.它通常被认为是一个交易边界.
* 不单独修改聚合根中的子实体
#### 聚合根例子
如果你想在应用程序中实现DDD,请参阅[实体设计最佳实践指南](Best-Practices/Entities.md).
### 聚合根例子
这是一个具有子实体集合的聚合根例子:
@ -155,6 +201,11 @@ public class OrderLine : Entity
{
Count = newCount;
}
public override object[] GetKeys()
{
return new Object[] {OrderId, ProductId};
}
}
````
@ -169,8 +220,73 @@ public class OrderLine : Entity
* `Order.AddProduct`实现了业务规则将商品添加到订单中
* 所有属性都有`protected`的set.这是为了防止实体在实体外部任意改变.因此,在没有向订单中添加新产品的情况下设置 `TotalItemCount`将是危险的.它的值由`AddProduct`方法维护.
ABP不强制你应用任何DDD规则或模式.但是,当你准备应用的DDD规则或模式时候,ABP会让这变的可能而且更简单.文档同样遵循这个原则.
ABP框架不强制你应用任何DDD规则或模式.但是,当你准备应用的DDD规则或模式时候,ABP会让这变的可能而且更简单.文档同样遵循这个原则.
#### 带有组合键的聚合根
### 带有组合键的聚合根
虽然这种聚合根并不常见(也不建议使用),但实际上可以按照与上面提到的跟实体相同的方式定义复合键.在这种情况下,要使用非泛型的`AggregateRoot`基类.
## 基类和接口的审计属性
有一些属性,像`CreationTime`,`CreatorId`,`LastModificationTime`...在所有应用中都很常见. ABP框架提供了一些接口和基类来**标准化**这些属性,并**自动设置它们的值**.
### 审计接口
有很多的审计接口,你可以实现一个你需要的那个.
> 虽然可以手动实现这些接口,但是可以使用下一节中定义的**基类**简化代码.
* `IHasCreationTime` 定义了以下属性:
* `CreationTime`
* `IMayHaveCreator` 定义了以下属性:
* `CreatorId`
* `ICreationAuditedObject` 继承 `IHasCreationTime` 和 `IMayHaveCreator`, 所以它定义了以下属性:
* `CreationTime`
* `CreatorId`
* `IHasModificationTime` 定义了以下属性:
* `LastModificationTime`
* `IModificationAuditedObject` 扩展 `IHasModificationTime` 并添加了 `LastModifierId` 属性. 所以它定义了以下属性:
* `LastModificationTime`
* `LastModifierId`
* `IAuditedObject` 扩展 `ICreationAuditedObject` 和 `IModificationAuditedObject`, 所以它定义了以下属性:
* `CreationTime`
* `CreatorId`
* `LastModificationTime`
* `LastModifierId`
* `ISoftDelete` (参阅 [数据过滤文档](Data-Filtering.md)) 定义了以下属性:
* `IsDeleted`
* `IHasDeletionTime` 扩展 `ISoftDelete` 并添加了 `DeletionTime` 属性. 所以它定义了以下属性:
* `IsDeleted`
* `DeletionTime`
* `IDeletionAuditedObject` 扩展 `IHasDeletionTime` 并添加了 `DeleterId` 属性. 所以它定义了以下属性:
* `IsDeleted`
* `DeletionTime`
* `DeleterId`
* `IFullAuditedObject` 继承 `IAuditedObject` 和 `IDeletionAuditedObject`, 所以它定义了以下属性:
* `CreationTime`
* `CreatorId`
* `LastModificationTime`
* `LastModifierId`
* `IsDeleted`
* `DeletionTime`
* `DeleterId`
当你实现了任意接口,或者从下一节定义的类派生,ABP框架就会尽可能地自动管理这些属性.
> 实现 `ISoftDelete` , `IDeletionAuditedObject` 或 `IFullAuditedObject` 让你的实体**软删除**. 参阅[数据过滤文档](Data-Filtering.md),了解软删除模式.
### 审计基类
虽然可以手动实现以上定义的任何接口,但建议从这里定义的基类继承:
* `CreationAuditedEntity<TKey>` 和 `CreationAuditedAggregateRoot<TKey>` 实现了 `ICreationAuditedObject` 接口.
* `AuditedEntity<TKey>` 和 `AuditedAggregateRoot<TKey>` 实现了 `IAuditedObject` 接口.
* `FullAuditedEntity<TKey>` and `FullAuditedAggregateRoot<TKey>` 实现了 `IFullAuditedObject` 接口.
所有这些基类都有非泛型版本,可以使用 `AuditedEntity` 和 `FullAuditedAggregateRoot` 来支持复合主键;
所有这些基类也有 `... WithUser`,像 `FullAuditedAggregateRootWithUser<TUser>` 和 `FullAuditedAggregateRootWithUser<TKey, TUser>`. 这样就可以将导航属性添加到你的用户实体. 但在聚合根之间添加导航属性不是一个好做法,所以这种用法是不建议的(除非你使用EF Core之类的ORM可以很好地支持这种情况,并且你真的需要它. 请记住这种方法不适用于NoSQL数据库(如MongoDB),你必须真正实现聚合模式).
## 另请参阅
* [实体设计最佳实践指南](Best-Practices/Entities.md)

8
docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md

@ -2,9 +2,13 @@
**[应用程序启动模板](Startup-Templates/Application.md)** 为EF Core预配置了Sql Server提供程序,EF Core支持许多其它DBMS,你可以在基于ABP的应用程序使用它们.
ABP框架为一些常见的DMBS提供了简化配置的集成包(有关可用集成包的列表,请参阅[EF Core文档](Entity-Framework-Core.md)),你也可以不使用集成包配置DBMS提供程序.
ABP框架为一些常见的DMBS提供了简化配置的**集成包**,你可以通过以下文档来学习如何**切换到你喜欢的DBMS**:
虽然总是建议使用集成包(它也使不同模块之间的依赖版本成为标准版本),但是如果没有用于DBMS提供程序的集成包,也可以手动集成.
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
* [SQLite](Entity-Framework-Core-SQLite.md)
你也可以不使用集成包配置DBMS提供程序,虽然总是建议使用集成包(它也使不同模块之间的依赖版本成为标准版本),但是如果没有用于DBMS提供程序的集成包,也可以手动集成.
本文介绍了如何在不使用[MySQL集成包](Entity-Framework-Core-MySQL.md)的情况下切换到MySQL.

9
docs/zh-Hans/Entity-Framework-Core.md

@ -32,14 +32,9 @@ namespace MyCompany.MyProject
EF Core支持多种数据库管理系统([查看全部](https://docs.microsoft.com/en-us/ef/core/providers/)). ABP框架和本文档不依赖于任何特定的DBMS.
如果要创建一个可重用的库,应避免依赖于特定的DBMS包.但在最终的应用程序中,始终会选择一个DBMS.
如果要创建一个可重用的[应用程序模块](Modules/Index.md),应避免依赖于特定的DBMS包.但在最终的应用程序中,始终会选择一个DBMS.
ABP框架为一些常见的DBMS提供了集成包,使配置变得更加简单. [启动模板](Startup-Templates/Index.md)附带**预先配置的SQL Server (localdb)**.请参阅以下文档,了解如何配置其他DBMS提供程序:
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
* [SQLite](Entity-Framework-Core-SQLite.md)
* [Others](Entity-Framework-Core-Other-DBMS.md)
参阅[为Entity Framework Core切换到其他DBMS](Entity-Framework-Core-Other-DBMS.md)文档学习如何切换DBMS.
## 创建 DbContext

2
docs/zh-Hans/Exception-Handling.md

@ -190,7 +190,7 @@ throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"
"UserNameShouldBeUniqueMessage": "Username should be unique! '{0}' is already taken!"
````
* `IUserFriendlyException`接口派生自`IBusinessException`,而 `UserFriendlyException `类派生自`BusinessException`类.
* `IUserFriendlyException`接口派生自`IBusinessException`,而 `UserFriendlyException`类派生自`BusinessException`类.
#### 使用错误代码

3
docs/zh-Hans/Tutorials/Angular/Part-I.md

@ -0,0 +1,3 @@
## Angular 教程 - 第一章
TODO...

26
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-I.md

@ -16,7 +16,7 @@
### 创建项目
创建一个名为`Acme.BookStore`的新项目, 创建数据库并按照[入门文档](../../Getting-Started-AspNetCore-MVC-Template.md)运行应用程序.
创建一个名为`Acme.BookStore`的新项目, 创建数据库并按照[入门文档](../../../Getting-Started-AspNetCore-MVC-Template.md)运行应用程序.
### 解决方案的结构
@ -24,16 +24,16 @@
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
> 你可以查看[应用程序模板文档](../../Startup-Templates/Application.md)以详细了解解决方案结构.但是,你将通过本教程了解基础知识.
> 你可以查看[应用程序模板文档](../../../Startup-Templates/Application.md)以详细了解解决方案结构.但是,你将通过本教程了解基础知识.
### 创建Book实体
启动模板中的域层分为两个项目:
- `Acme.BookStore.Domain`包含你的[实体](../../Entities.md), [领域服务](../../Domain-Services.md)和其他核心域对象.
- `Acme.BookStore.Domain`包含你的[实体](../../../Entities.md), [领域服务](../../../Domain-Services.md)和其他核心域对象.
- `Acme.BookStore.Domain.Shared`包含可与客户共享的常量,枚举或其他域相关对象.
在解决方案的**领域层**(`Acme.BookStore.Domain`项目)中定义[实体](../../Entities.md). 该应用程序的主要实体是`Book`. 在`Acme.BookStore.Domain`项目中创建一个名为`Book`的类,如下所示:
在解决方案的**领域层**(`Acme.BookStore.Domain`项目)中定义[实体](../../../Entities.md). 该应用程序的主要实体是`Book`. 在`Acme.BookStore.Domain`项目中创建一个名为`Book`的类,如下所示:
````C#
using System;
@ -66,7 +66,7 @@ namespace Acme.BookStore
}
````
* ABP为实体提供了两个基本的基类: `AggregateRoot`和`Entity`. **Aggregate Root**是**域驱动设计(DDD)** 概念之一. 有关详细信息和最佳做法,请参阅[实体文档](../../Entities.md).
* ABP为实体提供了两个基本的基类: `AggregateRoot`和`Entity`. **Aggregate Root**是**域驱动设计(DDD)** 概念之一. 有关详细信息和最佳做法,请参阅[实体文档](../../../Entities.md).
* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了一些审计属性(`CreationTime`, `CreatorId`, `LastModificationTime` 等).
* `Guid`是`Book`实体的主键类型.
* 使用 **数据注解** 为EF Core添加映射.或者你也可以使用 EF Core 自带的[fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling).
@ -138,7 +138,7 @@ PM> Update-Database
### 创建应用服务
下一步是创建[应用服务](../../Application-Services.md)来管理(创建,列出,更新,删除)书籍. 启动模板中的应用程序层分为两个项目:
下一步是创建[应用服务](../../../Application-Services.md)来管理(创建,列出,更新,删除)书籍. 启动模板中的应用程序层分为两个项目:
* `Acme.BookStore.Application.Contracts`主要包含你的DTO和应用程序服务接口.
* `Acme.BookStore.Application`包含应用程序服务的实现.
@ -166,7 +166,7 @@ namespace Acme.BookStore
}
````
* **DTO**类被用来在 **表示层** 和 **应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息.
* **DTO**类被用来在 **表示层** 和 **应用层** **传递数据**.查看[DTO文档](../../../Data-Transfer-Objects.md)查看更多信息.
* 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到表示层.
* `BookDto`继承自 `AuditedEntityDto<Guid>`.跟上面定义的`Book`类一样具有一些审计属性.
@ -217,7 +217,7 @@ namespace Acme.BookStore
````
* 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息.
* 它定义了数据注释属性(如`[Required]`)来定义属性的验证. DTO由ABP框架[自动验证](../../Validation.md).
* 它定义了数据注释属性(如`[Required]`)来定义属性的验证. DTO由ABP框架[自动验证](../../../Validation.md).
就像上面的`BookDto`一样,创建一个从`CreateUpdateBookDto`对象到`Book`实体的映射:
@ -281,12 +281,12 @@ namespace Acme.BookStore
````
* `BookAppService`继承了`CrudAppService<...>`.它实现了上面定义的CRUD方法.
* `BookAppService`注入`IRepository <Book,Guid>`,这是`Book`实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅[仓储文档](../../Repositories.md)
* `BookAppService`注入`IRepository <Book,Guid>`,这是`Book`实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅[仓储文档](../../../Repositories.md)
* `BookAppService`使用`IObjectMapper`将`Book`对象转换为`BookDto`对象, 将`CreateUpdateBookDto`对象转换为`Book`对象. 启动模板使用[AutoMapper](http://automapper.org/)库作为对象映射提供程序. 你之前定义了映射, 因此它将按预期工作.
### 自动生成API Controllers
你通常创建**Controller**以将应用程序服务公开为**HTTP API**端点. 因此允许浏览器或第三方客户端通过AJAX调用它们. ABP可以[**自动**](../../AspNetCore/Auto-API-Controllers.md)按照惯例将你的应用程序服务配置为MVC API控制器.
你通常创建**Controller**以将应用程序服务公开为**HTTP API**端点. 因此允许浏览器或第三方客户端通过AJAX调用它们. ABP可以[**自动**](../../../AspNetCore/Auto-API-Controllers.md)按照惯例将你的应用程序服务配置为MVC API控制器.
#### Swagger UI
@ -392,7 +392,7 @@ context.Menu.AddItem(
}
````
* ABP的本地化功能建立在[ASP.NET Core's standard localization]((https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization))之上并增加了一些扩展.查看[本地化文档](../../Localization.md).
* ABP的本地化功能建立在[ASP.NET Core's standard localization]((https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization))之上并增加了一些扩展.查看[本地化文档](../../../Localization.md).
* 本地化key是任意的. 你可以设置任何名称. 我们更喜欢为菜单项添加`Menu:`前缀以区别于其他文本. 如果未在本地化文件中定义文本,则它将**返回**到本地化的key(ASP.NET Core的标准行为).
运行该应用程序,看到新菜单项已添加到顶部栏:
@ -437,8 +437,8 @@ context.Menu.AddItem(
</abp-card>
````
* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)用于将外部的 **脚本** 添加到页面中.它比标准的`script`标签多了很多额外的功能.它可以处理 **最小化**和 **版本**.查看[捆绑 & 压缩文档](../../AspNetCore/Bundling-Minification.md)获取更多信息.
* `abp-card` 和 `abp-table` 是为Twitter Bootstrap的[card component](http://getbootstrap.com/docs/4.1/components/card/)封装的 **tag helpers**.ABP中有很多tag helpers,可以很方便的使用大多数[bootstrap](https://getbootstrap.com/)组件.你也可以使用原生的HTML标签代替tag helpers.使用tag helper可以通过智能提示和编译时类型检查减少HTML代码并防止错误.查看[tag helpers 文档](../../AspNetCore/Tag-Helpers/Index.md).
* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)用于将外部的 **脚本** 添加到页面中.它比标准的`script`标签多了很多额外的功能.它可以处理 **最小化**和 **版本**.查看[捆绑 & 压缩文档](../../../AspNetCore/Bundling-Minification.md)获取更多信息.
* `abp-card` 和 `abp-table` 是为Twitter Bootstrap的[card component](http://getbootstrap.com/docs/4.1/components/card/)封装的 **tag helpers**.ABP中有很多tag helpers,可以很方便的使用大多数[bootstrap](https://getbootstrap.com/)组件.你也可以使用原生的HTML标签代替tag helpers.使用tag helper可以通过智能提示和编译时类型检查减少HTML代码并防止错误.查看[tag helpers 文档](../../../AspNetCore/Tag-Helpers/Index.md).
* 你可以像上面本地化菜单一样 **本地化** 列名.
#### 添加脚本文件

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-II.md

2
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/Part-III.md

@ -68,7 +68,7 @@ namespace Acme.BookStore
````
* 注入`IRepository<Book,Guid>`并在`SeedAsync`中使用它来创建两个书实体作为测试数据.
* 使用`IGuidGenerator`服务创建GUID. 虽然`Guid.NewGuid()`非常适合测试,但`IGuidGenerator`在使用真实数据库时还有其他特别重要的功能(参见[Guid生成文档](../../Guid-Generation.md)了解更多信息).
* 使用`IGuidGenerator`服务创建GUID. 虽然`Guid.NewGuid()`非常适合测试,但`IGuidGenerator`在使用真实数据库时还有其他特别重要的功能(参见[Guid生成文档](../../../Guid-Generation.md)了解更多信息).
### 测试 BookAppService

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-create-dialog-v2.png

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-edit-dialog.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-edit-dialog.png

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-add-index-page-v2.png

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-appservice-tests.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-appservice-tests.png

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-book-list-2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-book-list-2.png

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-book-list.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-book-list.png

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-books-table-actions.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-books-table-actions.png

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-books-table.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-books-table.png

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-create-dialog-2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-dialog-2.png

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-create-dialog.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-dialog.png

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-create-template.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-create-template.png

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-homepage.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-homepage.png

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-index-js-file-v2.png

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-localization-files-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-localization-files-v2.png

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-menu-items.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-menu-items.png

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-new-book-button.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-new-book-button.png

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration.png

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-swagger.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-swagger.png

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist-network.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist-network.png

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-js-proxy-getlist.png

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-test-projects-v2.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-test-projects-v2.png

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-user-management.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-user-management.png

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png → docs/zh-Hans/Tutorials/AspNetCore-Mvc/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v3.png

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

6
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Index.md

@ -0,0 +1,6 @@
# 教程
## 应用开发
* [使用ASP.NET Core MVC/ Razor Pages UI](AspNetCore-Mvc/Part-I.md)
* [使用Angular UI](Angular/Part-I.md)

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

@ -29,6 +29,7 @@
},
{
"text": "教程",
"path": "Tutorials/Index.md",
"items": [
{
"text": "应用开发",
@ -277,20 +278,22 @@
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "切换到MySql",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "切换到PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": "切换到SQLite",
"path": "Entity-Framework-Core-SQLite.md"
},
{
"text": "切换到其他DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md"
"text": "切换DMBS",
"path": "Entity-Framework-Core-Other-DBMS.md",
"items":[
{
"text": "到MySql",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "到PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": "到SQLite",
"path": "Entity-Framework-Core-SQLite.md"
}
]
}
]
},

1
framework/src/Volo.Abp.Authorization/Microsoft/Extensions/DependencyInjection/AbpAuthorizationServiceCollectionExtensions.cs

@ -11,6 +11,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.Replace(ServiceDescriptor.Singleton<IAuthorizationService, AlwaysAllowAuthorizationService>());
services.Replace(ServiceDescriptor.Singleton<IAbpAuthorizationService, AlwaysAllowAuthorizationService>());
services.Replace(ServiceDescriptor.Singleton<IMethodInvocationAuthorizationService, AlwaysAllowMethodInvocationAuthorizationService>());
return services.Replace(ServiceDescriptor.Singleton<IPermissionChecker, AlwaysAllowPermissionChecker>());
}
}

12
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AlwaysAllowMethodInvocationAuthorizationService.cs

@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace Volo.Abp.Authorization
{
public class AlwaysAllowMethodInvocationAuthorizationService : IMethodInvocationAuthorizationService
{
public Task CheckAsync(MethodInvocationAuthorizationContext context)
{
return Task.CompletedTask;
}
}
}

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

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Licensing;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands.Services
{
public class AbpNuGetIndexUrlService : ITransientDependency
{
private readonly IApiKeyService _apiKeyService;
public ILogger<AbpNuGetIndexUrlService> Logger { get; set; }
public AbpNuGetIndexUrlService(IApiKeyService apiKeyService)
{
_apiKeyService = apiKeyService;
Logger = NullLogger<AbpNuGetIndexUrlService>.Instance;
}
public async Task<string> GetAsync()
{
var apiKeyResult = await _apiKeyService.GetApiKeyOrNullAsync();
if (apiKeyResult == null)
{
Logger.LogWarning("You are not signed in! Use the CLI command \"abp login <username>\" to sign in, then try again.");
return null;
}
if (!string.IsNullOrWhiteSpace(apiKeyResult.ErrorMessage))
{
Logger.LogWarning(apiKeyResult.ErrorMessage);
return null;
}
if (string.IsNullOrEmpty(apiKeyResult.ApiKey))
{
Logger.LogError("Couldn't retrieve your NuGet API key! You can re-sign in with the CLI command \"abp login <username>\".");
return null;
}
return CliUrls.GetNuGetServiceIndexUrl(apiKeyResult.ApiKey);
}
}
}

38
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs

@ -1,11 +1,10 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Licensing;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
@ -13,13 +12,13 @@ namespace Volo.Abp.Cli.Commands
{
public class SuiteCommand : IConsoleCommand, ITransientDependency
{
private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
private const string SuitePackageName = "Volo.Abp.Suite";
public ILogger<SuiteCommand> Logger { get; set; }
private readonly IApiKeyService _apiKeyService;
public SuiteCommand(IApiKeyService apiKeyService)
public SuiteCommand(AbpNuGetIndexUrlService nuGetIndexUrlService)
{
_apiKeyService = apiKeyService;
_nuGetIndexUrlService = nuGetIndexUrlService;
Logger = NullLogger<SuiteCommand>.Instance;
}
@ -53,7 +52,7 @@ namespace Volo.Abp.Cli.Commands
private async Task InstallSuiteAsync()
{
var nugetIndexUrl = await GetNuGetIndexUrlAsync();
var nugetIndexUrl = await _nuGetIndexUrlService.GetAsync();
if (nugetIndexUrl == null)
{
@ -71,7 +70,7 @@ namespace Volo.Abp.Cli.Commands
private async Task UpdateSuiteAsync()
{
var nugetIndexUrl = await GetNuGetIndexUrlAsync();
var nugetIndexUrl = await _nuGetIndexUrlService.GetAsync();
if (nugetIndexUrl == null)
{
@ -104,31 +103,6 @@ namespace Volo.Abp.Cli.Commands
CmdHelper.RunCmd("abp-suite");
}
private async Task<string> GetNuGetIndexUrlAsync()
{
var apiKeyResult = await _apiKeyService.GetApiKeyOrNullAsync();
if (apiKeyResult == null)
{
Logger.LogWarning("You are not signed in! Use the CLI command \"abp login <username>\" to sign in, then try again.");
return null;
}
if (!string.IsNullOrWhiteSpace(apiKeyResult.ErrorMessage))
{
Logger.LogWarning(apiKeyResult.ErrorMessage);
return null;
}
if (string.IsNullOrEmpty(apiKeyResult.ApiKey))
{
Logger.LogError("Couldn't retrieve your NuGet API key! You can re-sign in with the CLI command \"abp login <username>\".");
return null;
}
return CliUrls.GetNuGetServiceIndexUrl(apiKeyResult.ApiKey);
}
public string GetUsageInfo()
{
var sb = new StringBuilder();

4
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedAggregateRootWithUser.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class AuditedAggregateRootWithUser<TUser> : AuditedAggregateRoot, IAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
@ -25,7 +25,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class AuditedAggregateRootWithUser<TKey, TUser> : AuditedAggregateRoot<TKey>, IAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }

4
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/AuditedEntityWithUser.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class AuditedEntityWithUser<TUser> : AuditedEntity, IAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }
@ -25,7 +25,7 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class AuditedEntityWithUser<TKey, TUser> : AuditedEntity<TKey>, IAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Creator { get; set; }

8
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs

@ -15,10 +15,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public TUser Creator { get; set; }
public virtual TUser Creator { get; set; }
/// <inheritdoc />
public TUser LastModifier { get; set; }
public virtual TUser LastModifier { get; set; }
}
/// <summary>
@ -34,10 +34,10 @@ namespace Volo.Abp.Domain.Entities.Auditing
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public TUser Creator { get; set; }
public virtual TUser Creator { get; set; }
/// <inheritdoc />
public TUser LastModifier { get; set; }
public virtual TUser LastModifier { get; set; }
protected FullAuditedAggregateRootWithUser()
{

12
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedEntityWithUser.cs

@ -9,16 +9,16 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class FullAuditedEntityWithUser<TUser> : FullAuditedEntity, IFullAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public TUser Creator { get; set; }
public virtual TUser Creator { get; set; }
/// <inheritdoc />
public TUser LastModifier { get; set; }
public virtual TUser LastModifier { get; set; }
}
/// <summary>
@ -28,16 +28,16 @@ namespace Volo.Abp.Domain.Entities.Auditing
/// <typeparam name="TUser">Type of the user</typeparam>
[Serializable]
public abstract class FullAuditedEntityWithUser<TKey, TUser> : FullAuditedEntity<TKey>, IFullAuditedObject<TUser>
where TUser : IEntity<long>
where TUser : IEntity<Guid>
{
/// <inheritdoc />
public virtual TUser Deleter { get; set; }
/// <inheritdoc />
public TUser Creator { get; set; }
public virtual TUser Creator { get; set; }
/// <inheritdoc />
public TUser LastModifier { get; set; }
public virtual TUser LastModifier { get; set; }
protected FullAuditedEntityWithUser()
{

3
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs

@ -106,6 +106,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false)
{
var nHttpStatusCode = (int?) httpStatusCode;
return DbSet.AsNoTracking()
.IncludeDetails(includeDetails)
.WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime)
@ -117,7 +118,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
.WhereIf(userName != null, auditLog => auditLog.UserName == userName)
.WhereIf(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
.WhereIf(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)
.WhereIf(httpStatusCode != null && httpStatusCode > 0, auditLog => auditLog.HttpStatusCode == (int?)httpStatusCode)
.WhereIf(httpStatusCode != null && httpStatusCode > 0, auditLog => auditLog.HttpStatusCode == nHttpStatusCode)
.WhereIf(maxExecutionDuration != null && maxExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration <= maxExecutionDuration)
.WhereIf(minExecutionDuration != null && minExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration >= minExecutionDuration);
}

6
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml

@ -142,15 +142,15 @@
var oddPost = index % 2 == 1;
<div class="list-group-item">
<div class="row @(oddPost ? "align-middle" : "")">
<div class="col-md-4 order-md-@(oddPost ? "last" : "first")">
<div class="row">
<div class="col-md-4">
<div class="img-container">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">
<img src="@post.CoverImage" class="box-article-img">
</a>
</div>
</div>
<div class="col order-md-@(oddPost ? "first" : "last")">
<div class="col">
<h3>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a>
</h3>

2
modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs

@ -149,4 +149,4 @@ namespace Volo.Abp.Users
}
}
}
}
}

Loading…
Cancel
Save