Browse Source

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

pull/992/head
maliming 7 years ago
parent
commit
5ec6f33efc
  1. 16
      abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
  2. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/HomePageLayout.cshtml
  3. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Layout.cshtml
  4. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/LayoutEmpty.cshtml
  5. 39
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/NugetReferenceReplaceStep.cs
  6. 1
      build-all.ps1
  7. 2
      docs/en/Contribution/Index.md
  8. 14
      docs/en/Multi-Tenancy.md
  9. 26
      docs/en/Nightly-Builds.md
  10. 26
      docs/en/Samples/Microservice-Demo.md
  11. 4
      docs/en/docs-nav.json
  12. BIN
      docs/en/images/microservice-sample-update-database-authserver.png
  13. BIN
      docs/en/images/microservice-sample-update-database-products.png
  14. BIN
      docs/en/images/night-build-add-nuget-package.png
  15. BIN
      docs/en/images/night-build-add-nuget-source.png
  16. 14
      docs/zh-Hans/Multi-Tenancy.md
  17. 5
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs
  18. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs
  19. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/pt-BR.json
  20. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/AbpAspNetCoreMvcUIBasicThemeModule.cs
  21. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml
  22. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml
  23. 34
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml
  24. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml
  25. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml
  26. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj
  27. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js
  28. 30
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/jquery-extensions.js
  29. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs
  30. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs
  31. 7
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs
  32. 15
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs
  33. 12
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs
  34. 13
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs
  35. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs
  36. 14
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs
  37. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs
  38. 23
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs
  39. 1
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs
  40. 1
      framework/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
  41. 9
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
  42. 56
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  43. 9
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCacheSerializer.cs
  44. 26
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/Utf8JsonDistributedCacheSerializer.cs
  45. 2
      framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj
  46. 62
      framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs
  47. 10
      framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs
  48. 4
      framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj
  49. 97
      framework/src/Volo.Abp.Core/Volo/Abp/Check.cs
  50. 12
      framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs
  51. 2
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs
  52. 11
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs
  53. 25
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs
  54. 4
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs
  55. 16
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSenderConfiguration.cs
  56. 3
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/ISmtpEmailSender.cs
  57. 18
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/ISmtpEmailSenderConfiguration.cs
  58. 32
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs
  59. 42
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSenderConfiguration.cs
  60. 5
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  61. 1
      framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj
  62. 4
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs
  63. 13
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  64. 4
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/RemoteServiceConfiguration.cs
  65. 14
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs
  66. 25
      framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpClaimsIdentityExtensions.cs
  67. 28
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentClaimsPrincipalTenantResolveContributor.cs
  68. 7
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantExtensions.cs
  69. 24
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentUserTenantResolveContributor.cs
  70. 5
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantResolveResultAccessor.cs
  71. 13
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/NullTenantResolveResultAccessor.cs
  72. 2
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantResolveOptions.cs
  73. 9
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs
  74. 4
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs
  75. 80
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs
  76. 5
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs
  77. 4
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
  78. 18
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json
  79. 6
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
  80. 1
      framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json
  81. 16
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
  82. 3
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/pt-BR.json
  83. 4
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/_Layout.cshtml
  84. 2
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs
  85. 2
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs
  86. 3
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json
  87. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/pt-BR.json
  88. 2
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/pt-BR.json
  89. 5
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/pt-BR.json
  90. 22
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/AbpAccountWebIdentityServerModule.cs
  91. 2
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
  92. 2
      modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs
  93. 14
      modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json
  94. 2
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AuditLogConsts.cs
  95. 41
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLog.cs
  96. 4
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogAction.cs
  97. 23
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs
  98. 8
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityPropertyChange.cs
  99. 11
      modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs
  100. 11
      modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogRepository_Tests.cs

16
abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs

@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@ -14,7 +13,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
@ -182,18 +180,8 @@ namespace Volo.AbpWebSite
AsyncHelper.RunSync(async () =>
{
await scope.ServiceProvider
.GetRequiredService<IIdentityDataSeeder>()
.SeedAsync(
"1q2w3E*"
);
await scope.ServiceProvider
.GetRequiredService<IPermissionDataSeeder>()
.SeedAsync(
RolePermissionValueProvider.ProviderName,
"admin",
IdentityPermissions.GetAll().Union(BloggingPermissions.GetAll())
);
.GetRequiredService<IDataSeeder>()
.SeedAsync();
});
}
}

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/HomePageLayout.cshtml

@ -17,7 +17,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@AbpIoBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body>
@ -47,7 +47,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Layout.cshtml

@ -17,7 +17,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@AbpIoBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body>
@ -58,7 +58,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/LayoutEmpty.cshtml

@ -18,7 +18,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@StandardBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body class="abp-empty-layout">
@ -41,7 +41,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

39
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/NugetReferenceReplaceStep.cs

@ -16,7 +16,8 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
new NugetReferenceReplacer(
context.Files,
"MyCompanyName",
"MyProjectName"
"MyProjectName",
context.Template.Version
).Run();
}
@ -27,12 +28,12 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
private readonly string _projectNamePlaceHolder;
private readonly string _latestNugetPackageVersion;
public NugetReferenceReplacer(List<FileEntry> entries, string companyNamePlaceHolder, string projectNamePlaceHolder)
public NugetReferenceReplacer(List<FileEntry> entries, string companyNamePlaceHolder, string projectNamePlaceHolder, string latestNugetPackageVersion)
{
_entries = entries;
_companyNamePlaceHolder = companyNamePlaceHolder;
_projectNamePlaceHolder = projectNamePlaceHolder;
_latestNugetPackageVersion = GetLatestNugetPackageVersion();
_latestNugetPackageVersion = latestNugetPackageVersion;
}
public void Run()
@ -110,38 +111,6 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
stream.Position = 0;
return stream;
}
private string GetLatestNugetPackageVersion()
{
//TODO: This should get it from the related release! Not always from the master!
var commonPropsUrl = "https://raw.githubusercontent.com/abpframework/abp/master/common.props";
var content = "";
using (var webClient = new WebClient())
{
try
{
content = webClient.DownloadString(commonPropsUrl);
}
catch (Exception)
{
throw new Exception("The Common.pros doesn't exist on github or removed to anywhere else.");
}
}
var doc = new HtmlDocument();
doc.Load(GenerateStreamFromString(content));
try
{
return doc.DocumentNode.SelectNodes("//version").FirstOrDefault().InnerHtml.Trim();
}
catch (Exception e)
{
return "";
}
}
}
}
}

1
build-all.ps1

@ -18,6 +18,7 @@ $solutionPaths = (
"modules/blogging",
"modules/audit-logging",
"modules/background-jobs",
"modules/client-simulation",
"abp_io",
"templates/module",
"templates/service",

2
docs/en/Contribution/Index.md

@ -49,4 +49,4 @@ If you decide to create some tutorials or blog posts on ABP, please inform us (b
### Bug Report
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).

14
docs/en/Multi-Tenancy.md

@ -6,17 +6,17 @@ Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) multi-tenancy as
> Software **Multi-tenancy** refers to a software **architecture** in which a **single instance** of a software runs on a server and serves **multiple tenants**. A tenant is a group of users who share a common access with specific privileges to the software instance. With a multitenant architecture, a software application is designed to provide every tenant a **dedicated share of the instance including its data**, configuration, user management, tenant individual functionality and non-functional properties. Multi-tenancy contrasts with multi-instance architectures, where separate software instances operate on behalf of different tenants.
### Volo.Abp.MultiTenancy.Abstractions Package
### Volo.Abp.MultiTenancy Package
Volo.Abp.MultiTenancy.Abstractions package defines fundamental interfaces to make your code "multi-tenancy ready". So, install it to your project using the package manager console (PMC):
Volo.Abp.MultiTenancy package defines fundamental interfaces to make your code "multi-tenancy ready". So, install it to your project using the package manager console (PMC):
````
Install-Package Volo.Abp.MultiTenancy.Abstractions
Install-Package Volo.Abp.MultiTenancy
````
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module:
Then you can add **AbpMultiTenancyModule** dependency to your module:
````C#
using Volo.Abp.Modularity;
@ -24,7 +24,7 @@ using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
@ -98,7 +98,7 @@ Volo.Abp.MultiTenancy is the actual package that makes your application multi-te
Install-Package Volo.Abp.MultiTenancy
````
Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module:
Then you can add **AbpMultiTenancyModule** dependency to your module:
````C#
using Volo.Abp.Modularity;
@ -114,7 +114,7 @@ namespace MyCompany.MyProject
}
````
> If you add AbpMultiTenancyModule dependency to your module, then you don't need to add AbpMultiTenancyAbstractionsModule dependency separately since AbpMultiTenancyModule already depends on it.
> If you add AbpMultiTenancyModule dependency to your module, then you don't need to add AbpMultiTenancyModule dependency separately since AbpMultiTenancyModule already depends on it.
#### Determining Current Tenant

26
docs/en/Nightly-Builds.md

@ -0,0 +1,26 @@
# Nightly Builds
All framework & module packages are deployed to MyGet every night in weekdays. So, you can use or test the latest code without waiting the next release.
## Configure Visual Studio
> Requires Visual Studio 2017+
1. Go to `Tools > Options > NuGet Package Manager > Package Source`.
2. Click the green `+` icon.
3. Set `ABP Nightly` as *Name* and `https://www.myget.org/F/abp-nightly/api/v3/index.json` as the *Source* as shown below:
![night-build-add-nuget-source](images/night-build-add-nuget-source.png)
4. Click the `Update` button.
5. Click the `OK` button to save changes.
## Install Package
Now, you can install preview / nightly packages to your project from Nuget Browser or Package Manager Console.
![night-build-add-nuget-package](images/night-build-add-nuget-package.png)
1. In the nuget browser, select "Include prereleases".
2. Change package source to "All".
3. Search a package. You will see prereleases of the package formatted as `(VERSION)-preview(DATE)` (like *v0.16.0-preview20190401* in this sample).
4. You can click to the `Install` button to add package to your project.

