Browse Source

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

pull/4228/head
maliming 8 years ago
parent
commit
e4331645f8
  1. 14
      .dockerignore
  2. 2
      abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
  3. 28
      abp_io/src/Volo.AbpWebSite.Web/CorrelationIdLogEventEnricher.cs
  4. 31
      abp_io/src/Volo.AbpWebSite.Web/Program.cs
  5. 10
      abp_io/src/Volo.AbpWebSite.Web/Startup.cs
  6. 2
      abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
  7. 50
      build/build.ps1
  8. 28
      docker/docker-compose.yml
  9. 1
      docker/down.ps1
  10. 18
      docker/haproxy.cfg
  11. 8
      docker/up.ps1
  12. 3
      docs/en/Audit-Logging.md
  13. 21
      docs/en/Getting-Started-AspNetCore-Application.md
  14. 1408
      docs/en/Samples/Microservice-Demo.md
  15. BIN
      docs/en/images/microservice-sample-authserver-home.png
  16. BIN
      docs/en/images/microservice-sample-authserver-login.png
  17. BIN
      docs/en/images/microservice-sample-backend-ui-permissions.png
  18. BIN
      docs/en/images/microservice-sample-backend-ui.png
  19. BIN
      docs/en/images/microservice-sample-blogservice-permission-in-database.png
  20. BIN
      docs/en/images/microservice-sample-kibana-1.png
  21. BIN
      docs/en/images/microservice-sample-kibana-2.png
  22. BIN
      docs/en/images/microservice-sample-product-module-in-solution.png
  23. BIN
      docs/en/images/microservice-sample-public-product-list.png
  24. BIN
      docs/en/images/microservice-sample-solution.png
  25. 3
      docs/zh-Hans/Domain-Services.md
  26. 3
      docs/zh-Hans/Dynamic-Proxying-Interceptors.md
  27. 3
      docs/zh-Hans/Guid-Generation.md
  28. 3
      docs/zh-Hans/Unit-Of-Work.md
  29. 3
      docs/zh-Hans/Validation.md
  30. 11
      docs/zh-Hans/docs-nav.json
  31. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  32. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
  33. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs
  34. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClientExtensions.cs
  35. 70
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs
  36. 33
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs
  37. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
  38. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationSettingConfigurationDto.cs
  39. 88
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs
  40. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbItemTagHelperService.cs
  41. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselItemTagHelperService.cs
  42. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
  43. 27
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
  44. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownTagHelperService.cs
  45. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/ModelExplorerExtensions.cs
  46. 25
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperAttributeExtensions.cs
  47. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperContextExtensions.cs
  48. 41
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs
  49. 18
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperOutputExtensions.cs
  50. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  51. 65
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  52. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs
  53. 53
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  54. 44
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs
  55. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs
  56. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs
  57. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelper.cs
  58. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelperService.cs
  59. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
  60. 14
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Popover/AbpPopoverTagHelperService.cs
  61. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs
  62. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs
  63. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs
  64. 37
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs
  65. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  66. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs
  67. 37
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs
  68. 13
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
  69. 1
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs
  70. 2
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs
  71. 58
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs
  72. 52
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdProvider.cs
  73. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs
  74. 6
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs
  75. 13
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs
  76. 1
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs
  77. 11
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs
  78. 35
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs
  79. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs
  80. 14
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs
  81. 31
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs
  82. 11
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs
  83. 15
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheNameAttribute.cs
  84. 32
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  85. 9
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/CorrelationIdOptions.cs
  86. 18
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/DefaultCorrelationIdProvider.cs
  87. 10
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/ICorrelationIdProvider.cs
  88. 43
      framework/src/Volo.Abp.Data/Volo/Abp/Data/HasExtraPropertiesExtensions.cs
  89. 1
      framework/src/Volo.Abp.Ddd.Application/Volo.Abp.Ddd.Application.csproj
  90. 17
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/AbpDddApplicationModule.cs
  91. 2
      framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs
  92. 8
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs
  93. 101
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs
  94. 3
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs
  95. 10
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs
  96. 10
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSenderConfiguration.cs
  97. 26
      framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs
  98. 35
      framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs
  99. 1
      framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj
  100. 9
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs

14
.dockerignore

@ -0,0 +1,14 @@
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
.env
*/bin
*/obj
README.md
LICENSE
.vscode
.vs

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

@ -140,6 +140,8 @@ namespace Volo.AbpWebSite
var app = context.GetApplicationBuilder(); var app = context.GetApplicationBuilder();
var env = context.GetEnvironment(); var env = context.GetEnvironment();
app.UseCorrelationId();
app.UseAbpRequestLocalization(); app.UseAbpRequestLocalization();
if (env.IsDevelopment()) if (env.IsDevelopment())

28
abp_io/src/Volo.AbpWebSite.Web/CorrelationIdLogEventEnricher.cs

@ -0,0 +1,28 @@
using Serilog.Core;
using Serilog.Events;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Tracing;
namespace Volo.AbpWebSite
{
//This is for trial for now
public class CorrelationIdLogEventEnricher : ILogEventEnricher, ITransientDependency
{
private readonly ICorrelationIdProvider _correlationIdProvider;
public CorrelationIdLogEventEnricher(ICorrelationIdProvider correlationIdProvider)
{
_correlationIdProvider = correlationIdProvider;
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
logEvent.AddOrUpdateProperty(
new LogEventProperty(
"CorrelationId",
new ScalarValue("CorrId:" + _correlationIdProvider.Get())
)
);
}
}
}

31
abp_io/src/Volo.AbpWebSite.Web/Program.cs

@ -1,13 +1,37 @@
using System.IO; using System;
using System.IO;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Serilog;
using Serilog.Events;
namespace Volo.AbpWebSite namespace Volo.AbpWebSite
{ {
public class Program public class Program
{ {
public static void Main(string[] args) public static int Main(string[] args)
{ {
BuildWebHostInternal(args).Run(); Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() //TODO: Should be configurable!
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.File("Logs/logs.txt")
.CreateLogger();
try
{
Log.Information("Starting web host.");
BuildWebHostInternal(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
} }
internal static IWebHost BuildWebHostInternal(string[] args) => internal static IWebHost BuildWebHostInternal(string[] args) =>
@ -16,6 +40,7 @@ namespace Volo.AbpWebSite
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration() .UseIISIntegration()
.UseStartup<Startup>() .UseStartup<Startup>()
.UseSerilog()
.Build(); .Build();
} }
} }

10
abp_io/src/Volo.AbpWebSite.Web/Startup.cs

@ -3,7 +3,6 @@ using System.Text;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Serilog;
using Volo.Abp; using Volo.Abp;
namespace Volo.AbpWebSite namespace Volo.AbpWebSite
@ -23,15 +22,6 @@ namespace Volo.AbpWebSite
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{ {
loggerFactory
.AddConsole()
.AddDebug()
.AddSerilog(new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.File("Logs/logs.txt")
.CreateLogger()
);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
app.InitializeApplication(); app.InitializeApplication();

2
abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj

@ -15,7 +15,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" /> <PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
</ItemGroup> </ItemGroup>

50
build/build.ps1

@ -1,50 +0,0 @@
# COMMON PATHS
$buildFolder = (Get-Item -Path "./" -Verbose).FullName
$slnFolder = Join-Path $buildFolder "../"
$outputFolder = Join-Path $buildFolder "outputs"
$abpDeskFolder = Join-Path $slnFolder "src/AbpDesk"
$abpDeskWebFolder = Join-Path $abpDeskFolder "AbpDesk.Web.Mvc"
## CLEAR ######################################################################
Remove-Item $outputFolder -Force -Recurse
New-Item -Path $outputFolder -ItemType Directory
## RESTORE NUGET PACKAGES #####################################################
Set-Location $slnFolder
dotnet restore
## PUBLISH ASPDESK WEB ########################################################
Set-Location $abpDeskWebFolder
dotnet publish --output (Join-Path $outputFolder "AbpDesk/Web")
New-Item -Path (Join-Path $outputFolder "AbpDesk/Web/PlugIns") -ItemType Directory
Copy-Item (Join-Path $abpDeskFolder "Web_PlugIns/*") (Join-Path $outputFolder "AbpDesk/Web/PlugIns/")
## PUBLISH IDENTITY HTTP API HOST #############################################
Set-Location (Join-Path $slnFolder "src/Volo.Abp.Identity.HttpApi.Host")
dotnet publish --output (Join-Path $outputFolder "AbpIdentity/HttpApiHost")
## CREATE DOCKER IMAGES #######################################################
Set-Location (Join-Path $outputFolder "AbpDesk/Web")
docker rmi abpdesk/web -f
docker build -t abpdesk/web .
Set-Location (Join-Path $outputFolder "AbpIdentity/HttpApiHost")
docker rmi abpidentity/httpapihost -f
docker build -t abpidentity/httpapihost .
## DOCKER COMPOSE FILES #######################################################
Copy-Item (Join-Path $slnFolder "docker/*.*") $outputFolder
## FINALIZE ###################################################################
Set-Location $outputFolder

28
docker/docker-compose.yml

@ -1,28 +0,0 @@
version: '2'
services:
mongodb:
image: tutum/mongodb
environment:
- AUTH=no
ports:
- "27017:27017"
- "28017:28017"
abpidentity_httpapihost:
image: abpidentity/httpapihost
environment:
- ASPNETCORE_ENVIRONMENT=Staging
abpdesk_web:
image: abpdesk/web
environment:
- ASPNETCORE_ENVIRONMENT=Staging
load_balancer:
image: haproxy:1.7.1
volumes:
- "./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg"
ports:
- "9005:8080"

1
docker/down.ps1

@ -1 +0,0 @@
docker-compose down -v --rmi local

18
docker/haproxy.cfg

@ -1,18 +0,0 @@
global
maxconn 4096
defaults
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
listen http-in
bind *:8080
server web-1 outputs_abpdesk_web_1:80
server web-2 outputs_abpdesk_web_2:80
stats enable
stats uri /haproxy
stats refresh 1s

8
docker/up.ps1

@ -1,8 +0,0 @@
docker rm $(docker ps -aq)
docker-compose up -d mongodb
docker-compose up -d abpidentity_httpapihost
docker-compose up -d abpdesk_web
sleep 2
docker-compose scale abpdesk_web=2
sleep 2
docker-compose up -d load_balancer

3
docs/en/Audit-Logging.md

@ -0,0 +1,3 @@
# Audit Logging
TODO

21
docs/en/Getting-Started-AspNetCore-Application.md

@ -152,6 +152,27 @@ services.AddApplication<AppModule>(options =>
}); });
```` ````
4. Update `Program.cs` to not use the `WebHost.CreateDefaultBuilder()` method since it uses the default DI container:
````csharp
public class Program
{
public static void Main(string[] args)
{
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
````
## Source Code ## Source Code
Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication). Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication).

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

File diff suppressed because it is too large

BIN
docs/en/images/microservice-sample-authserver-home.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/images/microservice-sample-authserver-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/microservice-sample-backend-ui-permissions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/en/images/microservice-sample-backend-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/en/images/microservice-sample-blogservice-permission-in-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
docs/en/images/microservice-sample-kibana-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
docs/en/images/microservice-sample-kibana-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/en/images/microservice-sample-product-module-in-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/en/images/microservice-sample-public-product-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/images/microservice-sample-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

3
docs/zh-Hans/Domain-Services.md

@ -0,0 +1,3 @@
# ABP Documentation
待添加

3
docs/zh-Hans/Dynamic-Proxying-Interceptors.md

@ -0,0 +1,3 @@
## Dynamic Proxying / Interceptors
待添加

3
docs/zh-Hans/Guid-Generation.md

@ -0,0 +1,3 @@
## Guid 生成
待添加

3
docs/zh-Hans/Unit-Of-Work.md

@ -0,0 +1,3 @@
## Unit of Work
待添加

3
docs/zh-Hans/Validation.md

@ -0,0 +1,3 @@
## Validation
待添加

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

@ -67,7 +67,8 @@
"path": "Exception-Handling.md" "path": "Exception-Handling.md"
}, },
{ {
"text": "验证" "text": "验证",
"path": "Validation.md"
}, },
{ {
"text": "授权" "text": "授权"
@ -160,7 +161,8 @@
"path": "Repositories.md" "path": "Repositories.md"
}, },
{ {
"text": "领域服务" "text": "领域服务",
"path": "Domain-Services.md"
}, },
{ {
"text": "规约" "text": "规约"
@ -178,7 +180,8 @@
"text": "数据传输对象(DTO)" "text": "数据传输对象(DTO)"
}, },
{ {
"text": "工作单元" "text": "工作单元",
"path": "Unit-Of-Work.md"
} }
] ]
} }
@ -189,7 +192,7 @@
"items": [ "items": [
{ {
"text": "API", "text": "API",
"items": [ "items": [
{ {
"text": "自动API控制器", "text": "自动API控制器",
"path": "AspNetCore/Auto-API-Controllers.md" "path": "AspNetCore/Auto-API-Controllers.md"

1
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj

@ -17,6 +17,7 @@
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj" /> <ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" /> <ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" /> <ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

9
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.Http.Client; using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Client namespace Volo.Abp.AspNetCore.Mvc.Client
@ -8,7 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
[DependsOn( [DependsOn(
typeof(AbpHttpClientModule), typeof(AbpHttpClientModule),
typeof(AbpAspNetCoreMvcContractsModule), typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpCachingModule) typeof(AbpCachingModule),
typeof(AbpLocalizationModule)
)] )]
public class AbpAspNetCoreMvcClientModule : AbpModule public class AbpAspNetCoreMvcClientModule : AbpModule
{ {
@ -21,6 +23,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
RemoteServiceName, RemoteServiceName,
asDefaultServices: false asDefaultServices: false
); );
Configure<AbpLocalizationOptions>(options =>
{
options.GlobalContributors.Add<RemoteLocalizationContributor>();
});
} }
} }
} }

5
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Globalization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
@ -45,7 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
async () => await Proxy.Service.GetAsync(), async () => await Proxy.Service.GetAsync(),
() => new DistributedCacheEntryOptions () => new DistributedCacheEntryOptions
{ {
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5) AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60) //TODO: Should be configurable. Default value should be higher (5 mins would be good).
} }
); );
@ -59,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
protected virtual string CreateCacheKey() protected virtual string CreateCacheKey()
{ {
return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}"; return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}_{CultureInfo.CurrentUICulture.Name}";
} }
} }
} }

