Browse Source

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

pull/4522/head
Akın Sabri Çam 6 years ago
parent
commit
50be19f321
  1. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json
  2. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/tr.json
  3. 2
      docs/en/Unit-Of-Work.md
  4. 14
      framework/Volo.Abp.sln
  5. 27
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json
  6. 27
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Properties/launchSettings.json
  7. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Properties/launchSettings.json
  8. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs
  9. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Properties/launchSettings.json
  10. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Properties/launchSettings.json
  11. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Properties/launchSettings.json
  12. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Properties/launchSettings.json
  13. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Uppy/UppyScriptContributor.cs
  14. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Uppy/UppyStyleContributor.cs
  15. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Properties/launchSettings.json
  16. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj
  17. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj
  18. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Properties/launchSettings.json
  19. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj
  20. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Properties/launchSettings.json
  21. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Properties/launchSettings.json
  22. 27
      framework/src/Volo.Abp.AspNetCore.Mvc/Properties/launchSettings.json
  23. 5
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  24. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs
  25. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs
  26. 29
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DataAnnotations/AbpValidationAttributeAdapterProvider.cs
  27. 54
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DataAnnotations/DynamicStringLengthAttributeAdapter.cs
  28. 27
      framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json
  29. 27
      framework/src/Volo.Abp.AspNetCore.SignalR/Properties/launchSettings.json
  30. 27
      framework/src/Volo.Abp.AspNetCore.TestBase/Properties/launchSettings.json
  31. 27
      framework/src/Volo.Abp.AspNetCore/Properties/launchSettings.json
  32. 1
      framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobContainerConfigurationExtensions.cs
  33. 52
      framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobNamingNormalizer.cs
  34. 9
      framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobContainerConfigurationExtensions.cs
  35. 41
      framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobNamingNormalizer.cs
  36. 62
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs
  37. 10
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerConfiguration.cs
  38. 24
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactory.cs
  39. 9
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/IBlobNamingNormalizer.cs
  40. 3
      framework/src/Volo.Abp.Caching.StackExchangeRedis/FodyWeavers.xml
  41. 30
      framework/src/Volo.Abp.Caching.StackExchangeRedis/FodyWeavers.xsd
  42. 25
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo.Abp.Caching.StackExchangeRedis.csproj
  43. 30
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisModule.cs
  44. 294
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs
  45. 47
      framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisExtensions.cs
  46. 393
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  47. 30
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/ICacheSupportsMultipleItems.cs
  48. 63
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs
  49. 12
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs
  50. 47
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs
  51. 6
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AngularEnvironmentFilePortChangeForSeparatedIdentityServersStep.cs
  52. 45
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
  53. 7
      framework/src/Volo.Abp.Cli/Properties/launchSettings.json
  54. 9
      framework/src/Volo.Abp.Core/System/Runtime/IOSPlatformProvider.cs
  55. 23
      framework/src/Volo.Abp.Core/System/Runtime/OSPlatformProvider.cs
  56. 2
      framework/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs
  57. 5
      framework/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs
  58. 58
      framework/src/Volo.Abp.Core/Volo/Abp/Validation/DynamicStringLengthAttribute.cs
  59. 61
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  60. 27
      framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Properties/launchSettings.json
  61. 27
      framework/src/Volo.Abp.Http.Client.IdentityModel/Properties/launchSettings.json
  62. 27
      framework/src/Volo.Abp.Http.Client/Properties/launchSettings.json
  63. 18
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs
  64. 49
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  65. 79
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs
  66. 11
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
  67. 24
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController.cs
  68. 16
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs
  69. 26
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithAuditedAndHasCustomAuditingProperties.cs
  70. 21
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppFullAuditedEntityWithAudited.cs
  71. 4
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs
  72. 59
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs
  73. 57
      framework/test/Volo.Abp.BlobStoring.Azure.Tests/Volo/Abp/BlobStoring/Azure/DefaultAzureBlobNamingNormalizerProvider_Tests.cs
  74. 62
      framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/DefaultFileSystemBlobNamingNormalizerProvider_Tests.cs
  75. 17
      framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo.Abp.Caching.StackExchangeRedis.Tests.csproj
  76. 12
      framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisTestBase.cs
  77. 15
      framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisTestModule.cs
  78. 22
      framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache_Tests.cs
  79. 31
      framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs
  80. 5
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json
  81. 7
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json
  82. 7
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/RegisterDto.cs
  83. 21
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs
  84. 27
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json
  85. 2
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj
  86. 31
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.cshtml
  87. 30
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.cshtml.cs
  88. 5
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.css
  89. 5
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.js
  90. 4
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
  91. 18
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs
  92. 7
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs
  93. 27
      modules/account/src/Volo.Abp.Account.Web/Properties/launchSettings.json
  94. 2
      modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj
  95. 27
      modules/blogging/src/Volo.Blogging.Admin.Web/Properties/launchSettings.json
  96. 1
      modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.csproj
  97. 27
      modules/blogging/src/Volo.Blogging.Web/Properties/launchSettings.json
  98. 2
      modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj
  99. 27
      modules/client-simulation/src/Volo.ClientSimulation.Web/Properties/launchSettings.json
  100. 2
      modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj

3
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json

@ -8,6 +8,7 @@
"FrameworkDocumentation": "Framework documentation",
"OfficialBlog": "Official blog",
"CommercialHomePage": "Commercial home page",
"CommercialSupportWebSite": "Commercial support web site"
"CommercialSupportWebSite": "Commercial support web site",
"CommunityWebSite": "ABP community web site"
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/tr.json

@ -8,6 +8,7 @@
"FrameworkDocumentation": "Framework Dokümantasyon",
"OfficialBlog": "Resmi blog",
"CommercialHomePage": "Kurumsal ana sayfa",
"CommercialSupportWebSite": "Kurumsal destek web sitesi"
"CommercialSupportWebSite": "Kurumsal destek web sitesi",
"CommunityWebSite": "ABP topluluk web sitesi"
}
}

2
docs/en/Unit-Of-Work.md

@ -325,7 +325,7 @@ public async Task<int> CreateAsync(string name)
If your intent is just to save the changes after creating/updating/deleting an entity, it is suggested to use the `autoSave` option instead of manually using the `CurrentUnitOfWork.SaveChangesAsync()`.
> **Note-1**: All changes are automatically saved when a unit of work ends without any error. So, don't call `SaveChangesAsync()` unless you really need it.
> **Note-1**: All changes are automatically saved when a unit of work ends without any error. So, don't call `SaveChangesAsync()` and don't set `autoSave` to `true` unless you really need it.
>
> **Note-2**: If you use `Guid` as the primary key, you never need to save changes on insert to just get the generated id, because `Guid` keys are set in the application and are immediately available once you create a new entity.

14
framework/Volo.Abp.sln

@ -307,6 +307,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Azure.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EntityFrameworkCore.Oracle", "src\Volo.Abp.EntityFrameworkCore.Oracle\Volo.Abp.EntityFrameworkCore.Oracle.csproj", "{1738845A-5348-4EB8-B736-CD1D22A808B4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching.StackExchangeRedis", "src\Volo.Abp.Caching.StackExchangeRedis\Volo.Abp.Caching.StackExchangeRedis.csproj", "{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching.StackExchangeRedis.Tests", "test\Volo.Abp.Caching.StackExchangeRedis.Tests\Volo.Abp.Caching.StackExchangeRedis.Tests.csproj", "{60D0E384-965E-4F81-9D71-B28F419254FC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -913,6 +917,14 @@ Global
{1738845A-5348-4EB8-B736-CD1D22A808B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1738845A-5348-4EB8-B736-CD1D22A808B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1738845A-5348-4EB8-B736-CD1D22A808B4}.Release|Any CPU.Build.0 = Release|Any CPU
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}.Release|Any CPU.Build.0 = Release|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1068,6 +1080,8 @@ Global
{C44242F7-D55D-4867-AAF4-A786E404312E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{A80E9A0B-8932-4B5D-83FB-6751708FD484} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{1738845A-5348-4EB8-B736-CD1D22A808B4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{60D0E384-965E-4F81-9D71-B28F419254FC} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

27
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53450/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Authentication.OAuth": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53451/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53760/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.MultiTenancy": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53763/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52302/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.Client": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:52303/"
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentUserDto.cs

@ -14,5 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
public string UserName { get; set; }
public string Email { get; set; }
public string[] Roles { get; set; }
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:61183/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Bootstrap": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53762/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Bundling": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53765/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56918/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.TenantSwitch": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:56919/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53766/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Packages": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53768/"
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Uppy/UppyScriptContributor.cs

@ -0,0 +1,13 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy
{
public class UppyScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/uppy/uppy.min.js");
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Uppy/UppyStyleContributor.cs

@ -0,0 +1,13 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy
{
public class UppyStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/uppy/uppy.min.css");
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50398/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:50399/"
}
}
}

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

@ -22,8 +22,6 @@
<ItemGroup>
<Content Remove="wwwroot\**\*.*" />
<Content Remove="Properties\launchSettings.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
<ItemGroup>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj

@ -18,8 +18,6 @@
<ItemGroup>
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
<ItemGroup>

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:51544/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:51545/"
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj

@ -23,9 +23,7 @@
<ItemGroup>
<Content Remove="wwwroot\**\*.*" />
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
<None Include="compilerconfig.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
<ItemGroup>

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53761/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI.Widgets": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53764/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55913/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc.UI": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Mvc/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53767/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Mvc": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53769/"
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -16,6 +16,7 @@ using System.Net;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
@ -25,6 +26,7 @@ using Microsoft.Extensions.Localization;
using Volo.Abp.ApiVersioning;
using Volo.Abp.AspNetCore.Mvc.ApiExploring;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Json;
using Volo.Abp.AspNetCore.Mvc.Localization;
@ -164,6 +166,9 @@ namespace Volo.Abp.AspNetCore.Mvc
partManager.FeatureProviders.Add(new AbpConventionalControllerFeatureProvider(application));
partManager.ApplicationParts.AddIfNotContains(typeof(AbpAspNetCoreMvcModule).Assembly);
context.Services.Replace(ServiceDescriptor.Singleton<IValidationAttributeAdapterProvider, AbpValidationAttributeAdapterProvider>());
context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(context.Services);

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs

@ -5,7 +5,6 @@ using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Features;
using Volo.Abp.AspNetCore.Mvc.ModelBinding;
using Volo.Abp.AspNetCore.Mvc.ModelBinding.Metadata;
using Volo.Abp.AspNetCore.Mvc.Response;
using Volo.Abp.AspNetCore.Mvc.Uow;
using Volo.Abp.AspNetCore.Mvc.Validation;

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs

@ -117,7 +117,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
Id = _currentUser.Id,
TenantId = _currentUser.TenantId,
UserName = _currentUser.UserName,
Email = _currentUser.Email
Email = _currentUser.Email,
Roles = _currentUser.Roles
};
}

29
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DataAnnotations/AbpValidationAttributeAdapterProvider.cs

@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.Extensions.Localization;
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.DataAnnotations
{
public class AbpValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
private readonly ValidationAttributeAdapterProvider _defaultAdapter;
public AbpValidationAttributeAdapterProvider(ValidationAttributeAdapterProvider defaultAdapter)
{
_defaultAdapter = defaultAdapter;
}
public virtual IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
{
var type = attribute.GetType();
if (type == typeof(DynamicStringLengthAttribute))
{
return new DynamicStringLengthAttributeAdapter((DynamicStringLengthAttribute) attribute, stringLocalizer);
}
return _defaultAdapter.GetAttributeAdapter(attribute, stringLocalizer);
}
}
}