26
docs/en/Samples/Microservice-Demo.md

@ -116,11 +116,29 @@ To be able to run the solution from source code, following tools should be insta
* Run `dotnet restore` from the command line inside the `samples\MicroserviceDemo` folder.
* Build the solution in Visual Studio.
#### Restore Databases
#### Create Databases
Open `MsDemo_Identity.zip` and `MsDemo_ProductManagement.zip` inside the `samples\MicroserviceDemo\databases` folder and restore to the SQL Server.
MongoDB database is created dynamically, however you need to create database schemas for SQL server databases. The solution is configured to use Entity Core Code First migrations, so you can easily create databases.
> Notice that: These databases have EF Core migrations in the solution, however they don't have seed data, especially required for IdentityServer4 configuration. So, restoring the databases is much more easier.
There are two SQL server databases in this solution.
##### MsDemo_Identity Database
* Right click to the `AuthServer.Host` project and click to the `Set as startup project`.
* Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console)
* Select `AuthServer.Host` as the **Default project**.
* Run `Update-Database` command.
![microservice-sample-update-database-authserver](../images/microservice-sample-update-database-authserver.png)
##### MsDemo_ProductManagement
- Right click to the `ProductService.Host` project and click to the `Set as startup project`.
- Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console)
- Select `ProductService.Host` as the **Default project**.
- Run `Update-Database` command.
![microservice-sample-update-database-products](../images/microservice-sample-update-database-products.png)
#### Run Projects
@ -136,6 +154,8 @@ Run the projects with the following order (right click to each project, set as s
* BackendAdminApp.Host
* PublicWebSite.Host
When you run projects, they will add some initial demo data to their databases.
## A Brief Overview of the Solution
The Visual Studio solution consists of multiple projects each have different roles in the system:

4
docs/en/docs-nav.json

@ -276,6 +276,10 @@
{
"text": "Testing"
},
{
"text": "Nightly Builds",
"path": "Nightly-Builds.md"
},
{
"text": "Contribution Guide",
"path": "Contribution/Index.md"

BIN
docs/en/images/microservice-sample-update-database-authserver.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
docs/en/images/microservice-sample-update-database-products.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
docs/en/images/night-build-add-nuget-package.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/en/images/night-build-add-nuget-source.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

14
docs/zh-Hans/Multi-Tenancy.md

@ -6,17 +6,17 @@ ABP的多租户模块提供了创建多租户应用程序的基本功能.
> 软件多租户技术指的是一种软件架构,这种架构可以使用软件的单实例运行并为多个租户提供服务.租户是通过软件实例的特定权限共享通用访问的一组用户.使用多租户架构,软件应用为每个租户提供实例的专用共享,包括实例的数据、配置、用户管理、租户的私有功能和非功能属性.多租户与多实例架构形成对比,将软件实例的行为根据不同的租户分割开来.
### Volo.Abp.MultiTenancy.Abstractions
### Volo.Abp.MultiTenancy
Volo.Abp.MultiTenancy.Abstractions定义了一些基础接口让你的代码"multi-tenancy ready",使用包管理器控制台(PMC)将它安装到你的项目中:
Volo.Abp.MultiTenancy"multi-tenancy ready",使用包管理器控制台(PMC)将它安装到你的项目中:
````
Install-Package Volo.Abp.MultiTenancy.Abstractions
Install-Package Volo.Abp.MultiTenancy
````
> 这个包默认安装在了快速启动模板中.所以,大多数情况下,你不需要手动安装它.
然后你可以添加 **AbpMultiTenancyAbstractionsModule** 依赖到你的模块:
然后你可以添加 **AbpMultiTenancyModule** 依赖到你的模块:
````C#
using Volo.Abp.Modularity;
@ -24,7 +24,7 @@ using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
@ -98,7 +98,7 @@ Volo.Abp.MultiTenancy 才是让你的程序实现多租户的真正的包.使用
Install-Package Volo.Abp.MultiTenancy
````
然后添加 **AbpMultiTenancyAbstractionsModule** 依赖到你的模块中:
然后添加 **AbpMultiTenancyModule** 依赖到你的模块中:
````C#
using Volo.Abp.Modularity;
@ -114,7 +114,7 @@ namespace MyCompany.MyProject
}
````
> 如果你添加了AbpMultiTenancyModule依赖,就不需要再另外添加AbpMultiTenancyAbstractionsModule依赖了,因为AbpMultiTenancyModule已经依赖它了.
> 如果你添加了AbpMultiTenancyModule依赖,就不需要再另外添加AbpMultiTenancyModule依赖了,因为AbpMultiTenancyModule已经依赖它了.
#### 确定当前租户

5
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpContextTenantResolveResultAccessor.cs

@ -1,13 +1,12 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.MultiTenancy
{
[Dependency(ReplaceServices = true)]
public class HttpContextTenantResolveResultAccessor : ITenantResolveResultAccessor, ITransientDependency
{
[CanBeNull]
public TenantResolveResult Result
{
get

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.MultiTenancy
public static void AddDomainTenantResolver(this TenantResolveOptions options, string domainFormat)
{
options.TenantResolvers.InsertAfter(
r => r is CurrentClaimsPrincipalTenantResolveContributor,
r => r is CurrentUserTenantResolveContributor,
new DomainTenantResolveContributor(domainFormat)
);
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/pt-BR.json

@ -1,9 +1,11 @@
{
"culture": "pt-BR",
"texts": {
"GivenTenantIsNotAvailable": "Tenant não está disponível: {0}",
"SwitchTenant": "Trocar tenant",
"GivenTenantIsNotAvailable": "Inquilino não está disponível: {0}",
"Tenant": "Inquilino",
"Switch": "trocar",
"Name": "Nome",
"SwitchTenantHint": "Deixe o campo de nome em branco para alternar para o lado do host."
"SwitchTenantHint": "Deixe o campo de nome em branco para alternar para o lado do host.",
"NotSelected": "Não selecionado"
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/AbpAspNetCoreMvcUIBasicThemeModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
@ -11,7 +12,8 @@ using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
{
[DependsOn(
typeof(AbpAspNetCoreMvcUiThemeSharedModule)
typeof(AbpAspNetCoreMvcUiThemeSharedModule),
typeof(AbpAspNetCoreMvcUiMultiTenancyModule)
)]
public class AbpAspNetCoreMvcUiBasicThemeModule : AbpModule
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml

@ -7,7 +7,7 @@
var disabled = menuItem.IsDisabled ? "disabled" : string.Empty;
if (menuItem.IsLeaf)
{
@if (menuItem.Url != null)
if (menuItem.Url != null)
{
<li class="nav-item @cssClass @disabled" @elementId>
<a class="nav-link" href="@(menuItem.Url ?? "#")">

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml

@ -7,7 +7,7 @@
}
@if (Model.IsLeaf)
{
@if (Model.Url != null)
if (Model.Url != null)
{
<a class="dropdown-item @cssClass @disabled" href="@(Model.Url ?? "#")" @Html.Raw(elementId)>
@Model.DisplayName

34
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml

@ -1,10 +1,20 @@
@using Volo.Abp.AspNetCore.Mvc.AntiForgery
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.MultiTenancy
@using Volo.Abp.AspNetCore.Mvc.AntiForgery
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.MainNavbar
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.PageAlerts
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components
@using Volo.Abp.MultiTenancy
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@inject IBrandingProvider BrandingProvider
@inject IOptions<MultiTenancyOptions> MultiTenancyOptions
@inject ICurrentTenant CurrentTenant
@inject IStringLocalizer<AbpUiMultiTenancyResource> MultiTenancyStringLocalizer
@inject ITenantResolveResultAccessor TenantResolveResultAccessor
@{
Layout = null;
AbpAntiForgeryManager.SetCookie();
@ -23,7 +33,7 @@
<abp-style-bundle name="@BasicThemeBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body class="abp-account-layout">
@ -32,6 +42,24 @@
<div class="@containerClass">
<abp-row>
<abp-column size-md="_4" offset-md="_4">
@if (MultiTenancyOptions.Value.IsEnabled &&
(TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true))
{
<div class="tenant-switch-box" style="background-color: #eee; margin-bottom: 20px; color: #000; padding: 10px; text-align: center;">
<span style="color: #666;">@MultiTenancyStringLocalizer["Tenant"]: </span>
<strong>
@if (CurrentTenant.Id == null)
{
<i>@MultiTenancyStringLocalizer["NotSelected"]</i>
}
else
{
@(CurrentTenant.Name ?? CurrentTenant.Id.Value.ToString())
}
</strong>
(<a id="AbpTenantSwitchLink" style="color: #333; cursor: pointer">@MultiTenancyStringLocalizer["Switch"]</a>)
</div>
}
@(await Component.InvokeAsync<PageAlertsViewComponent>())
@RenderBody()
</abp-column>
@ -43,7 +71,7 @@
<script type="text/javascript" src="~/Abp/ApplicationConfigurationScript"></script>
<script type="text/javascript" src="~/Abp/ServiceProxyScript"></script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml

@ -23,7 +23,7 @@
<abp-style-bundle name="@BasicThemeBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body class="abp-application-layout">
@ -39,7 +39,7 @@
<script type="text/javascript" src="~/Abp/ApplicationConfigurationScript"></script>
<script type="text/javascript" src="~/Abp/ServiceProxyScript"></script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml

@ -22,7 +22,7 @@
<abp-style-bundle name="@BasicThemeBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body class="abp-empty-layout">
@ -36,7 +36,7 @@
<script type="text/javascript" src="~/Abp/ApplicationConfigurationScript"></script>
<script type="text/javascript" src="~/Abp/ServiceProxyScript"></script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj

@ -31,6 +31,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy\Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
</ItemGroup>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js

@ -69,6 +69,10 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f
//TODO: data-ajaxForm comparison seems wrong!
if (_$form.attr('data-ajaxForm') === undefined || _$form.attr('data-ajaxForm') === false) {
_$form.abpAjaxForm();
}
if (_$form.attr('data-check-form-on-close') === undefined || _$form.attr('data-check-form-on-close') != 'false') {
_$form.needConfirmationOnUnsavedClose(_$modal);
}
_$form.on('abp-ajax-success',

30
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/jquery/jquery-extensions.js

@ -3,6 +3,10 @@
return;
}
var localize = function (key) {
return abp.localization.getResource('AbpUi')(key);
};
/* A simple jQuery plug-in to make a button busy. */
$.fn.buttonBusy = function (isBusy) {
return $(this).each(function () {
@ -127,4 +131,30 @@
});
};
$.fn.needConfirmationOnUnsavedClose = function ($modal) {
var $form = $(this);
var formSaved = false;
var unEditedForm = JSON.stringify($form.serializeFormToObject());
$modal.on("hide.bs.modal", function (e) {
var currentForm = JSON.stringify($form.serializeFormToObject());
var thereAreUnsavedChanges = currentForm !== unEditedForm;
if (!formSaved && thereAreUnsavedChanges) {
e.preventDefault();
abp.message.confirm(localize('AreYouSureYouWantToCancelEditingWarningMessage'),
function (result) {
if (result) {
formSaved = true;
$modal.modal('hide');
}
});
}
});
$(this).on('abp-ajax-success',function () {
formSaved = true;
});
};
})(jQuery);

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs

@ -92,6 +92,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
auditLog,
context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(),
context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo,
context.ActionArguments

6
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs

@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
public class AuditLogActionInfo : IMultiTenant, IHasExtraProperties
[Serializable]
public class AuditLogActionInfo : IHasExtraProperties
{
public Guid? TenantId { get; set; }
public string ServiceName { get; set; }
public string MethodName { get; set; }

7
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs

@ -3,12 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
//TODO: Make serializable!
public class AuditLogInfo : IMultiTenant, IHasExtraProperties
[Serializable]
public class AuditLogInfo : IHasExtraProperties
{
public string ApplicationName { get; set; }
@ -18,6 +17,8 @@ namespace Volo.Abp.Auditing
public Guid? TenantId { get; set; }
public string TenantName { get; set; }
public Guid? ImpersonatorUserId { get; set; }
public Guid? ImpersonatorTenantId { get; set; }

15
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs

@ -92,6 +92,7 @@ namespace Volo.Abp.Auditing
{
ApplicationName = Options.ApplicationName,
TenantId = CurrentTenant.Id,
TenantName = CurrentTenant.Name,
UserId = CurrentUser.Id,
UserName = CurrentUser.UserName,
ClientId = CurrentClient.Id,
@ -106,12 +107,20 @@ namespace Volo.Abp.Auditing
return auditInfo;
}
public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments)
public virtual AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
object[] arguments)
{
return CreateAuditLogAction(type, method, CreateArgumentsDictionary(method, arguments));
return CreateAuditLogAction(auditLog, type, method, CreateArgumentsDictionary(method, arguments));
}
public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary<string, object> arguments)
public virtual AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
IDictionary<string, object> arguments)
{
var actionInfo = new AuditLogActionInfo
{

12
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs

@ -49,7 +49,7 @@ namespace Volo.Abp.Auditing
{
if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction))
{
invocation.Proceed();
await invocation.ProceedAsync();
return;
}
@ -72,7 +72,10 @@ namespace Volo.Abp.Auditing
}
}
protected virtual bool ShouldIntercept(IAbpMethodInvocation invocation, out AuditLogInfo auditLog, out AuditLogActionInfo auditLogAction)
protected virtual bool ShouldIntercept(
IAbpMethodInvocation invocation,
out AuditLogInfo auditLog,
out AuditLogActionInfo auditLogAction)
{
auditLog = null;
auditLogAction = null;
@ -95,7 +98,10 @@ namespace Volo.Abp.Auditing
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments
auditLog,
invocation.TargetObject.GetType(),
invocation.Method,
invocation.Arguments
);
return true;

13
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs

@ -2,22 +2,27 @@
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
public class EntityChangeInfo : IMultiTenant, IHasExtraProperties
[Serializable]
public class EntityChangeInfo : IHasExtraProperties
{
public DateTime ChangeTime { get; set; }
public EntityChangeType ChangeType { get; set; }
/// <summary>
/// TenantId of the related entity.
/// This is not the TenantId of the audit log entry.
/// There can be multiple tenant data changes in a single audit log entry.
/// </summary>
public Guid? EntityTenantId { get; set; }
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
public Guid? TenantId { get; set; }
public List<EntityPropertyChangeInfo> PropertyChanges { get; set; }
public Dictionary<string, object> ExtraProperties { get; }

6
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs

@ -1,9 +1,9 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
public class EntityPropertyChangeInfo : IMultiTenant
[Serializable]
public class EntityPropertyChangeInfo
{
/// <summary>
/// Maximum length of <see cref="PropertyName"/> property.
@ -23,8 +23,6 @@ namespace Volo.Abp.Auditing
/// </summary>
public const int MaxPropertyTypeFullNameLength = 192;
public Guid? TenantId { get; set; }
public virtual string NewValue { get; set; }
public virtual string OriginalValue { get; set; }

14
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs

@ -11,8 +11,18 @@ namespace Volo.Abp.Auditing
AuditLogInfo CreateAuditLogInfo();
AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments);
AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
object[] arguments
);
AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary<string, object> arguments);
AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
IDictionary<string, object> arguments
);
}
}

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs

@ -35,7 +35,7 @@ namespace Volo.Abp.Authorization
return;
}
AsyncHelper.RunSync(() => AuthorizeAsync(invocation));
await AuthorizeAsync(invocation);
await invocation.ProceedAsync();
}

23
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs

@ -4,8 +4,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Authorization.Permissions
@ -18,6 +20,8 @@ namespace Volo.Abp.Authorization.Permissions
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
protected ICurrentTenant CurrentTenant { get; }
protected PermissionOptions Options { get; }
private readonly Lazy<List<IPermissionValueProvider>> _lazyProviders;
@ -26,10 +30,12 @@ namespace Volo.Abp.Authorization.Permissions
IOptions<PermissionOptions> options,
IServiceProvider serviceProvider,
ICurrentPrincipalAccessor principalAccessor,
IPermissionDefinitionManager permissionDefinitionManager)
IPermissionDefinitionManager permissionDefinitionManager,
ICurrentTenant currentTenant)
{
PrincipalAccessor = principalAccessor;
PermissionDefinitionManager = permissionDefinitionManager;
CurrentTenant = currentTenant;
Options = options.Value;
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(
@ -50,13 +56,18 @@ namespace Volo.Abp.Authorization.Permissions
{
Check.NotNull(name, nameof(name));
var context = new PermissionValueCheckContext(
PermissionDefinitionManager.Get(name),
claimsPrincipal
);
var permission = PermissionDefinitionManager.Get(name);
var isGranted = false;
var multiTenancySide = claimsPrincipal?.GetMultiTenancySide()
?? CurrentTenant.GetMultiTenancySide();
if (!permission.MultiTenancySide.HasFlag(multiTenancySide))
{
return false;
}
var isGranted = false;
var context = new PermissionValueCheckContext(permission, claimsPrincipal);
foreach (var provider in ValueProviders)
{
if (context.Permission.Providers.Any() &&

1
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs

@ -19,6 +19,7 @@ namespace Volo.Abp.Authorization.Permissions
public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray();
if (roles == null || !roles.Any())
{
return PermissionGrantResult.Undefined;

1
framework/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.Serialization\Volo.Abp.Serialization.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />

9
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Serialization;
@ -7,9 +8,11 @@ using Volo.Abp.Threading;
namespace Volo.Abp.Caching
{
[DependsOn(typeof(AbpThreadingModule))]
[DependsOn(typeof(AbpSerializationModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
[DependsOn(
typeof(AbpThreadingModule),
typeof(AbpSerializationModule),
typeof(AbpMultiTenancyModule),
typeof(AbpJsonModule))]
public class AbpCachingModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)

56
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs

@ -25,7 +25,8 @@ namespace Volo.Abp.Caching
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected IObjectSerializer ObjectSerializer { get; }
//TODO: Create IDistributedCacheSerializer
protected IDistributedCacheSerializer Serializer { get; }
protected ICurrentTenant CurrentTenant { get; }
@ -42,8 +43,7 @@ namespace Volo.Abp.Caching
IOptions<DistributedCacheOptions> distributedCacheOption,
IDistributedCache cache,
ICancellationTokenProvider cancellationTokenProvider,
IObjectSerializer objectSerializer,
IDistributedCacheSerializer serializer,
ICurrentTenant currentTenant)
{
_distributedCacheOption = distributedCacheOption.Value;
@ -51,13 +51,15 @@ namespace Volo.Abp.Caching
Cache = cache;
CancellationTokenProvider = cancellationTokenProvider;
Logger = NullLogger<DistributedCache<TCacheItem>>.Instance;
ObjectSerializer = objectSerializer;
Serializer = serializer;
CurrentTenant = currentTenant;
SetDefaultOptions();
}
public virtual TCacheItem Get(string key, bool? hideErrors = null)
public virtual TCacheItem Get(
string key,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -83,10 +85,13 @@ namespace Volo.Abp.Caching
return null;
}
return ObjectSerializer.Deserialize<TCacheItem>(cachedBytes);
return Serializer.Deserialize<TCacheItem>(cachedBytes);
}
public virtual async Task<TCacheItem> GetAsync(string key, bool? hideErrors = null, CancellationToken token = default)
public virtual async Task<TCacheItem> GetAsync(
string key,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -115,7 +120,7 @@ namespace Volo.Abp.Caching
return null;
}
return ObjectSerializer.Deserialize<TCacheItem>(cachedBytes);
return Serializer.Deserialize<TCacheItem>(cachedBytes);
}
public TCacheItem GetOrAdd(
@ -174,7 +179,11 @@ namespace Volo.Abp.Caching
return value;
}
public virtual void Set(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null)
public virtual void Set(
string key,
TCacheItem value,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -182,7 +191,7 @@ namespace Volo.Abp.Caching
{
Cache.Set(
NormalizeKey(key),
ObjectSerializer.Serialize(value),
Serializer.Serialize(value),
options ?? DefaultCacheOptions
);
}
@ -198,7 +207,12 @@ namespace Volo.Abp.Caching
}
}
public virtual async Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default)
public virtual async Task SetAsync(
string key,
TCacheItem value,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -206,7 +220,7 @@ namespace Volo.Abp.Caching
{
await Cache.SetAsync(
NormalizeKey(key),
ObjectSerializer.Serialize(value),
Serializer.Serialize(value),
options ?? DefaultCacheOptions,
CancellationTokenProvider.FallbackToProvider(token)
);
@ -223,7 +237,9 @@ namespace Volo.Abp.Caching
}
}
public virtual void Refresh(string key, bool? hideErrors = null)
public virtual void Refresh(
string key,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -243,7 +259,10 @@ namespace Volo.Abp.Caching
}
}
public virtual async Task RefreshAsync(string key, bool? hideErrors = null, CancellationToken token = default)
public virtual async Task RefreshAsync(
string key,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -263,7 +282,9 @@ namespace Volo.Abp.Caching
}
}
public virtual void Remove(string key, bool? hideErrors = null)
public virtual void Remove(
string key,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -282,7 +303,10 @@ namespace Volo.Abp.Caching
}
}
public virtual async Task RemoveAsync(string key, bool? hideErrors = null, CancellationToken token = default)
public virtual async Task RemoveAsync(
string key,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

9
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCacheSerializer.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Caching
{
public interface IDistributedCacheSerializer
{
byte[] Serialize<T>(T obj);
T Deserialize<T>(byte[] bytes);
}
}

26
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/Utf8JsonDistributedCacheSerializer.cs

@ -0,0 +1,26 @@
using System.Text;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.Caching
{
public class Utf8JsonDistributedCacheSerializer : IDistributedCacheSerializer, ITransientDependency
{
protected IJsonSerializer JsonSerializer { get; }
public Utf8JsonDistributedCacheSerializer(IJsonSerializer jsonSerializer)
{
JsonSerializer = jsonSerializer;
}
public byte[] Serialize<T>(T obj)
{
return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(obj));
}
public T Deserialize<T>(byte[] bytes)
{
return (T)JsonSerializer.Deserialize(typeof(T), Encoding.UTF8.GetString(bytes));
}
}
}

2
framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj

@ -14,7 +14,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.3.1" />
<PackageReference Include="Castle.Core" Version="4.4.0" />
</ItemGroup>
<ItemGroup>

62
framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Reflection;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading;
@ -8,6 +9,20 @@ namespace Volo.Abp.Castle.DynamicProxy
public class CastleAbpInterceptorAdapter<TInterceptor> : IInterceptor
where TInterceptor : IAbpInterceptor
{
private static readonly MethodInfo MethodExecuteWithoutReturnValueAsync =
typeof(CastleAbpInterceptorAdapter<TInterceptor>)
.GetMethod(
nameof(ExecuteWithoutReturnValueAsync),
BindingFlags.NonPublic | BindingFlags.Instance
);
private static readonly MethodInfo MethodExecuteWithReturnValueAsync =
typeof(CastleAbpInterceptorAdapter<TInterceptor>)
.GetMethod(
nameof(ExecuteWithReturnValueAsync),
BindingFlags.NonPublic | BindingFlags.Instance
);
private readonly TInterceptor _abpInterceptor;
public CastleAbpInterceptorAdapter(TInterceptor abpInterceptor)
@ -17,39 +32,58 @@ namespace Volo.Abp.Castle.DynamicProxy
public void Intercept(IInvocation invocation)
{
var proceedInfo = invocation.CaptureProceedInfo();
var method = invocation.MethodInvocationTarget ?? invocation.Method;
if (method.IsAsync())
{
InterceptAsyncMethod(invocation);
InterceptAsyncMethod(invocation, proceedInfo);
}
else
{
InterceptSyncMethod(invocation);
InterceptSyncMethod(invocation, proceedInfo);
}
}
private void InterceptAsyncMethod(IInvocation invocation)
private void InterceptSyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
_abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation, proceedInfo));
}
private void InterceptAsyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
if (invocation.Method.ReturnType == typeof(Task))
{
invocation.ReturnValue = _abpInterceptor.InterceptAsync(new CastleAbpMethodInvocationAdapter(invocation));
invocation.ReturnValue = MethodExecuteWithoutReturnValueAsync
.Invoke(this, new object[] { invocation, proceedInfo });
}
else
{
var interceptResult = _abpInterceptor.InterceptAsync(new CastleAbpMethodInvocationAdapter(invocation));
var actualReturnValue = invocation.ReturnValue;
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
() => actualReturnValue,
() => interceptResult
);
invocation.ReturnValue = MethodExecuteWithReturnValueAsync
.MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0])
.Invoke(this, new object[] {invocation, proceedInfo});
}
}
private void InterceptSyncMethod(IInvocation invocation)
private async Task ExecuteWithoutReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
_abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation));
await Task.Yield();
await _abpInterceptor.InterceptAsync(
new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)
);
}
private async Task<T> ExecuteWithReturnValueAsync<T>(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
await Task.Yield();
await _abpInterceptor.InterceptAsync(
new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)
);
return await (Task<T>)invocation.ReturnValue;
}
}
}