13
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClientExtensions.cs

@ -0,0 +1,13 @@
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public static class CachedApplicationConfigurationClientExtensions
{
public static ApplicationConfigurationDto Get(this ICachedApplicationConfigurationClient client)
{
return AsyncHelper.RunSync(client.GetAsync);
}
}
}

70
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs

@ -0,0 +1,70 @@
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class RemoteLocalizationContributor : ILocalizationResourceContributor
{
private LocalizationResource _resource;
private ICachedApplicationConfigurationClient _applicationConfigurationClient;
private ILogger<RemoteLocalizationContributor> _logger;
public void Initialize(LocalizationResourceInitializationContext context)
{
_resource = context.Resource;
_applicationConfigurationClient = context.ServiceProvider.GetRequiredService<ICachedApplicationConfigurationClient>();
_logger = context.ServiceProvider.GetService<ILogger<RemoteLocalizationContributor>>()
?? NullLogger<RemoteLocalizationContributor>.Instance;
}
public LocalizedString GetOrNull(string cultureName, string name)
{
var resource = GetResourceOrNull();
if (resource == null)
{
return null;
}
var value = resource.GetOrDefault(name);
if (value == null)
{
return null;
}
return new LocalizedString(name, value);
}
public void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary)
{
var resource = GetResourceOrNull();
if (resource == null)
{
return;
}
foreach (var keyValue in resource)
{
dictionary[keyValue.Key] = new LocalizedString(keyValue.Key, keyValue.Value);
}
}
private Dictionary<string, string> GetResourceOrNull()
{
var resource = _applicationConfigurationClient
.Get()
.Localization.Values
.GetOrDefault(_resource.ResourceName);
if (resource == null)
{
_logger.LogWarning($"Could not find the localization resource {_resource.ResourceName} on the remote server!");
}
return resource;
}
}
}

33
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs

@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class RemoteSettingProvider : ISettingProvider, ITransientDependency
{
protected ICachedApplicationConfigurationClient ConfigurationClient { get; }
public RemoteSettingProvider(ICachedApplicationConfigurationClient configurationClient)
{
ConfigurationClient = configurationClient;
}
public async Task<string> GetOrNullAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return configuration.Setting.Values.GetOrDefault(name);
}
public async Task<List<SettingValue>> GetAllAsync()
{
var configuration = await ConfigurationClient.GetAsync();
return configuration
.Setting.Values
.Select(s => new SettingValue(s.Key, s.Value))
.ToList();
}
}
}

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

@ -9,6 +9,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
public ApplicationAuthConfigurationDto Auth { get; set; } public ApplicationAuthConfigurationDto Auth { get; set; }
public ApplicationSettingConfigurationDto Setting { get; set; }
public CurrentUserDto CurrentUser { get; set; } public CurrentUserDto CurrentUser { get; set; }
} }
} }

11
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationSettingConfigurationDto.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
[Serializable]
public class ApplicationSettingConfigurationDto
{
public Dictionary<string, string> Values { get; set; }
}
}

88
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperService.cs

@ -56,93 +56,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers
Process(context, output); Process(context, output);
return Task.CompletedTask; return Task.CompletedTask;
} }
protected virtual TagHelperOutput GetInnerTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{
TagMode = tagMode
};
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync)
{
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));
}
else
{
tagHelper.Process(innerContext, innerOutput);
}
return innerOutput;
}
protected virtual string RenderTagHelper(TagHelperAttributeList attributeList, TagHelperContext context, TagHelper tagHelper, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = GetInnerTagHelper(attributeList, context, tagHelper, tagName, tagMode, runAsync);
return RenderTagHelperOutput(innerOutput, htmlEncoder);
}
protected virtual string RenderTagHelperOutput(TagHelperOutput output, HtmlEncoder htmlEncoder)
{
using (var writer = new StringWriter())
{
output.WriteTo(writer, htmlEncoder);
return writer.ToString();
}
}
protected virtual T GetAttribute<T>(ModelExplorer property) where T : Attribute
{
return property?.Metadata?.ContainerType?.GetTypeInfo()?.GetProperty(property.Metadata.PropertyName)?.GetCustomAttribute<T>();
}
protected virtual List<FormGroupItem> GetFormGroupContentsList(TagHelperContext context, out bool surpress)
{
var items = GetValueFromContext<List<FormGroupItem>>(context, FormGroupContents);
surpress = items != null;
return items ?? new List<FormGroupItem>();
}
protected virtual T GetValueFromContext<T>(TagHelperContext context, string key)
{
if (!context.Items.ContainsKey(key))
{
return default(T);
}
return (T)context.Items[key];
}
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual int GetInputOrder(ModelExplorer explorer)
{
return GetAttribute<DisplayOrder>(explorer)?.Number ?? DisplayOrder.Default;
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = GetFormGroupContentsList(context, out surpress);
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
} }
} }

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbItemTagHelperService.cs

@ -2,6 +2,7 @@
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
{ {
@ -20,13 +21,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
output.Attributes.AddClass("breadcrumb-item"); output.Attributes.AddClass("breadcrumb-item");
output.Attributes.AddClass(AbpBreadcrumbItemActivePlaceholder); output.Attributes.AddClass(AbpBreadcrumbItemActivePlaceholder);
var list = GetValueFromContext<List<BreadcrumbItem>>(context, BreadcrumbItemsContent); var list = context.GetValue<List<BreadcrumbItem>>(BreadcrumbItemsContent);
output.Content.SetHtmlContent(GetInnerHtml(context, output)); output.Content.SetHtmlContent(GetInnerHtml(context, output));
list.Add(new BreadcrumbItem list.Add(new BreadcrumbItem
{ {
Html = RenderTagHelperOutput(output, _encoder), Html = output.Render(_encoder),
Active = TagHelper.Active Active = TagHelper.Active
}); });

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselItemTagHelperService.cs

@ -3,6 +3,7 @@ using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
{ {
@ -32,9 +33,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
private void AddToContext(TagHelperContext context, TagHelperOutput output) private void AddToContext(TagHelperContext context, TagHelperOutput output)
{ {
var getOutputAsHtml = RenderTagHelperOutput(output, _encoder); var getOutputAsHtml = output.Render(_encoder);
var itemList = GetValueFromContext<List<CarouselItem>>(context, CarouselItemsContent); var itemList = context.GetValue<List<CarouselItem>>(CarouselItemsContent);
itemList.Add(new CarouselItem(getOutputAsHtml, TagHelper.Active ?? false)); itemList.Add(new CarouselItem(getOutputAsHtml, TagHelper.Active ?? false));
} }

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{ {
@ -15,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
var html = GetAccordionHeaderItem(context, output) + GetAccordionContentItem(context, output, innerContent); var html = GetAccordionHeaderItem(context, output) + GetAccordionContentItem(context, output, innerContent);
var tabHeaderItems = GetValueFromContext<List<string>>(context, AccordionItems); var tabHeaderItems = context.GetValue<List<string>>(AccordionItems);
tabHeaderItems.Add(html); tabHeaderItems.Add(html);

27
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs

@ -1,10 +1,12 @@
using System; using System;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
{ {
@ -22,22 +24,25 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
public override void Process(TagHelperContext context, TagHelperOutput output) public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{ {
var buttonsAsHtml = GetButtonsAsHtml(context, output); var content = await output.GetChildContentAsync();
var buttonsAsHtml = GetButtonsAsHtml(context, output, content);
output.PreElement.SetHtmlContent(buttonsAsHtml); output.PreElement.SetHtmlContent(buttonsAsHtml);
output.TagName = "div"; output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag; output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetContent("");
output.Attributes.Clear(); output.Attributes.Clear();
} }
protected virtual string GetButtonsAsHtml(TagHelperContext context, TagHelperOutput output) protected virtual string GetButtonsAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperContent content)
{ {
var buttonBuilder = new StringBuilder(""); var buttonBuilder = new StringBuilder("");
var mainButton = GetMainButton(context, output); var mainButton = GetMainButton(context, output, content);
buttonBuilder.AppendLine(mainButton); buttonBuilder.AppendLine(mainButton);
@ -51,10 +56,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
return buttonBuilder.ToString(); return buttonBuilder.ToString();
} }
protected virtual string GetMainButton(TagHelperContext context, TagHelperOutput output) protected virtual string GetMainButton(TagHelperContext context, TagHelperOutput output, TagHelperContent content)
{ {
var abpButtonTagHelper = _serviceProvider.GetRequiredService<AbpButtonTagHelper>(); var abpButtonTagHelper = _serviceProvider.GetRequiredService<AbpButtonTagHelper>();
abpButtonTagHelper.Icon = TagHelper.Icon; abpButtonTagHelper.Icon = TagHelper.Icon;
abpButtonTagHelper.Text = TagHelper.Text; abpButtonTagHelper.Text = TagHelper.Text;
abpButtonTagHelper.IconType = TagHelper.IconType; abpButtonTagHelper.IconType = TagHelper.IconType;
@ -62,15 +67,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType; abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForMainButton(context, output); var attributes = GetAttributesForMainButton(context, output);
var buttonTag = GetInnerTagHelper(attributes, context, abpButtonTagHelper, "button", TagMode.StartTagAndEndTag); var buttonTag = abpButtonTagHelper.ProcessAndGetOutput(attributes, context, "button", TagMode.StartTagAndEndTag);
buttonTag.PreContent.SetHtmlContent(content.GetContent());
if ((TagHelper.NavLink ?? false) || (TagHelper.Link ?? false)) if ((TagHelper.NavLink ?? false) || (TagHelper.Link ?? false))
{ {
var linkTag = ConvertButtonToLink(buttonTag); var linkTag = ConvertButtonToLink(buttonTag);
return RenderTagHelperOutput(linkTag, _htmlEncoder); return linkTag.Render(_htmlEncoder);
} }
return RenderTagHelperOutput(buttonTag, _htmlEncoder); return buttonTag.Render(_htmlEncoder);
} }
protected virtual string GetSplitButton(TagHelperContext context, TagHelperOutput output) protected virtual string GetSplitButton(TagHelperContext context, TagHelperOutput output)
@ -81,7 +88,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
abpButtonTagHelper.ButtonType = TagHelper.ButtonType; abpButtonTagHelper.ButtonType = TagHelper.ButtonType;
var attributes = GetAttributesForSplitButton(context, output); var attributes = GetAttributesForSplitButton(context, output);
return RenderTagHelper(attributes, context, abpButtonTagHelper, _htmlEncoder, "button", TagMode.StartTagAndEndTag); return abpButtonTagHelper.Render(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
} }
protected virtual TagHelperAttributeList GetAttributesForMainButton(TagHelperContext context, TagHelperOutput output) protected virtual TagHelperAttributeList GetAttributesForMainButton(TagHelperContext context, TagHelperOutput output)

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownTagHelperService.cs

@ -8,6 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
output.TagName = "div"; output.TagName = "div";
output.Attributes.AddClass("dropdown");
output.Attributes.AddClass("btn-group"); output.Attributes.AddClass("btn-group");
SetDirection(context, output); SetDirection(context, output);

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/ModelExplorerExtensions.cs

@ -0,0 +1,20 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class ModelExplorerExtensions
{
public static T GetAttribute<T>(this ModelExplorer property) where T : Attribute
{
return property?.Metadata?.ContainerType?.GetTypeInfo()?.GetProperty(property.Metadata.PropertyName)?.GetCustomAttribute<T>();
}
public static int GetDisplayOrder(this ModelExplorer explorer)
{
return GetAttribute<DisplayOrder>(explorer)?.Number ?? DisplayOrder.Default;
}
}
}

25
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperAttributeExtensions.cs

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperAttributeExtensions
{
public static string ToHtmlAttributeAsString(this TagHelperAttribute attribute)
{
return attribute.Name + "=\"" + attribute.Value + "\"";
}
public static string ToHtmlAttributesAsString(this List<TagHelperAttribute> attributes)
{
var attributesAsString = "";
foreach (var attribute in attributes)
{
attributesAsString += attribute.ToHtmlAttributeAsString() + " ";
}
return attributesAsString;
}
}
}

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperContextExtensions.cs

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperContextExtensions
{
public static T GetValue<T>(this TagHelperContext context, string key)
{
if (!context.Items.ContainsKey(key))
{
return default(T);
}
return (T)context.Items[key];
}
}
}

41
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs

@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text.Encodings.Web;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperExtensions
{
public static TagHelperOutput ProcessAndGetOutput(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run<TagHelperContent>(() => new DefaultTagHelperContent()))
{
TagMode = tagMode
};
var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString());
tagHelper.Init(context);
if (runAsync)
{
AsyncHelper.RunSync(() => tagHelper.ProcessAsync(innerContext, innerOutput));
}
else
{
tagHelper.Process(innerContext, innerOutput);
}
return innerOutput;
}
public static string Render(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing, bool runAsync = false)
{
var innerOutput = tagHelper.ProcessAndGetOutput(attributeList, context, tagName, tagMode, runAsync);
return innerOutput.Render(htmlEncoder);
}
}
}