54
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DataAnnotations/DynamicStringLengthAttributeAdapter.cs

@ -0,0 +1,54 @@
using System;
using System.Globalization;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Localization;
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.DataAnnotations
{
public class DynamicStringLengthAttributeAdapter : AttributeAdapterBase<DynamicStringLengthAttribute>
{
private readonly string _max;
private readonly string _min;
public DynamicStringLengthAttributeAdapter(
DynamicStringLengthAttribute attribute,
IStringLocalizer stringLocalizer)
: base(attribute, stringLocalizer)
{
_max = Attribute.MaximumLength.ToString(CultureInfo.InvariantCulture);
_min = Attribute.MinimumLength.ToString(CultureInfo.InvariantCulture);
}
public override void AddValidation(ClientModelValidationContext context)
{
Check.NotNull(context, nameof(context));
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-length", GetErrorMessage(context));
if (Attribute.MaximumLength != int.MaxValue)
{
MergeAttribute(context.Attributes, "data-val-length-max", _max);
}
if (Attribute.MinimumLength != 0)
{
MergeAttribute(context.Attributes, "data-val-length-min", _min);
}
}
public override string GetErrorMessage(ModelValidationContextBase validationContext)
{
Check.NotNull(validationContext, nameof(validationContext));
return GetErrorMessage(
validationContext.ModelMetadata,
validationContext.ModelMetadata.GetDisplayName(),
Attribute.MaximumLength,
Attribute.MinimumLength
);
}
}
}

27
framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:61851/",
"sslPort": 44301
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Serilog": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.SignalR/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53900/",
"sslPort": 44362
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.SignalR": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

27
framework/src/Volo.Abp.AspNetCore.TestBase/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53783/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.TestBase": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53784/"
}
}
}

27
framework/src/Volo.Abp.AspNetCore/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53374/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:53375/"
}
}
}

1
framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobContainerConfigurationExtensions.cs

@ -15,6 +15,7 @@ namespace Volo.Abp.BlobStoring.Azure
Action<AzureBlobProviderConfiguration> azureConfigureAction)
{
containerConfiguration.ProviderType = typeof(AzureBlobProvider);
containerConfiguration.NamingNormalizers.TryAdd<AzureBlobNamingNormalizer>();
azureConfigureAction(new AzureBlobProviderConfiguration(containerConfiguration));

52
framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobNamingNormalizer.cs

@ -0,0 +1,52 @@
using System.Text.RegularExpressions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.Azure
{
public class AzureBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency
{
/// <summary>
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names
/// </summary>
public virtual string NormalizeContainerName(string containerName)
{
// All letters in a container name must be lowercase.
containerName = containerName.ToLower();
// Container names can contain only letters, numbers, and the dash (-) character.
containerName = Regex.Replace(containerName, "[^a-z0-9-]", string.Empty);
// Every dash (-) character must be immediately preceded and followed by a letter or number;
// consecutive dashes are not permitted in container names.
// Container names must start or end with a letter or number
containerName = Regex.Replace(containerName, "-{2,}", "-");
containerName = Regex.Replace(containerName, "^-", string.Empty);
containerName = Regex.Replace(containerName, "-$", string.Empty);
// Container names must be from 3 through 63 characters long.
if (containerName.Length < 3)
{
var length = containerName.Length;
for (var i = 0; i < 3 - length; i++)
{
containerName += "0";
}
}
if (containerName.Length > 63)
{
containerName = containerName.Substring(0, 63);
}
return containerName;
}
/// <summary>
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#blob-names
/// </summary>
public virtual string NormalizeBlobName(string blobName)
{
return blobName;
}
}
}

9
framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobContainerConfigurationExtensions.cs

@ -9,16 +9,17 @@ namespace Volo.Abp.BlobStoring.FileSystem
{
return new FileSystemBlobProviderConfiguration(containerConfiguration);
}
public static BlobContainerConfiguration UseFileSystem(
this BlobContainerConfiguration containerConfiguration,
Action<FileSystemBlobProviderConfiguration> fileSystemConfigureAction)
{
containerConfiguration.ProviderType = typeof(FileSystemBlobProvider);
containerConfiguration.NamingNormalizers.TryAdd<FileSystemBlobNamingNormalizer>();
fileSystemConfigureAction(new FileSystemBlobProviderConfiguration(containerConfiguration));
return containerConfiguration;
}
}
}
}

41
framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobNamingNormalizer.cs

@ -0,0 +1,41 @@
using System;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.FileSystem
{
public class FileSystemBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency
{
private readonly IOSPlatformProvider _iosPlatformProvider;
public FileSystemBlobNamingNormalizer(IOSPlatformProvider iosPlatformProvider)
{
_iosPlatformProvider = iosPlatformProvider;
}
public virtual string NormalizeContainerName(string containerName)
{
return Normalize(containerName);
}
public virtual string NormalizeBlobName(string blobName)
{
return Normalize(blobName);
}
protected virtual string Normalize(string fileName)
{
var os = _iosPlatformProvider.GetCurrentOSPlatform();
if (os == OSPlatform.Windows)
{
// A filename cannot contain any of the following characters: \ / : * ? " < > |
// In order to support the directory included in the blob name, remove / and \
fileName = Regex.Replace(fileName, "[:\\*\\?\"<>\\|]", string.Empty);
}
return fileName;
}
}
}

62
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs

@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
@ -84,18 +86,22 @@ namespace Volo.Abp.BlobStoring
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected IServiceProvider ServiceProvider { get; }
public BlobContainer(
string containerName,
BlobContainerConfiguration configuration,
IBlobProvider provider,
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider)
ICancellationTokenProvider cancellationTokenProvider,
IServiceProvider serviceProvider)
{
ContainerName = containerName;
Configuration = configuration;
Provider = provider;
CurrentTenant = currentTenant;
CancellationTokenProvider = cancellationTokenProvider;
ServiceProvider = serviceProvider;
}
public virtual async Task SaveAsync(
@ -106,11 +112,13 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) = NormalizeNaming(ContainerName, name);
await Provider.SaveAsync(
new BlobProviderSaveArgs(
ContainerName,
normalizedContainerName,
Configuration,
name,
normalizedBlobName,
stream,
overrideExisting,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
@ -125,11 +133,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
return await Provider.DeleteAsync(
new BlobProviderDeleteArgs(
ContainerName,
normalizedContainerName,
Configuration,
name,
normalizedBlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -142,11 +153,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
return await Provider.ExistsAsync(
new BlobProviderExistsArgs(
ContainerName,
normalizedContainerName,
Configuration,
name,
normalizedBlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -158,7 +172,7 @@ namespace Volo.Abp.BlobStoring
CancellationToken cancellationToken = default)
{
var stream = await GetOrNullAsync(name, cancellationToken);
if (stream == null)
{
//TODO: Consider to throw some type of "not found" exception and handle on the HTTP status side
@ -175,11 +189,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
return await Provider.GetOrNullAsync(
new BlobProviderGetArgs(
ContainerName,
normalizedContainerName,
Configuration,
name,
normalizedBlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -195,5 +212,28 @@ namespace Volo.Abp.BlobStoring
return CurrentTenant.Id;
}
protected virtual (string, string) NormalizeNaming(string containerName, string blobName)
{
if (!Configuration.NamingNormalizers.Any())
{
return (containerName, blobName);
}
using (var scope = ServiceProvider.CreateScope())
{
foreach (var normalizerType in Configuration.NamingNormalizers)
{
var normalizer = scope.ServiceProvider
.GetRequiredService(normalizerType)
.As<IBlobNamingNormalizer>();
containerName = normalizer.NormalizeContainerName(containerName);
blobName = normalizer.NormalizeBlobName(blobName);
}
return (containerName, blobName);
}
}
}
}
}

10
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerConfiguration.cs

@ -1,6 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Collections;
namespace Volo.Abp.BlobStoring
{
@ -18,17 +19,20 @@ namespace Volo.Abp.BlobStoring
/// then the container is shared by all tenants in the system.
///
/// This can be <code>true</code> even if your application is not multi-tenant.
///
///
/// Default: true.
/// </summary>
public bool IsMultiTenant { get; set; } = true;
public ITypeList<IBlobNamingNormalizer> NamingNormalizers { get; }
[NotNull] private readonly Dictionary<string, object> _properties;
[CanBeNull] private readonly BlobContainerConfiguration _fallbackConfiguration;
public BlobContainerConfiguration(BlobContainerConfiguration fallbackConfiguration = null)
{
NamingNormalizers = new TypeList<IBlobNamingNormalizer>();
_fallbackConfiguration = fallbackConfiguration;
_properties = new Dictionary<string, object>();
}
@ -68,4 +72,4 @@ namespace Volo.Abp.BlobStoring
return this;
}
}
}
}

24
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactory.cs

@ -1,4 +1,5 @@
using Volo.Abp.DependencyInjection;
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
@ -7,36 +8,41 @@ namespace Volo.Abp.BlobStoring
public class BlobContainerFactory : IBlobContainerFactory, ITransientDependency
{
protected IBlobProviderSelector ProviderSelector { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected IServiceProvider ServiceProvider { get; }
public BlobContainerFactory(
IBlobContainerConfigurationProvider configurationProvider,
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider,
IBlobProviderSelector providerSelector)
ICancellationTokenProvider cancellationTokenProvider,
IBlobProviderSelector providerSelector,
IServiceProvider serviceProvider)
{
ConfigurationProvider = configurationProvider;
CurrentTenant = currentTenant;
CancellationTokenProvider = cancellationTokenProvider;
ProviderSelector = providerSelector;
ServiceProvider = serviceProvider;
}
public virtual IBlobContainer Create(string name)
{
var configuration = ConfigurationProvider.Get(name);
return new BlobContainer(
name,
configuration,
ProviderSelector.Get(name),
CurrentTenant,
CancellationTokenProvider
CancellationTokenProvider,
ServiceProvider
);
}
}
}
}