10
framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs

@ -30,17 +30,19 @@ namespace Volo.Abp.Castle.DynamicProxy
private object _actualReturnValue;
protected IInvocation Invocation { get; }
protected IInvocationProceedInfo ProceedInfo { get; }
public CastleAbpMethodInvocationAdapter(IInvocation invocation)
public CastleAbpMethodInvocationAdapter(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
Invocation = invocation;
ProceedInfo = proceedInfo;
_lazyArgumentsDictionary = new Lazy<IReadOnlyDictionary<string, object>>(GetArgumentsDictionary);
}
public void Proceed()
{
Invocation.Proceed();
ProceedInfo.Invoke();
if (Invocation.Method.IsAsync())
{
@ -50,8 +52,10 @@ namespace Volo.Abp.Castle.DynamicProxy
public Task ProceedAsync()
{
Invocation.Proceed();
ProceedInfo.Invoke();
_actualReturnValue = Invocation.ReturnValue;
return Invocation.Method.IsAsync()
? (Task)_actualReturnValue
: Task.FromResult(_actualReturnValue);

4
framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj

@ -24,7 +24,7 @@
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageReference Include="JetBrains.Annotations" Version="2018.3.0" />
<PackageReference Include="Nito.AsyncEx.Coordination" Version="1.0.2" />
<PackageReference Include="Nito.AsyncEx.Context" Version="1.1.0" />
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.0.0" />
<PackageReference Include="Nito.AsyncEx.Context" Version="5.0.0" />
</ItemGroup>
</Project>

97
framework/src/Volo.Abp.Core/Volo/Abp/Check.cs

@ -1,7 +1,7 @@
using System;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using JetBrains.Annotations;
namespace Volo.Abp
{
@ -9,7 +9,9 @@ namespace Volo.Abp
public static class Check
{
[ContractAnnotation("value:null => halt")]
public static T NotNull<T>(T value, [InvokerParameterName] [NotNull] string parameterName)
public static T NotNull<T>(
T value,
[InvokerParameterName] [NotNull] string parameterName)
{
if (value == null)
{
@ -20,7 +22,10 @@ namespace Volo.Abp
}
[ContractAnnotation("value:null => halt")]
public static T NotNull<T>(T value, [InvokerParameterName] [NotNull] string parameterName, string message)
public static T NotNull<T>(
T value,
[InvokerParameterName] [NotNull] string parameterName,
string message)
{
if (value == null)
{
@ -31,24 +36,77 @@ namespace Volo.Abp
}
[ContractAnnotation("value:null => halt")]
public static string NotNullOrWhiteSpace(string value, [InvokerParameterName] [NotNull] string parameterName)
public static string NotNull(
string value,
[InvokerParameterName] [NotNull] string parameterName,
int maxLength = int.MaxValue,
int minLength = 0)
{
if (value == null)
{
throw new ArgumentException($"{parameterName} can not be null!", parameterName);
}
if (value.Length > maxLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName);
}
if (minLength > 0 && value.Length < minLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName);
}
return value;
}
[ContractAnnotation("value:null => halt")]
public static string NotNullOrWhiteSpace(
string value,
[InvokerParameterName] [NotNull] string parameterName,
int maxLength = int.MaxValue,
int minLength = 0)
{
if (value.IsNullOrWhiteSpace())
{
throw new ArgumentException($"{parameterName} can not be null, empty or white space!", parameterName);
}
if (value.Length > maxLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName);
}
if (minLength > 0 && value.Length < minLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName);
}
return value;
}
[ContractAnnotation("value:null => halt")]
public static string NotNullOrEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)
public static string NotNullOrEmpty(
string value,
[InvokerParameterName] [NotNull] string parameterName,
int maxLength = int.MaxValue,
int minLength = 0)
{
if (value.IsNullOrEmpty())
{
throw new ArgumentException($"{parameterName} can not be null or empty!", parameterName);
}
if (value.Length > maxLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName);
}
if (minLength > 0 && value.Length < minLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName);
}
return value;
}
@ -62,5 +120,32 @@ namespace Volo.Abp
return value;
}
public static string Length(
string value,
[InvokerParameterName] [NotNull] string parameterName,
int maxLength,
int minLength = 0)
{
if (minLength > 0)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException(parameterName + " can not be null or empty!", parameterName);
}
if (value.Length < minLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName);
}
}
if (value != null && value.Length > maxLength)
{
throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName);
}
return value;
}
}
}