18
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperOutputExtensions.cs

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.IO;
using System.Text.Encodings.Web;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions
{
public static class TagHelperOutputExtensions
{
public static string Render(this TagHelperOutput output, HtmlEncoder htmlEncoder)
{
using (var writer = new StringWriter())
{
output.WriteTo(writer, htmlEncoder);
return writer.ToString();
}
}
}
}

19
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
@ -66,7 +67,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext ViewContext = TagHelper.ViewContext
}; };
var formTagOutput = GetInnerTagHelper(output.Attributes, context, formTagHelper, "form", TagMode.StartTagAndEndTag); var formTagOutput = formTagHelper.ProcessAndGetOutput(output.Attributes, context, "form", TagMode.StartTagAndEndTag);
await formTagOutput.GetChildContentAsync(); await formTagOutput.GetChildContentAsync();
@ -146,7 +147,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
var abpSelectTagHelper = GetSelectGroupTagHelper(context, output, model); var abpSelectTagHelper = GetSelectGroupTagHelper(context, output, model);
RenderTagHelper(new TagHelperAttributeList(), context, abpSelectTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag); abpSelectTagHelper.Render(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
} }
protected virtual AbpTagHelper GetSelectGroupTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model) protected virtual AbpTagHelper GetSelectGroupTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@ -156,7 +157,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
GetSelectTagHelper(model); GetSelectTagHelper(model);
} }
private AbpTagHelper GetSelectTagHelper(ModelExpression model) protected virtual AbpTagHelper GetSelectTagHelper(ModelExpression model)
{ {
var abpSelectTagHelper = _serviceProvider.GetRequiredService<AbpSelectTagHelper>(); var abpSelectTagHelper = _serviceProvider.GetRequiredService<AbpSelectTagHelper>();
abpSelectTagHelper.AspFor = model; abpSelectTagHelper.AspFor = model;
@ -165,9 +166,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return abpSelectTagHelper; return abpSelectTagHelper;
} }
private AbpTagHelper GetAbpRadioInputTagHelper(ModelExpression model) protected virtual AbpTagHelper GetAbpRadioInputTagHelper(ModelExpression model)
{ {
var radioButtonAttribute = GetAttribute<AbpRadioButton>(model.ModelExplorer); var radioButtonAttribute = model.ModelExplorer.GetAttribute<AbpRadioButton>();
var abpRadioInputTagHelper = _serviceProvider.GetRequiredService<AbpRadioInputTagHelper>(); var abpRadioInputTagHelper = _serviceProvider.GetRequiredService<AbpRadioInputTagHelper>();
abpRadioInputTagHelper.AspFor = model; abpRadioInputTagHelper.AspFor = model;
abpRadioInputTagHelper.AspItems = null; abpRadioInputTagHelper.AspItems = null;
@ -184,7 +185,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpButtonTagHelper.Text = "Submit"; abpButtonTagHelper.Text = "Submit";
abpButtonTagHelper.ButtonType = AbpButtonType.Primary; abpButtonTagHelper.ButtonType = AbpButtonType.Primary;
return RenderTagHelper(attributes, context, abpButtonTagHelper, _htmlEncoder, "button", TagMode.StartTagAndEndTag); return abpButtonTagHelper.Render(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);
} }
protected virtual void ProcessInputGroup(TagHelperContext context, TagHelperOutput output, ModelExpression model) protected virtual void ProcessInputGroup(TagHelperContext context, TagHelperOutput output, ModelExpression model)
@ -194,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
abpInputTagHelper.ViewContext = TagHelper.ViewContext; abpInputTagHelper.ViewContext = TagHelper.ViewContext;
abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true; abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true;
RenderTagHelper(new TagHelperAttributeList(), context, abpInputTagHelper, _htmlEncoder, "div", TagMode.StartTagAndEndTag); abpInputTagHelper.Render(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag);
} }
protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output) protected virtual List<ModelExpression> GetModels(TagHelperContext context, TagHelperOutput output)
@ -280,12 +281,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual bool AreSelectItemsProvided(ModelExplorer explorer) protected virtual bool AreSelectItemsProvided(ModelExplorer explorer)
{ {
return GetAttribute<SelectItems>(explorer) != null; return explorer.GetAttribute<SelectItems>() != null;
} }
protected virtual bool IsRadioGroup(ModelExplorer explorer) protected virtual bool IsRadioGroup(ModelExplorer explorer)
{ {
return GetAttribute<AbpRadioButton>(explorer) != null; return explorer.GetAttribute<AbpRadioButton>() != null;
} }
} }
} }

65
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
@ -6,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
@ -26,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
var innerHtml = GetFormInputGroupAsHtml(context, output, out var isCheckbox); var innerHtml = GetFormInputGroupAsHtml(context, output, out var isCheckbox);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer); var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
AddGroupToFormGroupContents( AddGroupToFormGroupContents(
context, context,
@ -45,7 +47,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.TagMode = TagMode.StartTagAndEndTag; output.TagMode = TagMode.StartTagAndEndTag;
output.TagName = "div"; output.TagName = "div";
LeaveOnlyGroupAttributes(context, output); LeaveOnlyGroupAttributes(context, output);
output.Attributes.AddClass(isCheckbox ? "form-check" : "form-group"); output.Attributes.AddClass(isCheckbox ? "custom-checkbox" : "form-group");
output.Attributes.AddClass(isCheckbox ? "custom-control" : "");
output.Attributes.AddClass(isCheckbox ? "mb-2" : ""); output.Attributes.AddClass(isCheckbox ? "mb-2" : "");
output.Content.SetHtmlContent(output.Content.GetContent() + innerHtml); output.Content.SetHtmlContent(output.Content.GetContent() + innerHtml);
} }
@ -54,8 +57,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox) protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output, out bool isCheckbox)
{ {
var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox); var inputTag = GetInputTagHelperOutput(context, output, out isCheckbox);
var inputHtml = RenderTagHelperOutput(inputTag, _encoder); var inputHtml = inputTag.Render(_encoder);
var label = GetLabelAsHtml(context, output, inputTag, isCheckbox); var label = GetLabelAsHtml(context, output, inputTag, isCheckbox);
var info = GetInfoAsHtml(context, output, inputTag, isCheckbox); var info = GetInfoAsHtml(context, output, inputTag, isCheckbox);
var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag); var validation = isCheckbox ? "" : GetValidationAsHtml(context, output, inputTag);
@ -78,7 +81,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } }; var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true); return validationMessageTagHelper.Render(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag, true);
} }
protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox) protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox)
@ -92,14 +95,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox) protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox)
{ {
return "<div class=\"" + (isCheckbox ? "form-check" : "form-group") + "\">" + return "<div class=\"" + (isCheckbox ? "custom-checkbox custom-control" : "form-group") + "\">" +
Environment.NewLine + innerHtml + Environment.NewLine + Environment.NewLine + innerHtml + Environment.NewLine +
"</div>"; "</div>";
} }
protected virtual TagHelper GetInputTagHelper(TagHelperContext context, TagHelperOutput output) protected virtual TagHelper GetInputTagHelper(TagHelperContext context, TagHelperOutput output)
{ {
var textAreaAttribute = GetAttribute<TextArea>(TagHelper.AspFor.ModelExplorer); var textAreaAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<TextArea>();
if (textAreaAttribute != null) if (textAreaAttribute != null)
{ {
@ -121,7 +124,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
var tagHelper = GetInputTagHelper(context, output); var tagHelper = GetInputTagHelper(context, output);
var inputTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, tagHelper, "input"); var inputTagHelperOutput = tagHelper.ProcessAndGetOutput(GetInputAttributes(context, output), context, "input");
ConvertToTextAreaIfTextArea(inputTagHelperOutput); ConvertToTextAreaIfTextArea(inputTagHelperOutput);
AddDisabledAttribute(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput);
@ -141,7 +144,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
if (isCheckbox) if (isCheckbox)
{ {
className = "form-check-input"; className = "custom-control-input";
} }
inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output)); inputTagHelperOutput.Attributes.AddClass(className + " " + GetSize(context, output));
@ -158,7 +161,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{ {
if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false && if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false &&
(TagHelper.IsDisabled || GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer) != null)) (TagHelper.IsDisabled || TagHelper.AspFor.ModelExplorer.GetAttribute<DisabledInput>() != null))
{ {
inputTagHelperOutput.Attributes.Add("disabled", ""); inputTagHelperOutput.Attributes.Add("disabled", "");
} }
@ -167,7 +170,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput)
{ {
if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false && if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false &&
(TagHelper.IsReadonly != false || GetAttribute<ReadOnlyInput>(TagHelper.AspFor.ModelExplorer) != null)) (TagHelper.IsReadonly != false || TagHelper.AspFor.ModelExplorer.GetAttribute<ReadOnlyInput>() != null))
{ {
inputTagHelperOutput.Attributes.Add("readonly", ""); inputTagHelperOutput.Attributes.Add("readonly", "");
} }
@ -180,7 +183,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return; return;
} }
var attribute = GetAttribute<Placeholder>(TagHelper.AspFor.ModelExplorer); var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<Placeholder>();
if (attribute != null) if (attribute != null)
{ {
@ -192,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{ {
if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null) if (TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>() == null)
{ {
return; return;
} }
@ -226,7 +229,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag); return GetLabelAsHtmlUsingTagHelper(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag);
} }
var checkboxClass = isCheckbox ? "class=\"form-check-label\" " : ""; var checkboxClass = isCheckbox ? "class=\"custom-control-label\" " : "";
return "<label " + checkboxClass + GetIdAttributeAsString(inputTag) + ">" return "<label " + checkboxClass + GetIdAttributeAsString(inputTag) + ">"
+ TagHelper.Label + + TagHelper.Label +
@ -240,7 +243,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return ""; return "";
} }
return GetAttribute<RequiredAttribute>(TagHelper.AspFor.ModelExplorer) != null ? "<span> * </span>":""; return TagHelper.AspFor.ModelExplorer.GetAttribute<RequiredAttribute>() != null ? "<span> * </span>":"";
} }
protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox)
@ -263,7 +266,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
} }
else else
{ {
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer); var infoAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>();
if (infoAttribute != null) if (infoAttribute != null)
{ {
text = infoAttribute.Text; text = infoAttribute.Text;
@ -294,15 +297,15 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
if (isCheckbox) if (isCheckbox)
{ {
attributeList.AddClass("form-check-label"); attributeList.AddClass("custom-control-label");
} }
return RenderTagHelper(attributeList, context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true); return labelTagHelper.Render(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag, true);
} }
protected virtual void ConvertToTextAreaIfTextArea(TagHelperOutput tagHelperOutput) protected virtual void ConvertToTextAreaIfTextArea(TagHelperOutput tagHelperOutput)
{ {
var textAreaAttribute = GetAttribute<TextArea>(TagHelper.AspFor.ModelExplorer); var textAreaAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<TextArea>();
if (textAreaAttribute == null) if (textAreaAttribute == null)
{ {
@ -354,7 +357,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{ {
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer); var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<FormControlSize>();
if (attribute != null) if (attribute != null)
{ {
@ -378,5 +381,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden"); return inputTag.Attributes.Any(a => a.Name.ToLowerInvariant() == "type" && a.Value.ToString().ToLowerInvariant() == "hidden");
} }
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
} }
} }

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
@ -24,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var selectItems = GetSelectItems(context,output); var selectItems = GetSelectItems(context,output);
SetSelectedValue(context, output, selectItems); SetSelectedValue(context, output, selectItems);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer); var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
var html = GetHtml(context, output, selectItems); var html = GetHtml(context, output, selectItems);
@ -78,7 +79,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer); return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
} }
var selectItemsAttribute = GetAttribute<SelectItems>(TagHelper.AspFor.ModelExplorer); var selectItemsAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<SelectItems>();
if (selectItemsAttribute != null) if (selectItemsAttribute != null)
{ {
return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer); return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
@ -155,5 +156,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return TagHelper.AspFor.ModelExplorer.Model?.ToString(); return TagHelper.AspFor.ModelExplorer.Model?.ToString();
} }
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
} }
} }