9
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/IBlobNamingNormalizer.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.BlobStoring
{
public interface IBlobNamingNormalizer
{
string NormalizeContainerName(string containerName);
string NormalizeBlobName(string blobName);
}
}

3
framework/src/Volo.Abp.Caching.StackExchangeRedis/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.Caching.StackExchangeRedis/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

25
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo.Abp.Caching.StackExchangeRedis.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.Caching.StackExchangeRedis</AssemblyName>
<PackageId>Volo.Abp.Caching.StackExchangeRedis</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.1.5" />
</ItemGroup>
</Project>

30
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisModule.cs

@ -0,0 +1,30 @@
using System;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Modularity;
namespace Volo.Abp.Caching.StackExchangeRedis
{
[DependsOn(
typeof(AbpCachingModule)
)]
public class AbpCachingStackExchangeRedisModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddStackExchangeRedisCache(options =>
{
var redisConfiguration = configuration["Redis:Configuration"];
if (!redisConfiguration.IsNullOrEmpty())
{
options.Configuration = configuration["Redis:Configuration"];
}
});
context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache, AbpRedisCache>());
}
}
}

294
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs

@ -0,0 +1,294 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Caching.StackExchangeRedis
{
[DisableConventionalRegistration]
public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
{
protected static readonly string SetScript;
protected static readonly string AbsoluteExpirationKey;
protected static readonly string SlidingExpirationKey;
protected static readonly string DataKey;
protected static readonly long NotPresent;
private static readonly FieldInfo RedisDatabaseField;
private static readonly MethodInfo ConnectMethod;
private static readonly MethodInfo ConnectAsyncMethod;
private static readonly MethodInfo MapMetadataMethod;
private static readonly MethodInfo GetAbsoluteExpirationMethod;
private static readonly MethodInfo GetExpirationInSecondsMethod;
protected IDatabase RedisDatabase => GetRedisDatabase();
private IDatabase _redisDatabase;
protected string Instance { get; }
static AbpRedisCache()
{
var type = typeof(RedisCache);
RedisDatabaseField = type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic);
ConnectMethod = type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic);
ConnectAsyncMethod = type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic);
MapMetadataMethod = type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic);
GetAbsoluteExpirationMethod = type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic);
GetExpirationInSecondsMethod = type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic);
SetScript = type.GetField("SetScript", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString();
AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString();
SlidingExpirationKey = type.GetField("SlidingExpirationKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString();
DataKey = type.GetField("DataKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString();
NotPresent = type.GetField("NotPresent", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).To<int>();
}
public AbpRedisCache(IOptions<RedisCacheOptions> optionsAccessor)
: base(optionsAccessor)
{
Instance = optionsAccessor.Value.InstanceName ?? string.Empty;
}
protected virtual void Connect()
{
if (GetRedisDatabase() != null)
{
return;
}
ConnectMethod.Invoke(this, Array.Empty<object>());
}
protected virtual Task ConnectAsync(CancellationToken token = default)
{
if (GetRedisDatabase() != null)
{
return Task.CompletedTask;
}
return (Task) ConnectAsyncMethod.Invoke(this, new object[] {token});
}
public byte[][] GetMany(
IEnumerable<string> keys)
{
keys = Check.NotNull(keys, nameof(keys));
return GetAndRefreshMany(keys, true);
}
public async Task<byte[][]> GetManyAsync(
IEnumerable<string> keys,
CancellationToken token = default)
{
keys = Check.NotNull(keys, nameof(keys));
return await GetAndRefreshManyAsync(keys, true, token);
}
public void SetMany(
IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options)
{
Connect();
Task.WaitAll(PipelineSetMany(items, options));
}
public async Task SetManyAsync(
IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options,
CancellationToken token = default)
{
token.ThrowIfCancellationRequested();
await ConnectAsync(token);
await Task.WhenAll(PipelineSetMany(items, options));
}
protected virtual byte[][] GetAndRefreshMany(
IEnumerable<string> keys,
bool getData)
{
Connect();
var keyArray = keys.Select(key => Instance + key).ToArray();
RedisValue[][] results;
if (getData)
{
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey,
SlidingExpirationKey, DataKey);
}
else
{
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey,
SlidingExpirationKey);
}
Task.WaitAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes));
return bytes;
}
protected virtual async Task<byte[][]> GetAndRefreshManyAsync(
IEnumerable<string> keys,
bool getData,
CancellationToken token = default)
{
token.ThrowIfCancellationRequested();
await ConnectAsync(token);
var keyArray = keys.Select(key => Instance + key).ToArray();
RedisValue[][] results;
if (getData)
{
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey,
SlidingExpirationKey, DataKey);
}
else
{
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey,
SlidingExpirationKey);
}
await Task.WhenAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes));
return bytes;
}
protected virtual Task[] PipelineRefreshManyAndOutData(
string[] keys,
RedisValue[][] results,
out byte[][] bytes)
{
bytes = new byte[keys.Length][];
var tasks = new Task[keys.Length];
for (var i = 0; i < keys.Length; i++)
{
if (results[i].Length >= 2)
{
MapMetadata(results[i], out DateTimeOffset? absExpr, out TimeSpan? sldExpr);
if (sldExpr.HasValue)
{
TimeSpan? expr;
if (absExpr.HasValue)
{
var relExpr = absExpr.Value - DateTimeOffset.Now;
expr = relExpr <= sldExpr.Value ? relExpr : sldExpr;
}
else
{
expr = sldExpr;
}
tasks[i] = RedisDatabase.KeyExpireAsync(keys[i], expr);
}
else
{
tasks[i] = Task.CompletedTask;
}
}
if (results[i].Length >= 3 && results[i][2].HasValue)
{
bytes[i] = results[i][2];
}
else
{
bytes[i] = null;
}
}
return tasks;
}
protected virtual Task[] PipelineSetMany(
IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options)
{
items = Check.NotNull(items, nameof(items));
options = Check.NotNull(options, nameof(options));
var itemArray = items.ToArray();
var tasks = new Task[itemArray.Length];
var creationTime = DateTimeOffset.UtcNow;
var absoluteExpiration = GetAbsoluteExpiration(creationTime, options);
for (var i = 0; i < itemArray.Length; i++)
{
tasks[i] = RedisDatabase.ScriptEvaluateAsync(SetScript, new RedisKey[] {Instance + itemArray[i].Key},
new RedisValue[]
{
absoluteExpiration?.Ticks ?? NotPresent,
options.SlidingExpiration?.Ticks ?? NotPresent,
GetExpirationInSeconds(creationTime, absoluteExpiration, options) ?? NotPresent,
itemArray[i].Value
});
}
return tasks;
}
protected virtual void MapMetadata(
RedisValue[] results,
out DateTimeOffset? absoluteExpiration,
out TimeSpan? slidingExpiration)
{
var parameters = new object[] {results, null, null};
MapMetadataMethod.Invoke(this, parameters);
absoluteExpiration = (DateTimeOffset?) parameters[1];
slidingExpiration = (TimeSpan?) parameters[2];
}
protected virtual long? GetExpirationInSeconds(
DateTimeOffset creationTime,
DateTimeOffset? absoluteExpiration,
DistributedCacheEntryOptions options)
{
return (long?) GetExpirationInSecondsMethod.Invoke(null,
new object[] {creationTime, absoluteExpiration, options});
}
protected virtual DateTimeOffset? GetAbsoluteExpiration(
DateTimeOffset creationTime,
DistributedCacheEntryOptions options)
{
return (DateTimeOffset?) GetAbsoluteExpirationMethod.Invoke(null, new object[] {creationTime, options});
}
private IDatabase GetRedisDatabase()
{
if (_redisDatabase == null)
{
_redisDatabase = RedisDatabaseField.GetValue(this) as IDatabase;
}
return _redisDatabase;
}
}
}

47
framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisExtensions.cs