12
framework/src/Volo.Abp.Core/Volo/Abp/RandomHelper.cs

@ -72,6 +72,18 @@ namespace Volo.Abp
return objs[GetRandom(0, objs.Length)];
}
/// <summary>
/// Gets random item from the given list.
/// </summary>
/// <typeparam name="T">Type of the objects</typeparam>
/// <param name="list">List of object to select a random one</param>
public static T GetRandomOfList<T>([NotNull] IList<T> list)
{
Check.NotNullOrEmpty(list, nameof(list));
return list[GetRandom(0, list.Count)];
}
/// <summary>
/// Generates a randomized list from given enumerable.
/// </summary>

2
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs

@ -34,10 +34,8 @@ namespace Volo.Abp.Application.Services
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TCreateInput>
where TGetAllInput : IPagedAndSortedResultRequest
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
where TCreateInput : IEntityDto<TKey>
{
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)

11
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs

@ -3,6 +3,7 @@ using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Threading;
namespace Volo.Abp.Emailing
{
@ -60,7 +61,7 @@ namespace Volo.Abp.Emailing
{
if (normalize)
{
NormalizeMail(mail);
await NormalizeMailAsync(mail);
}
await SendEmailAsync(mail);
@ -89,7 +90,7 @@ namespace Volo.Abp.Emailing
{
if (normalize)
{
NormalizeMail(mail);
AsyncHelper.RunSync(() => NormalizeMailAsync(mail));
}
SendEmail(mail);
@ -113,13 +114,13 @@ namespace Volo.Abp.Emailing
/// Sets encodings to UTF8 if they are not set before.
/// </summary>
/// <param name="mail">Mail to be normalized</param>
protected virtual void NormalizeMail(MailMessage mail)
protected virtual async Task NormalizeMailAsync(MailMessage mail)
{
if (mail.From == null || mail.From.Address.IsNullOrEmpty())
{
mail.From = new MailAddress(
Configuration.DefaultFromAddress,
Configuration.DefaultFromDisplayName,
await Configuration.GetDefaultFromAddressAsync(),
await Configuration.GetDefaultFromDisplayNameAsync(),
Encoding.UTF8
);
}

25
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs

@ -1,19 +1,16 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Settings;
namespace Volo.Abp.Emailing
{
/// <summary>
/// Implementation of <see cref="IEmailSenderConfiguration"/> that reads settings
/// from <see cref="ISettingManager"/>.
/// Base implementation of <see cref="IEmailSenderConfiguration"/> that reads settings
/// from <see cref="ISettingProvider"/>.
/// </summary>
public abstract class EmailSenderConfiguration : IEmailSenderConfiguration
{
public virtual string DefaultFromAddress => GetNotEmptySettingValue(EmailSettingNames.DefaultFromAddress);
public virtual string DefaultFromDisplayName => SettingProvider.GetOrNull(EmailSettingNames.DefaultFromDisplayName);
protected readonly ISettingProvider SettingProvider;
protected ISettingProvider SettingProvider { get; }
/// <summary>
/// Creates a new <see cref="EmailSenderConfiguration"/>.
@ -23,14 +20,24 @@ namespace Volo.Abp.Emailing
SettingProvider = settingProvider;
}
public Task<string> GetDefaultFromAddressAsync()
{
return GetNotEmptySettingValueAsync(EmailSettingNames.DefaultFromAddress);
}
public Task<string> GetDefaultFromDisplayNameAsync()
{
return GetNotEmptySettingValueAsync(EmailSettingNames.DefaultFromDisplayName);
}
/// <summary>
/// Gets a setting value by checking. Throws <see cref="AbpException"/> if it's null or empty.
/// </summary>
/// <param name="name">Name of the setting</param>
/// <returns>Value of the setting</returns>
protected string GetNotEmptySettingValue(string name)
protected async Task<string> GetNotEmptySettingValueAsync(string name)
{
var value = SettingProvider.GetOrNull(name);
var value = await SettingProvider.GetOrNullAsync(name);
if (value.IsNullOrEmpty())
{

4
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs

@ -18,8 +18,8 @@ namespace Volo.Abp.Emailing
new SettingDefinition(EmailSettingNames.Smtp.Domain),
new SettingDefinition(EmailSettingNames.Smtp.EnableSsl, "false"),
new SettingDefinition(EmailSettingNames.Smtp.UseDefaultCredentials, "true"),
new SettingDefinition(EmailSettingNames.DefaultFromAddress),
new SettingDefinition(EmailSettingNames.DefaultFromDisplayName)
new SettingDefinition(EmailSettingNames.DefaultFromAddress, "noreply@abp.io"),
new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, "ABP application")
);
}
}

16
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/IEmailSenderConfiguration.cs

@ -1,18 +1,14 @@
namespace Volo.Abp.Emailing
using System.Threading.Tasks;
namespace Volo.Abp.Emailing
{
/// <summary>
/// Defines configurations used while sending emails.
/// </summary>
public interface IEmailSenderConfiguration
{
/// <summary>
/// Default from address.
/// </summary>
string DefaultFromAddress { get; }
/// <summary>
/// Default display name.
/// </summary>
string DefaultFromDisplayName { get; }
Task<string> GetDefaultFromAddressAsync();
Task<string> GetDefaultFromDisplayNameAsync();
}
}

3
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/ISmtpEmailSender.cs

@ -1,4 +1,5 @@
using System.Net.Mail;
using System.Threading.Tasks;
namespace Volo.Abp.Emailing.Smtp
{
@ -13,6 +14,6 @@ namespace Volo.Abp.Emailing.Smtp
/// <returns>
/// An <see cref="SmtpClient"/> object that is ready to send emails.
/// </returns>
SmtpClient BuildClient();
Task<SmtpClient> BuildClientAsync();
}
}

18
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/ISmtpEmailSenderConfiguration.cs

@ -1,4 +1,6 @@
namespace Volo.Abp.Emailing.Smtp
using System.Threading.Tasks;
namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Defines configurations to used by SmtpClient object.
@ -8,36 +10,36 @@
/// <summary>
/// SMTP Host name/IP.
/// </summary>
string Host { get; }
Task<string> GetHostAsync();
/// <summary>
/// SMTP Port.
/// </summary>
int Port { get; }
Task<int> GetPortAsync();
/// <summary>
/// User name to login to SMTP server.
/// </summary>
string UserName { get; }
Task<string> GetUserNameAsync();
/// <summary>
/// Password to login to SMTP server.
/// </summary>
string Password { get; }
Task<string> GetPasswordAsync();
/// <summary>
/// Domain name to login to SMTP server.
/// </summary>
string Domain { get; }
Task<string> GetDomainAsync();
/// <summary>
/// Is SSL enabled?
/// </summary>
bool EnableSsl { get; }
Task<bool> GetEnableSslAsync();
/// <summary>
/// Use default credentials?
/// </summary>
bool UseDefaultCredentials { get; }
Task<bool> GetUseDefaultCredentialsAsync();
}
}