53
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
@ -30,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
var innerHtml = GetFormInputGroupAsHtml(context, output); var innerHtml = GetFormInputGroupAsHtml(context, output);
var order = GetInputOrder(TagHelper.AspFor.ModelExplorer); var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder();
AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, SurroundInnerHtmlAndGet(context, output, innerHtml), order, out var surpress); AddGroupToFormGroupContents(context, TagHelper.AspFor.Name, SurroundInnerHtmlAndGet(context, output, innerHtml), order, out var surpress);
@ -51,7 +52,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output) protected virtual string GetFormInputGroupAsHtml(TagHelperContext context, TagHelperOutput output)
{ {
var selectTag = GetSelectTag(context, output); var selectTag = GetSelectTag(context, output);
var selectAsHtml = RenderTagHelperOutput(selectTag, _encoder); var selectAsHtml = selectTag.Render(_encoder);
var label = GetLabelAsHtml(context, output, selectTag); var label = GetLabelAsHtml(context, output, selectTag);
var validation = GetValidationAsHtml(context, output, selectTag); var validation = GetValidationAsHtml(context, output, selectTag);
var infoText = GetInfoAsHtml(context, output, selectTag); var infoText = GetInfoAsHtml(context, output, selectTag);
@ -73,7 +74,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext ViewContext = TagHelper.ViewContext
}; };
var selectTagHelperOutput = GetInnerTagHelper(GetInputAttributes(context, output), context, selectTagHelper, "select", TagMode.StartTagAndEndTag); var selectTagHelperOutput = selectTagHelper.ProcessAndGetOutput(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag);
selectTagHelperOutput.Attributes.AddClass("form-control"); selectTagHelperOutput.Attributes.AddClass("form-control");
selectTagHelperOutput.Attributes.AddClass(GetSize(context, output)); selectTagHelperOutput.Attributes.AddClass(GetSize(context, output));
@ -85,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput)
{ {
var disabledAttribute = GetAttribute<DisabledInput>(TagHelper.AspFor.ModelExplorer); var disabledAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<DisabledInput>();
if (disabledAttribute != null && !inputTagHelperOutput.Attributes.ContainsName("disabled")) if (disabledAttribute != null && !inputTagHelperOutput.Attributes.ContainsName("disabled"))
{ {
@ -105,7 +106,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer); return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer);
} }
var selectItemsAttribute = GetAttribute<SelectItems>(TagHelper.AspFor.ModelExplorer); var selectItemsAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<SelectItems>();
if (selectItemsAttribute != null) if (selectItemsAttribute != null)
{ {
return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer); return GetSelectItemsFromAttribute(selectItemsAttribute, TagHelper.AspFor.ModelExplorer);
@ -132,12 +133,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
return ""; return "";
} }
return GetAttribute<RequiredAttribute>(TagHelper.AspFor.ModelExplorer) != null ? "<span> * </span>" : ""; return TagHelper.AspFor.ModelExplorer.GetAttribute<RequiredAttribute>() != null ? "<span> * </span>" : "";
} }
protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput)
{ {
if (GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer) == null) if (TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>() == null)
{ {
return; return;
} }
@ -164,7 +165,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
} }
else else
{ {
var infoAttribute = GetAttribute<InputInfoText>(TagHelper.AspFor.ModelExplorer); var infoAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<InputInfoText>();
if (infoAttribute != null) if (infoAttribute != null)
{ {
text = infoAttribute.Text; text = infoAttribute.Text;
@ -227,7 +228,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
ViewContext = TagHelper.ViewContext ViewContext = TagHelper.ViewContext
}; };
return RenderTagHelper(new TagHelperAttributeList(), context, labelTagHelper, _encoder, "label", TagMode.StartTagAndEndTag, true); return labelTagHelper.Render(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag, true);
} }
protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) protected virtual string GetValidationAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag)
@ -240,12 +241,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
var attributeList = new TagHelperAttributeList { { "class", "text-danger" } }; var attributeList = new TagHelperAttributeList { { "class", "text-danger" } };
return RenderTagHelper(attributeList, context, validationMessageTagHelper, _encoder, "span", TagMode.StartTagAndEndTag, true); return validationMessageTagHelper.Render(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag, true);
} }
protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) protected virtual string GetSize(TagHelperContext context, TagHelperOutput output)
{ {
var attribute = GetAttribute<FormControlSize>(TagHelper.AspFor.ModelExplorer); var attribute = TagHelper.AspFor.ModelExplorer.GetAttribute<FormControlSize>();
if (attribute != null) if (attribute != null)
{ {
@ -255,11 +256,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
switch (TagHelper.Size) switch (TagHelper.Size)
{ {
case AbpFormControlSize.Small: case AbpFormControlSize.Small:
return "form-control-sm"; return "custom-select-sm";
case AbpFormControlSize.Medium: case AbpFormControlSize.Medium:
return "form-control-md"; return "custom-select-md";
case AbpFormControlSize.Large: case AbpFormControlSize.Large:
return "form-control-lg"; return "custom-select-lg";
} }
return ""; return "";
@ -277,6 +278,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
attrList.Add(tagHelperAttribute); attrList.Add(tagHelperAttribute);
} }
attrList.AddClass("custom-select");
return attrList; return attrList;
} }
@ -294,5 +297,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
output.Attributes.Add(newAttritube); output.Attributes.Add(newAttritube);
} }
} }
protected virtual string GetIdAttributeAsString(TagHelperOutput inputTag)
{
var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id");
return idAttr != null ? "for=\"" + idAttr.Value + "\"" : "";
}
protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, int order, out bool surpress)
{
var list = context.GetValue<List<FormGroupItem>>(FormGroupContents) ?? new List<FormGroupItem>();
surpress = list == null;
if (list != null && !list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\"")))
{
list.Add(new FormGroupItem
{
HtmlContent = html,
Order = order
});
}
}
} }
} }

44
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs

@ -10,23 +10,31 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.TagName = "div"; output.TagName = "div";
output.Attributes.AddClass("col"); output.Attributes.AddClass("col");
ProcessSizeClass(output, TagHelper.Size, ""); ProcessSizeClasses(context, output);
ProcessSizeClass(output, TagHelper.SizeSm, "-sm"); ProcessOffsetClasses(context, output);
ProcessSizeClass(output, TagHelper.SizeMd, "-md"); ProcessColumnOrder(context, output);
ProcessSizeClass(output, TagHelper.SizeLg, "-lg"); ProcessVerticalAlign(context, output);
ProcessSizeClass(output, TagHelper.SizeXl, "-xl");
ProcessOffsetClass(output, TagHelper.Offset, "");
ProcessOffsetClass(output, TagHelper.OffsetSm, "-sm");
ProcessOffsetClass(output, TagHelper.OffsetMd, "-md");
ProcessOffsetClass(output, TagHelper.OffsetLg, "-lg");
ProcessOffsetClass(output, TagHelper.OffsetXl, "-xl");
ProcessColumnOrder(output);
ProcessVerticalAlign(output);
} }
protected virtual void ProcessSizeClass(TagHelperOutput output, ColumnSize size, string breakpoint) protected virtual void ProcessSizeClasses(TagHelperContext context, TagHelperOutput output)
{
ProcessSizeClass(context, output, TagHelper.Size, "");
ProcessSizeClass(context, output, TagHelper.SizeSm, "-sm");
ProcessSizeClass(context, output, TagHelper.SizeMd, "-md");
ProcessSizeClass(context, output, TagHelper.SizeLg, "-lg");
ProcessSizeClass(context, output, TagHelper.SizeXl, "-xl");
}
protected virtual void ProcessOffsetClasses(TagHelperContext context, TagHelperOutput output)
{
ProcessOffsetClass(context, output, TagHelper.Offset, "");
ProcessOffsetClass(context, output, TagHelper.OffsetSm, "-sm");
ProcessOffsetClass(context, output, TagHelper.OffsetMd, "-md");
ProcessOffsetClass(context, output, TagHelper.OffsetLg, "-lg");
ProcessOffsetClass(context, output, TagHelper.OffsetXl, "-xl");
}
protected virtual void ProcessSizeClass(TagHelperContext context, TagHelperOutput output, ColumnSize size, string breakpoint)
{ {
if (size == ColumnSize.Undefined) if (size == ColumnSize.Undefined)
{ {
@ -47,7 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass(classString); output.Attributes.AddClass(classString);
} }
protected virtual void ProcessOffsetClass(TagHelperOutput output, ColumnSize size, string breakpoint) protected virtual void ProcessOffsetClass(TagHelperContext context, TagHelperOutput output, ColumnSize size, string breakpoint)
{ {
if (size == ColumnSize.Undefined) if (size == ColumnSize.Undefined)
{ {
@ -68,7 +76,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass(classString); output.Attributes.AddClass(classString);
} }
protected virtual void ProcessVerticalAlign(TagHelperOutput output) protected virtual void ProcessVerticalAlign(TagHelperContext context, TagHelperOutput output)
{ {
if (TagHelper.VAlign == VerticalAlign.Default) if (TagHelper.VAlign == VerticalAlign.Default)
{ {
@ -78,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
output.Attributes.AddClass("align-self-" + TagHelper.VAlign.ToString().ToLowerInvariant()); output.Attributes.AddClass("align-self-" + TagHelper.VAlign.ToString().ToLowerInvariant());
} }
protected virtual void ProcessColumnOrder(TagHelperOutput output) protected virtual void ProcessColumnOrder(TagHelperContext context, TagHelperOutput output)
{ {
if (TagHelper.ColumnOrder == ColumnOrder.Undefined) if (TagHelper.ColumnOrder == ColumnOrder.Undefined)
{ {

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelper.cs

@ -1,5 +1,9 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{ {
[HtmlTargetElement("abp-row")]
[HtmlTargetElement("abp-form-row")]
public class AbpRowTagHelper : AbpTagHelper<AbpRowTagHelper, AbpRowTagHelperService> public class AbpRowTagHelper : AbpTagHelper<AbpRowTagHelper, AbpRowTagHelperService>
{ {
public VerticalAlign VAlign { get; set; } = VerticalAlign.Default; public VerticalAlign VAlign { get; set; } = VerticalAlign.Default;

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpRowTagHelperService.cs

@ -7,8 +7,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
if (output.TagName == "abp-row")
{
output.Attributes.AddClass("row");
}
if (output.TagName == "abp-form-row")
{
output.Attributes.AddClass("form-row");
}
output.TagName = "div"; output.TagName = "div";
output.Attributes.AddClass("row");
ProcessVerticalAlign(output); ProcessVerticalAlign(output);
ProcessHorizontalAlign(output); ProcessHorizontalAlign(output);

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelper.cs

@ -1,11 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Label
{
public class AbpLabelTagHelper : AbpTagHelper<AbpLabelTagHelper, AbpLabelTagHelperService>
{
public AbpLabelTagHelper(AbpLabelTagHelperService tagHelperService)
: base(tagHelperService)
{
}
}
}

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Label/AbpLabelTagHelperService.cs

@ -1,12 +0,0 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Label
{
public class AbpLabelTagHelperService : AbpTagHelperService<AbpLabelTagHelper>
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//TODO: fill
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
{ {
@ -121,11 +122,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList); var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList);
var tagHelperOutput = GetInnerTagHelper(attributeList, context, anchorTagHelper, "a", TagMode.StartTagAndEndTag); var tagHelperOutput = anchorTagHelper.ProcessAndGetOutput(attributeList, context, "a", TagMode.StartTagAndEndTag);
tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]); tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]);
var renderedHtml = RenderTagHelperOutput(tagHelperOutput, _encoder); var renderedHtml = tagHelperOutput.Render(_encoder);
return renderedHtml; return renderedHtml;
} }

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Popover/AbpPopoverTagHelperService.cs

@ -7,7 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Popover
{ {
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
if (!TagHelper.Disabled??true) if (!TagHelper.Disabled ?? true)
{ {
SetDataToggle(context, output); SetDataToggle(context, output);
SetDataPlacement(context, output); SetDataPlacement(context, output);
@ -16,21 +16,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Popover
} }
else else
{ {
SetDisabled(context,output); SetDisabled(context, output);
} }
} }
protected virtual void SetDisabled(TagHelperContext context, TagHelperOutput output) protected virtual void SetDisabled(TagHelperContext context, TagHelperOutput output)
{ {
var triggerAsHtml = TagHelper.Dismissible ?? false ? "datatrigger=\"focus\" " : ""; var triggerAsHtml = TagHelper.Dismissible ?? false ? "datatrigger=\"focus\" " : "";
var dataPlacementAsHtml = "data-placement=\"" + GetDirectory().ToString().ToLowerInvariant() + "\" ";
var dataPlacementAsHtml = "data-placement=\"" +GetDirectory().ToString().ToLowerInvariant() + "\" ";
var titleAttribute = output.Attributes.FirstOrDefault(at => at.Name == "title"); var titleAttribute = output.Attributes.FirstOrDefault(at => at.Name == "title");
var titleAsHtml = titleAttribute == null? "":"title=\""+ titleAttribute.Value +"\" "; var titleAsHtml = titleAttribute == null ? "" : "title=\"" + titleAttribute.Value + "\" ";
var preElementHtml = "<span class=\"d-inline-block\" " + titleAsHtml + triggerAsHtml + dataPlacementAsHtml + "data-toggle=\"popover\" data-content=\"" + GetDataContent() + "\">";
var preElementHtml = "<span class=\"d-inline-block\" "+ titleAsHtml + triggerAsHtml + dataPlacementAsHtml + "data-toggle=\"popover\" data-content=\"" +GetDataContent()+"\">";
var postElementHtml = "</span>"; var postElementHtml = "</span>";
output.PreElement.SetHtmlContent(preElementHtml); output.PreElement.SetHtmlContent(preElementHtml);

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/ProgressBar/AbpProgressGroupTagHelperService.cs

@ -10,6 +10,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar
output.Attributes.AddClass("progress"); output.Attributes.AddClass("progress");
output.TagName = "div"; output.TagName = "div";
} }
} }
} }

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{ {
@ -17,7 +18,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
await output.GetChildContentAsync(); await output.GetChildContentAsync();
var tabHeader = GetTabHeaderItem(context, output); var tabHeader = GetTabHeaderItem(context, output);
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems); var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, "", true)); tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, "", true));

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{ {
@ -12,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var tabHeader = GetTabHeaderItem(context, output); var tabHeader = GetTabHeaderItem(context, output);
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems); var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, TagHelper.ParentDropdownName, false)); tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, TagHelper.ParentDropdownName, false));

37
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs

@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{ {
@ -12,9 +14,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var innerContent = await output.GetChildContentAsync(); var innerContent = await output.GetChildContentAsync();
var tabHeader = GetTabHeaderItem(context, output); var tabHeader = GetTabHeaderItem(context, output);
var tabContent = GetTabContentItem(innerContent.GetContent()); var tabContent = GetTabContentItem(context, output, innerContent.GetContent());
var tabHeaderItems = GetValueFromContext<List<TabItem>>(context, TabItems); var tabHeaderItems = context.GetValue<List<TabItem>>(TabItems);
var active = TagHelper.Active ?? false; var active = TagHelper.Active ?? false;
@ -29,23 +31,31 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
var link = TagHelper.Name; var link = TagHelper.Name;
var control = TagHelper.Name; var control = TagHelper.Name;
var title = TagHelper.Title; var title = TagHelper.Title;
var attributes = GetTabHeaderAttributes(context, output);
var classAttributesAsString = attributes.Where(a=>a.Name == "class").ToList().Select(a=>a.Value).JoinAsString(" ");
var otherAttributesAsString = attributes.Where(a => a.Name != "class").ToList().ToHtmlAttributesAsString();
if (!string.IsNullOrWhiteSpace(TagHelper.ParentDropdownName)) if (!string.IsNullOrWhiteSpace(TagHelper.ParentDropdownName))
{ {
return "<a class=\"dropdown-item\" id=\"" + id + "\" href=\"#" + link + "\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"false\">" + title + "</a>"; return "<a class=\"dropdown-item "+ classAttributesAsString + "\" id=\"" + id + "\" href=\"#" + link + "\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"false\" "+ otherAttributesAsString + ">" + title + "</a>";
} }
return "<li class=\"nav-item\"><a class=\"nav-link" + AbpTabItemActivePlaceholder + "\" id=\"" + id + "\" data-toggle=\"" + TabItemsDataTogglePlaceHolder + "\" href=\"#" + link + "\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"" + AbpTabItemSelectedPlaceholder + "\">" + return "<li class=\"nav-item\"><a class=\"nav-link " + classAttributesAsString + " " + AbpTabItemActivePlaceholder + "\" id=\"" + id + "\" data-toggle=\"" + TabItemsDataTogglePlaceHolder + "\" href=\"#" + link + "\" role=\"tab\" aria-controls=\"" + control + "\" aria-selected=\"" + AbpTabItemSelectedPlaceholder + "\" "+ otherAttributesAsString + ">" +
title + title +
"</a></li>"; "</a></li>";
} }
protected virtual string GetTabContentItem(string content) protected virtual string GetTabContentItem(TagHelperContext context, TagHelperOutput output, string content)
{ {
var headerId = TagHelper.Name + "-tab"; var headerId = TagHelper.Name + "-tab";
var id = TagHelper.Name; var id = TagHelper.Name;
var attributes = GetTabContentAttributes(context, output);
var classAttributesAsString = attributes.Where(a => a.Name == "class").ToList().Select(a => a.Name).JoinAsString(" ");
var otherAttributesAsString = attributes.Where(a => a.Name != "class").ToList().ToHtmlAttributesAsString();
return "<div class=\"tab-pane fade" + AbpTabItemShowActivePlaceholder + "\" id=\"" + id + "\" role=\"tabpanel\" aria-labelledby=\"" + headerId + "\">" + return "<div class=\"tab-pane fade " + classAttributesAsString + " " + AbpTabItemShowActivePlaceholder + "\" id=\"" + id + "\" role=\"tabpanel\" aria-labelledby=\"" + headerId + "\" " + otherAttributesAsString + ">" +
content + content +
"</div>"; "</div>";
} }
@ -57,5 +67,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
TagHelper.Name = TabItemNamePlaceHolder; TagHelper.Name = TabItemNamePlaceHolder;
} }
} }
protected virtual List<TagHelperAttribute> GetTabContentAttributes(TagHelperContext context, TagHelperOutput output) {
var contentprefix = "content-";
return GetTabAttributesByPrefix(output.Attributes, contentprefix);
}
protected virtual List<TagHelperAttribute> GetTabHeaderAttributes(TagHelperContext context, TagHelperOutput output) {
var headerprefix = "header-";
return GetTabAttributesByPrefix(output.Attributes, headerprefix);
}
private List<TagHelperAttribute> GetTabAttributesByPrefix(TagHelperAttributeList attributes, string prefix) {
return attributes.Where(a=>a.Name.StartsWith(prefix))
.Select(a=> new TagHelperAttribute(a.Name.Substring(prefix.Length), a.Value)).ToList();
}
} }
} }

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