@ -0,0 +1,47 @@
using System.Linq;
using System.Threading.Tasks;
using StackExchange.Redis;
namespace Volo.Abp.Caching.StackExchangeRedis
{
public static class AbpRedisExtensions
{
public static RedisValue[][] HashMemberGetMany(
this IDatabase cache,
string[] keys,
params string[] members)
{
var tasks = new Task<RedisValue[]>[keys.Length];
var fields = members.Select(member => (RedisValue) member).ToArray();
var results = new RedisValue[keys.Length][];
for (var i = 0; i < keys.Length; i++)
{
tasks[i] = cache.HashGetAsync((RedisKey) keys[i], fields);
}
for (var i = 0; i < tasks.Length; i++)
{
results[i] = cache.Wait(tasks[i]);
}
return results;
}
public static async Task<RedisValue[][]> HashMemberGetManyAsync(
this IDatabase cache,
string[] keys,
params string[] members)
{
var tasks = new Task<RedisValue[]>[keys.Length];
var fields = members.Select(member => (RedisValue) member).ToArray();
for (var i = 0; i < keys.Length; i++)
{
tasks[i] = cache.HashGetAsync((RedisKey) keys[i], fields);
}
return await Task.WhenAll(tasks);
}
}
}

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

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -28,16 +31,16 @@ namespace Volo.Abp.Caching
IDistributedCacheSerializer serializer,
IDistributedCacheKeyNormalizer keyNormalizer,
IHybridServiceScopeFactory serviceScopeFactory) : base(
distributedCacheOption: distributedCacheOption,
cache: cache,
cancellationTokenProvider: cancellationTokenProvider,
serializer: serializer,
keyNormalizer: keyNormalizer,
serviceScopeFactory: serviceScopeFactory)
distributedCacheOption: distributedCacheOption,
cache: cache,
cancellationTokenProvider: cancellationTokenProvider,
serializer: serializer,
keyNormalizer: keyNormalizer,
serviceScopeFactory: serviceScopeFactory)
{
}
}
/// <summary>
/// Represents a distributed cache of <typeparamref name="TCacheItem" /> type.
/// Uses a generic cache key type of <typeparamref name="TCacheKey" /> type.
@ -148,19 +151,151 @@ namespace Volo.Abp.Caching
{
if (hideErrors == true)
{
AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
HandleException(ex);
return null;
}
throw;
}
if (cachedBytes == null)
return ToCacheItem(cachedBytes);
}
public virtual KeyValuePair<TCacheKey, TCacheItem>[] GetMany(
IEnumerable<TCacheKey> keys,
bool? hideErrors = null)
{
var keyArray = keys.ToArray();
var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
if (cacheSupportsMultipleItems == null)
{
return null;
return GetManyFallback(
keyArray,
hideErrors
);
}
return Serializer.Deserialize<TCacheItem>(cachedBytes);
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
byte[][] cachedBytes;
try
{
cachedBytes = cacheSupportsMultipleItems.GetMany(keyArray.Select(NormalizeKey));
}
catch (Exception ex)
{
if (hideErrors == true)
{
HandleException(ex);
return ToCacheItemsWithDefaultValues(keyArray);
}
throw;
}
return ToCacheItems(cachedBytes, keyArray);
}
protected virtual KeyValuePair<TCacheKey, TCacheItem>[] GetManyFallback(
TCacheKey[] keys,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
return keys
.Select(key => new KeyValuePair<TCacheKey, TCacheItem>(
key,
Get(key, hideErrors: false)
)
).ToArray();
}
catch (Exception ex)
{
if (hideErrors == true)
{
HandleException(ex);
return ToCacheItemsWithDefaultValues(keys);
}
throw;
}
}
public virtual async Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyAsync(
IEnumerable<TCacheKey> keys,
bool? hideErrors = null,
CancellationToken token = default)
{
var keyArray = keys.ToArray();
var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
if (cacheSupportsMultipleItems == null)
{
return await GetManyFallbackAsync(
keyArray,
hideErrors,
token
);
}
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
byte[][] cachedBytes;
try
{
cachedBytes = await cacheSupportsMultipleItems.GetManyAsync(
keyArray.Select(NormalizeKey),
CancellationTokenProvider.FallbackToProvider(token)
);
}
catch (Exception ex)
{
if (hideErrors == true)
{
await HandleExceptionAsync(ex);
return ToCacheItemsWithDefaultValues(keyArray);
}
throw;
}
return ToCacheItems(cachedBytes, keyArray);
}
protected virtual async Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyFallbackAsync(
TCacheKey[] keys,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
var result = new List<KeyValuePair<TCacheKey, TCacheItem>>();
foreach (var key in keys)
{
result.Add(new KeyValuePair<TCacheKey, TCacheItem>(
key,
await GetAsync(key, false, token))
);
}
return result.ToArray();
}
catch (Exception ex)
{
if (hideErrors == true)
{
await HandleExceptionAsync(ex);
return ToCacheItemsWithDefaultValues(keys);
}
throw;
}
}
/// <summary>
@ -307,7 +442,7 @@ namespace Volo.Abp.Caching
{
if (hideErrors == true)
{
AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
HandleException(ex);
return;
}
@ -354,14 +489,156 @@ namespace Volo.Abp.Caching
}
}
/// <summary>
/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
public void SetMany(
IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null)
{
var itemsArray = items.ToArray();
var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
if (cacheSupportsMultipleItems == null)
{
SetManyFallback(
itemsArray,
options,
hideErrors
);
return;
}
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
cacheSupportsMultipleItems.SetMany(
ToRawCacheItems(itemsArray),
options ?? DefaultCacheOptions
);
}
catch (Exception ex)
{
if (hideErrors == true)
{
HandleException(ex);
return;
}
throw;
}
}
protected virtual void SetManyFallback(
KeyValuePair<TCacheKey, TCacheItem>[] items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
foreach (var item in items)
{
Set(
item.Key,
item.Value,
options: options,
hideErrors: false
);
}
}
catch (Exception ex)
{
if (hideErrors == true)
{
HandleException(ex);
return;
}
throw;
}
}
public virtual async Task SetManyAsync(
IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null,
CancellationToken token = default)
{
var itemsArray = items.ToArray();
var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
if (cacheSupportsMultipleItems == null)
{
await SetManyFallbackAsync(
itemsArray,
options,
hideErrors,
token
);
return;
}
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
await cacheSupportsMultipleItems.SetManyAsync(
ToRawCacheItems(itemsArray),
options ?? DefaultCacheOptions,
CancellationTokenProvider.FallbackToProvider(token)
);
}
catch (Exception ex)
{
if (hideErrors == true)
{
await HandleExceptionAsync(ex);
return;
}
throw;
}
}
protected virtual async Task SetManyFallbackAsync(
KeyValuePair<TCacheKey, TCacheItem>[] items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null,
CancellationToken token = default)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try
{
foreach (var item in items)
{
await SetAsync(
item.Key,
item.Value,
options: options,
hideErrors: false,
token: token
);
}
}
catch (Exception ex)
{
if (hideErrors == true)
{
await HandleExceptionAsync(ex);
return;
}
throw;
}
}
public virtual void Refresh(
TCacheKey key, bool?
hideErrors = null)
hideErrors = null)
{
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
@ -373,20 +650,14 @@ namespace Volo.Abp.Caching
{
if (hideErrors == true)
{
AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
HandleException(ex);
return;
}
throw;
}
}
/// <summary>
/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
public virtual async Task RefreshAsync(
TCacheKey key,
bool? hideErrors = null,
@ -410,11 +681,6 @@ namespace Volo.Abp.Caching
}
}
/// <summary>
/// Removes the cache item for given key from cache.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
public virtual void Remove(
TCacheKey key,
bool? hideErrors = null)
@ -429,7 +695,7 @@ namespace Volo.Abp.Caching
{
if (hideErrors == true)
{
AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
HandleException(ex);
return;
}
@ -437,13 +703,6 @@ namespace Volo.Abp.Caching
}
}
/// <summary>
/// Removes the cache item for given key from cache.
/// </summary>
/// <param name="key">The key of cached item to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
public virtual async Task RemoveAsync(
TCacheKey key,
bool? hideErrors = null,
@ -467,6 +726,11 @@ namespace Volo.Abp.Caching
}
}
protected virtual void HandleException(Exception ex)
{
AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
}
protected virtual async Task HandleExceptionAsync(Exception ex)
{
Logger.LogException(ex, LogLevel.Warning);
@ -478,5 +742,56 @@ namespace Volo.Abp.Caching
.NotifyAsync(new ExceptionNotificationContext(ex, LogLevel.Warning));
}
}
protected virtual KeyValuePair<TCacheKey, TCacheItem>[] ToCacheItems(byte[][] itemBytes, TCacheKey[] itemKeys)
{
if (itemBytes.Length != itemKeys.Length)
{
throw new AbpException("count of the item bytes should be same with the count of the given keys");
}
var result = new List<KeyValuePair<TCacheKey, TCacheItem>>();
for (int i = 0; i < itemKeys.Length; i++)
{
result.Add(
new KeyValuePair<TCacheKey, TCacheItem>(
itemKeys[i],
ToCacheItem(itemBytes[i])
)
);
}
return result.ToArray();
}
[CanBeNull]
protected virtual TCacheItem ToCacheItem([CanBeNull] byte[] bytes)
{
if (bytes == null)
{
return null;
}
return Serializer.Deserialize<TCacheItem>(bytes);
}
protected virtual KeyValuePair<string, byte[]>[] ToRawCacheItems(KeyValuePair<TCacheKey, TCacheItem>[] items)
{
return items
.Select(i => new KeyValuePair<string, byte[]>(
NormalizeKey(i.Key),
Serializer.Serialize(i.Value)
)
).ToArray();
}
private static KeyValuePair<TCacheKey, TCacheItem>[] ToCacheItemsWithDefaultValues(TCacheKey[] keys)
{
return keys
.Select(key => new KeyValuePair<TCacheKey, TCacheItem>(key, default))
.ToArray();
}
}
}

30
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/ICacheSupportsMultipleItems.cs

@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
namespace Volo.Abp.Caching
{
public interface ICacheSupportsMultipleItems
{
byte[][] GetMany(
IEnumerable<string> keys
);
Task<byte[][]> GetManyAsync(
IEnumerable<string> keys,
CancellationToken token = default
);
void SetMany(
IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options
);
Task SetManyAsync(
IEnumerable<KeyValuePair<string, byte[]>> items,
DistributedCacheEntryOptions options,
CancellationToken token = default
);
}
}

63
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -34,6 +35,39 @@ namespace Volo.Abp.Caching
TCacheKey key,
bool? hideErrors = null
);
/// <summary>
/// Gets multiple cache items with the given keys.
///
/// The returned list contains exactly the same count of items specified in the given keys.
/// An item in the return list can not be null, but an item in the list has null value
/// if the related key not found in the cache.
/// </summary>
/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <returns>List of cache items.</returns>
KeyValuePair<TCacheKey, TCacheItem>[] GetMany(
IEnumerable<TCacheKey> keys,
bool? hideErrors = null
);
/// <summary>
/// Gets multiple cache items with the given keys.
///
/// The returned list contains exactly the same count of items specified in the given keys.
/// An item in the return list can not be null, but an item in the list has null value
/// if the related key not found in the cache.
///
/// </summary>
/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// /// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>List of cache items.</returns>
Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyAsync(
IEnumerable<TCacheKey> keys,
bool? hideErrors = null,
CancellationToken token = default
);
/// <summary>
/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
@ -113,6 +147,35 @@ namespace Volo.Abp.Caching
CancellationToken token = default
);
/// <summary>
/// Sets multiple cache items.
/// Based on the implementation, this can be more efficient than setting multiple items individually.
/// </summary>
/// <param name="items">Items to set on the cache</param>
/// <param name="options">The cache options for the value.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
void SetMany(
IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null
);
/// <summary>
/// Sets multiple cache items.
/// Based on the implementation, this can be more efficient than setting multiple items individually.
/// </summary>
/// <param name="items">Items to set on the cache</param>
/// <param name="options">The cache options for the value.</param>
/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
Task SetManyAsync(
IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
DistributedCacheEntryOptions options = null,
bool? hideErrors = null,
CancellationToken token = default
);
/// <summary>
/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
/// </summary>

12
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs

@ -51,7 +51,7 @@ namespace Volo.Abp.Cli.Commands
var apiUrl = commandLineArgs.Options.GetOrNull(Options.ApiUrl.Short, Options.ApiUrl.Long);
if (string.IsNullOrWhiteSpace(apiUrl))
{
var environmentJson = File.ReadAllText("src/environments/environment.ts").Split("export const environment = ")[1].Replace(";", " ");
var environmentJson = File.ReadAllText("projects/dev-app/src/environments/environment.ts").Split("export const environment = ")[1].Replace(";", " ");
var environment = JObject.Parse(environmentJson);
apiUrl = environment["apis"]["default"]["url"].ToString();
}
@ -61,7 +61,7 @@ namespace Volo.Abp.Cli.Commands
output = commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long);
if (!string.IsNullOrWhiteSpace(output) && !(output.EndsWith("/") || output.EndsWith("\\")))
{
{
output += "/";
}
@ -110,7 +110,7 @@ namespace Volo.Abp.Cli.Commands
if (rootPath != "app")
{
Logger.LogInformation($"{rootPath} directory is creating");
}
}
if (rootPath == "app")
{
@ -536,7 +536,7 @@ namespace Volo.Abp.Cli.Commands
modelFileText.AppendLine(Environment.NewLine);
modelFileText.AppendLine($"import {{ {baseTypeName} }} from '{baseTypeKebabCase}';");
extends = "extends " + (!string.IsNullOrWhiteSpace(customBaseTypeName) ? customBaseTypeName : baseTypeName);
var modelIndex = CreateType(data, baseType, rootPath, modelIndexList, controllerPathName);
@ -628,7 +628,7 @@ namespace Volo.Abp.Cli.Commands
{
from = "./" + propertyTypeKebabCase;
}
modelFileText.Insert(0, $"import {{ {propertyType} }} from '{from}';");
modelFileText.Insert(0, Environment.NewLine);
modelIndexList.Add(modelIndex);
@ -816,4 +816,4 @@ namespace Volo.Abp.Cli.Commands
public bool IsOptional { get; set; }
public string BindingSourceId { get; set; }
}
}
}

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

@ -59,15 +59,33 @@ namespace Volo.Abp.Cli.Commands
return;
}
var result = CmdHelper.RunCmd("dotnet tool install " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g");
try
{
var result = CmdHelper.RunCmd("dotnet tool install " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g");
if (result == 0)
if (result == 0)
{
Logger.LogInformation("ABP Suite has been successfully installed.");
Logger.LogInformation("You can run it with the CLI command \"abp suite\"");
}
else
{
ShowSuiteManualInstallCommand();
}
}
catch (Exception e)
{
Logger.LogInformation("ABP Suite has been successfully installed.");
Logger.LogInformation("You can run it with the CLI command \"abp suite\"");
Logger.LogError("Couldn't install ABP Suite." + e.Message);
ShowSuiteManualInstallCommand();
}
}
private void ShowSuiteManualInstallCommand()
{
Logger.LogInformation("You can also run the following command to install ABP Suite.");
Logger.LogInformation("dotnet tool install -g Volo.Abp.Suite");
}
private async Task UpdateSuiteAsync()
{
var nugetIndexUrl = await _nuGetIndexUrlService.GetAsync();
@ -77,7 +95,26 @@ namespace Volo.Abp.Cli.Commands
return;
}
CmdHelper.RunCmd("dotnet tool update " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g");
try
{
var result = CmdHelper.RunCmd("dotnet tool update " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g");
if (result != 0)
{
ShowSuiteManualUpdateCommand();
}
}
catch (Exception ex)
{
Logger.LogError("Couldn't update ABP Suite." + ex.Message);
ShowSuiteManualUpdateCommand();
}
}
private void ShowSuiteManualUpdateCommand()
{
Logger.LogError("You can also run the following command to update ABP Suite.");
Logger.LogError("dotnet tool update -g Volo.Abp.Suite");
}
private static void RemoveSuite()

6
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AngularEnvironmentFilePortChangeForSeparatedIdentityServersStep.cs

@ -10,9 +10,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
var fileEntries = context.Files.Where(x =>
!x.IsDirectory &&
(x.Name.EndsWith("angular/src/environments/environment.ts", StringComparison.InvariantCultureIgnoreCase) ||
x.Name.EndsWith("angular/src/environments/environment.hmr.ts", StringComparison.InvariantCultureIgnoreCase) ||
x.Name.EndsWith("angular/src/environments/environment.prod.ts", StringComparison.InvariantCultureIgnoreCase))
(x.Name.EndsWith("angular/projects/dev-app/src/environments/environment.ts", StringComparison.InvariantCultureIgnoreCase) ||
x.Name.EndsWith("angular/projects/dev-app/src/environments/environment.hmr.ts", StringComparison.InvariantCultureIgnoreCase) ||
x.Name.EndsWith("angular/projects/dev-app/src/environments/environment.prod.ts", StringComparison.InvariantCultureIgnoreCase))
)
.ToList();

45
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs

@ -54,11 +54,12 @@ namespace Volo.Abp.Cli.ProjectModification
_npmGlobalPackagesChecker.Check();
var packagesUpdated = new ConcurrentDictionary<string, bool>();
async Task UpdateAsync(string file)
{
var updated = await UpdatePackagesInFile(file, includePreviews, switchToStable);
packagesUpdated.TryAdd(file, updated);
};
}
Task.WaitAll(fileList.Select(UpdateAsync).ToArray());
@ -66,23 +67,20 @@ namespace Volo.Abp.Cli.ProjectModification
{
var fileDirectory = Path.GetDirectoryName(file.Key).EnsureEndsWith(Path.DirectorySeparatorChar);
if (IsAngularProject(fileDirectory))
if (includePreviews)
{
if (includePreviews)
{
await CreateNpmrcFileAsync(Path.GetDirectoryName(file.Key));
}
else if (switchToStable)
{
await DeleteNpmrcFileAsync(Path.GetDirectoryName(file.Key));
}
await CreateNpmrcFileAsync(Path.GetDirectoryName(file.Key));
RunNpmInstall(fileDirectory);
}
else if (switchToStable)
{
await DeleteNpmrcFileAsync(Path.GetDirectoryName(file.Key));
RunYarn(fileDirectory);
}
RunYarn(fileDirectory);
if (!IsAngularProject(fileDirectory))
{
Thread.Sleep(500);
Thread.Sleep(1000);
RunGulp(fileDirectory);
}
}
@ -166,7 +164,8 @@ namespace Volo.Abp.Cli.ProjectModification
return File.Exists(Path.Combine(fileDirectory, "angular.json"));
}
protected virtual async Task<bool> UpdatePackagesInFile(string filePath, bool includePreviews = false, bool switchToStable = false)
protected virtual async Task<bool> UpdatePackagesInFile(string filePath, bool includePreviews = false,
bool switchToStable = false)
{
var packagesUpdated = false;
var fileContent = File.ReadAllText(filePath);
@ -201,7 +200,7 @@ namespace Volo.Abp.Cli.ProjectModification
bool includePreviews = false,
bool switchToStable = false)
{
var currentVersion = (string)package.Value;
var currentVersion = (string) package.Value;
var version = await GetLatestVersion(package, currentVersion, includePreviews, switchToStable);
@ -214,7 +213,8 @@ namespace Volo.Abp.Cli.ProjectModification
package.Value.Replace(versionWithPrefix);
Logger.LogInformation($"Updated {package.Name} to {version} in {filePath.Replace(Directory.GetCurrentDirectory(), "")}.");
Logger.LogInformation(
$"Updated {package.Name} to {version} in {filePath.Replace(Directory.GetCurrentDirectory(), "")}.");
return true;
}
@ -256,12 +256,12 @@ namespace Volo.Abp.Cli.ProjectModification
protected virtual List<JProperty> GetAbpPackagesFromPackageJson(JObject fileObject)
{
var dependencyList = new[] { "dependencies", "devDependencies", "peerDependencies" };
var dependencyList = new[] {"dependencies", "devDependencies", "peerDependencies"};
var abpPackages = new List<JProperty>();
foreach (var dependencyListName in dependencyList)
{
var dependencies = (JObject)fileObject[dependencyListName];
var dependencies = (JObject) fileObject[dependencyListName];
if (dependencies == null)
{
@ -269,7 +269,8 @@ namespace Volo.Abp.Cli.ProjectModification
}
var properties = dependencies.Properties().ToList();
abpPackages.AddRange(properties.Where(p => p.Name.StartsWith("@abp/") || p.Name.StartsWith("@volo/")).ToList());
abpPackages.AddRange(properties.Where(p => p.Name.StartsWith("@abp/") || p.Name.StartsWith("@volo/"))
.ToList());
}
return abpPackages;
@ -286,5 +287,11 @@ namespace Volo.Abp.Cli.ProjectModification
Logger.LogInformation($"Running Yarn on {fileDirectory}");
CmdHelper.RunCmd($"cd {fileDirectory} && yarn");
}
protected virtual void RunNpmInstall(string fileDirectory)
{
Logger.LogInformation($"Running npm install on {fileDirectory}");
CmdHelper.RunCmd($"cd {fileDirectory} && npm install");
}
}
}

7
framework/src/Volo.Abp.Cli/Properties/launchSettings.json

@ -1,7 +0,0 @@
{
"profiles": {
"Volo.Abp.Cli": {
"commandName": "Project"
}
}
}

9
framework/src/Volo.Abp.Core/System/Runtime/IOSPlatformProvider.cs

@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace System.Runtime
{
public interface IOSPlatformProvider
{
OSPlatform GetCurrentOSPlatform();
}
}

23
framework/src/Volo.Abp.Core/System/Runtime/OSPlatformProvider.cs

@ -0,0 +1,23 @@
using System.Runtime.InteropServices;
using Volo.Abp.DependencyInjection;
namespace System.Runtime
{
public class OSPlatformProvider : IOSPlatformProvider, ITransientDependency
{
public virtual OSPlatform GetCurrentOSPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return OSPlatform.OSX; //MAC
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return OSPlatform.Windows;
}
return OSPlatform.Linux;
}
}
}

2
framework/src/Volo.Abp.Core/Volo/Abp/Collections/ITypeList.cs

@ -27,7 +27,7 @@ namespace Volo.Abp.Collections
/// Adds a type to list if it's not already in the list.
/// </summary>
/// <typeparam name="T">Type</typeparam>
void TryAdd<T>() where T : TBaseType;
bool TryAdd<T>() where T : TBaseType;
/// <summary>
/// Checks if a type exists in the list.

5
framework/src/Volo.Abp.Core/Volo/Abp/Collections/TypeList.cs

@ -60,14 +60,15 @@ namespace Volo.Abp.Collections
_typeList.Add(typeof(T));
}
public void TryAdd<T>() where T : TBaseType
public bool TryAdd<T>() where T : TBaseType
{
if (Contains<T>())
{
return;
return false;
}
Add<T>();
return true;
}
/// <inheritdoc/>

58
framework/src/Volo.Abp.Core/Volo/Abp/Validation/DynamicStringLengthAttribute.cs