32
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs

@ -4,6 +4,7 @@ using System.Net.Mail;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Emailing.Smtp
{
@ -12,31 +13,34 @@ namespace Volo.Abp.Emailing.Smtp
/// </summary>
public class SmtpEmailSender : EmailSenderBase, ISmtpEmailSender, ITransientDependency
{
private readonly ISmtpEmailSenderConfiguration _configuration;
protected ISmtpEmailSenderConfiguration SmtpConfiguration { get; }
/// <summary>
/// Creates a new <see cref="SmtpEmailSender"/>.
/// </summary>
public SmtpEmailSender(ISmtpEmailSenderConfiguration configuration, IBackgroundJobManager backgroundJobManager)
: base(configuration, backgroundJobManager)
public SmtpEmailSender(
ISmtpEmailSenderConfiguration smtpConfiguration,
IBackgroundJobManager backgroundJobManager)
: base(smtpConfiguration, backgroundJobManager)
{
_configuration = configuration;
SmtpConfiguration = smtpConfiguration;
}
public SmtpClient BuildClient()
public async Task<SmtpClient> BuildClientAsync()
{
var host = _configuration.Host;
var port = _configuration.Port;
var host = await SmtpConfiguration.GetHostAsync();
var port = await SmtpConfiguration.GetPortAsync();
var smtpClient = new SmtpClient(host, port);
try
{
if (_configuration.EnableSsl)
if (await SmtpConfiguration.GetEnableSslAsync())
{
smtpClient.EnableSsl = true;
}
if (_configuration.UseDefaultCredentials)
if (await SmtpConfiguration.GetUseDefaultCredentialsAsync())
{
smtpClient.UseDefaultCredentials = true;
}
@ -44,11 +48,11 @@ namespace Volo.Abp.Emailing.Smtp
{
smtpClient.UseDefaultCredentials = false;
var userName = _configuration.UserName;
var userName = await SmtpConfiguration.GetUserNameAsync();
if (!userName.IsNullOrEmpty())
{
var password = _configuration.Password;
var domain = _configuration.Domain;
var password = await SmtpConfiguration.GetPasswordAsync();
var domain = await SmtpConfiguration.GetDomainAsync();
smtpClient.Credentials = !domain.IsNullOrEmpty()
? new NetworkCredential(userName, password, domain)
: new NetworkCredential(userName, password);
@ -66,7 +70,7 @@ namespace Volo.Abp.Emailing.Smtp
protected override async Task SendEmailAsync(MailMessage mail)
{
using (var smtpClient = BuildClient())
using (var smtpClient = await BuildClientAsync())
{
await smtpClient.SendMailAsync(mail);
}
@ -74,7 +78,7 @@ namespace Volo.Abp.Emailing.Smtp
protected override void SendEmail(MailMessage mail)
{
using (var smtpClient = BuildClient())
using (var smtpClient = AsyncHelper.RunSync(BuildClientAsync))
{
smtpClient.Send(mail);
}

42
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSenderConfiguration.cs

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
@ -6,28 +7,49 @@ namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Implementation of <see cref="ISmtpEmailSenderConfiguration"/> that reads settings
/// from <see cref="ISettingManager"/>.
/// from <see cref="ISettingProvider"/>.
/// </summary>
public class SmtpEmailSenderConfiguration : EmailSenderConfiguration, ISmtpEmailSenderConfiguration, ITransientDependency
{
public virtual string Host => GetNotEmptySettingValue(EmailSettingNames.Smtp.Host);
public SmtpEmailSenderConfiguration(ISettingProvider settingProvider)
: base(settingProvider)
{
public virtual int Port => GetNotEmptySettingValue(EmailSettingNames.Smtp.Port).To<int>();
}
public virtual string UserName => GetNotEmptySettingValue(EmailSettingNames.Smtp.UserName);
public Task<string> GetHostAsync()
{
return GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.Host);
}
public virtual string Password => GetNotEmptySettingValue(EmailSettingNames.Smtp.Password);
public async Task<int> GetPortAsync()
{
return (await GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.Port)).To<int>();
}
public virtual string Domain => SettingProvider.GetOrNull(EmailSettingNames.Smtp.Domain);
public Task<string> GetUserNameAsync()
{
return GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.UserName);
}
public virtual bool EnableSsl => SettingProvider.GetOrNull(EmailSettingNames.Smtp.EnableSsl).To<bool>();
public Task<string> GetPasswordAsync()
{
return GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.Password);
}
public virtual bool UseDefaultCredentials => SettingProvider.GetOrNull(EmailSettingNames.Smtp.UseDefaultCredentials).To<bool>();
public Task<string> GetDomainAsync()
{
return SettingProvider.GetOrNullAsync(EmailSettingNames.Smtp.Domain);
}
public SmtpEmailSenderConfiguration(ISettingProvider settingProvider)
: base(settingProvider)
public async Task<bool> GetEnableSslAsync()
{
return (await GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.EnableSsl)).To<bool>();
}
public async Task<bool> GetUseDefaultCredentialsAsync()
{
return (await GetNotEmptySettingValueAsync(EmailSettingNames.Smtp.UseDefaultCredentials)).To<bool>();
}
}
}

5
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -103,7 +103,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
EntityId = entityId,
EntityTypeFullName = entityType.FullName,
PropertyChanges = GetPropertyChanges(entityEntry),
TenantId = GetTenantId(entity)
EntityTenantId = GetTenantId(entity)
};
return entityChange;
@ -171,8 +171,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
NewValue = isDeleted ? null : JsonSerializer.Serialize(propertyEntry.CurrentValue).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
OriginalValue = isCreated ? null : JsonSerializer.Serialize(propertyEntry.OriginalValue).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
PropertyName = property.Name,
PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName,
TenantId = GetTenantId(entityEntry.Entity)
PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName
});
}
}