@ -52,7 +52,7 @@
*************************************************************************/ *************************************************************************/
var localize = function (key) { var localize = function (key) {
return abp.localization.getResource('AbpUi')(key); return abp.localization.getResource('AbpUi')(key);
} };
var recordActions = function () { var recordActions = function () {
if (!$.fn.dataTableExt) { if (!$.fn.dataTableExt) {
@ -69,7 +69,7 @@
} else { } else {
return visibilityField; return visibilityField;
} }
} };
var _createDropdownItem = function (record, fieldItem) { var _createDropdownItem = function (record, fieldItem) {
var $li = $('<li/>'); var $li = $('<li/>');
@ -83,7 +83,7 @@
$a.append($("<i>").addClass("fa fa-" + fieldItem.icon + " mr-1")); $a.append($("<i>").addClass("fa fa-" + fieldItem.icon + " mr-1"));
} else if (fieldItem.iconClass) { } else if (fieldItem.iconClass) {
$a.append($("<i>").addClass(fieldItem.iconClass + " mr-1")); $a.append($("<i>").addClass(fieldItem.iconClass + " mr-1"));
} }
$a.append(fieldItem.text); $a.append(fieldItem.text);
} }
@ -109,7 +109,7 @@
$a.appendTo($li); $a.appendTo($li);
return $li; return $li;
} };
var _createButtonDropdown = function (record, field) { var _createButtonDropdown = function (record, field) {
var $container = $('<div/>') var $container = $('<div/>')
@ -200,11 +200,11 @@
} }
throw "DTE#1: Cannot create row action. Either set element or items fields!"; throw "DTE#1: Cannot create row action. Either set element or items fields!";
} };
var hideColumnWithoutRedraw = function (tableInstance, colIndex) { var hideColumnWithoutRedraw = function (tableInstance, colIndex) {
tableInstance.fnSetColumnVis(colIndex, false, false); tableInstance.fnSetColumnVis(colIndex, false, false);
} };
var hideEmptyColumn = function (cellContent, tableInstance, colIndex) { var hideEmptyColumn = function (cellContent, tableInstance, colIndex) {
if (cellContent == "") { if (cellContent == "") {
@ -307,8 +307,8 @@
}); });
}); });
} }
} };
} };
}(); }();
/************************************************************************ /************************************************************************
@ -338,9 +338,10 @@
} }
} }
configuration.dom = '<"dataTable_filters"f>rt<"row dataTable_footer"<"col-auto"l><"col-auto"i><"col"p>>';
return configuration; return configuration;
} };
}(); }();

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs

@ -60,7 +60,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
public ICurrentTenant CurrentTenant { get; set; } public ICurrentTenant CurrentTenant { get; set; }
public ISettingManager SettingManager { get; set; } public ISettingProvider SettingProvider { get; set; }
public IModelStateValidator ModelValidator { get; set; } public IModelStateValidator ModelValidator { get; set; }

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

@ -4,10 +4,12 @@ using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Settings;
using Volo.Abp.Users; using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
@ -19,18 +21,24 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider; private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider;
private readonly IAuthorizationService _authorizationService; private readonly IAuthorizationService _authorizationService;
private readonly ICurrentUser _currentUser; private readonly ICurrentUser _currentUser;
private readonly ISettingProvider _settingProvider;
private readonly ISettingDefinitionManager _settingDefinitionManager;
public AbpApplicationConfigurationAppService( public AbpApplicationConfigurationAppService(
IOptions<AbpLocalizationOptions> localizationOptions, IOptions<AbpLocalizationOptions> localizationOptions,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider,
IAuthorizationService authorizationService, IAuthorizationService authorizationService,
ICurrentUser currentUser) ICurrentUser currentUser,
ISettingProvider settingProvider,
SettingDefinitionManager settingDefinitionManager)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider;
_authorizationService = authorizationService; _authorizationService = authorizationService;
_currentUser = currentUser; _currentUser = currentUser;
_settingProvider = settingProvider;
_settingDefinitionManager = settingDefinitionManager;
_localizationOptions = localizationOptions.Value; _localizationOptions = localizationOptions.Value;
} }
@ -40,9 +48,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
return new ApplicationConfigurationDto return new ApplicationConfigurationDto
{ {
Auth = await GetAuthConfig(), Auth = await GetAuthConfigAsync(),
Localization = GetLocalizationConfig(), Localization = GetLocalizationConfig(),
CurrentUser = GetCurrentUser() CurrentUser = GetCurrentUser(),
Setting = await GetSettingConfigAsync()
}; };
} }
@ -57,7 +66,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
}; };
} }
protected virtual async Task<ApplicationAuthConfigurationDto> GetAuthConfig() protected virtual async Task<ApplicationAuthConfigurationDto> GetAuthConfigAsync()
{ {
var authConfig = new ApplicationAuthConfigurationDto(); var authConfig = new ApplicationAuthConfigurationDto();
@ -97,5 +106,25 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
return localizationConfig; return localizationConfig;
} }
private async Task<ApplicationSettingConfigurationDto> GetSettingConfigAsync()
{
var result = new ApplicationSettingConfigurationDto
{
Values = new Dictionary<string, string>()
};
foreach (var settingDefinition in _settingDefinitionManager.GetAll())
{
if (!settingDefinition.IsVisibleToClients)
{
continue;
}
result.Values[settingDefinition.Name] = await _settingProvider.GetOrNullAsync(settingDefinition.Name);
}
return result;
}
} }
} }

13
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Tracing;
using Volo.Abp.AspNetCore.Uow; using Volo.Abp.AspNetCore.Uow;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization; using Volo.Abp.Localization;
@ -40,6 +41,12 @@ namespace Microsoft.AspNetCore.Builder
.UseMiddleware<AbpUnitOfWorkMiddleware>(); .UseMiddleware<AbpUnitOfWorkMiddleware>();
} }
public static IApplicationBuilder UseCorrelationId(this IApplicationBuilder app)
{
return app
.UseMiddleware<AbpCorrelationIdMiddleware>();
}
public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app) public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app)
{ {
IReadOnlyList<LanguageInfo> languages; IReadOnlyList<LanguageInfo> languages;
@ -48,10 +55,10 @@ namespace Microsoft.AspNetCore.Builder
using (var scope = app.ApplicationServices.CreateScope()) using (var scope = app.ApplicationServices.CreateScope())
{ {
var languageProvider = scope.ServiceProvider.GetRequiredService<ILanguageProvider>(); var languageProvider = scope.ServiceProvider.GetRequiredService<ILanguageProvider>();
var settingManager = scope.ServiceProvider.GetRequiredService<ISettingManager>(); languages = languageProvider.GetLanguages();
languages = AsyncHelper.RunSync(() => languageProvider.GetLanguagesAsync()); var settingProvider = scope.ServiceProvider.GetRequiredService<ISettingProvider>();
defaultLanguage = settingManager.GetOrNull(LocalizationSettingNames.DefaultLanguage); defaultLanguage = settingProvider.GetOrNull(LocalizationSettingNames.DefaultLanguage);
} }
if (!languages.Any()) if (!languages.Any())

1
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs

@ -13,7 +13,6 @@ using Volo.Abp.ExceptionHandling;
using Volo.Abp.Http; using Volo.Abp.Http;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.UI;
using Volo.Abp.Validation; using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling

2
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Threading
[Dependency(ReplaceServices = true)] [Dependency(ReplaceServices = true)]
public class HttpContextCancellationTokenProvider : ICancellationTokenProvider, ITransientDependency public class HttpContextCancellationTokenProvider : ICancellationTokenProvider, ITransientDependency
{ {
public CancellationToken Token => _httpContextAccessor.HttpContext?.RequestAborted ?? default; public CancellationToken Token => _httpContextAccessor.HttpContext?.RequestAborted ?? CancellationToken.None;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpContextAccessor _httpContextAccessor;

58
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs

@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.Tracing;
namespace Volo.Abp.AspNetCore.Tracing
{
public class AbpCorrelationIdMiddleware
{
private readonly RequestDelegate _next;
public AbpCorrelationIdMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(
HttpContext httpContext,
IOptions<CorrelationIdOptions> options,
ICorrelationIdProvider correlationIdProvider)
{
var correlationId = correlationIdProvider.Get();
var optionsValue = options.Value;
try
{
await _next(httpContext);
}
finally
{
CheckAndSetCorrelationIdOnResponse(httpContext, optionsValue, correlationId);
}
}
protected virtual void CheckAndSetCorrelationIdOnResponse(
HttpContext httpContext,
CorrelationIdOptions options,
string correlationId)
{
if (httpContext.Response.HasStarted)
{
return;
}
if (!options.SetResponseHeader)
{
return;
}
if (httpContext.Response.Headers.ContainsKey(options.HttpHeaderName))
{
return;
}
httpContext.Response.Headers[options.HttpHeaderName] = correlationId;
}
}
}

52
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdProvider.cs

@ -0,0 +1,52 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Tracing;
namespace Volo.Abp.AspNetCore.Tracing
{
[Dependency(ReplaceServices = true)]
public class AspNetCoreCorrelationIdProvider : ICorrelationIdProvider, ITransientDependency
{
protected IHttpContextAccessor HttpContextAccessor { get; }
protected CorrelationIdOptions Options { get; }
public AspNetCoreCorrelationIdProvider(
IHttpContextAccessor httpContextAccessor,
IOptions<CorrelationIdOptions> options)
{
HttpContextAccessor = httpContextAccessor;
Options = options.Value;
}
public virtual string Get()
{
if (HttpContextAccessor.HttpContext?.Request?.Headers == null)
{
return CreateNewCorrelationId();
}
string correlationId = HttpContextAccessor.HttpContext.Request.Headers[Options.HttpHeaderName];
if (correlationId.IsNullOrEmpty())
{
lock (HttpContextAccessor.HttpContext.Request.Headers)
{
if (correlationId.IsNullOrEmpty())
{
correlationId = CreateNewCorrelationId();
HttpContextAccessor.HttpContext.Request.Headers[Options.HttpHeaderName] = correlationId;
}
}
}
return correlationId;
}
protected virtual string CreateNewCorrelationId()
{
return Guid.NewGuid().ToString("N");
}
}
}

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

@ -14,6 +14,12 @@ namespace Volo.Abp.Auditing
/// </summary> /// </summary>
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
/// <summary>
/// The name of the application or service writing audit logs.
/// Default: null.
/// </summary>
public string ApplicationName { get; set; }
/// <summary> /// <summary>
/// Default: true. /// Default: true.
/// </summary> /// </summary>

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

@ -10,6 +10,8 @@ namespace Volo.Abp.Auditing
//TODO: Make serializable! //TODO: Make serializable!
public class AuditLogInfo : IMultiTenant, IHasExtraProperties public class AuditLogInfo : IMultiTenant, IHasExtraProperties
{ {
public string ApplicationName { get; set; }
public Guid? UserId { get; set; } public Guid? UserId { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
@ -24,6 +26,10 @@ namespace Volo.Abp.Auditing
public int ExecutionDuration { get; set; } public int ExecutionDuration { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
public string ClientIpAddress { get; set; } public string ClientIpAddress { get; set; }
public string ClientName { get; set; } public string ClientName { get; set; }

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

@ -5,9 +5,11 @@ using System.Reflection;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing; using Volo.Abp.Timing;
using Volo.Abp.Tracing;
using Volo.Abp.Users; using Volo.Abp.Users;
namespace Volo.Abp.Auditing namespace Volo.Abp.Auditing
@ -18,30 +20,36 @@ namespace Volo.Abp.Auditing
protected IAuditingStore AuditingStore { get; } protected IAuditingStore AuditingStore { get; }
protected ICurrentUser CurrentUser { get; } protected ICurrentUser CurrentUser { get; }
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected ICurrentClient CurrentClient { get; }
protected IClock Clock { get; } protected IClock Clock { get; }
protected AbpAuditingOptions Options; protected AbpAuditingOptions Options;
protected IAuditSerializer AuditSerializer; protected IAuditSerializer AuditSerializer;
protected IServiceProvider ServiceProvider; protected IServiceProvider ServiceProvider;
protected ICorrelationIdProvider CorrelationIdProvider { get; }
public AuditingHelper( public AuditingHelper(
IAuditSerializer auditSerializer, IAuditSerializer auditSerializer,
IOptions<AbpAuditingOptions> options, IOptions<AbpAuditingOptions> options,
ICurrentUser currentUser, ICurrentUser currentUser,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
ICurrentClient currentClient,
IClock clock, IClock clock,
IAuditingStore auditingStore, IAuditingStore auditingStore,
ILogger<AuditingHelper> logger, ILogger<AuditingHelper> logger,
IServiceProvider serviceProvider) IServiceProvider serviceProvider,
ICorrelationIdProvider correlationIdProvider)
{ {
Options = options.Value; Options = options.Value;
AuditSerializer = auditSerializer; AuditSerializer = auditSerializer;
CurrentUser = currentUser; CurrentUser = currentUser;
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
CurrentClient = currentClient;
Clock = clock; Clock = clock;
AuditingStore = auditingStore; AuditingStore = auditingStore;
Logger = logger; Logger = logger;
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;
CorrelationIdProvider = correlationIdProvider;
} }
public virtual bool ShouldSaveAudit(MethodInfo methodInfo, bool defaultValue = false) public virtual bool ShouldSaveAudit(MethodInfo methodInfo, bool defaultValue = false)
@ -82,9 +90,12 @@ namespace Volo.Abp.Auditing
{ {
var auditInfo = new AuditLogInfo var auditInfo = new AuditLogInfo
{ {
ApplicationName = Options.ApplicationName,
TenantId = CurrentTenant.Id, TenantId = CurrentTenant.Id,
UserId = CurrentUser.Id, UserId = CurrentUser.Id,
UserName = CurrentUser.UserName, UserName = CurrentUser.UserName,
ClientId = CurrentClient.Id,
CorrelationId = CorrelationIdProvider.Get(),
//ImpersonatorUserId = AbpSession.ImpersonatorUserId, //TODO: Impersonation system is not available yet! //ImpersonatorUserId = AbpSession.ImpersonatorUserId, //TODO: Impersonation system is not available yet!
//ImpersonatorTenantId = AbpSession.ImpersonatorTenantId, //ImpersonatorTenantId = AbpSession.ImpersonatorTenantId,
ExecutionTime = Clock.Now ExecutionTime = Clock.Now

1
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs

@ -28,6 +28,7 @@ namespace Volo.Abp.Authorization
{ {
options.ValueProviders.Add<UserPermissionValueProvider>(); options.ValueProviders.Add<UserPermissionValueProvider>();
options.ValueProviders.Add<RolePermissionValueProvider>(); options.ValueProviders.Add<RolePermissionValueProvider>();
options.ValueProviders.Add<ClientPermissionValueProvider>();
}); });
} }
} }

11
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs

@ -1,6 +1,7 @@
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Users; using Volo.Abp.Users;
@ -10,11 +11,16 @@ namespace Volo.Abp.Authorization
{ {
private readonly IAuthorizationService _authorizationService; private readonly IAuthorizationService _authorizationService;
private readonly ICurrentUser _currentUser; private readonly ICurrentUser _currentUser;
private readonly ICurrentClient _currentClient;
public MethodInvocationAuthorizationService(IAuthorizationService authorizationService, ICurrentUser currentUser) public MethodInvocationAuthorizationService(
IAuthorizationService authorizationService,
ICurrentUser currentUser,
ICurrentClient currentClient)
{ {
_authorizationService = authorizationService; _authorizationService = authorizationService;
_currentUser = currentUser; _currentUser = currentUser;
_currentClient = currentClient;
} }
public async Task CheckAsync(MethodInvocationAuthorizationContext context) public async Task CheckAsync(MethodInvocationAuthorizationContext context)
@ -53,7 +59,8 @@ namespace Volo.Abp.Authorization
{ {
if (authorizationAttribute.Policy == null) if (authorizationAttribute.Policy == null)
{ {
if (!_currentUser.IsAuthenticated) //TODO: What about API calls without user id? //TODO: Can we find a better, unified, way of checking if current request has been authenticated
if (!_currentUser.IsAuthenticated && !_currentClient.IsAuthenticated)
{ {
throw new AbpAuthorizationException("Authorization failed! User has not logged in."); throw new AbpAuthorizationException("Authorization failed! User has not logged in.");
} }

35
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs

@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Authorization.Permissions
{
public class ClientPermissionValueProvider : PermissionValueProvider
{
public const string ProviderName = "Client";
public override string Name => ProviderName;
public ClientPermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
public override async Task<PermissionValueProviderGrantInfo> CheckAsync(PermissionValueCheckContext context)
{
var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value;
if (clientId == null)
{
return PermissionValueProviderGrantInfo.NonGranted;
}
if (await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, clientId))
{
return new PermissionValueProviderGrantInfo(true, clientId);
}
return PermissionValueProviderGrantInfo.NonGranted;
}
}
}

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs

@ -9,5 +9,7 @@ namespace Volo.Abp.Authorization.Permissions
PermissionGroupDefinition GetGroupOrNull(string name); PermissionGroupDefinition GetGroupOrNull(string name);
PermissionGroupDefinition AddGroup([NotNull] string name, ILocalizableString displayName = null); PermissionGroupDefinition AddGroup([NotNull] string name, ILocalizableString displayName = null);
void RemoveGroup(string name);
} }
} }

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

@ -1,10 +1,10 @@
using System; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims; using Volo.Abp.Security.Claims;
@ -40,7 +40,7 @@ namespace Volo.Abp.Authorization.Permissions
true true
); );
} }
public virtual Task<PermissionGrantInfo> CheckAsync(string name) public virtual Task<PermissionGrantInfo> CheckAsync(string name)
{ {
return CheckAsync(PrincipalAccessor.Principal, name); return CheckAsync(PrincipalAccessor.Principal, name);
@ -57,6 +57,12 @@ namespace Volo.Abp.Authorization.Permissions
foreach (var provider in ValueProviders) foreach (var provider in ValueProviders)
{ {
if (context.Permission.Providers.Any() &&
!context.Permission.Providers.Contains(provider.Name))
{
continue;
}
var result = await provider.CheckAsync(context); var result = await provider.CheckAsync(context);
if (result.IsGranted) if (result.IsGranted)
{ {

31
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs

@ -18,6 +18,12 @@ namespace Volo.Abp.Authorization.Permissions
/// </summary> /// </summary>
public PermissionDefinition Parent { get; private set; } public PermissionDefinition Parent { get; private set; }
/// <summary>
/// A list of allowed providers to get/set value of this permission.
/// An empty list indicates that all providers are allowed.
/// </summary>
public List<string> Providers { get; }
public ILocalizableString DisplayName public ILocalizableString DisplayName
{ {
get => _displayName; get => _displayName;
@ -53,6 +59,7 @@ namespace Volo.Abp.Authorization.Permissions
DisplayName = displayName ?? new FixedLocalizableString(name); DisplayName = displayName ?? new FixedLocalizableString(name);
Properties = new Dictionary<string, object>(); Properties = new Dictionary<string, object>();
Providers = new List<string>();
_children = new List<PermissionDefinition>(); _children = new List<PermissionDefinition>();
} }
@ -68,6 +75,30 @@ namespace Volo.Abp.Authorization.Permissions
return child; return child;
} }
/// <summary>
/// Sets a property in the <see cref="Properties"/> dictionary.
/// This is a shortcut for nested calls on this object.
/// </summary>
public virtual PermissionDefinition WithProperty(string key, object value)
{
Properties[key] = value;
return this;
}
/// <summary>
/// Sets a property in the <see cref="Properties"/> dictionary.
/// This is a shortcut for nested calls on this object.
/// </summary>
public virtual PermissionDefinition WithProviders(params string[] providers)
{
if (!providers.IsNullOrEmpty())
{
Providers.AddRange(providers);
}
return this;
}
public override string ToString() public override string ToString()
{ {
return $"[{nameof(PermissionDefinition)} {Name}]"; return $"[{nameof(PermissionDefinition)} {Name}]";

11
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs

@ -36,5 +36,16 @@ namespace Volo.Abp.Authorization.Permissions
return Groups[name]; return Groups[name];
} }
public virtual void RemoveGroup(string name)
{
Check.NotNull(name, nameof(name));
if (!Groups.ContainsKey(name))
{
throw new AbpException($"Not found permission group with name: {name}");
}
Groups.Remove(name);
}
} }
} }

15
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheNameAttribute.cs

@ -15,5 +15,20 @@ namespace Volo.Abp.Caching
Name = name; Name = name;
} }
public static string GetCacheName(Type cacheItemType)
{
var cacheNameAttribute = cacheItemType
.GetCustomAttributes(true)
.OfType<CacheNameAttribute>()
.FirstOrDefault();
if (cacheNameAttribute != null)
{
return cacheNameAttribute.Name;
}
return cacheItemType.FullName.RemovePostFix("CacheItem");
}
} }
} }

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

@ -103,6 +103,7 @@ namespace Volo.Abp.Caching
Logger.LogException(ex, LogLevel.Warning); Logger.LogException(ex, LogLevel.Warning);
return null; return null;
} }
throw; throw;
} }
@ -126,7 +127,7 @@ namespace Volo.Abp.Caching
return value; return value;
} }
using (AsyncLock.Lock()) using (AsyncLock.Lock(CancellationTokenProvider.Token))
{ {
value = Get(key, hideErrors); value = Get(key, hideErrors);
if (value != null) if (value != null)
@ -194,13 +195,13 @@ namespace Volo.Abp.Caching
} }
} }
public virtual Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default) public virtual async Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default)
{ {
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try try
{ {
return Cache.SetAsync( await Cache.SetAsync(
NormalizeKey(key), NormalizeKey(key),
ObjectSerializer.Serialize(value), ObjectSerializer.Serialize(value),
options ?? DefaultCacheOptions, options ?? DefaultCacheOptions,
@ -212,8 +213,9 @@ namespace Volo.Abp.Caching
if ((bool)hideErrors) if ((bool)hideErrors)
{ {
Logger.LogException(ex, LogLevel.Warning); Logger.LogException(ex, LogLevel.Warning);
return Task.CompletedTask; return;
} }
throw; throw;
} }
} }
@ -238,21 +240,22 @@ namespace Volo.Abp.Caching
} }
} }
public virtual Task RefreshAsync(string key, bool? hideErrors = null, CancellationToken token = default) public virtual async Task RefreshAsync(string key, bool? hideErrors = null, CancellationToken token = default)
{ {
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try try
{ {
return Cache.RefreshAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); await Cache.RefreshAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token));
} }
catch (Exception ex) catch (Exception ex)
{ {
if ((bool)hideErrors) if ((bool)hideErrors)
{ {
Logger.LogException(ex, LogLevel.Warning); Logger.LogException(ex, LogLevel.Warning);
return Task.CompletedTask; return;
} }
throw; throw;
} }
} }
@ -276,21 +279,22 @@ namespace Volo.Abp.Caching
} }
} }
public virtual Task RemoveAsync(string key, bool? hideErrors = null, CancellationToken token = default) public virtual async Task RemoveAsync(string key, bool? hideErrors = null, CancellationToken token = default)
{ {
hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
try try
{ {
return Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token));
} }
catch (Exception ex) catch (Exception ex)
{ {
if ((bool)hideErrors) if ((bool)hideErrors)
{ {
Logger.LogException(ex, LogLevel.Warning); Logger.LogException(ex, LogLevel.Warning);
return Task.CompletedTask; return;
} }
throw; throw;
} }
} }
@ -322,13 +326,7 @@ namespace Volo.Abp.Caching
protected virtual void SetDefaultOptions() protected virtual void SetDefaultOptions()
{ {
//CacheName CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem));
var cacheNameAttribute = typeof(TCacheItem)
.GetCustomAttributes(true)
.OfType<CacheNameAttribute>()
.FirstOrDefault();
CacheName = cacheNameAttribute != null ? cacheNameAttribute.Name : typeof(TCacheItem).FullName;
//IgnoreMultiTenancy //IgnoreMultiTenancy
IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true);

9
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/CorrelationIdOptions.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Tracing
{
public class CorrelationIdOptions
{
public string HttpHeaderName { get; set; } = "X-Correlation-Id";
public bool SetResponseHeader { get; set; } = true;
}
}

18
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/DefaultCorrelationIdProvider.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Tracing
{
public class DefaultCorrelationIdProvider : ICorrelationIdProvider, ISingletonDependency
{
public string Get()
{
return CreateNewCorrelationId();
}
protected virtual string CreateNewCorrelationId()
{
return Guid.NewGuid().ToString("N");
}
}
}

10
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/ICorrelationIdProvider.cs

@ -0,0 +1,10 @@
using JetBrains.Annotations;
namespace Volo.Abp.Tracing
{
public interface ICorrelationIdProvider
{
[NotNull]
string Get();
}
}

43
framework/src/Volo.Abp.Data/Volo/Abp/Data/HasExtraPropertiesExtensions.cs

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Volo.Abp.Reflection;
namespace Volo.Abp.Data
{
public static class HasExtraPropertiesExtensions
{
public static bool HasProperty(this IHasExtraProperties source, string name)
{
return source.ExtraProperties.ContainsKey(name);
}
public static object GetProperty(this IHasExtraProperties source, string name)
{
return source.ExtraProperties?.GetOrDefault(name);
}
public static TProperty GetProperty<TProperty>(this IHasExtraProperties source, string name)
{
var value = source.GetProperty(name);
if (value == default)
{
return default;
}
if (TypeHelper.IsPrimitiveExtended(typeof(TProperty), includeEnums: true))
{
return (TProperty)Convert.ChangeType(value, typeof(TProperty), CultureInfo.InvariantCulture);
}
throw new AbpException("GetProperty<TProperty> does not support non-primitive types. Use non-generic GetProperty method and handle type casting manually.");
}
public static TSource SetProperty<TSource>(this TSource source, string name, object value)
where TSource : IHasExtraProperties
{
source.ExtraProperties[name] = value;
return source;
}
}
}

1
framework/src/Volo.Abp.Ddd.Application/Volo.Abp.Ddd.Application.csproj

@ -20,6 +20,7 @@
<ProjectReference Include="..\Volo.Abp.Http.Abstractions\Volo.Abp.Http.Abstractions.csproj" /> <ProjectReference Include="..\Volo.Abp.Http.Abstractions\Volo.Abp.Http.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.ObjectMapping\Volo.Abp.ObjectMapping.csproj" /> <ProjectReference Include="..\Volo.Abp.ObjectMapping\Volo.Abp.ObjectMapping.csproj" />
<ProjectReference Include="..\Volo.Abp.Security\Volo.Abp.Security.csproj" /> <ProjectReference Include="..\Volo.Abp.Security\Volo.Abp.Security.csproj" />
<ProjectReference Include="..\Volo.Abp.Settings\Volo.Abp.Settings.csproj" />
<ProjectReference Include="..\Volo.Abp.Validation\Volo.Abp.Validation.csproj" /> <ProjectReference Include="..\Volo.Abp.Validation\Volo.Abp.Validation.csproj" />
</ItemGroup> </ItemGroup>

17
framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/AbpDddApplicationModule.cs

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
using Volo.Abp.Domain; using Volo.Abp.Domain;
@ -8,17 +7,21 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.ObjectMapping; using Volo.Abp.ObjectMapping;
using Volo.Abp.Security; using Volo.Abp.Security;
using Volo.Abp.Settings;
using Volo.Abp.Uow; using Volo.Abp.Uow;
using Volo.Abp.Validation; using Volo.Abp.Validation;
namespace Volo.Abp.Application namespace Volo.Abp.Application
{ {
[DependsOn(typeof(AbpDddDomainModule))] [DependsOn(
[DependsOn(typeof(AbpSecurityModule))] typeof(AbpDddDomainModule),
[DependsOn(typeof(AbpObjectMappingModule))] typeof(AbpSecurityModule),
[DependsOn(typeof(AbpValidationModule))] typeof(AbpObjectMappingModule),
[DependsOn(typeof(AbpAuthorizationModule))] typeof(AbpValidationModule),
[DependsOn(typeof(AbpHttpAbstractionsModule))] typeof(AbpAuthorizationModule),
typeof(AbpHttpAbstractionsModule),
typeof(AbpSettingsModule)
)]
public class AbpDddApplicationModule : AbpModule public class AbpDddApplicationModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)

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

@ -45,7 +45,7 @@ namespace Volo.Abp.Application.Services
public ICurrentUser CurrentUser { get; set; } public ICurrentUser CurrentUser { get; set; }
public ISettingManager SettingManager { get; set; } public ISettingProvider SettingProvider { get; set; }
public IClock Clock { get; set; } public IClock Clock { get; set; }

8
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs

@ -13,10 +13,10 @@ namespace Volo.Abp.Domain.Entities
IHasExtraProperties, IHasExtraProperties,
IHasConcurrencyStamp IHasConcurrencyStamp
{ {
public Dictionary<string, object> ExtraProperties { get; protected set; } public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
[DisableAuditing] [DisableAuditing]
public string ConcurrencyStamp { get; set; } public virtual string ConcurrencyStamp { get; set; }
private readonly ICollection<object> _localEvents = new Collection<object>(); private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>(); private readonly ICollection<object> _distributedEvents = new Collection<object>();
@ -65,10 +65,10 @@ namespace Volo.Abp.Domain.Entities
IHasExtraProperties, IHasExtraProperties,
IHasConcurrencyStamp IHasConcurrencyStamp
{ {
public Dictionary<string, object> ExtraProperties { get; protected set; } public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
[DisableAuditing] [DisableAuditing]
public string ConcurrencyStamp { get; set; } public virtual string ConcurrencyStamp { get; set; }
private readonly ICollection<object> _localEvents = new Collection<object>(); private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>(); private readonly ICollection<object> _distributedEvents = new Collection<object>();

101
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Values/ValueObject.cs

@ -1,98 +1,61 @@
using System; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace Volo.Abp.Domain.Values namespace Volo.Abp.Domain.Values
{ {
//Inspired from https://blogs.msdn.microsoft.com/cesardelatorre/2011/06/06/implementing-a-value-object-base-class-supertype-patternddd-patterns-related/ //Inspired from https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/implement-value-objects
/// <summary> public abstract class ValueObject
/// Base class for value objects.
/// </summary>
/// <typeparam name="TValueObject">The type of the value object.</typeparam>
public abstract class ValueObject<TValueObject> : IEquatable<TValueObject>
where TValueObject : ValueObject<TValueObject>
{ {
public bool Equals(TValueObject other) protected static bool EqualOperator(ValueObject left, ValueObject right)
{ {
if ((object)other == null) if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
{ {
return false; return false;
} }
return ReferenceEquals(left, null) || left.Equals(right);
}
var publicProperties = GetType().GetTypeInfo().GetProperties(); protected static bool NotEqualOperator(ValueObject left, ValueObject right)
if (!publicProperties.Any()) {
{ return !(EqualOperator(left, right));
return true;
}
return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null)));
} }
protected abstract IEnumerable<object> GetAtomicValues();
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj == null) if (obj == null || obj.GetType() != GetType())
{ {
return false; return false;
} }
var item = obj as ValueObject<TValueObject>; ValueObject other = (ValueObject)obj;
return (object)item != null && Equals((TValueObject)item); IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
} IEnumerator<object> otherValues = other.GetAtomicValues().GetEnumerator();
while (thisValues.MoveNext() && otherValues.MoveNext())
public override int GetHashCode()
{
//TODO: Can we cache the hash value assuming value objects are always immutable? We can make a Reset-like method to reset it's mutated.
const int index = 1;
const int initialHasCode = 31;
var publicProperties = GetType().GetTypeInfo().GetProperties();
if (!publicProperties.Any())
{ {
return initialHasCode; if (ReferenceEquals(thisValues.Current, null) ^
} ReferenceEquals(otherValues.Current, null))
var hashCode = initialHasCode;
var changeMultiplier = false;
foreach (var property in publicProperties)
{
var value = property.GetValue(this, null);
if (value == null)
{ {
//support {"a",null,null,"a"} != {null,"a","a",null} return false;
hashCode = hashCode ^ (index * 13);
continue;
} }
hashCode = hashCode * (changeMultiplier ? 59 : 114) + value.GetHashCode(); if (thisValues.Current != null &&
changeMultiplier = !changeMultiplier; !thisValues.Current.Equals(otherValues.Current))
} {
return false;
return hashCode; }
}
public static bool operator ==(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (((object)x == null) || ((object)y == null))
{
return false;
} }
return !thisValues.MoveNext() && !otherValues.MoveNext();
return x.Equals(y);
} }
public static bool operator !=(ValueObject<TValueObject> x, ValueObject<TValueObject> y) public override int GetHashCode()
{ {
return !(x == y); return GetAtomicValues()
.Select(x => x != null ? x.GetHashCode() : 0)
.Aggregate((x, y) => x ^ y);
} }
// Other utilility methods
} }
} }

3
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection; using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Emailing.Templates; using Volo.Abp.Emailing.Templates;
using Volo.Abp.Emailing.Templates.Virtual; using Volo.Abp.Emailing.Templates.Virtual;
using Volo.Abp.Localization; using Volo.Abp.Localization;

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

@ -11,16 +11,16 @@ namespace Volo.Abp.Emailing
{ {
public virtual string DefaultFromAddress => GetNotEmptySettingValue(EmailSettingNames.DefaultFromAddress); public virtual string DefaultFromAddress => GetNotEmptySettingValue(EmailSettingNames.DefaultFromAddress);
public virtual string DefaultFromDisplayName => SettingManager.GetOrNull(EmailSettingNames.DefaultFromDisplayName); public virtual string DefaultFromDisplayName => SettingProvider.GetOrNull(EmailSettingNames.DefaultFromDisplayName);
protected readonly ISettingManager SettingManager; protected readonly ISettingProvider SettingProvider;
/// <summary> /// <summary>
/// Creates a new <see cref="EmailSenderConfiguration"/>. /// Creates a new <see cref="EmailSenderConfiguration"/>.
/// </summary> /// </summary>
protected EmailSenderConfiguration(ISettingManager settingManager) protected EmailSenderConfiguration(ISettingProvider settingProvider)
{ {
SettingManager = settingManager; SettingProvider = settingProvider;
} }
/// <summary> /// <summary>
@ -30,7 +30,7 @@ namespace Volo.Abp.Emailing
/// <returns>Value of the setting</returns> /// <returns>Value of the setting</returns>
protected string GetNotEmptySettingValue(string name) protected string GetNotEmptySettingValue(string name)
{ {
var value = SettingManager.GetOrNull(name); var value = SettingProvider.GetOrNull(name);
if (value.IsNullOrEmpty()) if (value.IsNullOrEmpty())
{ {

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

@ -18,14 +18,14 @@ namespace Volo.Abp.Emailing.Smtp
public virtual string Password => GetNotEmptySettingValue(EmailSettingNames.Smtp.Password); public virtual string Password => GetNotEmptySettingValue(EmailSettingNames.Smtp.Password);
public virtual string Domain => SettingManager.GetOrNull(EmailSettingNames.Smtp.Domain); public virtual string Domain => SettingProvider.GetOrNull(EmailSettingNames.Smtp.Domain);
public virtual bool EnableSsl => SettingManager.GetOrNull(EmailSettingNames.Smtp.EnableSsl).To<bool>(); public virtual bool EnableSsl => SettingProvider.GetOrNull(EmailSettingNames.Smtp.EnableSsl).To<bool>();
public virtual bool UseDefaultCredentials => SettingManager.GetOrNull(EmailSettingNames.Smtp.UseDefaultCredentials).To<bool>(); public virtual bool UseDefaultCredentials => SettingProvider.GetOrNull(EmailSettingNames.Smtp.UseDefaultCredentials).To<bool>();
public SmtpEmailSenderConfiguration(ISettingManager settingManager) public SmtpEmailSenderConfiguration(ISettingProvider settingProvider)
: base(settingManager) : base(settingProvider)
{ {
} }

26
framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs

@ -22,26 +22,24 @@ namespace Volo.Abp.Http.Client.IdentityModel
public async Task Authenticate(RemoteServiceHttpClientAuthenticateContext context) public async Task Authenticate(RemoteServiceHttpClientAuthenticateContext context)
{ {
var accessToken = await GetAccessTokenFromHttpContextOrNullAsync(); if (context.RemoteService.GetUseCurrentAccessToken() != false)
if (accessToken != null)
{
context.Client.SetBearerToken(accessToken);
}
else
{ {
await IdentityModelHttpClientAuthenticator.AuthenticateAsync( var accessToken = await GetAccessTokenFromHttpContextOrNullAsync();
new IdentityModelHttpClientAuthenticateContext( if (accessToken != null)
context.Client, {
context.RemoteService.GetIdentityClient() context.Client.SetBearerToken(accessToken);
) return;
); }
} }
await IdentityModelHttpClientAuthenticator.AuthenticateAsync(
context.Client,
context.RemoteService.GetIdentityClient()
);
} }
protected virtual async Task<string> GetAccessTokenFromHttpContextOrNullAsync() protected virtual async Task<string> GetAccessTokenFromHttpContextOrNullAsync()
{ {
//TODO: What if the access_token in the current Http Request is not usable for this client?
var httpContext = HttpContextAccessor?.HttpContext; var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext == null) if (httpContext == null)
{ {

35
framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/RemoteServiceConfigurationExtensions.cs

@ -5,19 +5,48 @@ namespace Volo.Abp.Http.Client
{ {
public static class RemoteServiceConfigurationExtensions public static class RemoteServiceConfigurationExtensions
{ {
public const string IdentityClient = "IdentityClient"; public const string IdentityClientName = "IdentityClient";
public const string UseCurrentAccessTokenName = "UseCurrentAccessToken";
[CanBeNull] [CanBeNull]
public static string GetIdentityClient([NotNull] this RemoteServiceConfiguration configuration) public static string GetIdentityClient([NotNull] this RemoteServiceConfiguration configuration)
{ {
Check.NotNullOrEmpty(configuration, nameof(configuration)); Check.NotNullOrEmpty(configuration, nameof(configuration));
return configuration.GetOrDefault(IdentityClient); return configuration.GetOrDefault(IdentityClientName);
} }
public static RemoteServiceConfiguration SetIdentityClient([NotNull] this RemoteServiceConfiguration configuration, [CanBeNull] string value) public static RemoteServiceConfiguration SetIdentityClient([NotNull] this RemoteServiceConfiguration configuration, [CanBeNull] string value)
{ {
configuration[IdentityClient] = value; configuration[IdentityClientName] = value;
return configuration;
}
[CanBeNull]
public static bool? GetUseCurrentAccessToken([NotNull] this RemoteServiceConfiguration configuration)
{
Check.NotNullOrEmpty(configuration, nameof(configuration));
var value = configuration.GetOrDefault(UseCurrentAccessTokenName);
if (value == null)
{
return null;
}
return bool.Parse(value);
}
public static RemoteServiceConfiguration SetUseCurrentAccessToken([NotNull] this RemoteServiceConfiguration configuration, [CanBeNull] bool? value)
{
if (value == null)
{
configuration.Remove(UseCurrentAccessTokenName);
}
else
{
configuration[UseCurrentAccessTokenName] = value.Value.ToString().ToLowerInvariant();
}
return configuration; return configuration;
} }
} }

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

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

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

@ -1,17 +1,20 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Castle; using Volo.Abp.Castle;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client namespace Volo.Abp.Http.Client
{ {
[DependsOn(typeof(AbpHttpModule))] [DependsOn(
[DependsOn(typeof(AbpCastleCoreModule))] typeof(AbpHttpModule),
typeof(AbpCastleCoreModule),
typeof(AbpThreadingModule)
)]
public class AbpHttpClientModule : AbpModule public class AbpHttpClientModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
Configure<RemoteServiceOptions>(configuration); Configure<RemoteServiceOptions>(configuration);
} }
} }

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

Loading…
Cancel
Save