@ -0,0 +1,58 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Reflection;
using JetBrains.Annotations;
namespace Volo.Abp.Validation
{
/// <summary>
/// Used to determine <see cref="StringLengthAttribute.MaximumLength"/> and <see cref="StringLengthAttribute.MinimumLength"/>
/// properties on the runtime.
/// </summary>
public class DynamicStringLengthAttribute : StringLengthAttribute
{
private static readonly FieldInfo MaximumLengthField;
static DynamicStringLengthAttribute()
{
MaximumLengthField = typeof(StringLengthAttribute).GetField(
"<MaximumLength>k__BackingField",
BindingFlags.Instance | BindingFlags.NonPublic
);
Debug.Assert(MaximumLengthField != null, nameof(MaximumLengthField) + " != null");
}
/// <param name="sourceType">A type to get the values of the properties</param>
/// <param name="maximumLengthPropertyName">The name of the public static property for the <see cref="StringLengthAttribute.MaximumLength"/></param>
/// <param name="minimumLengthPropertyName">The name of the public static property for the <see cref="StringLengthAttribute.MinimumLength"/></param>
public DynamicStringLengthAttribute(
[NotNull] Type sourceType,
[CanBeNull] string maximumLengthPropertyName,
[CanBeNull] string minimumLengthPropertyName = null)
: base(0)
{
Check.NotNull(sourceType, nameof(sourceType));
if (maximumLengthPropertyName != null)
{
var maximumLengthProperty = sourceType.GetProperty(
maximumLengthPropertyName,
BindingFlags.Static | BindingFlags.Public
);
Debug.Assert(maximumLengthProperty != null, nameof(maximumLengthProperty) + " != null");
MaximumLengthField.SetValue(this, (int) maximumLengthProperty.GetValue(null));
}
if (minimumLengthPropertyName != null)
{
var minimumLengthProperty = sourceType.GetProperty(
minimumLengthPropertyName,
BindingFlags.Static | BindingFlags.Public
);
Debug.Assert(minimumLengthProperty != null, nameof(minimumLengthProperty) + " != null");
MinimumLength = (int) minimumLengthProperty.GetValue(null);
}
}
}
}

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

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
@ -241,6 +242,11 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
}
}
if (IsBaseAuditProperty(propertyInfo, entityType))
{
return false;
}
var isModified = !(propertyEntry.OriginalValue?.Equals(propertyEntry.CurrentValue) ?? propertyEntry.CurrentValue == null);
if (isModified)
{
@ -250,6 +256,59 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
return defaultValue;
}
private bool IsBaseAuditProperty(PropertyInfo propertyInfo, Type entityType)
{
if (entityType.IsAssignableTo<IHasCreationTime>()
&& propertyInfo.Name == nameof(IHasCreationTime.CreationTime))
{
return true;
}
if (entityType.IsAssignableTo<IMayHaveCreator>()
&& propertyInfo.Name == nameof(IMayHaveCreator.CreatorId))
{
return true;
}
if (entityType.IsAssignableTo<IMustHaveCreator>()
&& propertyInfo.Name == nameof(IMustHaveCreator.CreatorId))
{
return true;
}
if (entityType.IsAssignableTo<IHasModificationTime>()
&& propertyInfo.Name == nameof(IHasModificationTime.LastModificationTime))
{
return true;
}
if (entityType.IsAssignableTo<IModificationAuditedObject>()
&& propertyInfo.Name == nameof(IModificationAuditedObject.LastModifierId))
{
return true;
}
if (entityType.IsAssignableTo<ISoftDelete>()
&& propertyInfo.Name == nameof(ISoftDelete.IsDeleted))
{
return true;
}
if (entityType.IsAssignableTo<IHasDeletionTime>()
&& propertyInfo.Name == nameof(IHasDeletionTime.DeletionTime))
{
return true;
}
if (entityType.IsAssignableTo<IDeletionAuditedObject>()
&& propertyInfo.Name == nameof(IDeletionAuditedObject.DeleterId))
{
return true;
}
return false;
}
/// <summary>
/// Updates change time, entity id and foreign keys after SaveChanges is called.
/// </summary>
@ -313,4 +372,4 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
}
}
}
}
}

27
framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52306/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.Http.Client.IdentityModel": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:52307/"
}
}
}

27
framework/src/Volo.Abp.Http.Client.IdentityModel/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52306/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.Http.Client.IdentityModel": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:52307/"
}
}
}

27
framework/src/Volo.Abp.Http.Client/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52208/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.Http.Client": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:52209/"
}
}
}

18
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepositoryFilterer.cs

@ -0,0 +1,18 @@
using System.Collections.Generic;
using MongoDB.Driver;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Domain.Repositories.MongoDB
{
public interface IMongoDbRepositoryFilterer<TEntity> where TEntity : class, IEntity
{
void AddGlobalFilters(List<FilterDefinition<TEntity>> filters);
}
public interface IMongoDbRepositoryFilterer<TEntity, TKey> : IMongoDbRepositoryFilterer<TEntity> where TEntity : class, IEntity<TKey>
{
FilterDefinition<TEntity> CreateEntityFilter(TKey id, bool applyFilters = false);
FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null);
}
}

49
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -14,7 +14,6 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Domain.Repositories.MongoDB
{
@ -331,6 +330,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
where TMongoDbContext : IAbpMongoDbContext
where TEntity : class, IEntity<TKey>
{
public IMongoDbRepositoryFilterer<TEntity, TKey> RepositoryFilterer { get; set; }
public MongoDbRepository(IMongoDbContextProvider<TMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
@ -358,7 +359,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
CancellationToken cancellationToken = default)
{
return await Collection
.Find(CreateEntityFilter(id, true))
.Find(RepositoryFilterer.CreateEntityFilter(id, true))
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
@ -372,49 +373,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
protected override FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null)
{
if (!withConcurrencyStamp || !(entity is IHasConcurrencyStamp entityWithConcurrencyStamp))
{
return Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id);
}
if (concurrencyStamp == null)
{
concurrencyStamp = entityWithConcurrencyStamp.ConcurrencyStamp;
}
return Builders<TEntity>.Filter.And(
Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id),
Builders<TEntity>.Filter.Eq(e => ((IHasConcurrencyStamp)e).ConcurrencyStamp, concurrencyStamp)
);
}
protected virtual FilterDefinition<TEntity> CreateEntityFilter(TKey id, bool applyFilters = false)
{
var filters = new List<FilterDefinition<TEntity>>
{
Builders<TEntity>.Filter.Eq(e => e.Id, id)
};
if (applyFilters)
{
AddGlobalFilters(filters);
}
return Builders<TEntity>.Filter.And(filters);
}
protected virtual void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && DataFilter.IsEnabled<ISoftDelete>())
{
filters.Add(Builders<TEntity>.Filter.Eq(e => ((ISoftDelete)e).IsDeleted, false));
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
var tenantId = CurrentTenant.Id;
filters.Add(Builders<TEntity>.Filter.Eq(e => ((IMultiTenant)e).TenantId, tenantId));
}
return RepositoryFilterer.CreateEntityFilter(entity, withConcurrencyStamp, concurrencyStamp);
}
}
}

79
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepositoryFilterer.cs

@ -0,0 +1,79 @@
using System.Collections.Generic;
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Domain.Repositories.MongoDB
{
public class MongoDbRepositoryFilterer<TEntity> : IMongoDbRepositoryFilterer<TEntity>
where TEntity : class, IEntity
{
protected IDataFilter DataFilter { get; }
protected ICurrentTenant CurrentTenant { get; }
public MongoDbRepositoryFilterer(IDataFilter dataFilter, ICurrentTenant currentTenant)
{
DataFilter = dataFilter;
CurrentTenant = currentTenant;
}
public virtual void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && DataFilter.IsEnabled<ISoftDelete>())
{
filters.Add(Builders<TEntity>.Filter.Eq(e => ((ISoftDelete) e).IsDeleted, false));
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
var tenantId = CurrentTenant.Id;
filters.Add(Builders<TEntity>.Filter.Eq(e => ((IMultiTenant) e).TenantId, tenantId));
}
}
}
public class MongoDbRepositoryFilterer<TEntity, TKey> : MongoDbRepositoryFilterer<TEntity>,
IMongoDbRepositoryFilterer<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public MongoDbRepositoryFilterer(IDataFilter dataFilter, ICurrentTenant currentTenant)
: base(dataFilter, currentTenant)
{
}
public FilterDefinition<TEntity> CreateEntityFilter(TKey id, bool applyFilters = false)
{
var filters = new List<FilterDefinition<TEntity>>
{
Builders<TEntity>.Filter.Eq(e => e.Id, id)
};
if (applyFilters)
{
AddGlobalFilters(filters);
}
return Builders<TEntity>.Filter.And(filters);
}
public FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null)
{
if (!withConcurrencyStamp || !(entity is IHasConcurrencyStamp entityWithConcurrencyStamp))
{
return Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id);
}
if (concurrencyStamp == null)
{
concurrencyStamp = entityWithConcurrencyStamp.ConcurrencyStamp;
}
return Builders<TEntity>.Filter.And(
Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id),
Builders<TEntity>.Filter.Eq(e => ((IHasConcurrencyStamp) e).ConcurrencyStamp, concurrencyStamp)
);
}
}
}

11
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.Modularity;
using Volo.Abp.Uow.MongoDB;
@ -14,6 +15,16 @@ namespace Volo.Abp.MongoDB
typeof(IMongoDbContextProvider<>),
typeof(UnitOfWorkMongoDbContextProvider<>)
);
context.Services.TryAddTransient(
typeof(IMongoDbRepositoryFilterer<>),
typeof(MongoDbRepositoryFilterer<>)
);
context.Services.TryAddTransient(
typeof(IMongoDbRepositoryFilterer<,>),
typeof(MongoDbRepositoryFilterer<,>)
);
}
}
}

24
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController.cs

@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Shouldly;
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.Validation
{
@ -31,6 +32,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
{
return Content("ModelState.IsValid: " + ModelState.IsValid.ToString().ToLowerInvariant());
}
[HttpGet]
[Route("object-result-action-dynamic-length")]
public Task<string> ObjectResultActionDynamicLength(ValidationDynamicTestModel model)
{
ModelState.IsValid.ShouldBeTrue(); //AbpValidationFilter throws exception otherwise
return Task.FromResult(model.Value1);
}
public class ValidationTest1Model
{
@ -38,6 +47,18 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
[StringLength(5, MinimumLength = 2)]
public string Value1 { get; set; }
}
public class ValidationDynamicTestModel
{
[DynamicStringLength(typeof(Consts), nameof(Consts.MaxValue2Length), nameof(Consts.MinValue2Length))]
public string Value1 { get; set; }
public static class Consts
{
public static int MinValue2Length { get; set; } = 2;
public static int MaxValue2Length { get; set; } = 7;
}
}
public class CustomValidateModel : IValidatableObject
{
@ -51,6 +72,5 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
}
}
}
}
}
}

16
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs

@ -58,5 +58,21 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
result.Error.ValidationErrors.ShouldContain(x => x.Message == "Value1 should be hello");
}
[Fact]
public async Task Should_Validate_Dynamic_Length_Object_Result_Success()
{
var result = await GetResponseAsStringAsync("/api/validation-test/object-result-action-dynamic-length?value1=hello");
result.ShouldBe("hello");
}
[Fact]
public async Task Should_Validate_Dynamic_Length_Object_Result_Failing()
{
var result = await GetResponseAsObjectAsync<RemoteServiceErrorResponse>("/api/validation-test/object-result-action-dynamic-length?value1=a", HttpStatusCode.BadRequest); //value1 has min length of 2 chars.
result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0);
result = await GetResponseAsObjectAsync<RemoteServiceErrorResponse>("/api/validation-test/object-result-action-dynamic-length?value1=12345678", HttpStatusCode.BadRequest); //value1 has max length of 7 chars.
result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0);
}
}
}

26
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppEntityWithAuditedAndHasCustomAuditingProperties.cs

@ -0,0 +1,26 @@
using System;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Auditing.App.Entities
{
[Audited]
public class AppEntityWithAuditedAndHasCustomAuditingProperties : AggregateRoot<Guid>
{
protected AppEntityWithAuditedAndHasCustomAuditingProperties()
{
}
public AppEntityWithAuditedAndHasCustomAuditingProperties(Guid id)
: base(id)
{
}
public DateTime? CreationTime { get; set; }
public Guid? CreatorId { get; set; }
public DateTime? LastModificationTime { get; set; }
public Guid? LastModifierId { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletionTime { get; set; }
public Guid? DeleterId { get; set; }
}
}

21
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/Entities/AppFullAuditedEntityWithAudited.cs

@ -0,0 +1,21 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Volo.Abp.Auditing.App.Entities
{
[Audited]
public class AppFullAuditedEntityWithAudited : FullAuditedAggregateRoot<Guid>
{
protected AppFullAuditedEntityWithAudited()
{
}
public AppFullAuditedEntityWithAudited(Guid id, string name)
: base(id)
{
Name = name;
}
public string Name { get; set; }
}
}

4
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/App/EntityFrameworkCore/AbpAuditingTestDbContext.cs

@ -17,6 +17,10 @@ namespace Volo.Abp.Auditing.App.EntityFrameworkCore
public DbSet<AppEntityWithPropertyHasAudited> AppEntityWithPropertyHasAudited { get; set; }
public DbSet<AppEntityWithSelector> AppEntityWithSelector { get; set; }
public DbSet<AppFullAuditedEntityWithAudited> AppFullAuditedEntityWithAudited { get; set; }
public DbSet<AppEntityWithAuditedAndHasCustomAuditingProperties> AppEntityWithAuditedAndHasCustomAuditingProperties { get; set; }
public AbpAuditingTestDbContext(DbContextOptions<AbpAuditingTestDbContext> options)
: base(options)

59
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
@ -215,5 +216,63 @@ namespace Volo.Abp.Auditing
#pragma warning restore 4014
}
private static List<string> GetBaseAuditPropertyNames()
{
return new List<string>
{
nameof(IHasCreationTime.CreationTime),
nameof(IMustHaveCreator.CreatorId),
nameof(IHasModificationTime.LastModificationTime),
nameof(IModificationAuditedObject.LastModifierId),
nameof(ISoftDelete.IsDeleted),
nameof(IHasDeletionTime.DeletionTime),
nameof(IDeletionAuditedObject.DeleterId)
};
}
[Fact]
public virtual async Task Should_Write_AuditLog_Ignoring_Base_Auditing_Properties_For_Entity_That_Has_Audited_Attribute()
{
using (var scope = _auditingManager.BeginScope())
{
var repository = ServiceProvider.GetRequiredService<IBasicRepository<AppFullAuditedEntityWithAudited, Guid>>();
await repository.InsertAsync(new AppFullAuditedEntityWithAudited(Guid.NewGuid(), "test name"));
await scope.SaveAsync();
}
#pragma warning disable 4014
_auditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 1
&& x.EntityChanges[0].PropertyChanges.Any(y =>
!GetBaseAuditPropertyNames().Contains(y.PropertyName))));
#pragma warning restore 4014
}
[Fact]
public virtual async Task Should_Write_AuditLog_Including_Custom_Base_Auditing_Properties_For_Entity_That_Has_Audited_Attribute()
{
using (var scope = _auditingManager.BeginScope())
{
var repository = ServiceProvider.GetRequiredService<IBasicRepository<AppEntityWithAuditedAndHasCustomAuditingProperties, Guid>>();
await repository.InsertAsync(new AppEntityWithAuditedAndHasCustomAuditingProperties(Guid.NewGuid())
{
CreationTime = DateTime.Now,
CreatorId = Guid.NewGuid(),
LastModificationTime = DateTime.Now,
LastModifierId = Guid.NewGuid(),
IsDeleted = true,
DeletionTime = DateTime.Now,
DeleterId = Guid.NewGuid()
});
await scope.SaveAsync();
}
#pragma warning disable 4014
_auditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 1
&& x.EntityChanges[0].PropertyChanges
.Where(y => y.PropertyName != nameof(AppEntityWithAuditedAndHasCustomAuditingProperties
.ExtraProperties))
.All(y => GetBaseAuditPropertyNames().Contains(y.PropertyName))));
#pragma warning restore 4014
}
}
}

57
framework/test/Volo.Abp.BlobStoring.Azure.Tests/Volo/Abp/BlobStoring/Azure/DefaultAzureBlobNamingNormalizerProvider_Tests.cs

@ -0,0 +1,57 @@
using Shouldly;
using Xunit;
namespace Volo.Abp.BlobStoring.Azure
{
public class DefaultAzureBlobNamingNormalizerProvider_Tests : AbpBlobStoringAzureTestCommonBase
{
private readonly IBlobNamingNormalizer _blobNamingNormalizer;
public DefaultAzureBlobNamingNormalizerProvider_Tests()
{
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>();
}
[Fact]
public void NormalizeContainerName_Lowercase()
{
var filename = "ThisIsMyContainerName";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe("thisismycontainername");
}
[Fact]
public void NormalizeContainerName_Only_Letters_Numbers_Dash()
{
var filename = ",./this-i,./s-my-c,./ont,./ai+*/.=!@#$n^&*er-name.+/";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe("this-is-my-container-name");
}
[Fact]
public void NormalizeContainerName_Dash()
{
var filename = "-this--is----my-container----name-";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe("this-is-my-container-name");
}
[Fact]
public void NormalizeContainerName_Min_Length()
{
var filename = "a";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.Length.ShouldBeGreaterThanOrEqualTo(3);
}
[Fact]
public void NormalizeContainerName_Max_Length()
{
var filename = "abpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabp";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.Length.ShouldBeLessThanOrEqualTo(63);
}
}
}

62
framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/DefaultFileSystemBlobNamingNormalizerProvider_Tests.cs

@ -0,0 +1,62 @@
using System.Runtime;
using System.Runtime.InteropServices;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Shouldly;
using Xunit;
namespace Volo.Abp.BlobStoring.FileSystem
{
public class DefaultFileSystemBlobNamingNormalizerProvider_Tests : AbpBlobStoringFileSystemTestBase
{
private readonly IBlobNamingNormalizer _blobNamingNormalizer;
public DefaultFileSystemBlobNamingNormalizerProvider_Tests()
{
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
var _iosPlatformProvider = Substitute.For<IOSPlatformProvider>();
_iosPlatformProvider.GetCurrentOSPlatform().Returns(OSPlatform.Windows);
services.AddSingleton(_iosPlatformProvider);
}
[Fact]
public void NormalizeContainerName()
{
var filename = "thisismy:*?\"<>|foldername";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe("thisismyfoldername");
}
[Fact]
public void NormalizeBlobName()
{
var filename = "thisismy:*?\"<>|filename";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe("thisismyfilename");
}
[Theory]
[InlineData("/")]
[InlineData("\\")]
public void NormalizeContainerName_With_Directory(string delimiter)
{
var filename = $"thisis{delimiter}my:*?\"<>|{delimiter}foldername";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe($"thisis{delimiter}my{delimiter}foldername");
}
[Theory]
[InlineData("/")]
[InlineData("\\")]
public void NormalizeBlobName_With_Directory(string delimiter)
{
var filename = $"thisis{delimiter}my:*?\"<>|{delimiter}filename";
filename = _blobNamingNormalizer.NormalizeContainerName(filename);
filename.ShouldBe($"thisis{delimiter}my{delimiter}filename");
}
}
}

17
framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo.Abp.Caching.StackExchangeRedis.Tests.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Caching.StackExchangeRedis\Volo.Abp.Caching.StackExchangeRedis.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
</ItemGroup>
</Project>

12
framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisTestBase.cs

@ -0,0 +1,12 @@
using Volo.Abp.Testing;
namespace Volo.Abp.Caching.StackExchangeRedis
{
public abstract class AbpCachingStackExchangeRedisTestBase : AbpIntegratedTest<AbpCachingStackExchangeRedisTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

15
framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpCachingStackExchangeRedisTestModule.cs

@ -0,0 +1,15 @@
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace Volo.Abp.Caching.StackExchangeRedis
{
[DependsOn(
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpTestBaseModule),
typeof(AbpAutofacModule)
)]
public class AbpCachingStackExchangeRedisTestModule : AbpModule
{
}
}

22
framework/test/Volo.Abp.Caching.StackExchangeRedis.Tests/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache_Tests.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.Caching.Distributed;
using Shouldly;
using Xunit;
namespace Volo.Abp.Caching.StackExchangeRedis
{
public class AbpRedisCache_Tests : AbpCachingStackExchangeRedisTestBase
{
private readonly IDistributedCache _distributedCache;
public AbpRedisCache_Tests()
{
_distributedCache = GetRequiredService<IDistributedCache>();
}
[Fact]
public void Should_Replace_RedisCache()
{
(_distributedCache is AbpRedisCache).ShouldBeTrue();
}
}
}