1
framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj

@ -20,6 +20,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Castle.Core\Volo.Abp.Castle.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.Http\Volo.Abp.Http.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup>

4
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Castle;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client
@ -8,7 +9,8 @@ namespace Volo.Abp.Http.Client
[DependsOn(
typeof(AbpHttpModule),
typeof(AbpCastleCoreModule),
typeof(AbpThreadingModule)
typeof(AbpThreadingModule),
typeof(AbpMultiTenancyModule)
)]
public class AbpHttpClientModule : AbpModule
{

13
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -16,6 +16,7 @@ using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;
@ -29,6 +30,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
protected CorrelationIdOptions CorrelationIdOptions { get; }
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; }
protected IApiDescriptionFinder ApiDescriptionFinder { get; }
@ -55,10 +57,12 @@ namespace Volo.Abp.Http.Client.DynamicProxying
IRemoteServiceHttpClientAuthenticator clientAuthenticator,
ICancellationTokenProvider cancellationTokenProvider,
ICorrelationIdProvider correlationIdProvider,
IOptions<CorrelationIdOptions> correlationIdOptions)
IOptions<CorrelationIdOptions> correlationIdOptions,
ICurrentTenant currentTenant)
{
CancellationTokenProvider = cancellationTokenProvider;
CorrelationIdProvider = correlationIdProvider;
CurrentTenant = currentTenant;
CorrelationIdOptions = correlationIdOptions.Value;
HttpClientFactory = httpClientFactory;
ApiDescriptionFinder = apiDescriptionFinder;
@ -213,6 +217,13 @@ namespace Volo.Abp.Http.Client.DynamicProxying
//CorrelationId
requestMessage.Headers.Add(CorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get());
//TenantId
if (CurrentTenant.Id.HasValue)
{
//TODO: Use AspNetCoreMultiTenancyOptions to get the key
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentUICulture.Name));
}

4
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/RemoteServiceConfiguration.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.Http.Client
public string BaseUrl
{
get => this.GetOrDefault(nameof(BaseUrl));
set => this[BaseUrl] = value;
set => this[nameof(BaseUrl)] = value;
}
/// <summary>
@ -19,7 +19,7 @@ namespace Volo.Abp.Http.Client
public string Version
{
get => this.GetOrDefault(nameof(Version));
set => this[Version] = value;
set => this[nameof(Version)] = value;
}
public RemoteServiceConfiguration()

14
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.IdentityModel
public string GrantType
{
get => this.GetOrDefault(nameof(GrantType));
set => this[GrantType] = value;
set => this[nameof(GrantType)] = value;
}
/// <summary>
@ -21,7 +21,7 @@ namespace Volo.Abp.IdentityModel
public string ClientId
{
get => this.GetOrDefault(nameof(ClientId));
set => this[ClientId] = value;
set => this[nameof(ClientId)] = value;
}
/// <summary>
@ -30,7 +30,7 @@ namespace Volo.Abp.IdentityModel
public string ClientSecret
{
get => this.GetOrDefault(nameof(ClientSecret));
set => this[ClientSecret] = value;
set => this[nameof(ClientSecret)] = value;
}
/// <summary>
@ -40,7 +40,7 @@ namespace Volo.Abp.IdentityModel
public string UserName
{
get => this.GetOrDefault(nameof(UserName));
set => this[UserName] = value;
set => this[nameof(UserName)] = value;
}
/// <summary>
@ -50,7 +50,7 @@ namespace Volo.Abp.IdentityModel
public string UserPassword
{
get => this.GetOrDefault(nameof(UserPassword));
set => this[UserPassword] = value;
set => this[nameof(UserPassword)] = value;
}
/// <summary>
@ -59,7 +59,7 @@ namespace Volo.Abp.IdentityModel
public string Authority
{
get => this.GetOrDefault(nameof(Authority));
set => this[Authority] = value;
set => this[nameof(Authority)] = value;
}
/// <summary>
@ -68,7 +68,7 @@ namespace Volo.Abp.IdentityModel
public string Scope
{
get => this.GetOrDefault(nameof(Scope));
set => this[Scope] = value;
set => this[nameof(Scope)] = value;
}
public IdentityClientConfiguration()

25
framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpClaimsIdentityExtensions.cs

@ -0,0 +1,25 @@
using System.Security.Claims;
using JetBrains.Annotations;
using Volo.Abp.MultiTenancy;
namespace System.Security.Principal
{
public static class AbpMultiTenancyClaimsIdentityExtensions
{
public static MultiTenancySides GetMultiTenancySide([NotNull] this IIdentity identity)
{
var tenantId = identity.FindTenantId();
return tenantId.HasValue
? MultiTenancySides.Tenant
: MultiTenancySides.Host;
}
public static MultiTenancySides GetMultiTenancySide([NotNull] this ClaimsPrincipal principal)
{
var tenantId = principal.FindTenantId();
return tenantId.HasValue
? MultiTenancySides.Tenant
: MultiTenancySides.Host;
}
}
}

28
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentClaimsPrincipalTenantResolveContributor.cs

@ -1,28 +0,0 @@
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.MultiTenancy
{
public class CurrentClaimsPrincipalTenantResolveContributor : TenantResolveContributorBase
{
public const string ContributorName = "CurrentClaims";
public override string Name => ContributorName;
public override void Resolve(ITenantResolveContext context)
{
var principal = context.ServiceProvider.GetRequiredService<ICurrentPrincipalAccessor>().Principal;
if (principal?.Identity?.IsAuthenticated != true)
{
return;
}
context.Handled = true;
context.TenantIdOrName = principal
.Claims
.FirstOrDefault(c => c.Type == AbpClaimTypes.TenantId)
?.Value;
}
}
}

7
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentTenantExtensions.cs

@ -16,5 +16,12 @@ namespace Volo.Abp.MultiTenancy
return currentTenant.Id.Value;
}
public static MultiTenancySides GetMultiTenancySide(this ICurrentTenant currentTenant)
{
return currentTenant.Id.HasValue
? MultiTenancySides.Tenant
: MultiTenancySides.Host;
}
}
}

24
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/CurrentUserTenantResolveContributor.cs

@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Users;
namespace Volo.Abp.MultiTenancy
{
public class CurrentUserTenantResolveContributor : TenantResolveContributorBase
{
public const string ContributorName = "CurrentUser";
public override string Name => ContributorName;
public override void Resolve(ITenantResolveContext context)
{
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>();
if (currentUser.IsAuthenticated != true)
{
return;
}
context.Handled = true;
context.TenantIdOrName = currentUser.TenantId?.ToString();
}
}
}

5
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/ITenantResolveResultAccessor.cs → framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantResolveResultAccessor.cs

@ -1,9 +1,10 @@
using Volo.Abp.MultiTenancy;
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.MultiTenancy
namespace Volo.Abp.MultiTenancy
{
public interface ITenantResolveResultAccessor
{
[CanBeNull]
TenantResolveResult Result { get; set; }
}
}

13
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/NullTenantResolveResultAccessor.cs

@ -0,0 +1,13 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.MultiTenancy
{
public class NullTenantResolveResultAccessor : ITenantResolveResultAccessor, ISingletonDependency
{
public TenantResolveResult Result
{
get => null;
set { }
}
}
}

2
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantResolveOptions.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.MultiTenancy
{
TenantResolvers = new List<ITenantResolveContributor>
{
new CurrentClaimsPrincipalTenantResolveContributor()
new CurrentUserTenantResolveContributor()
};
}
}

9
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs

@ -39,6 +39,15 @@ namespace Volo.Abp.UI.Navigation
return menuWithItems.Items.FirstOrDefault(mi => mi.Name == menuItemName);
}
public static bool TryRemoveMenuItem(
[NotNull] this IHasMenuItems menuWithItems,
string menuItemName)
{
Check.NotNull(menuWithItems, nameof(menuWithItems));
return menuWithItems.Items.RemoveAll(item => item.Name == menuItemName) > 0;
}
[NotNull]
public static IHasMenuItems SetSubItemOrder(
[NotNull] this IHasMenuItems menuWithItems,

4
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlOptions.cs

@ -1,6 +1,4 @@
using Volo.Abp.Ui.Navigation.Urls;
namespace Volo.Abp.Ui.Navigation.Urls
namespace Volo.Abp.Ui.Navigation.Urls
{
public class AppUrlOptions
{

80
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs

@ -1,20 +1,42 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Ui.Navigation.Urls
{
public class AppUrlProvider : IAppUrlProvider, ITransientDependency
{
public const string TenantIdPlaceHolder = "{{tenantId}}";
public const string TenantNamePlaceHolder = "{{tenantName}}";
protected AppUrlOptions Options { get; }
protected ICurrentTenant CurrentTenant { get; }
protected ITenantStore TenantStore { get; }
public AppUrlProvider(IOptions<AppUrlOptions> options)
public AppUrlProvider(
IOptions<AppUrlOptions> options,
ICurrentTenant currentTenant,
ITenantStore tenantStore)
{
CurrentTenant = currentTenant;
TenantStore = tenantStore;
Options = options.Value;
}
public virtual string GetUrl(string appName, string urlName = null)
public virtual async Task<string> GetUrlAsync(string appName, string urlName = null)
{
return await ReplacePlaceHoldersAsync(
await GetConfiguredUrl(
appName,
urlName
)
);
}
protected virtual Task<string> GetConfiguredUrl(string appName, string urlName)
{
var app = Options.Applications[appName];
@ -22,24 +44,70 @@ namespace Volo.Abp.Ui.Navigation.Urls
{
if (app.RootUrl.IsNullOrEmpty())
{
throw new AbpException($"RootUrl for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!");
throw new AbpException(
$"RootUrl for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!"
);
}
return app.RootUrl;
return Task.FromResult(app.RootUrl);
}
var url = app.Urls.GetOrDefault(urlName);
if (url.IsNullOrEmpty())
{
throw new AbpException($"Url, named '{urlName}', for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!");
throw new AbpException(
$"Url, named '{urlName}', for the application '{appName}' was not configured. Use {nameof(AppUrlOptions)} to configure it!"
);
}
if (app.RootUrl == null)
{
return Task.FromResult(url);
}
return Task.FromResult(app.RootUrl.EnsureEndsWith('/') + url);
}
protected virtual async Task<string> ReplacePlaceHoldersAsync(string url)
{
url = url.Replace(
TenantIdPlaceHolder,
CurrentTenant.Id.HasValue ? CurrentTenant.Id.Value.ToString() : ""
);
if (!url.Contains(TenantNamePlaceHolder))
{
return url;
}
return app.RootUrl.EnsureEndsWith('/') + url;
var tenantNamePlaceHolder = TenantNamePlaceHolder;
if (url.Contains(TenantNamePlaceHolder + '.'))
{
tenantNamePlaceHolder = TenantNamePlaceHolder + '.';
}
if (CurrentTenant.Id.HasValue)
{
url = url.Replace(tenantNamePlaceHolder, await GetCurrentTenantNameAsync());
}
else
{
url = url.Replace(tenantNamePlaceHolder, "");
}
return url;
}
private async Task<string> GetCurrentTenantNameAsync()
{
if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty())
{
var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value);
return tenantConfiguration.Name;
}
return CurrentTenant.Name;
}
}
}

5
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/IAppUrlProvider.cs

@ -1,9 +1,10 @@
using JetBrains.Annotations;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Ui.Navigation.Urls
{
public interface IAppUrlProvider
{
string GetUrl([NotNull] string appName, [CanBeNull] string urlName = null);
Task<string> GetUrlAsync([NotNull] string appName, [CanBeNull] string urlName = null);
}
}

4
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json

@ -24,6 +24,7 @@
"Actions": "Actions",
"Delete": "Delete",
"Edit": "Edit",
"Refresh": "Refresh",
"ProcessingWithThreeDot": "Processing...",
"LoadingWithThreeDot": "Loading...",
"Welcome": "Welcome",
@ -44,6 +45,7 @@
"PagerShowMenuEntries": "Show _MENU_ entries",
"DatatableActionDropdownDefaultText": "Actions",
"ChangePassword": "Change password",
"PersonalInfo": "My profile"
"PersonalInfo": "My profile",
"AreYouSureYouWantToCancelEditingWarningMessage": "You have unsaved changes."
}
}

18
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json

@ -24,17 +24,27 @@
"Actions": "Ações",
"Delete": "Excluir",
"Edit": "Editar",
"Refresh": "Refrescar",
"ProcessingWithThreeDot": "Processando...",
"LoadingWithThreeDot": "Carregando...",
"Welcome": "Bem Vindo",
"Login": "Entrar",
"Register": "cadastrar",
"Register": "Registrar-se",
"Logout": "Sair",
"Submit": "Enviar",
"Back": "Voltar",
"PagerSearch": "Pesquisar",
"PagerNext": "Próximo",
"PagerPrevious": "Anterior",
"PagerInfo": "Mostrando _START_ até _END_ de _TOTAL_ registros.",
"PagerFirst": "Primeira",
"PagerLast": "Última",
"PagerInfo": "Mostrando _START_ até _END_ de _TOTAL_ registros",
"PagerInfoEmpty": "Mostrando 0 até 0 de 0 registros",
"PagerInfoFiltered": "(filtrado de um total de _MAX_ registros)",
"NoDataAvailableInDatatable": "Nenhum dado disponível",
"PagerShowMenuEntries": "Mostrando _MENU_ registros",
"DatatableActionDropdownDefaultText": "Ações",
"ChangePassword": "Alterar senha",
"ChangePassword": "Alterar Senha",
"PersonalInfo": "Perfil"
}
}
}

6
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json

@ -24,6 +24,7 @@
"Actions": "İşlemler",
"Delete": "Sil",
"Edit": "Düzenle",
"Refresh": "Yenile",
"ProcessingWithThreeDot": "İşleniyor...",
"LoadingWithThreeDot": "Yükleniyor...",
"Welcome": "Hoşgeldiniz",
@ -40,10 +41,11 @@
"PagerInfo": "_TOTAL_ kayıttan _START_ ile _END_ arası gösteriliyor.",
"PagerInfoEmpty": "0 kayıttan 0 ile 0 arası gösteriliyor.",
"PagerInfoFiltered": "(_MAX_ kayıt arasından filtrelendi)",
"NoDataAvailableInDatatable": "Tabloda kayır mevcut değil.",
"NoDataAvailableInDatatable": "Tabloda kayıt mevcut değil.",
"PagerShowMenuEntries": "Sayfada _MENU_ kayıt göster.",
"DatatableActionDropdownDefaultText": "İşlemler",
"ChangePassword": "Şifre değiştir",
"PersonalInfo": "Profilim"
"PersonalInfo": "Profilim",
"AreYouSureYouWantToCancelEditingWarningMessage": "Kaydedilmemiş değişiklikler var."
}
}

1
framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json

@ -24,6 +24,7 @@
"Actions": "操作",
"Delete": "删除",
"Edit": "修改",
"Refresh": "刷新",
"ProcessingWithThreeDot": "处理中...",
"LoadingWithThreeDot": "加载中...",
"Welcome": "欢迎",

16
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs

@ -1,4 +1,5 @@
using Volo.Abp.Aspects;
using System.Threading.Tasks;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
@ -26,6 +27,19 @@ namespace Volo.Abp.Validation
invocation.Proceed();
}
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Validation))
{
await invocation.ProceedAsync();
return;
}
Validate(invocation);
await invocation.ProceedAsync();
}
protected virtual void Validate(IAbpMethodInvocation invocation)
{
_validator.Validate(

3
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/pt-BR.json

@ -1,6 +1,7 @@
{
"culture": "pt-BR",
"texts": {
"BirthDate": "Aniversário"
"BirthDate": "Aniversário",
"Value1": "Valor Um"
}
}

4
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/_Layout.cshtml

@ -20,7 +20,7 @@
<abp-style-bundle name="@StandardBundles.Styles.Global" />
<link href="~/css/demo.min.css" rel="stylesheet" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body>
@ -30,7 +30,7 @@
<abp-script-bundle name="@StandardBundles.Scripts.Global" />
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

2
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs

@ -1,3 +1,4 @@
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.DynamicProxy
@ -6,6 +7,7 @@ namespace Volo.Abp.DynamicProxy
{
public virtual int GetValue(int v)
{
Thread.Sleep(5);
return v;
}

2
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs

@ -14,7 +14,7 @@ namespace Volo.Abp.DynamicProxy
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
//await Task.Delay(5); CAN NOT USE await before method execution! This is a restriction of Castle DynamicProxy
await Task.Delay(5);
(invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_BeforeInvocation");
await invocation.ProceedAsync();
(invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_AfterInvocation");

3
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/en.json

@ -1,6 +1,7 @@
{
"culture": "en",
"texts": {
"USA": "United States of America"
"USA": "United States of America",
"Brazil": "Brasil"
}
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/pt-BR.json

@ -4,4 +4,4 @@
"USA": "Estados Unidos da América",
"Brazil": "Brasil"
}
}
}

2
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/pt-BR.json

@ -4,4 +4,4 @@
"ThisFieldIsRequired": "Este campo é obrigatório",
"MaxLenghtErrorMessage": "Este campo pode ser no máximo de '{0}' caracteres"
}
}
}