31
framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Testing;
@ -80,7 +81,6 @@ namespace Volo.Abp.Caching
var personCache = GetRequiredService<IDistributedCache<PersonCacheItem>>();
var otherPersonCache = GetRequiredService<IDistributedCache<Sail.Testing.Caching.PersonCacheItem>>();
var cacheKey = Guid.NewGuid().ToString();
const string personName = "john nash";
@ -310,5 +310,34 @@ namespace Volo.Abp.Caching
cacheItem2.ShouldBeNull();
}
[Fact]
public async Task Should_Set_And_Get_Multiple_Items_Async()
{
var personCache = GetRequiredService<IDistributedCache<PersonCacheItem>>();
await personCache.SetManyAsync(new[]
{
new KeyValuePair<string, PersonCacheItem>("john", new PersonCacheItem("John Nash")),
new KeyValuePair<string, PersonCacheItem>("thomas", new PersonCacheItem("Thomas Moore"))
});
var cacheItems = await personCache.GetManyAsync(new[]
{
"john",
"thomas",
"baris" //doesn't exist
});
cacheItems.Length.ShouldBe(3);
cacheItems[0].Key.ShouldBe("john");
cacheItems[0].Value.Name.ShouldBe("John Nash");
cacheItems[1].Key.ShouldBe("thomas");
cacheItems[1].Value.Name.ShouldBe("Thomas Moore");
cacheItems[2].Key.ShouldBe("baris");
cacheItems[2].Value.ShouldBeNull();
(await personCache.GetAsync("john")).Name.ShouldBe("John Nash");
(await personCache.GetAsync("baris")).ShouldBeNull();
}
}
}

5
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json

@ -40,6 +40,9 @@
"DisplayName:Abp.Account.IsSelfRegistrationEnabled": "Is self-registration enabled",
"Description:Abp.Account.IsSelfRegistrationEnabled": "Whether a user can register the account by him or herself.",
"DisplayName:Abp.Account.EnableLocalLogin": "Authenticate with a local account",
"Description:Abp.Account.EnableLocalLogin": "Indicates if the server will allow users to authenticate with a local account."
"Description:Abp.Account.EnableLocalLogin": "Indicates if the server will allow users to authenticate with a local account.",
"LoggedOutTitle": "Signed Out",
"LoggedOutText": "You have been signed out and you will be redirected soon.",
"ReturnToText": "Click here to redirect to {0}"
}
}

7
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json

@ -40,6 +40,9 @@
"DisplayName:Abp.Account.IsSelfRegistrationEnabled": "self-registration etkin mi ?",
"Description:Abp.Account.IsSelfRegistrationEnabled": "Bir kullanıcının hesabı kendisi tarafından kaydedip kaydedememesidir.",
"DisplayName:Abp.Account.EnableLocalLogin": "Yerel bir hesapla kimlik doğrulaması",
"Description:Abp.Account.EnableLocalLogin": "Sunucunun, kullanıcıların yerel bir hesapla kimlik doğrulamasına izin verip vermeyeceğini belirtir."
"Description:Abp.Account.EnableLocalLogin": "Sunucunun, kullanıcıların yerel bir hesapla kimlik doğrulamasına izin verip vermeyeceğini belirtir.",
"LoggedOutTitle": "Çıkış Yaptınız",
"LoggedOutText": "Çıkış yaptınız ve birazdan yönlendirileceksiniz.",
"ReturnToText": "{0} uygulamasına dönmek için tıklayın."
}
}
}

7
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/RegisterDto.cs

@ -1,22 +1,23 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Auditing;
using Volo.Abp.Identity;
using Volo.Abp.Validation;
namespace Volo.Abp.Account
{
public class RegisterDto
{
[Required]
[StringLength(IdentityUserConsts.MaxUserNameLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))]
public string UserName { get; set; }
[Required]
[EmailAddress]
[StringLength(IdentityUserConsts.MaxEmailLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))]
public string EmailAddress { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[DataType(DataType.Password)]
[DisableAuditing]
public string Password { get; set; }

21
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs

@ -1,6 +1,8 @@
using IdentityServer4.Services;
using System.Security.Claims;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Account.Web.Pages.Account
@ -24,13 +26,20 @@ namespace Volo.Abp.Account.Web.Pages.Account
if (!string.IsNullOrEmpty(logoutId))
{
var logoutContext = await Interaction.GetLogoutContextAsync(logoutId);
await SignInManager.SignOutAsync();
var postLogoutUri = logoutContext.PostLogoutRedirectUri;
HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
if (!string.IsNullOrEmpty(postLogoutUri))
LoggedOutModel vm = new LoggedOutModel()
{
return Redirect(postLogoutUri);
}
PostLogoutRedirectUri = logoutContext?.PostLogoutRedirectUri,
ClientName = logoutContext?.ClientName,
SignOutIframeUrl = logoutContext?.SignOutIFrameUrl
};
Logger.LogInformation($"Redirecting to LoggedOut Page...");
return RedirectToPage("./LoggedOut", vm);
}
if (ReturnUrl != null)
@ -38,6 +47,8 @@ namespace Volo.Abp.Account.Web.Pages.Account
return LocalRedirect(ReturnUrl);
}
Logger.LogInformation(
$"IdentityServerSupportedLogoutModel couldn't find postLogoutUri... Redirecting to:/Account/Login..");
return RedirectToPage("/Account/Login");
}
}

27
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49583/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.Account.Web.IdentityServer": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:49584/"
}
}
}

2
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj

@ -21,8 +21,6 @@
<EmbeddedResource Include="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Properties\launchSettings.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
<ItemGroup>

31
modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.cshtml

@ -0,0 +1,31 @@
@page "/Account/LoggedOut"
@model Volo.Abp.Account.Web.Pages.Account.LoggedOutModel
@using Volo.Abp.Account.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.Account.Web.Pages.Account
@inject IHtmlLocalizer<AccountResource> L
@section scripts {
<abp-script-bundle name="@typeof(LoggedOutModel).FullName">
<abp-script src="/Pages/Account/LoggedOut.js"/>
</abp-script-bundle>
}
@section styles {
<abp-style src="/Pages/Account/LoggedOut.css"/>
}
<abp-card>
<abp-card-body>
<abp-card-title>@L["LoggedOutTitle"]</abp-card-title>
<abp-card-text>@L["LoggedOutText"]</abp-card-text>
@if (Model.PostLogoutRedirectUri != null)
{
<a abp-button="Primary" id="redirectButton" href="@Model.PostLogoutRedirectUri">@L["ReturnToText", Model.ClientName]</a>
}
@if (Model.SignOutIframeUrl != null)
{
<iframe class="signout logoutiframe" src="@Model.SignOutIframeUrl"></iframe>
}
</abp-card-body>
</abp-card>

30
modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.cshtml.cs

@ -0,0 +1,30 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Volo.Abp.Account.Web.Pages.Account
{
public class LoggedOutModel : AccountPageModel
{
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ClientName { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string SignOutIframeUrl { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string PostLogoutRedirectUri { get; set; }
public virtual Task<IActionResult> OnGetAsync()
{
return Task.FromResult<IActionResult>(Page());
}
public virtual Task<IActionResult> OnPostAsync()
{
return Task.FromResult<IActionResult>(Page());
}
}
}

5
modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.css

@ -0,0 +1,5 @@
.logoutiframe {
display: none;
width:0;
height: 0;
}

5
modules/account/src/Volo.Abp.Account.Web/Pages/Account/LoggedOut.js

@ -0,0 +1,5 @@
document.addEventListener("DOMContentLoaded", function (event) {
setTimeout(function () {
window.location = document.getElementById("redirectButton").getAttribute("href");
}, 3000)
});

4
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs

@ -254,11 +254,11 @@ namespace Volo.Abp.Account.Web.Pages.Account
public class LoginInputModel
{
[Required]
[StringLength(IdentityUserConsts.MaxEmailLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))]
public string UserNameOrEmailAddress { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[DataType(DataType.Password)]
[DisableAuditing]
public string Password { get; set; }

18
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Validation;
namespace Volo.Abp.Account.Web.Pages.Account
{
@ -36,44 +37,45 @@ namespace Volo.Abp.Account.Web.Pages.Account
public class ChangePasswordInfoModel
{
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[Display(Name = "DisplayName:CurrentPassword")]
[DataType(DataType.Password)]
public string CurrentPassword { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[Display(Name = "DisplayName:NewPassword")]
[DataType(DataType.Password)]
public string NewPassword { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[Display(Name = "DisplayName:NewPasswordConfirm")]
[DataType(DataType.Password)]
public string NewPasswordConfirm { get; set; }
}
public class PersonalSettingsInfoModel
{
[Required]
[StringLength(IdentityUserConsts.MaxUserNameLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))]
[Display(Name = "DisplayName:UserName")]
public string UserName { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxEmailLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))]
[Display(Name = "DisplayName:Email")]
public string Email { get; set; }
[StringLength(IdentityUserConsts.MaxNameLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxNameLength))]
[Display(Name = "DisplayName:Name")]
public string Name { get; set; }
[StringLength(IdentityUserConsts.MaxSurnameLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxSurnameLength))]
[Display(Name = "DisplayName:Surname")]
public string Surname { get; set; }
[StringLength(IdentityUserConsts.MaxPhoneNumberLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))]
[Display(Name = "DisplayName:PhoneNumber")]
public string PhoneNumber { get; set; }
}

7
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs

@ -9,6 +9,7 @@ using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;
using Volo.Abp.Settings;
using Volo.Abp.Uow;
using Volo.Abp.Validation;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace Volo.Abp.Account.Web.Pages.Account
@ -74,16 +75,16 @@ namespace Volo.Abp.Account.Web.Pages.Account
public class PostInput
{
[Required]
[StringLength(IdentityUserConsts.MaxUserNameLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))]
public string UserName { get; set; }
[Required]
[EmailAddress]
[StringLength(IdentityUserConsts.MaxEmailLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxEmailLength))]
public string EmailAddress { get; set; }
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPasswordLength))]
[DataType(DataType.Password)]
[DisableAuditing]
public string Password { get; set; }

27
modules/account/src/Volo.Abp.Account.Web/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56009/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.Account.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:56013/"
}
}
}

2
modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj

@ -25,8 +25,6 @@
<Content Remove="Modules\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="Properties\launchSettings.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
<ItemGroup>

27
modules/blogging/src/Volo.Blogging.Admin.Web/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50000/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Blogging.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:50014/"
}
}
}

1
modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.csproj

@ -28,7 +28,6 @@
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
</ItemGroup>
</Project>

27
modules/blogging/src/Volo.Blogging.Web/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50000/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Blogging.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:50014/"
}
}
}

2
modules/blogging/src/Volo.Blogging.Web/Volo.Blogging.Web.csproj

@ -28,9 +28,7 @@
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
<None Include="compilerconfig.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
</Project>

27
modules/client-simulation/src/Volo.ClientSimulation.Web/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:51023/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.ClientSimulation.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:51024/"
}
}
}

2
modules/client-simulation/src/Volo.ClientSimulation.Web/Volo.ClientSimulation.Web.csproj

@ -27,9 +27,7 @@
<Content Remove="Pages\**\*.css" />
<Content Remove="Pages\**\*.scss" />
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
<None Include="compilerconfig.json" />
<None Include="Properties\launchSettings.json" />
</ItemGroup>
</Project>

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

Loading…
Cancel
Save