5
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/pt-BR.json

@ -5,6 +5,7 @@
"Car": "Carro",
"CarPlural": "Carros",
"MaxLenghtErrorMessage": "O comprimento deste campo pode ser no máximo de '{0}' caracteres",
"Universe": "Universo"
"Universe": "Universo",
"FortyTwo": "Quarenta e Dois"
}
}
}

22
modules/account/src/Volo.Abp.Account.Web.IdentityServer/AbpAccountWebIdentityServerModule.cs

@ -1,4 +1,7 @@
using Volo.Abp.IdentityServer;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.IdentityServer;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -10,12 +13,29 @@ namespace Volo.Abp.Account.Web
)]
public class AbpAccountWebIdentityServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpIdentityAspNetCoreOptions>(options =>
{
options.ConfigureAuthentication = false;
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpAccountWebIdentityServerModule>("Volo.Abp.Account.Web");
});
//TODO: Try to reuse from AbpIdentityAspNetCoreModule
context.Services
.AddAuthentication(o =>
{
o.DefaultScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();
}
}
}

2
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs

@ -35,11 +35,9 @@ namespace Volo.Abp.Account.Web.Pages.Account
schemeProvider,
accountOptions)
{
_schemeProvider = schemeProvider;
Interaction = interaction;
ClientStore = clientStore;
IdentityServerEvents = identityServerEvents;
_accountOptions = accountOptions.Value;
}
public override async Task OnGetAsync()

2
modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs

@ -1,7 +1,6 @@
using Localization.Resources.AbpUi;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Account.Web.Localization;
using Volo.Abp.Account.Web.Settings;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars;
@ -9,7 +8,6 @@ using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Localization;
using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;

14
modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/tr.json

@ -11,12 +11,12 @@
"InvalidUserNameOrPassword": "Kullanıcı adı ya da şifre geçersiz!",
"LoginIsNotAllowed": "Giriş yapamazsınız! E-posta adresinizi ya da telefon numaranızı doğrulamanız gerekiyor.",
"SelfRegistrationDisabledMessage": "Bu uygulama için kullanıcıların kendi kendilerine kaydolmaları engellenmiştir. Yeni bir kullanıcı kaydetmek için lütfen uygulama yöneticisi ile iletişime geçin.",
"Login": "Login",
"Cancel": "Cancel",
"Register": "Register",
"UseAnotherServiceToLogIn.": "Use another service to log in.",
"InvalidLoginRequest": "Invalid login request",
"ThereAreNoLoginSchemesConfiguredForThisClient": "There are no login schemes configured for this client.",
"LogInUsingYourProviderAccount": "Log in using your {0} account"
"Login": "Giriş yap",
"Cancel": "İptal",
"Register": "Kayıt ol",
"UseAnotherServiceToLogIn.": "Başka bir servisle giriş yap.",
"InvalidLoginRequest": "Başarısız giriş isteği",
"ThereAreNoLoginSchemesConfiguredForThisClient": "Bu client için konfigüre edilmiş giriş şeması bulunamadı.",
"LogInUsingYourProviderAccount": "{0} hesabınızla giriş yapın."
}
}

2
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AuditLogConsts.cs

@ -23,5 +23,7 @@
public const int MaxHttpMethodLength = 16;
public const int MaxUserNameLength = 256;
public const int MaxTenantNameLength = 64;
}
}

41
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLog.cs

@ -19,6 +19,8 @@ namespace Volo.Abp.AuditLogging
public virtual Guid? TenantId { get; protected set; }
public virtual string TenantName { get; protected set; }
public virtual Guid? ImpersonatorUserId { get; protected set; }
public virtual Guid? ImpersonatorTenantId { get; protected set; }
@ -31,9 +33,9 @@ namespace Volo.Abp.AuditLogging
public virtual string ClientName { get; protected set; }
public string ClientId { get; set; }
public virtual string ClientId { get; set; }
public string CorrelationId { get; set; }
public virtual string CorrelationId { get; set; }
public virtual string BrowserInfo { get; protected set; }
@ -59,8 +61,9 @@ namespace Volo.Abp.AuditLogging
public AuditLog(IGuidGenerator guidGenerator, AuditLogInfo auditInfo)
{
Id = guidGenerator.Create();
ApplicationName = auditInfo.ApplicationName;
ApplicationName = auditInfo.ApplicationName.Truncate(AuditLogConsts.MaxApplicationNameLength);
TenantId = auditInfo.TenantId;
TenantName = auditInfo.TenantName.Truncate(AuditLogConsts.MaxTenantNameLength);
UserId = auditInfo.UserId;
UserName = auditInfo.UserName.Truncate(AuditLogConsts.MaxUserNameLength);
ExecutionTime = auditInfo.ExecutionTime;
@ -75,11 +78,33 @@ namespace Volo.Abp.AuditLogging
HttpStatusCode = auditInfo.HttpStatusCode;
ImpersonatorUserId = auditInfo.ImpersonatorUserId;
ImpersonatorTenantId = auditInfo.ImpersonatorTenantId;
ExtraProperties = auditInfo.ExtraProperties.ToDictionary(pair => pair.Key, pair => pair.Value);
EntityChanges = auditInfo.EntityChanges.Select(e => new EntityChange(guidGenerator, Id, e)).ToList();
Actions = auditInfo.Actions.Select(e => new AuditLogAction(guidGenerator.Create(), Id, e)).ToList();
Exceptions = auditInfo.Exceptions.JoinAsString(Environment.NewLine).Truncate(AuditLogConsts.MaxExceptionsLength);
Comments = auditInfo.Comments.JoinAsString(Environment.NewLine).Truncate(AuditLogConsts.MaxCommentsLength);
ExtraProperties = auditInfo
.ExtraProperties?
.ToDictionary(pair => pair.Key, pair => pair.Value)
?? new Dictionary<string, object>();
EntityChanges = auditInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(guidGenerator, Id, entityChangeInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<EntityChange>();
Actions = auditInfo
.Actions?
.Select(auditLogActionInfo => new AuditLogAction(guidGenerator.Create(), Id, auditLogActionInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<AuditLogAction>();
Exceptions = auditInfo
.Exceptions?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxExceptionsLength);
Comments = auditInfo
.Comments?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxCommentsLength);
}
}
}

4
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogAction.cs

@ -32,11 +32,11 @@ namespace Volo.Abp.AuditLogging
ExtraProperties = new Dictionary<string, object>();
}
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo)
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null)
{
Id = id;
TenantId = actionInfo.TenantId;
TenantId = tenantId;
AuditLogId = auditLogId;
ExecutionTime = actionInfo.ExecutionTime;
ExecutionDuration = actionInfo.ExecutionDuration;

23
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs

@ -20,6 +20,8 @@ namespace Volo.Abp.AuditLogging
public virtual EntityChangeType ChangeType { get; protected set; }
public virtual Guid? EntityTenantId { get; protected set; }
public virtual string EntityId { get; protected set; }
public virtual string EntityTypeFullName { get; protected set; }
@ -33,17 +35,30 @@ namespace Volo.Abp.AuditLogging
ExtraProperties = new Dictionary<string, object>();
}
public EntityChange(IGuidGenerator guidGenerator, Guid auditLogId, EntityChangeInfo entityChangeInfo)
public EntityChange(
IGuidGenerator guidGenerator,
Guid auditLogId,
EntityChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
AuditLogId = auditLogId;
TenantId = entityChangeInfo.TenantId;
TenantId = tenantId;
ChangeTime = entityChangeInfo.ChangeTime;
ChangeType = entityChangeInfo.ChangeType;
EntityId = entityChangeInfo.EntityId.Truncate(EntityChangeConsts.MaxEntityTypeFullNameLength);
EntityTypeFullName = entityChangeInfo.EntityTypeFullName.TruncateFromBeginning(EntityChangeConsts.MaxEntityTypeFullNameLength);
PropertyChanges = entityChangeInfo.PropertyChanges.Select(p => new EntityPropertyChange(guidGenerator, Id, p)).ToList();
ExtraProperties = entityChangeInfo.ExtraProperties.ToDictionary(pair => pair.Key, pair => pair.Value);
PropertyChanges = entityChangeInfo
.PropertyChanges?
.Select(p => new EntityPropertyChange(guidGenerator, Id, p, tenantId))
.ToList()
?? new List<EntityPropertyChange>();
ExtraProperties = entityChangeInfo
.ExtraProperties?
.ToDictionary(pair => pair.Key, pair => pair.Value)
?? new Dictionary<string, object>();
}
}
}

8
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityPropertyChange.cs

@ -26,10 +26,14 @@ namespace Volo.Abp.AuditLogging
}
public EntityPropertyChange(IGuidGenerator guidGenerator, Guid entityChangeId, EntityPropertyChangeInfo entityChangeInfo)
public EntityPropertyChange(
IGuidGenerator guidGenerator,
Guid entityChangeId,
EntityPropertyChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
TenantId = entityChangeInfo.TenantId;
TenantId = tenantId;
EntityChangeId = entityChangeId;
NewValue = entityChangeInfo.NewValue.Truncate(EntityPropertyChangeConsts.MaxNewValueLength);
OriginalValue = entityChangeInfo.OriginalValue.Truncate(EntityPropertyChangeConsts.MaxOriginalValueLength);

11
modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.AuditLogging.EntityFrameworkCore
{
public class AuditLogRepository_Tests : AuditLogRepository_Tests<AbpAuditLoggingEntityFrameworkCoreTestModule>
{
}
}

11
modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogRepository_Tests.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.AuditLogging.MongoDB
{
public class AuditLogRepository_Tests : AuditLogRepository_Tests<AbpAuditLoggingMongoDbTestModule>
{
}
}

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

Loading…
Cancel
Save