From a5ee78910afb9fd68b86f7892ba0c85378650ce1 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 12 May 2020 12:50:13 +0300 Subject: [PATCH 01/69] fix(theme-shared): fix loader bar problem --- .../components/loader-bar/loader-bar.component.scss | 5 ++++- .../components/loader-bar/loader-bar.component.ts | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss index 2dd3482e27..19a4f2ee8f 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss @@ -16,6 +16,9 @@ left: 0; position: fixed; top: 0; - transition: width 0.4s ease; + + &.progressing { + transition: width 0.4s ease; + } } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index 441359e476..de37ca18f7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -12,6 +12,7 @@ import { filter } from 'rxjs/operators';
Date: Tue, 12 May 2020 12:52:19 +0300 Subject: [PATCH 03/69] chore: change fn name resolves #3650 --- .../src/lib/components/loader-bar/loader-bar.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index de37ca18f7..426f3bb0f2 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -90,7 +90,7 @@ export class LoaderBarComponent implements OnDestroy, OnInit { this.isLoading = true; - const progress = () => { + const moveOn = () => { if (this.progressLevel < 75) { this.progressLevel += Math.random() * 10; } else if (this.progressLevel < 90) { @@ -103,8 +103,8 @@ export class LoaderBarComponent implements OnDestroy, OnInit { this.cdRef.detectChanges(); }; - progress(); - this.interval = interval(this.intervalPeriod).subscribe(() => progress()); + moveOn(); + this.interval = interval(this.intervalPeriod).subscribe(() => moveOn()); } stopLoading() { From 2a21eb7639c1b64d5d8bf149b36b35b4871fd3d5 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 12 May 2020 12:56:49 +0300 Subject: [PATCH 04/69] refactor(theme-shared): improve code quality --- .../src/lib/components/loader-bar/loader-bar.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index 426f3bb0f2..61f4d2f663 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -104,7 +104,7 @@ export class LoaderBarComponent implements OnDestroy, OnInit { }; moveOn(); - this.interval = interval(this.intervalPeriod).subscribe(() => moveOn()); + this.interval = interval(this.intervalPeriod).subscribe(moveOn); } stopLoading() { From bb68bdcdc599f0cedc3269e1cca2095921ab11c5 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 13 May 2020 14:49:09 +0800 Subject: [PATCH 05/69] Move localization middleware above authentication middleware --- .../applications/AuthServer.Host/AuthServerHostModule.cs | 2 +- .../BackendAdminApp.Host/BackendAdminAppHostModule.cs | 2 +- .../PublicWebSite.Host/PublicWebSiteHostModule.cs | 2 +- .../BloggingService.Host/BloggingServiceHostModule.cs | 2 +- .../IdentityService.Host/IdentityServiceHostModule.cs | 2 +- .../ProductService.Host/ProductServiceHostModule.cs | 2 +- .../TenantManagementServiceHostModule.cs | 2 +- .../MyProjectNameHttpApiHostModule.cs | 2 +- .../MyProjectNameHttpApiHostModule.cs | 2 +- .../MyProjectNameIdentityServerModule.cs | 4 ++-- .../MyProjectNameWebModule.cs | 6 ++---- .../MyProjectNameWebModule.cs | 2 +- .../MyProjectNameWebTestModule.cs | 4 ++-- .../MyProjectNameHttpApiHostModule.cs | 2 +- .../MyProjectNameIdentityServerModule.cs | 2 +- .../MyProjectNameWebHostModule.cs | 4 ++-- .../MyProjectNameWebUnifiedModule.cs | 2 +- 17 files changed, 21 insertions(+), 23 deletions(-) diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs index 08b6689cea..095f3c5ddc 100644 --- a/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs @@ -95,12 +95,12 @@ namespace AuthServer.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } app.UseIdentityServer(); - app.UseAbpRequestLocalization(); app.UseAuditing(); app.UseConfiguredEndpoints(); diff --git a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs index b0aba5af53..4414dc73ae 100644 --- a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs +++ b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs @@ -118,13 +118,13 @@ namespace BackendAdminApp.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs index bc0bb83021..9ea7543228 100644 --- a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs +++ b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs @@ -96,13 +96,13 @@ namespace PublicWebSite.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseConfiguredEndpoints(); } } diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs index 692d4c3d61..c546c57ae5 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs @@ -120,6 +120,7 @@ namespace BloggingService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -140,7 +141,6 @@ namespace BloggingService.Host { app.UseMultiTenancy(); } - app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index 982f4c09af..49c0bbd933 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -101,6 +101,7 @@ namespace IdentityService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); if (MsDemoConsts.IsMultiTenancyEnabled) { @@ -121,7 +122,6 @@ namespace IdentityService.Host await next(); }); - app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs index 44e23eeb78..9fb074fe76 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs @@ -104,6 +104,7 @@ namespace ProductService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -124,7 +125,6 @@ namespace ProductService.Host { app.UseMultiTenancy(); } - app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs index f9a818234f..f068c2adf9 100644 --- a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs @@ -105,6 +105,7 @@ namespace TenantManagementService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -125,7 +126,6 @@ namespace TenantManagementService.Host { app.UseMultiTenancy(); } - app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 2526aec04d..f560ac7e0a 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -178,13 +178,13 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs index 7a40f2eef5..06f52defb1 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs @@ -168,6 +168,7 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); + app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); @@ -178,7 +179,6 @@ namespace MyCompanyName.MyProjectName app.UseIdentityServer(); app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index 0a87b21a31..e3d6d5aa67 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -135,7 +135,7 @@ namespace MyCompanyName.MyProjectName }); }); } - + public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); @@ -154,6 +154,7 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { @@ -161,7 +162,6 @@ namespace MyCompanyName.MyProjectName } app.UseIdentityServer(); app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseAuditing(); app.UseAbpSerilogEnrichers(); app.UseConfiguredEndpoints(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs index 0809a70cc4..86738e3e1b 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs @@ -67,7 +67,7 @@ namespace MyCompanyName.MyProjectName.Web ); }); } - + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -225,6 +225,7 @@ namespace MyCompanyName.MyProjectName.Web app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) @@ -234,9 +235,6 @@ namespace MyCompanyName.MyProjectName.Web app.UseAuthorization(); - - app.UseAbpRequestLocalization(); - app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs index 8330951dfc..541a2c5e3a 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs @@ -204,6 +204,7 @@ namespace MyCompanyName.MyProjectName.Web app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); @@ -213,7 +214,6 @@ namespace MyCompanyName.MyProjectName.Web } app.UseIdentityServer(); app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs index 20f7e793c2..edde134027 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs @@ -89,10 +89,10 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.Use(async (ctx, next) => { @@ -110,4 +110,4 @@ namespace MyCompanyName.MyProjectName app.UseConfiguredEndpoints(); } } -} \ No newline at end of file +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index e425512797..8de889e88e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -165,13 +165,13 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index 9d0cb8397c..4bfd5f689a 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -186,6 +186,7 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); + app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); if (MultiTenancyConsts.IsEnabled) @@ -194,7 +195,6 @@ namespace MyCompanyName.MyProjectName } app.UseIdentityServer(); app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs index 385b840e75..6d16829e25 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs @@ -73,7 +73,7 @@ namespace MyCompanyName.MyProjectName ); }); } - + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -234,6 +234,7 @@ namespace MyCompanyName.MyProjectName app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) @@ -243,7 +244,6 @@ namespace MyCompanyName.MyProjectName app.UseAuthorization(); - app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs index 48b0667350..57b77e5f50 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs @@ -127,6 +127,7 @@ namespace MyCompanyName.MyProjectName app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); + app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseAuthorization(); if (MultiTenancyConsts.IsEnabled) @@ -140,7 +141,6 @@ namespace MyCompanyName.MyProjectName options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support APP API"); }); - app.UseAbpRequestLocalization(); app.UseAuditing(); app.UseAbpSerilogEnrichers(); app.UseConfiguredEndpoints(); From 5b91c8954beae73903cb9a405ffe42d5374b86fa Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 13 May 2020 18:13:05 +0800 Subject: [PATCH 06/69] Check whether MethodInfo's DeclaringType has auditing disabled. --- .../Volo/Abp/Auditing/AuditingHelper.cs | 19 ++++++++++--------- .../Auditing/AuditingInterceptorRegistrar.cs | 10 +++++----- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs index e53ba5b9a6..4c3ede4ca8 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs @@ -36,7 +36,7 @@ namespace Volo.Abp.Auditing IClock clock, IAuditingStore auditingStore, ILogger logger, - IServiceProvider serviceProvider, + IServiceProvider serviceProvider, ICorrelationIdProvider correlationIdProvider) { Options = options.Value; @@ -77,9 +77,10 @@ namespace Volo.Abp.Auditing var classType = methodInfo.DeclaringType; if (classType != null) { - if (AuditingInterceptorRegistrar.ShouldAuditTypeByDefault(classType)) + var shouldAudit = AuditingInterceptorRegistrar.ShouldAuditTypeByDefaultOrNull(classType); + if (shouldAudit != null) { - return true; + return shouldAudit.Value; } } @@ -123,7 +124,7 @@ namespace Volo.Abp.Auditing return defaultValue; } - + public virtual AuditLogInfo CreateAuditLogInfo() { var auditInfo = new AuditLogInfo @@ -147,8 +148,8 @@ namespace Volo.Abp.Auditing public virtual AuditLogActionInfo CreateAuditLogAction( AuditLogInfo auditLog, - Type type, - MethodInfo method, + Type type, + MethodInfo method, object[] arguments) { return CreateAuditLogAction(auditLog, type, method, CreateArgumentsDictionary(method, arguments)); @@ -156,8 +157,8 @@ namespace Volo.Abp.Auditing public virtual AuditLogActionInfo CreateAuditLogAction( AuditLogInfo auditLog, - Type type, - MethodInfo method, + Type type, + MethodInfo method, IDictionary arguments) { var actionInfo = new AuditLogActionInfo @@ -240,4 +241,4 @@ namespace Volo.Abp.Auditing return dictionary; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs index a407335f3d..54607a55ca 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs @@ -21,8 +21,8 @@ namespace Volo.Abp.Auditing { return false; } - - if (ShouldAuditTypeByDefault(type)) + + if (ShouldAuditTypeByDefaultOrNull(type) == true) { return true; } @@ -36,7 +36,7 @@ namespace Volo.Abp.Auditing } //TODO: Move to a better place - public static bool ShouldAuditTypeByDefault(Type type) + public static bool? ShouldAuditTypeByDefaultOrNull(Type type) { //TODO: In an inheritance chain, it would be better to check the attributes on the top class first. @@ -55,7 +55,7 @@ namespace Volo.Abp.Auditing return true; } - return false; + return null; } } -} \ No newline at end of file +} From f5e5edae820ac0e3b35feb4f0714530fd0844cc3 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 14 May 2020 09:49:49 +0800 Subject: [PATCH 07/69] Search phone number --- .../MongoDB/MongoIdentityUserRepository.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index 9eb1664bd5..52a345b0c4 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -15,13 +15,13 @@ namespace Volo.Abp.Identity.MongoDB { public class MongoIdentityUserRepository : MongoDbRepository, IIdentityUserRepository { - public MongoIdentityUserRepository(IMongoDbContextProvider dbContextProvider) + public MongoIdentityUserRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { } public virtual async Task FindByNormalizedUserNameAsync( - string normalizedUserName, + string normalizedUserName, bool includeDetails = true, CancellationToken cancellationToken = default) { @@ -33,7 +33,7 @@ namespace Volo.Abp.Identity.MongoDB } public virtual async Task> GetRoleNamesAsync( - Guid id, + Guid id, CancellationToken cancellationToken = default) { var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)); @@ -42,8 +42,8 @@ namespace Volo.Abp.Identity.MongoDB } public virtual async Task FindByLoginAsync( - string loginProvider, - string providerKey, + string loginProvider, + string providerKey, bool includeDetails = true, CancellationToken cancellationToken = default) { @@ -71,7 +71,7 @@ namespace Volo.Abp.Identity.MongoDB } public virtual async Task> GetListByNormalizedRoleNameAsync( - string normalizedRoleName, + string normalizedRoleName, bool includeDetails = false, CancellationToken cancellationToken = default) { @@ -89,9 +89,9 @@ namespace Volo.Abp.Identity.MongoDB public virtual async Task> GetListAsync( string sorting = null, - int maxResultCount = int.MaxValue, - int skipCount = 0, - string filter = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default) { @@ -100,7 +100,8 @@ namespace Volo.Abp.Identity.MongoDB !filter.IsNullOrWhiteSpace(), u => u.UserName.Contains(filter) || - u.Email.Contains(filter) + u.Email.Contains(filter) || + (u.PhoneNumber != null && u.PhoneNumber.Contains(filter)) ) .OrderBy(sorting ?? nameof(IdentityUser.UserName)) .As>() @@ -132,4 +133,4 @@ namespace Volo.Abp.Identity.MongoDB .LongCountAsync(GetCancellationToken(cancellationToken)); } } -} \ No newline at end of file +} From 0c51afc37112237cd73e4fc10f31dc2a2d95a93b Mon Sep 17 00:00:00 2001 From: Ahmet Date: Thu, 14 May 2020 16:35:20 +0300 Subject: [PATCH 08/69] Added escape blocks for text templating module --- docs/en/Text-Templating.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/en/Text-Templating.md b/docs/en/Text-Templating.md index 9cad6598f1..18a360c5c8 100644 --- a/docs/en/Text-Templating.md +++ b/docs/en/Text-Templating.md @@ -17,7 +17,7 @@ You can use the rendered output for any purpose, like sending emails or preparin Here, a simple template: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` You can define a class with a `Name` property to render this template: @@ -114,7 +114,7 @@ public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider Example `Hello.tpl` content is shown below: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class: @@ -204,7 +204,7 @@ Inline localization uses the [localization system](Localization.md) to localize Assuming you need to send an email to a user to reset her/his password. Here, the template content: ```` -{{L "ResetMyPassword"}} +{%{{{L "ResetMyPassword"}}}%} ```` `L` function is used to localize the given key based on the current user culture. You need to define the `ResetMyPassword` key inside your localization file: @@ -314,12 +314,12 @@ First, create a template file just like before: - {{content}} + {%{{{content}}}%} ```` -* A layout template must have a **{{content}}** part as a place holder for the rendered child content. +* A layout template must have a **{%{{{content}}}%}** part as a place holder for the rendered child content. The register your template in the template definition provider: @@ -357,7 +357,7 @@ ABP passes the `model` that can be used to access to the model inside the templa An example template content: ```` -A global object value: {{myGlobalObject}} +A global object value: {%{{{myGlobalObject}}}%} ```` This template assumes that that is a `myGlobalObject` object in the template rendering context. You can provide it like shown below: @@ -413,7 +413,7 @@ public class TemplateContentDemo : ITransientDependency The result will be the raw template content: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` * `GetContentOrNullAsync` returns `null` if no content defined for the requested template. From e9159fd1b969f8caa164926a9a50859b168e46f4 Mon Sep 17 00:00:00 2001 From: Ahmet Date: Thu, 14 May 2020 16:39:01 +0300 Subject: [PATCH 09/69] Added escape blocks for text templating documentation --- docs/en/Text-Templating.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/en/Text-Templating.md b/docs/en/Text-Templating.md index 9cad6598f1..18a360c5c8 100644 --- a/docs/en/Text-Templating.md +++ b/docs/en/Text-Templating.md @@ -17,7 +17,7 @@ You can use the rendered output for any purpose, like sending emails or preparin Here, a simple template: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` You can define a class with a `Name` property to render this template: @@ -114,7 +114,7 @@ public class DemoTemplateDefinitionProvider : TemplateDefinitionProvider Example `Hello.tpl` content is shown below: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` The [Virtual File System](Virtual-File-System.md) requires to add your files in the `ConfigureServices` method of your [module](Module-Development-Basics.md) class: @@ -204,7 +204,7 @@ Inline localization uses the [localization system](Localization.md) to localize Assuming you need to send an email to a user to reset her/his password. Here, the template content: ```` -{{L "ResetMyPassword"}} +{%{{{L "ResetMyPassword"}}}%} ```` `L` function is used to localize the given key based on the current user culture. You need to define the `ResetMyPassword` key inside your localization file: @@ -314,12 +314,12 @@ First, create a template file just like before: - {{content}} + {%{{{content}}}%} ```` -* A layout template must have a **{{content}}** part as a place holder for the rendered child content. +* A layout template must have a **{%{{{content}}}%}** part as a place holder for the rendered child content. The register your template in the template definition provider: @@ -357,7 +357,7 @@ ABP passes the `model` that can be used to access to the model inside the templa An example template content: ```` -A global object value: {{myGlobalObject}} +A global object value: {%{{{myGlobalObject}}}%} ```` This template assumes that that is a `myGlobalObject` object in the template rendering context. You can provide it like shown below: @@ -413,7 +413,7 @@ public class TemplateContentDemo : ITransientDependency The result will be the raw template content: ```` -Hello {{model.name}} :) +Hello {%{{{model.name}}}%} :) ```` * `GetContentOrNullAsync` returns `null` if no content defined for the requested template. From 41d63f6b7880dffee7dc598a1c3d915d045f9a44 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 14 May 2020 17:41:55 +0300 Subject: [PATCH 10/69] chore: add AuthGuard to setting-managent-routing.module --- .../src/lib/setting-management-routing.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts b/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts index f394abc962..55a056c411 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts +++ b/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts @@ -2,6 +2,7 @@ import { DynamicLayoutComponent, ReplaceableComponents, ReplaceableRouteContainerComponent, + AuthGuard, } from '@abp/ng.core'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; @@ -12,6 +13,7 @@ const routes: Routes = [ { path: '', component: DynamicLayoutComponent, + canActivate: [AuthGuard], children: [ { path: '', From d3543c7c4c33fb0b262200d90ea42bc1b5a571ca Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 18:46:14 +0300 Subject: [PATCH 11/69] refactor: move ops to seperate methods and properties --- .../loader-bar/loader-bar.component.ts | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts index 61f4d2f663..41a5850131 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts @@ -3,7 +3,7 @@ import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular import { NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; import { takeUntilDestroy } from '@ngx-validate/core'; import { Actions, ofActionSuccessful } from '@ngxs/store'; -import { interval, Subscription, timer } from 'rxjs'; +import { Subscription, timer } from 'rxjs'; import { filter } from 'rxjs/operators'; @Component({ @@ -30,6 +30,10 @@ export class LoaderBarComponent implements OnDestroy, OnInit { @Input() color = '#77b6ff'; + @Input() + filter = (action: StartLoader | StopLoader) => + action.payload.url.indexOf('openid-configuration') < 0; + @Input() isLoading = false; @@ -43,9 +47,23 @@ export class LoaderBarComponent implements OnDestroy, OnInit { stopDelay = 800; - @Input() - filter = (action: StartLoader | StopLoader) => - action.payload.url.indexOf('openid-configuration') < 0; + private readonly clearProgress = () => { + this.progressLevel = 0; + this.cdRef.detectChanges(); + }; + + private readonly reportProgress = () => { + if (this.progressLevel < 75) { + this.progressLevel += 1 + Math.random() * 9; + } else if (this.progressLevel < 90) { + this.progressLevel += 0.4; + } else if (this.progressLevel < 100) { + this.progressLevel += 0.1; + } else { + this.interval.unsubscribe(); + } + this.cdRef.detectChanges(); + }; get boxShadow(): string { return `0 0 10px rgba(${this.color}, 0.5)`; @@ -53,7 +71,7 @@ export class LoaderBarComponent implements OnDestroy, OnInit { constructor(private actions: Actions, private router: Router, private cdRef: ChangeDetectorRef) {} - ngOnInit() { + private subscribeToLoadActions() { this.actions .pipe( ofActionSuccessful(StartLoader, StopLoader), @@ -64,7 +82,9 @@ export class LoaderBarComponent implements OnDestroy, OnInit { if (action instanceof StartLoader) this.startLoading(); else this.stopLoading(); }); + } + private subscribeToRouterEvents() { this.router.events .pipe( filter( @@ -81,6 +101,11 @@ export class LoaderBarComponent implements OnDestroy, OnInit { }); } + ngOnInit() { + this.subscribeToLoadActions(); + this.subscribeToRouterEvents(); + } + ngOnDestroy() { if (this.interval) this.interval.unsubscribe(); } @@ -90,32 +115,17 @@ export class LoaderBarComponent implements OnDestroy, OnInit { this.isLoading = true; - const moveOn = () => { - if (this.progressLevel < 75) { - this.progressLevel += Math.random() * 10; - } else if (this.progressLevel < 90) { - this.progressLevel += 0.4; - } else if (this.progressLevel < 100) { - this.progressLevel += 0.1; - } else { - this.interval.unsubscribe(); - } - this.cdRef.detectChanges(); - }; - - moveOn(); - this.interval = interval(this.intervalPeriod).subscribe(moveOn); + this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress); } stopLoading() { if (this.interval) this.interval.unsubscribe(); + this.progressLevel = 100; this.isLoading = false; + if (this.timer && !this.timer.closed) return; - this.timer = timer(this.stopDelay).subscribe(() => { - this.progressLevel = 0; - this.cdRef.detectChanges(); - }); + this.timer = timer(this.stopDelay).subscribe(this.clearProgress); } } From 7678e39edd5231358ddae6ce0954af1f7d36cc0b Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 19:36:18 +0300 Subject: [PATCH 12/69] feat: add a token for list query debounce time --- npm/ng-packs/packages/core/src/lib/tokens/index.ts | 1 + npm/ng-packs/packages/core/src/lib/tokens/list.token.ts | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/tokens/list.token.ts diff --git a/npm/ng-packs/packages/core/src/lib/tokens/index.ts b/npm/ng-packs/packages/core/src/lib/tokens/index.ts index 683bc4b3db..8d23d581a5 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/index.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/index.ts @@ -1 +1,2 @@ +export * from './list.token'; export * from './options.token'; diff --git a/npm/ng-packs/packages/core/src/lib/tokens/list.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/list.token.ts new file mode 100644 index 0000000000..b51ffb9fb3 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tokens/list.token.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const LIST_QUERY_DEBOUNCE_TIME = new InjectionToken('LIST_QUERY_DEBOUNCE_TIME'); From 2d694e9e39a886abe4bd601f0896611cf48c1441 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 19:36:40 +0300 Subject: [PATCH 13/69] feat: add a service for easily querying lists --- .../packages/core/src/lib/services/index.ts | 1 + .../core/src/lib/services/list.service.ts | 96 +++++++++++ .../core/src/lib/tests/list.service.spec.ts | 150 ++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/services/list.service.ts create mode 100644 npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index f8b016bbd1..f01dc876de 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -4,6 +4,7 @@ export * from './config-state.service'; export * from './content-projection.service'; export * from './dom-insertion.service'; export * from './lazy-load.service'; +export * from './list.service'; export * from './localization.service'; export * from './profile-state.service'; export * from './profile.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts new file mode 100644 index 0000000000..1e0b8e22b9 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -0,0 +1,96 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; +import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { ABP } from '../models/common'; +import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token'; +import { takeUntilDestroy } from '../utils/rxjs-utils'; + +@Injectable() +export class ListService { + private _filter = ''; + set filter(value: string) { + this._filter = value; + this.get(); + } + get filter(): string { + return this._filter; + } + + private _maxResultCount = 10; + set maxResultCount(value: number) { + this._maxResultCount = value; + this.get(); + } + get maxResultCount(): number { + return this._maxResultCount; + } + + private _page = 1; + set page(value: number) { + this._page = value; + this.get(); + } + get page(): number { + return this._page; + } + + private _sortKey = ''; + set sortKey(value: string) { + console.log(value); + this._sortKey = value; + this.get(); + } + get sortKey(): string { + return this._sortKey; + } + + private _sortOrder = ''; + set sortOrder(value: string) { + this._sortOrder = value; + this.get(); + } + get sortOrder(): string { + return this._sortOrder; + } + + private _query$ = new ReplaySubject(1); + + get query$(): Observable { + return this._query$ + .asObservable() + .pipe(debounceTime(this.delay || 300), shareReplay({ bufferSize: 1, refCount: true })); + } + + private _isLoading$ = new BehaviorSubject(false); + + get isLoading$(): Observable { + return this._isLoading$.asObservable(); + } + + constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) { + this.get(); + } + + get() { + this._query$.next({ + filter: this._filter || undefined, + maxResultCount: this._maxResultCount, + skipCount: (this._page - 1) * this._maxResultCount, + sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined, + }); + } + + hookToQuery(streamCreatorCallback: QueryStreamCreatorCallback): Observable { + this._isLoading$.next(true); + + return this.query$.pipe( + switchMap(streamCreatorCallback), + tap(() => this._isLoading$.next(false)), + takeUntilDestroy(this), + ); + } + + ngOnDestroy() {} +} + +export type QueryStreamCreatorCallback = (query: ABP.PageQueryParams) => Observable; diff --git a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts new file mode 100644 index 0000000000..b7e2cc8450 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts @@ -0,0 +1,150 @@ +import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest'; +import { of } from 'rxjs'; +import { bufferCount, take } from 'rxjs/operators'; +import { ListService } from '../services/list.service'; +import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens'; + +describe('ListService', () => { + let spectator: SpectatorService; + let service: ListService; + + const createService = createServiceFactory({ + service: ListService, + providers: [ + { + provide: LIST_QUERY_DEBOUNCE_TIME, + useValue: 0, + }, + ], + }); + + beforeEach(() => { + spectator = createService(); + service = spectator.service; + }); + + describe('#filter', () => { + it('should initially be empty string', () => { + expect(service.filter).toBe(''); + }); + + it('should be changed', () => { + service.filter = 'foo'; + + expect(service.filter).toBe('foo'); + }); + }); + + describe('#maxResultCount', () => { + it('should initially be 10', () => { + expect(service.maxResultCount).toBe(10); + }); + + it('should be changed', () => { + service.maxResultCount = 20; + + expect(service.maxResultCount).toBe(20); + }); + }); + + describe('#page', () => { + it('should initially be 1', () => { + expect(service.page).toBe(1); + }); + + it('should be changed', () => { + service.page = 9; + + expect(service.page).toBe(9); + }); + }); + + describe('#sortKey', () => { + it('should initially be empty string', () => { + expect(service.sortKey).toBe(''); + }); + + it('should be changed', () => { + service.sortKey = 'foo'; + + expect(service.sortKey).toBe('foo'); + }); + }); + + describe('#sortOrder', () => { + it('should initially be empty string', () => { + expect(service.sortOrder).toBe(''); + }); + + it('should be changed', () => { + service.sortOrder = 'foo'; + + expect(service.sortOrder).toBe('foo'); + }); + }); + + describe('#query$', () => { + it('should initially emit default query', done => { + service.query$.pipe(take(1)).subscribe(query => { + expect(query).toEqual({ + filter: undefined, + maxResultCount: 10, + skipCount: 0, + sorting: undefined, + }); + + done(); + }); + }); + + it('should emit a query based on params set', done => { + service.filter = 'foo'; + service.sortKey = 'bar'; + service.sortOrder = 'baz'; + service.maxResultCount = 20; + service.page = 9; + + service.query$.pipe(take(1)).subscribe(query => { + expect(query).toEqual({ + filter: 'foo', + sorting: 'bar baz', + maxResultCount: 20, + skipCount: 160, + }); + + done(); + }); + }); + }); + + describe('#hookToQuery', () => { + it('should call given callback with the query', done => { + const callback = query => of(query); + + service.hookToQuery(callback).subscribe(query => { + expect(query).toEqual({ + filter: undefined, + maxResultCount: 10, + skipCount: 0, + sorting: undefined, + }); + + done(); + }); + }); + + it('should emit isLoading as side effect', done => { + const callback = query => of(query); + + service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => { + expect(idle).toBe(false); + expect(init).toBe(true); + expect(end).toBe(false); + + done(); + }); + + service.hookToQuery(callback).subscribe(); + }); + }); +}); From 0744544259a853a785c891de46f9ebff75746fa3 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 21:24:09 +0300 Subject: [PATCH 14/69] feat: shareReplay response and improve callback type --- .../core/src/lib/services/list.service.ts | 20 ++++++++++++------- .../core/src/lib/tests/list.service.spec.ts | 11 ++++++---- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index 1e0b8e22b9..c41b1f3ff6 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -2,6 +2,7 @@ import { Inject, Injectable, Optional } from '@angular/core'; import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators'; import { ABP } from '../models/common'; +import { PagedResultDto } from '../models/dtos'; import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token'; import { takeUntilDestroy } from '../utils/rxjs-utils'; @@ -67,25 +68,28 @@ export class ListService { return this._isLoading$.asObservable(); } - constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) { - this.get(); - } - - get() { + get = () => { this._query$.next({ filter: this._filter || undefined, maxResultCount: this._maxResultCount, skipCount: (this._page - 1) * this._maxResultCount, sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined, }); + }; + + constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) { + this.get(); } - hookToQuery(streamCreatorCallback: QueryStreamCreatorCallback): Observable { + hookToQuery( + streamCreatorCallback: QueryStreamCreatorCallback, + ): Observable> { this._isLoading$.next(true); return this.query$.pipe( switchMap(streamCreatorCallback), tap(() => this._isLoading$.next(false)), + shareReplay({ bufferSize: 1, refCount: true }), takeUntilDestroy(this), ); } @@ -93,4 +97,6 @@ export class ListService { ngOnDestroy() {} } -export type QueryStreamCreatorCallback = (query: ABP.PageQueryParams) => Observable; +export type QueryStreamCreatorCallback = ( + query: ABP.PageQueryParams, +) => Observable>; diff --git a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts index b7e2cc8450..c2118d7f3a 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts @@ -1,7 +1,8 @@ import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; import { bufferCount, take } from 'rxjs/operators'; -import { ListService } from '../services/list.service'; +import { ABP } from '../models'; +import { ListService, QueryStreamCreatorCallback } from '../services/list.service'; import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens'; describe('ListService', () => { @@ -119,9 +120,10 @@ describe('ListService', () => { describe('#hookToQuery', () => { it('should call given callback with the query', done => { - const callback = query => of(query); + const callback: QueryStreamCreatorCallback = query => + of({ items: [query], totalCount: 1 }); - service.hookToQuery(callback).subscribe(query => { + service.hookToQuery(callback).subscribe(({ items: [query] }) => { expect(query).toEqual({ filter: undefined, maxResultCount: 10, @@ -134,7 +136,8 @@ describe('ListService', () => { }); it('should emit isLoading as side effect', done => { - const callback = query => of(query); + const callback: QueryStreamCreatorCallback = query => + of({ items: [query], totalCount: 1 }); service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => { expect(idle).toBe(false); From e3034a7f949e846d15ed8dd0fb86048461fbd3ec Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 21:24:49 +0300 Subject: [PATCH 15/69] docs: describe how ListService is used --- docs/en/UI/Angular/List-Service.md | 155 +++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/en/UI/Angular/List-Service.md diff --git a/docs/en/UI/Angular/List-Service.md b/docs/en/UI/Angular/List-Service.md new file mode 100644 index 0000000000..b6a4dadf3e --- /dev/null +++ b/docs/en/UI/Angular/List-Service.md @@ -0,0 +1,155 @@ +# Querying Lists Easily with ListService + +`ListService` is a utility service to provide an easy pagination, sorting, and search implementation. + + + +## Getting Started + +`ListService` is **not provided in root**. The reason is, this way, it will clear any subscriptions on component destroy. You may use the optional `LIST_QUERY_DEBOUNCE_TIME` token to adjust the debounce behavior. + +```js +import { ListService } from '@abp/ng.core'; +import { BookDto } from '../models'; +import { BookService } from '../services'; + +@Component({ + /* class metadata here */ + providers: [ + // [Required] + ListService, + + // [Optional] + // Provide this token if you want a different debounce time. + // Default is 300. Cannot be 0. Any value below 100 is not recommended. + { provide: LIST_QUERY_DEBOUNCE_TIME, useValue: 500 }, + ], + template: ` + + `, +}) +class BookComponent { + items: BookDto[] = []; + count = 0; + + constructor( + public readonly list: ListService, + private bookService: BookService, + ) {} + + ngOnInit() { + // A function that gets query and returns an observable + const bookStreamCreator = query => this.bookService.getList(query); + + this.list.hookToQuery(bookStreamCreator).subscribe( + response => { + this.items = response.items; + this.count = response.count; + // If you use OnPush change detection strategy, + // call detectChanges method of ChangeDetectorRef here. + } + ); // Subscription is auto-cleared on destroy. + } +} +``` + +> Noticed `list` is `public` and `readonly`? That is because we will use `ListService` properties directly in the component's template. That may be considered as an anti-pattern, but it is much quicker to implement. You can always use public component properties instead. + +Place `ListService` properties into the template like this: + +```html + + + + + + + {%{{{ '::Name' | abpLocalization }}}%} + + + + + + + + {%{{{ data.name }}}%} + + +``` + +## Usage with Observables + +You may use observables in combination with [AsyncPipe](https://angular.io/guide/observables-in-angular#async-pipe) of Angular instead. Here are some possibilities: + +```ts + book$ = this.list.hookToQuery(query => this.bookService.getListByInput(query)); +``` + +```html + + + + + + +``` + +...or... + + +```ts + @Select(BookState.getBooks) + books$: Observable; + + @Select(BookState.getBookCount) + bookCount$: Observable; + + ngOnInit() { + this.list.hookToQuery((query) => this.store.dispatch(new GetBooks(query))).subscribe(); + } +``` + +```html + + + + +``` + +## How to Refresh Table on Create/Update/Delete + +`ListService` exposes a `get` method to trigger a request with the current query. So, basically, whenever a create, update, or delete action resolves, you can call `this.list.get();` and it will call hooked stream creator again. + +```ts +this.store.dispatch(new DeleteBook(id)).subscribe(this.list.get); +``` + +...or... + +```ts +this.bookService.createByInput(form.value) + .subscribe(() => { + this.list.get(); + + // Other subscription logic here + }) +``` From eca8cde624cbfbe4e353e4b956489403bb5c0168 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 21:25:21 +0300 Subject: [PATCH 16/69] docs: add links to ListService document --- docs/en/UI/Angular/Track-By-Service.md | 6 ++++++ docs/en/docs-nav.json | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/docs/en/UI/Angular/Track-By-Service.md b/docs/en/UI/Angular/Track-By-Service.md index e6b560a2eb..447cc4505a 100644 --- a/docs/en/UI/Angular/Track-By-Service.md +++ b/docs/en/UI/Angular/Track-By-Service.md @@ -111,3 +111,9 @@ class DemoComponent { trackByTenantAccountId = trackByDeep('tenant', 'account', 'id'); } ``` + + + +## What's Next? + +- [ListService](./List-Service.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 5f6203054e..47789023c4 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -383,6 +383,10 @@ { "text": "TrackByService", "path": "UI/Angular/Track-By-Service.md" + }, + { + "text": "ListService", + "path": "UI/Angular/List-Service.md" } ] }, From 7141295830895a5c8b13eded6eba95a3cebdc950 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 21:30:09 +0300 Subject: [PATCH 17/69] docs: describe how search is done using ListService --- docs/en/UI/Angular/List-Service.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/en/UI/Angular/List-Service.md b/docs/en/UI/Angular/List-Service.md index b6a4dadf3e..b3c8571866 100644 --- a/docs/en/UI/Angular/List-Service.md +++ b/docs/en/UI/Angular/List-Service.md @@ -153,3 +153,13 @@ this.bookService.createByInput(form.value) // Other subscription logic here }) ``` + +## How to Implement Server-Side Search in a Table + +`ListService` exposes a `filter` property that will trigger a request with the current query and the given search string. All you need to do is to bind it to an input element with two-way binding. + +```html + + + +``` From d4cdbd4e8a0fa2f12b171140a787304513508a51 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 14 May 2020 21:36:10 +0300 Subject: [PATCH 18/69] fix: avoid lint errors --- npm/ng-packs/packages/core/src/lib/services/list.service.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index c41b1f3ff6..944368ad88 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, OnDestroy, Optional } from '@angular/core'; import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators'; import { ABP } from '../models/common'; @@ -7,7 +7,7 @@ import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token'; import { takeUntilDestroy } from '../utils/rxjs-utils'; @Injectable() -export class ListService { +export class ListService implements OnDestroy { private _filter = ''; set filter(value: string) { this._filter = value; @@ -37,7 +37,6 @@ export class ListService { private _sortKey = ''; set sortKey(value: string) { - console.log(value); this._sortKey = value; this.get(); } From e0dffacd5c86f204c511ad8afaba43d703ce402f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 15 May 2020 00:42:42 +0300 Subject: [PATCH 19/69] Send all attributes to clients for extra properties. --- .../ExtensionPropertyAttributeDto.cs | 25 +---- .../CachedObjectExtensionsDtoService.cs | 22 +++-- .../ExtensionPropertyAttributeDtoFactory.cs | 95 +++++++++++++++++++ .../ICachedObjectExtensionsDtoService.cs | 0 .../IExtensionPropertyAttributeDtoFactory.cs | 9 ++ 5 files changed, 119 insertions(+), 32 deletions(-) rename framework/src/{Volo.Abp.AspNetCore.Mvc.Contracts => Volo.Abp.AspNetCore.Mvc}/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs (89%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs rename framework/src/{Volo.Abp.AspNetCore.Mvc.Contracts => Volo.Abp.AspNetCore.Mvc}/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs (100%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs index c1c19350c2..12941a3b89 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs @@ -1,36 +1,13 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending { [Serializable] public class ExtensionPropertyAttributeDto { - public string Type { get; set; } public string TypeSimple { get; set; } - public Dictionary Configuration { get; set; } - public static ExtensionPropertyAttributeDto Create(Attribute attribute) - { - var attributeType = attribute.GetType(); - var dto = new ExtensionPropertyAttributeDto - { - Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(attributeType), - TypeSimple = TypeHelper.GetSimplifiedName(attributeType), - Configuration = new Dictionary() - }; - - if (attribute is StringLengthAttribute stringLengthAttribute) - { - dto.Configuration["MaximumLength"] = stringLengthAttribute.MaximumLength; - dto.Configuration["MinimumLength"] = stringLengthAttribute.MinimumLength; - } - - //TODO: Others! - - return dto; - } + public Dictionary Config { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs similarity index 89% rename from framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index f87fef31aa..6e72a6863e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -10,23 +10,29 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending { public class CachedObjectExtensionsDtoService : ICachedObjectExtensionsDtoService, ISingletonDependency { - private volatile ObjectExtensionsDto _cachedValue; - private readonly object _syncLock = new object(); + protected IExtensionPropertyAttributeDtoFactory ExtensionPropertyAttributeDtoFactory { get; } + protected volatile ObjectExtensionsDto CachedValue; + protected readonly object SyncLock = new object(); + + public CachedObjectExtensionsDtoService(IExtensionPropertyAttributeDtoFactory extensionPropertyAttributeDtoFactory) + { + ExtensionPropertyAttributeDtoFactory = extensionPropertyAttributeDtoFactory; + } public virtual ObjectExtensionsDto Get() { - if (_cachedValue == null) + if (CachedValue == null) { - lock (_syncLock) + lock (SyncLock) { - if (_cachedValue == null) + if (CachedValue == null) { - _cachedValue = GenerateCacheValue(); + CachedValue = GenerateCacheValue(); } } } - return _cachedValue; + return CachedValue; } protected virtual ObjectExtensionsDto GenerateCacheValue() @@ -137,7 +143,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending foreach (var attribute in propertyConfig.Attributes) { extensionPropertyDto.Attributes.Add( - ExtensionPropertyAttributeDto.Create(attribute) + ExtensionPropertyAttributeDtoFactory.Create(attribute) ); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs new file mode 100644 index 0000000000..18c5f62591 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Reflection; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending +{ + public class ExtensionPropertyAttributeDtoFactory : IExtensionPropertyAttributeDtoFactory, ITransientDependency + { + public virtual ExtensionPropertyAttributeDto Create(Attribute attribute) + { + return new ExtensionPropertyAttributeDto + { + TypeSimple = GetSimplifiedName(attribute), + Config = CreateConfiguration(attribute) + }; + } + + protected virtual string GetSimplifiedName(Attribute attribute) + { + return attribute.GetType().Name.ToCamelCase().RemovePostFix("Attribute"); + } + + protected virtual Dictionary CreateConfiguration(Attribute attribute) + { + var configuration = new Dictionary(); + + AddPropertiesToConfiguration(attribute, configuration); + + return configuration; + } + + protected virtual void AddPropertiesToConfiguration(Attribute attribute, Dictionary configuration) + { + var properties = attribute + .GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var property in properties) + { + if (IgnoreProperty(attribute, property)) + { + continue; + } + + var value = GetPropertyValue(attribute, property); + if (value == null) + { + continue; + } + + configuration[property.Name.ToCamelCase()] = value; + } + } + + protected virtual bool IgnoreProperty(Attribute attribute, PropertyInfo property) + { + if (property.DeclaringType == null || + property.DeclaringType.IsIn(typeof(ValidationAttribute), typeof(Attribute), typeof(object))) + { + return true; + } + + if (property.PropertyType == typeof(DisplayFormatAttribute)) + { + return true; + } + + return false; + } + + protected virtual object GetPropertyValue(Attribute attribute, PropertyInfo property) + { + var value = property.GetValue(attribute); + if (value == null) + { + return null; + } + + if (property.PropertyType.IsEnum) + { + return Enum.GetName(property.PropertyType, value); + } + + if (property.PropertyType == typeof(Type)) + { + return TypeHelper.GetSimplifiedName((Type) value); + } + + return value; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs new file mode 100644 index 0000000000..5e01077604 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending +{ + public interface IExtensionPropertyAttributeDtoFactory + { + ExtensionPropertyAttributeDto Create(Attribute attribute); + } +} \ No newline at end of file From 25085b2959bf315814507cef9835d9e2a8d673a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 15 May 2020 03:10:40 +0300 Subject: [PATCH 20/69] Improve extension property model binding. --- .../AbpExtraPropertyModelBinder.cs | 4 ++- .../ObjectExtendingPropertyInfoExtensions.cs | 36 ++++++++++++++----- .../Volo/Abp/Reflection/TypeHelper.cs | 13 +++++++ .../Volo/Abp/Reflection/TypeHelper_Tests.cs | 8 +++++ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs index d3f570b1ce..c94ad08e74 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs @@ -1,7 +1,9 @@ using System; +using System.ComponentModel; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; using Volo.Abp.ObjectExtending; +using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { @@ -59,7 +61,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding return value; } - return Convert.ChangeType(value, propertyInfo.Type); + return TypeHelper.ConvertFromString(propertyInfo.Type, value); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs index 9bb6c903a9..04339eedd3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; @@ -6,6 +7,31 @@ namespace Volo.Abp.ObjectExtending { public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions { + private static readonly HashSet NumberTypes = new HashSet { + typeof(int), + typeof(long), + typeof(byte), + typeof(sbyte), + typeof(short), + typeof(ushort), + typeof(uint), + typeof(long), + typeof(ulong), + typeof(float), + typeof(double), + typeof(int?), + typeof(long?), + typeof(byte?), + typeof(sbyte?), + typeof(short?), + typeof(ushort?), + typeof(uint?), + typeof(long?), + typeof(ulong?), + typeof(float?), + typeof(double?), + }; + public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) { foreach (var attribute in propertyInfo.Attributes) @@ -79,15 +105,7 @@ namespace Volo.Abp.ObjectExtending return "datetime-local"; } - if (type == typeof(int) || - type == typeof(long) || - type == typeof(byte) || - type == typeof(sbyte) || - type == typeof(short) || - type == typeof(ushort) || - type == typeof(uint) || - type == typeof(long) || - type == typeof(ulong)) + if (NumberTypes.Contains(type)) { return "number"; } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 11f43f852e..63b3538c3a 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Reflection; using JetBrains.Annotations; @@ -264,5 +265,17 @@ namespace Volo.Abp.Reflection return type.FullName; } + + public static object ConvertFromString(string value) + { + return ConvertFromString(typeof(TTargetType), value); + } + + public static object ConvertFromString(Type targetType, string value) + { + return TypeDescriptor + .GetConverter(targetType) + .ConvertFromString(value); + } } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs index 23eba093a6..02056aab20 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs @@ -75,6 +75,14 @@ namespace Volo.Abp.Reflection TypeHelper.GetDefaultValue(typeof(string)).ShouldBeNull(); } + [Fact] + public void ConvertFromString() + { + TypeHelper.ConvertFromString("42").ShouldBe(42); + TypeHelper.ConvertFromString("42").ShouldBe((int?)42); + TypeHelper.ConvertFromString(null).ShouldBeNull(); + } + public class MyDictionary : Dictionary { From e97f07b011b1786255ad31684579e87330b8f7ae Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 15 May 2020 12:21:29 +0800 Subject: [PATCH 21/69] Put UseAbpRequestLocalization just after the UseAuthentication --- .../BackendAdminApp.Host/BackendAdminAppHostModule.cs | 4 ++-- .../PublicWebSite.Host/PublicWebSiteHostModule.cs | 4 ++-- .../BloggingService.Host/BloggingServiceHostModule.cs | 4 ++-- .../IdentityService.Host/IdentityServiceHostModule.cs | 7 ++++--- .../ProductService.Host/ProductServiceHostModule.cs | 4 ++-- .../TenantManagementServiceHostModule.cs | 4 ++-- .../MyProjectNameHttpApiHostModule.cs | 4 ++-- .../MyProjectNameHttpApiHostModule.cs | 6 +++--- .../MyProjectNameIdentityServerModule.cs | 6 ++++-- .../MyProjectNameWebModule.cs | 4 ++-- .../MyProjectNameWebModule.cs | 4 ++-- .../MyProjectNameWebTestModule.cs | 6 +++--- .../MyProjectNameHttpApiHostModule.cs | 8 +++++--- .../MyProjectNameIdentityServerModule.cs | 8 +++++--- .../MyProjectNameWebHostModule.cs | 2 +- .../MyProjectNameWebUnifiedModule.cs | 3 ++- 16 files changed, 43 insertions(+), 35 deletions(-) diff --git a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs index 4414dc73ae..0976699f07 100644 --- a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs +++ b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; @@ -118,8 +118,8 @@ namespace BackendAdminApp.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs index 9ea7543228..1b2c0de935 100644 --- a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs +++ b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; @@ -96,8 +96,8 @@ namespace PublicWebSite.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs index c546c57ae5..97c351e93e 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -120,7 +120,6 @@ namespace BloggingService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -137,6 +136,7 @@ namespace BloggingService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); + app.UseAbpRequestLocalization(); //TODO: localization? if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index 49c0bbd933..b950da980f 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using Microsoft.AspNetCore.Builder; @@ -101,12 +101,14 @@ namespace IdentityService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); + app.UseAbpRequestLocalization(); //TODO: localization? + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + app.Use(async (ctx, next) => { var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); @@ -121,7 +123,6 @@ namespace IdentityService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); - app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs index 9fb074fe76..6bb74c1f2b 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using Microsoft.AspNetCore.Builder; @@ -104,7 +104,6 @@ namespace ProductService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -121,6 +120,7 @@ namespace ProductService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); + app.UseAbpRequestLocalization(); //TODO: localization? if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs index f068c2adf9..61c0d5105a 100644 --- a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Security.Claims; using Microsoft.AspNetCore.Builder; @@ -105,7 +105,6 @@ namespace TenantManagementService.Host app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); //TODO: localization? app.UseAuthentication(); app.Use(async (ctx, next) => @@ -122,6 +121,7 @@ namespace TenantManagementService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); + app.UseAbpRequestLocalization(); //TODO: localization? if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index f560ac7e0a..5368ac81ed 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using Microsoft.AspNetCore.Builder; @@ -178,8 +178,8 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs index 06f52defb1..5b950c1d23 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Net.Http; @@ -168,10 +168,10 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); - app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); - + app.UseAbpRequestLocalization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index e3d6d5aa67..6835c537dc 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using Localization.Resources.AbpUi; @@ -154,12 +154,14 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseIdentityServer(); app.UseAuthorization(); app.UseAuditing(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs index 86738e3e1b..12c20e9ffe 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Builder; @@ -225,8 +225,8 @@ namespace MyCompanyName.MyProjectName.Web app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs index 541a2c5e3a..1a578ac994 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Localization.Resources.AbpUi; using Microsoft.AspNetCore; @@ -204,9 +204,9 @@ namespace MyCompanyName.MyProjectName.Web app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); + app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs index edde134027..28b5e3b55b 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using Localization.Resources.AbpUi; @@ -88,9 +88,9 @@ namespace MyCompanyName.MyProjectName }); app.UseVirtualFiles(); - app.UseRouting(); - app.UseAbpRequestLocalization(); + app.UseRouting(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); app.UseAuthorization(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 8de889e88e..845126a67b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using IdentityModel; @@ -164,13 +164,15 @@ namespace MyCompanyName.MyProjectName app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseCors(DefaultCorsPolicyName); - app.UseAbpRequestLocalization(); + app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); + app.UseAbpRequestLocalization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAuthorization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index 4bfd5f689a..11627c93b9 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; @@ -185,14 +185,16 @@ namespace MyCompanyName.MyProjectName app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); - app.UseCors(DefaultCorsPolicyName); - app.UseAbpRequestLocalization(); + app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); app.UseJwtTokenMiddleware(); + app.UseAbpRequestLocalization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseIdentityServer(); app.UseAuthorization(); app.UseSwagger(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs index 6d16829e25..cf306f5277 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs @@ -234,8 +234,8 @@ namespace MyCompanyName.MyProjectName app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs index 57b77e5f50..653738d8ac 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs @@ -127,9 +127,10 @@ namespace MyCompanyName.MyProjectName app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAbpRequestLocalization(); app.UseAuthentication(); + app.UseAbpRequestLocalization(); app.UseAuthorization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); From d0ef06e9287c84352d70de97353c5b5dfba52067 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 15 May 2020 14:44:27 +0800 Subject: [PATCH 22/69] Put UseAbpRequestLocalization after the UseMultiTenancy --- .../BackendAdminApp.Host/BackendAdminAppHostModule.cs | 4 +++- .../PublicWebSite.Host/PublicWebSiteHostModule.cs | 4 +++- .../BloggingService.Host/BloggingServiceHostModule.cs | 4 +++- .../IdentityService.Host/IdentityServiceHostModule.cs | 2 +- .../ProductService.Host/ProductServiceHostModule.cs | 4 +++- .../TenantManagementServiceHostModule.cs | 4 +++- .../MyProjectNameHttpApiHostModule.cs | 4 +++- .../MyProjectNameHttpApiHostModule.cs | 4 ++-- .../MyProjectNameIdentityServerModule.cs | 2 +- .../MyProjectNameWebModule.cs | 2 +- .../MyProjectNameWebModule.cs | 3 ++- .../MyProjectNameHttpApiHostModule.cs | 2 +- .../MyProjectNameIdentityServerModule.cs | 4 ++-- .../MyProjectNameWebHostModule.cs | 5 ++--- .../MyProjectNameWebUnifiedModule.cs | 7 ++++--- 15 files changed, 34 insertions(+), 21 deletions(-) diff --git a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs index 0976699f07..b351a33fb6 100644 --- a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs +++ b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs @@ -119,11 +119,13 @@ namespace BackendAdminApp.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - app.UseAbpRequestLocalization(); + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs index 1b2c0de935..e1c0b8c215 100644 --- a/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs +++ b/samples/MicroserviceDemo/applications/PublicWebSite.Host/PublicWebSiteHostModule.cs @@ -97,11 +97,13 @@ namespace PublicWebSite.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - app.UseAbpRequestLocalization(); + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseConfiguredEndpoints(); } diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs index 97c351e93e..bc9209c72a 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs @@ -136,11 +136,13 @@ namespace BloggingService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); - app.UseAbpRequestLocalization(); //TODO: localization? + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index b950da980f..457950cba4 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -102,7 +102,6 @@ namespace IdentityService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - app.UseAbpRequestLocalization(); //TODO: localization? if (MsDemoConsts.IsMultiTenancyEnabled) { @@ -123,6 +122,7 @@ namespace IdentityService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs index 6bb74c1f2b..4968ce75a4 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs @@ -120,11 +120,13 @@ namespace ProductService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); - app.UseAbpRequestLocalization(); //TODO: localization? + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs index 61c0d5105a..504713c047 100644 --- a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs @@ -121,11 +121,13 @@ namespace TenantManagementService.Host currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); - app.UseAbpRequestLocalization(); //TODO: localization? + if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 5368ac81ed..591b92ae44 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -179,11 +179,13 @@ namespace MyCompanyName.MyProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - app.UseAbpRequestLocalization(); + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseSwagger(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs index 5b950c1d23..0cd3762047 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs @@ -169,14 +169,14 @@ namespace MyCompanyName.MyProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - app.UseJwtTokenMiddleware(); - app.UseAbpRequestLocalization(); + app.UseJwtTokenMiddleware(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseIdentityServer(); app.UseAuthorization(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index 6835c537dc..8d23b73d0f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -155,13 +155,13 @@ namespace MyCompanyName.MyProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseIdentityServer(); app.UseAuthorization(); app.UseAuditing(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs index 12c20e9ffe..9e1930a260 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs @@ -226,13 +226,13 @@ namespace MyCompanyName.MyProjectName.Web app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseSwagger(); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs index 1a578ac994..8015f9ec45 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs @@ -206,12 +206,13 @@ namespace MyCompanyName.MyProjectName.Web app.UseRouting(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); - app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + + app.UseAbpRequestLocalization(); app.UseIdentityServer(); app.UseAuthorization(); app.UseSwagger(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index 845126a67b..ab77d8050b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -166,13 +166,13 @@ namespace MyCompanyName.MyProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - app.UseAbpRequestLocalization(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs index 11627c93b9..41d31efc53 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -188,13 +188,13 @@ namespace MyCompanyName.MyProjectName app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); app.UseJwtTokenMiddleware(); - app.UseAbpRequestLocalization(); - + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseIdentityServer(); app.UseAuthorization(); app.UseSwagger(); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs index cf306f5277..7381787bc3 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs @@ -234,17 +234,16 @@ namespace MyCompanyName.MyProjectName app.UseHttpsRedirection(); app.UseVirtualFiles(); app.UseRouting(); - app.UseAuthentication(); - app.UseAbpRequestLocalization(); + app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); app.UseAuthorization(); - app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs index 653738d8ac..246db32e3e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs @@ -128,14 +128,15 @@ namespace MyCompanyName.MyProjectName app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - app.UseAbpRequestLocalization(); - app.UseAuthorization(); - + if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } + app.UseAbpRequestLocalization(); + app.UseAuthorization(); + app.UseSwagger(); app.UseSwaggerUI(options => { From 6ce85f2df7fdb2951b7cd1c9ed47119069eb3e44 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 15 May 2020 19:45:34 +0800 Subject: [PATCH 23/69] Fix modal open event bug --- .../bootstrap/modal-manager.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js index 21a8e0ce21..cc4122a373 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js @@ -95,8 +95,11 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f }); _$modal.on('shown.bs.modal', function () { - //focuses first element if it's a typeable input. + //focuses first element if it's a typeable input. var $firstVisibleInput = _$modal.find('input:not([type=hidden]):first'); + + _onOpenCallbacks.triggerAll(_publicApi); + if ($firstVisibleInput.hasClass("datepicker")) { return; //don't pop-up date pickers... } @@ -107,7 +110,6 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f } $firstVisibleInput.focus(); - _onOpenCallbacks.triggerAll(_publicApi); }); var modalClass = abp.modals[options.modalClass]; From 72b9b43e9130c098a085dbe563a231e8eb6e2f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 15 May 2020 23:29:42 +0300 Subject: [PATCH 24/69] Resolved #3963: Create a jstree package & bundle contributor. --- .../JsTree/JQueryFormScriptContributor.cs | 16 ++++++++++++ .../Mvc/UI/Packages/JsTree/JsTreeOptions.cs | 13 ++++++++++ .../Packages/JsTree/JsTreeStyleContributor.cs | 26 +++++++++++++++++++ npm/packs/jstree/abp.resourcemapping.js | 5 ++++ npm/packs/jstree/package.json | 12 +++++++++ 5 files changed, 72 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs create mode 100644 npm/packs/jstree/abp.resourcemapping.js create mode 100644 npm/packs/jstree/package.json diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs new file mode 100644 index 0000000000..ca131c8aac --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; +using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree +{ + [DependsOn(typeof(JQueryScriptContributor))] + public class JsTreeScriptContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files.AddIfNotContains("/libs/jstree/jstree.min.js"); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs new file mode 100644 index 0000000000..d1dbe812bf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree +{ + public class JsTreeOptions + { + /// + /// Path of the style file for the JsTree library. + /// Setting to null ignores the style file. + /// + /// Default value: "/libs/jstree/themes/default/style.min.css". + /// + public string StylePath { get; set; } = "/libs/jstree/themes/default/style.min.css"; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs new file mode 100644 index 0000000000..5944310c2c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree +{ + public class JsTreeStyleContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + var options = context + .ServiceProvider + .GetRequiredService>() + .Value; + + if (options.StylePath.IsNullOrEmpty()) + { + return; + } + + context.Files.AddIfNotContains(options.StylePath); + } + } +} \ No newline at end of file diff --git a/npm/packs/jstree/abp.resourcemapping.js b/npm/packs/jstree/abp.resourcemapping.js new file mode 100644 index 0000000000..89b3e09d64 --- /dev/null +++ b/npm/packs/jstree/abp.resourcemapping.js @@ -0,0 +1,5 @@ +module.exports = { + mappings: { + "@node_modules/jstree/dist/**/*.*": "@libs/jstree/" + } +} \ No newline at end of file diff --git a/npm/packs/jstree/package.json b/npm/packs/jstree/package.json new file mode 100644 index 0000000000..feee4a81e2 --- /dev/null +++ b/npm/packs/jstree/package.json @@ -0,0 +1,12 @@ +{ + "version": "2.7.0", + "name": "@abp/jstree", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@abp/jquery": "^2.7.0", + "jstree": "^3.3.9" + }, + "gitHead": "0ea3895f3b0b489e3ea81fc88f8f0896b22b61bd" +} From 61c5186cd1b01b67032d30cb5dad36ee179d3375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 15 May 2020 23:58:13 +0300 Subject: [PATCH 25/69] Update badges --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 14b044f8b1..f89a8a86aa 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # ABP -[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity) [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) -[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) +[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement). From dc3360f92139df91f2ef4bf999840368d1ca903c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 00:03:54 +0300 Subject: [PATCH 26/69] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f89a8a86aa..7dd11a5362 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # ABP +[![Build & Test](https://github.com/abpframework/abp/workflows/Main/badge.svg)](https://github.com/abpframework/abp/actions?query=workflow%3AMain) [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) [![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) From 687fac36c83791681356f42c3b7db2205c7c12ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:04:29 +0300 Subject: [PATCH 27/69] add claims mapping middleware to the MyProjectNameHttpApiHostModule --- .../MyProjectNameHttpApiHostModule.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index e425512797..c5f72ff5b7 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Claims; using IdentityModel; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; @@ -170,6 +172,20 @@ namespace MyCompanyName.MyProjectName { app.UseMultiTenancy(); } + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); app.UseAuthorization(); app.UseAbpRequestLocalization(); app.UseSwagger(); From 73bf96c86f898be10bf51ef626b23547462fe1e3 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Sat, 16 May 2020 02:10:41 +0300 Subject: [PATCH 28/69] Update en.json --- .../AbpIoLocalization/Admin/Localization/Resources/en.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 14a4eb345c..46cd1cb470 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -127,7 +127,7 @@ "Generate": "Generate", "MissingQuantityField": "The quantity field is required!", "MissingPriceField": "The Price field is required!", - "CodeUsageStatus": "Code Usage Status", + "CodeUsageStatus": "Status", "Country": "Country", "DeveloperCount": "Developer Count", "RequestCode": "Request Code", @@ -147,6 +147,7 @@ "EmailSent": "Email Sent", "SuccessfullySent": "Successfully Sent", "SuccessfullyDeleted": "Successfully Deleted", - "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" + "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" , + "BusinessType": "Business Type" } } \ No newline at end of file From 94bb704bb64ced26cf1ad4fa644578381427f408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:39:10 +0300 Subject: [PATCH 29/69] Delete MyProjectNamePage.cs --- .../Pages/MyProjectNamePage.cs | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/MyProjectNamePage.cs diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/MyProjectNamePage.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/MyProjectNamePage.cs deleted file mode 100644 index 5fe044221d..0000000000 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/MyProjectNamePage.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Localization; -using Microsoft.AspNetCore.Mvc.Razor.Internal; -using MyCompanyName.MyProjectName.Localization; -using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; - -namespace MyCompanyName.MyProjectName.Web.Pages -{ - /* Inherit your UI Pages from this class. To do that, add this line to your Pages (.cshtml files under the Page folder): - * @inherits MyCompanyName.MyProjectName.Web.Pages.MyProjectNamePage - */ - public abstract class MyProjectNamePage : AbpPage - { - [RazorInject] - public IHtmlLocalizer L { get; set; } - } -} From 146ec7309cdae1976f87c276b29cc3dab0b3fffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:39:36 +0300 Subject: [PATCH 30/69] Implement #3967 for AbpPageModel. --- .../Mvc/UI/RazorPages/AbpPageModel.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs index 8d62a4e188..f616a2f32d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Volo.Abp.AspNetCore.Mvc.UI.Alerts; using Volo.Abp.AspNetCore.Mvc.Validation; using Volo.Abp.Guids; +using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectMapping; using Volo.Abp.Settings; @@ -90,17 +91,29 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages { if (_localizer == null) { - if (LocalizationResourceType == null) - { - throw new AbpException($"{nameof(LocalizationResourceType)} should be set before using the {nameof(L)} object!"); - } - - _localizer = StringLocalizerFactory.Create(LocalizationResourceType); + _localizer = CreateLocalizer(); } return _localizer; } } + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResourceType != null) + { + return StringLocalizerFactory.Create(LocalizationResourceType); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResourceType)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } + private IStringLocalizer _localizer; protected Type LocalizationResourceType { get; set; } From c122fdfad6d8fb8f670db060eaaf6ff55473fb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:48:29 +0300 Subject: [PATCH 31/69] Resolved #3967: Fallback to the default localization resource for base classes with the L property --- .../Mvc/UI/RazorPages/AbpPageModel.cs | 32 +++++----- .../Volo/Abp/AspNetCore/Mvc/AbpController.cs | 29 +++++++++- .../Volo/Abp/AspNetCore/SignalR/AbpHub.cs | 58 ++++++++++++++++++- .../Services/ApplicationService.cs | 29 +++++++++- 4 files changed, 128 insertions(+), 20 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs index f616a2f32d..db7b9041b7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs @@ -98,22 +98,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages } } - protected virtual IStringLocalizer CreateLocalizer() - { - if (LocalizationResourceType != null) - { - return StringLocalizerFactory.Create(LocalizationResourceType); - } - - var localizer = StringLocalizerFactory.CreateDefaultOrNull(); - if (localizer == null) - { - throw new AbpException($"Set {nameof(LocalizationResourceType)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); - } - - return localizer; - } - private IStringLocalizer _localizer; protected Type LocalizationResourceType { get; set; } @@ -165,5 +149,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages TempData = TempData }; } + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResourceType != null) + { + return StringLocalizerFactory.Create(LocalizationResourceType); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResourceType)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs index 2a3a25373e..52f01e0b2c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs @@ -101,7 +101,18 @@ namespace Volo.Abp.AspNetCore.Mvc public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory); private IStringLocalizerFactory _stringLocalizerFactory; - public IStringLocalizer L => _localizer ?? (_localizer = StringLocalizerFactory.Create(LocalizationResource)); + public IStringLocalizer L + { + get + { + if (_localizer == null) + { + _localizer = CreateLocalizer(); + } + + return _localizer; + } + } private IStringLocalizer _localizer; protected Type LocalizationResource @@ -121,5 +132,21 @@ namespace Volo.Abp.AspNetCore.Mvc { ModelValidator?.Validate(ModelState); } + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResource != null) + { + return StringLocalizerFactory.Create(LocalizationResource); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs index a1dc1437ea..0a58adf098 100644 --- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs +++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs @@ -57,7 +57,18 @@ namespace Volo.Abp.AspNetCore.SignalR public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory); private IStringLocalizerFactory _stringLocalizerFactory; - public IStringLocalizer L => _localizer ?? (_localizer = StringLocalizerFactory.Create(LocalizationResource)); + public IStringLocalizer L + { + get + { + if (_localizer == null) + { + _localizer = CreateLocalizer(); + } + + return _localizer; + } + } private IStringLocalizer _localizer; protected Type LocalizationResource @@ -70,6 +81,22 @@ namespace Volo.Abp.AspNetCore.SignalR } } private Type _localizationResource = typeof(DefaultResource); + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResource != null) + { + return StringLocalizerFactory.Create(LocalizationResource); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } } public abstract class AbpHub : Hub @@ -118,7 +145,18 @@ namespace Volo.Abp.AspNetCore.SignalR public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory); private IStringLocalizerFactory _stringLocalizerFactory; - public IStringLocalizer L => _localizer ?? (_localizer = StringLocalizerFactory.Create(LocalizationResource)); + public IStringLocalizer L + { + get + { + if (_localizer == null) + { + _localizer = CreateLocalizer(); + } + + return _localizer; + } + } private IStringLocalizer _localizer; protected Type LocalizationResource @@ -131,5 +169,21 @@ namespace Volo.Abp.AspNetCore.SignalR } } private Type _localizationResource = typeof(DefaultResource); + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResource != null) + { + return StringLocalizerFactory.Create(LocalizationResource); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } } } diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs index 32c90677b8..552aae426d 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs @@ -109,7 +109,18 @@ namespace Volo.Abp.Application.Services public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory); private IStringLocalizerFactory _stringLocalizerFactory; - public IStringLocalizer L => _localizer ?? (_localizer = StringLocalizerFactory.Create(LocalizationResource)); + public IStringLocalizer L + { + get + { + if (_localizer == null) + { + _localizer = CreateLocalizer(); + } + + return _localizer; + } + } private IStringLocalizer _localizer; protected Type LocalizationResource @@ -147,5 +158,21 @@ namespace Volo.Abp.Application.Services await AuthorizationService.CheckAsync(policyName); } + + protected virtual IStringLocalizer CreateLocalizer() + { + if (LocalizationResource != null) + { + return StringLocalizerFactory.Create(LocalizationResource); + } + + var localizer = StringLocalizerFactory.CreateDefaultOrNull(); + if (localizer == null) + { + throw new AbpException($"Set {nameof(LocalizationResource)} or define the default localization resource type (by configuring the {nameof(AbpLocalizationOptions)}.{nameof(AbpLocalizationOptions.DefaultResourceType)}) to be able to use the {nameof(L)} object!"); + } + + return localizer; + } } } \ No newline at end of file From 94a5bffebefb4e04ba45ee8d111aaa92d6bc50b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:51:35 +0300 Subject: [PATCH 32/69] Fix Index.cshtml of the app template --- .../src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml index e3df314288..a2fc159766 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml @@ -1,6 +1,10 @@ @page -@inherits MyCompanyName.MyProjectName.Web.Pages.MyProjectNamePage +@using Microsoft.AspNetCore.Mvc.Localization +@using MyCompanyName.MyProjectName.Localization +@using Volo.Abp.Users @model MyCompanyName.MyProjectName.Web.Pages.IndexModel +@inject IHtmlLocalizer +@inject ICurrentUser CurrentUser @section styles { From 8ad6a3a124fa55e61a3171e5c4ab8b9c74b62d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 02:51:54 +0300 Subject: [PATCH 33/69] Update Index.cshtml --- .../src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml index a2fc159766..7329ce019b 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/Pages/Index.cshtml @@ -3,7 +3,7 @@ @using MyCompanyName.MyProjectName.Localization @using Volo.Abp.Users @model MyCompanyName.MyProjectName.Web.Pages.IndexModel -@inject IHtmlLocalizer +@inject IHtmlLocalizer L @inject ICurrentUser CurrentUser @section styles { From 67a230d3a0e4f92ab65ffee6ebb8c5cbc307e7eb Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sat, 16 May 2020 14:02:47 +0800 Subject: [PATCH 34/69] Rename main.yml to build-and-test.yml Resolve #3965 --- .github/workflows/{main.yml => build-and-test.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{main.yml => build-and-test.yml} (96%) diff --git a/.github/workflows/main.yml b/.github/workflows/build-and-test.yml similarity index 96% rename from .github/workflows/main.yml rename to .github/workflows/build-and-test.yml index e33a07a197..395f88351a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/build-and-test.yml @@ -1,4 +1,4 @@ -name: "Main" +name: "build and test" on: pull_request: paths: From 37490be9a0fb16a859ba77d80d926096f65dfeca Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sat, 16 May 2020 14:12:04 +0800 Subject: [PATCH 35/69] Update README.md https://github.com/abpframework/abp/issues/3965 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7dd11a5362..72a47ddc4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ABP -[![Build & Test](https://github.com/abpframework/abp/workflows/Main/badge.svg)](https://github.com/abpframework/abp/actions?query=workflow%3AMain) +![build and test](https://github.com/abpframework/abp/workflows/build%20and%20test/badge.svg) [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) [![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) From 54c685f80170d5689b2fdcd43e8fe306d7b6fe5f Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Sat, 16 May 2020 17:31:05 +0800 Subject: [PATCH 36/69] Change HttpApiClient project target to netstandard2.0 --- .../MyCompanyName.MyProjectName.HttpApi.Client.csproj | 2 +- .../MyCompanyName.MyProjectName.HttpApi.Client.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj index 4c70886aaa..fa83d6c25e 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj @@ -3,7 +3,7 @@ - netcoreapp3.1 + netstandard2.0 MyCompanyName.MyProjectName diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj index 1466849524..4fb9f73c33 100644 --- a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj +++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj @@ -3,7 +3,7 @@ - netcoreapp3.1 + netstandard2.0 MyCompanyName.MyProjectName From 5f20c7726ee9c9213ac8abb6bd5d0fdc11d396b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 23:14:48 +0300 Subject: [PATCH 37/69] Resolved #3978: ObjectExtensionManager should automatically add RequiredAttribute & EnumDataTypeAttribute when needed --- .../Volo/Abp/Reflection/TypeHelper.cs | 24 ++++++ .../ExtensionPropertyHelper.cs | 23 ++++++ .../ExtensionPropertyConfiguration.cs | 2 + .../ModuleExtensionConfigurationHelper.cs | 1 + .../ObjectExtensionPropertyInfo.cs | 3 +- .../Volo/Abp/Reflection/TypeHelper_Tests.cs | 7 ++ .../ObjectExtensionManager_Tests.cs | 74 ++++++++++++++++++- 7 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 63b3538c3a..87b94774e7 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -10,6 +10,30 @@ namespace Volo.Abp.Reflection { public static class TypeHelper { + private static readonly HashSet NonNullablePrimitiveTypes = new HashSet + { + typeof(byte), + typeof(short), + typeof(int), + typeof(long), + typeof(sbyte), + typeof(ushort), + typeof(uint), + typeof(ulong), + typeof(bool), + typeof(float), + typeof(decimal), + typeof(DateTime), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(Guid) + }; + + public static bool IsNonNullablePrimitiveType(Type type) + { + return NonNullablePrimitiveTypes.Contains(type); + } + public static bool IsFunc(object obj) { if (obj == null) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs new file mode 100644 index 0000000000..507f67997a --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Reflection; + +namespace Volo.Abp.ObjectExtending +{ + public static class ExtensionPropertyHelper + { + public static IEnumerable GetDefaultAttributes(Type type) + { + if (TypeHelper.IsNonNullablePrimitiveType(type) || type.IsEnum) + { + yield return new RequiredAttribute(); + } + + if (type.IsEnum) + { + yield return new EnumDataTypeAttribute(type); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs index 0ff3941f4e..47882fdf93 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs @@ -61,6 +61,8 @@ namespace Volo.Abp.ObjectExtending.Modularity Entity = new ExtensionPropertyEntityConfiguration(); UI = new ExtensionPropertyUiConfiguration(); Api = new ExtensionPropertyApiConfiguration(); + + Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs index 1f1edd757e..d819918ac5 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs @@ -148,6 +148,7 @@ namespace Volo.Abp.ObjectExtending.Modularity propertyConfig.Name, property => { + property.Attributes.Clear(); property.Attributes.AddRange(propertyConfig.Attributes); property.DisplayName = propertyConfig.DisplayName; property.Validators.AddRange(propertyConfig.Validators); diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index 5d55325477..e89598e6d2 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; -using Microsoft.Extensions.Localization; using Volo.Abp.Localization; namespace Volo.Abp.ObjectExtending @@ -61,6 +60,8 @@ namespace Volo.Abp.ObjectExtending ValidationAttributes = new List(); Attributes = new List(); Validators = new List>(); + + Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); } } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs index 02056aab20..978bf9de54 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs @@ -7,6 +7,13 @@ namespace Volo.Abp.Reflection { public class TypeHelper_Tests { + [Fact] + public void IsNonNullablePrimitiveType() + { + TypeHelper.IsNonNullablePrimitiveType(typeof(int)).ShouldBeTrue(); + TypeHelper.IsNonNullablePrimitiveType(typeof(string)).ShouldBeFalse(); + } + [Fact] public void Should_Generic_Type_From_Nullable() { diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs index 857e2fd155..cb5b308c64 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.ComponentModel.DataAnnotations; +using System.Linq; using Shouldly; using Xunit; @@ -22,7 +23,7 @@ namespace Volo.Abp.ObjectExtending var objectExtension = _objectExtensionManager.GetOrNull(); objectExtension.ShouldNotBeNull(); - + var properties = objectExtension.GetProperties(); properties.Count.ShouldBe(1); properties.FirstOrDefault(p => p.Name == "TestProp").ShouldNotBeNull(); @@ -55,9 +56,78 @@ namespace Volo.Abp.ObjectExtending property.Configuration["TestConfig2"].ShouldBe("TestConfig2-Value"); } + [Fact] + public void Should_Automatically_Add_RequiredAttribute_To_Non_Nullable_Types_And_Enums() + { + _objectExtensionManager + .AddOrUpdateProperty("IntProp") + .AddOrUpdateProperty("BoolProp") + .AddOrUpdateProperty("NullableIntProp") + .AddOrUpdateProperty("StringProp") + .AddOrUpdateProperty("EnumProp"); + + _objectExtensionManager + .GetPropertyOrNull("IntProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("BoolProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("EnumProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("NullableIntProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("StringProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + } + + [Fact] + public void Should_Automatically_Add_EnumDataTypeAttribute_For_Enums() + { + _objectExtensionManager + .AddOrUpdateProperty("EnumProp"); + + _objectExtensionManager + .GetPropertyOrNull("EnumProp") + .Attributes + .ShouldContain(x => x is EnumDataTypeAttribute); + } + + [Fact] + public void Should_Be_Able_To_Clear_Auto_Added_Attributes() + { + _objectExtensionManager + .AddOrUpdateProperty("IntProp", property => + { + property.Attributes.Clear(); + }); + + _objectExtensionManager + .GetPropertyOrNull("IntProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + } + private class MyExtensibleObject : ExtensibleObject { } + + private enum MyTestEnum + { + EnumValue1, + EnumValue2, + } } } From 3345f7e988c599caa5e246912c0e8dca2cb46234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 23:18:49 +0300 Subject: [PATCH 38/69] Normalize UI/API configuration of an extension property if possible. --- .../EntityExtensionConfiguration.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs index ce84cb19e5..d03696b642 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs @@ -50,6 +50,8 @@ namespace Volo.Abp.ObjectExtending.Modularity configureAction?.Invoke(propertyInfo); + NormalizeProperty(propertyInfo); + return this; } @@ -58,5 +60,23 @@ namespace Volo.Abp.ObjectExtending.Modularity { return Properties.Values.ToImmutableList(); } + + private static void NormalizeProperty(ExtensionPropertyConfiguration propertyInfo) + { + if (!propertyInfo.Api.OnGet.IsAvailable) + { + propertyInfo.UI.OnTable.IsVisible = false; + } + + if (!propertyInfo.Api.OnCreate.IsAvailable) + { + propertyInfo.UI.OnCreateForm.IsVisible = false; + } + + if (!propertyInfo.Api.OnUpdate.IsAvailable) + { + propertyInfo.UI.OnEditForm.IsVisible = false; + } + } } } \ No newline at end of file From fa0a59ee44a2c87d84d62dc5f25a018dd8adaa4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 May 2020 23:24:43 +0300 Subject: [PATCH 39/69] Document Default Validation Attributes #3978 --- docs/en/Object-Extensions.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index bee229dc27..21391170d3 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -208,6 +208,15 @@ ObjectExtensionManager.Instance With this configuration, `IdentityUserCreateDto` objects will be invalid without a valid `SocialSecurityNumber` value provided. +#### Default Validation Attributes + +There are some attributes **automatically added** when you create certain type of properties; + +* `RequiredAttribute` is added for non nullable primitive property types (e.g. `int`, `bool`, `DateTime`...) and `enum` types. +* `EnumDataTypeAttribute` is added for enum types, to prevent to set invalid enum values. + +Use `options.Attributes.Clear();` if you don't want these attributes. + ### Custom Validation If you need, you can add a custom action that is executed to validate the extra properties. Example: From 2cd8311792de2505f3aca422cd348738205f241b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 00:11:19 +0300 Subject: [PATCH 40/69] #3979: Allow to set custom "default value" for extra properties. --- docs/en/Object-Extensions.md | 38 ++++++++++++++ .../ObjectExtending/ExtensionPropertyDto.cs | 2 + .../CachedObjectExtensionsDtoService.cs | 1 + .../Abp/Data/HasExtraPropertiesExtensions.cs | 9 +++- .../ExtensionPropertyHelper.cs | 16 +++++- .../ExtensionPropertyConfiguration.cs | 20 ++++++++ .../ModuleExtensionConfigurationHelper.cs | 2 + .../ObjectExtensionPropertyInfo.cs | 20 ++++++++ .../ObjectExtensionManager_Tests.cs | 50 +++++++++++++++++++ 9 files changed, 155 insertions(+), 3 deletions(-) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index 21391170d3..40a7ddd5ea 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -174,6 +174,44 @@ ObjectExtensionManager.Instance The following sections explain the fundamental property configuration options. +#### Default Value + +A default value is automatically set for the new property, which is the natural default value for the property type, like `null` for `string`, `false` for `bool` or `0` for `int`. + +There are two ways to override the default value: + +##### DefaultValue Option + +`DefaultValue` option can be set to any value: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + "MyIntProperty", + options => + { + options.DefaultValue = 42; + }); +```` + +##### DefaultValueFactory Options + +`DefaultValueFactory` can be set to a function that returns the default value: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + "MyIntProperty", + options => + { + options.DefaultValueFactory = () => 42; + }); +```` + +`options.DefaultValueFactory` has a higher priority than the `options.DefaultValue` . + +> Tip: Use `DefaultValueFactory` option only if the default value may change over the time. If it is a constant value, then use the `DefaultValue` option. + #### CheckPairDefinitionOnMapping Controls how to check property definitions while mapping two extensible objects. See the "Object to Object Mapping" section to understand the `CheckPairDefinitionOnMapping` option better. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyDto.cs index 74214914b9..b1ba6f7ea9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyDto.cs @@ -21,5 +21,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending public List Attributes { get; set; } public Dictionary Configuration { get; set; } + + public object DefaultValue { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index 6e72a6863e..c6e200f45d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -108,6 +108,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending Attributes = new List(), DisplayName = CreateDisplayNameDto(propertyConfig), Configuration = new Dictionary(), + DefaultValue = propertyConfig.GetDefaultValue(), Api = new ExtensionPropertyApiDto { OnGet = new ExtensionPropertyApiGetDto diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs index ca9cc0a4c1..6abb350328 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs @@ -65,8 +65,13 @@ namespace Volo.Abp.Data public static TSource SetDefaultsForExtraProperties(this TSource source, Type objectType = null) where TSource : IHasExtraProperties { + if (objectType == null) + { + objectType = typeof(TSource); + } + var properties = ObjectExtensionManager.Instance - .GetProperties(objectType ?? typeof(TSource)); + .GetProperties(objectType); foreach (var property in properties) { @@ -75,7 +80,7 @@ namespace Volo.Abp.Data continue; } - source.ExtraProperties[property.Name] = TypeHelper.GetDefaultValue(property.Type); + source.ExtraProperties[property.Name] = property.GetDefaultValue(); } return source; diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs index 507f67997a..ee36b397c8 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs @@ -5,7 +5,7 @@ using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending { - public static class ExtensionPropertyHelper + internal static class ExtensionPropertyHelper { public static IEnumerable GetDefaultAttributes(Type type) { @@ -19,5 +19,19 @@ namespace Volo.Abp.ObjectExtending yield return new EnumDataTypeAttribute(type); } } + + public static object GetDefaultValue( + Type propertyType, + Func defaultValueFactory, + object defaultValue) + { + if (defaultValueFactory != null) + { + return defaultValueFactory(); + } + + return defaultValue ?? + TypeHelper.GetDefaultValue(propertyType); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs index 47882fdf93..6d66e51337 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using JetBrains.Annotations; using Volo.Abp.Localization; +using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending.Modularity { @@ -45,6 +46,19 @@ namespace Volo.Abp.ObjectExtending.Modularity [NotNull] public ExtensionPropertyApiConfiguration Api { get; } + /// + /// Uses as the default value if was not set. + /// + [CanBeNull] + public object DefaultValue { get; set; } + + /// + /// Used with the first priority to create the default value for the property. + /// Uses to the if this was not set. + /// + [CanBeNull] + public Func DefaultValueFactory { get; set; } + public ExtensionPropertyConfiguration( [NotNull] EntityExtensionConfiguration entityExtensionConfiguration, [NotNull] Type type, @@ -63,6 +77,12 @@ namespace Volo.Abp.ObjectExtending.Modularity Api = new ExtensionPropertyApiConfiguration(); Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); + DefaultValue = TypeHelper.GetDefaultValue(Type); + } + + public object GetDefaultValue() + { + return ExtensionPropertyHelper.GetDefaultValue(Type, DefaultValueFactory, DefaultValue); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs index d819918ac5..cb5be17c1f 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs @@ -152,6 +152,8 @@ namespace Volo.Abp.ObjectExtending.Modularity property.Attributes.AddRange(propertyConfig.Attributes); property.DisplayName = propertyConfig.DisplayName; property.Validators.AddRange(propertyConfig.Validators); + property.DefaultValue = propertyConfig.DefaultValue; + property.DefaultValueFactory = propertyConfig.DefaultValueFactory; } ); } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index e89598e6d2..12b32ab241 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; using Volo.Abp.Localization; +using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending { @@ -47,6 +48,19 @@ namespace Volo.Abp.ObjectExtending [NotNull] public Dictionary Configuration { get; } + /// + /// Uses as the default value if was not set. + /// + [CanBeNull] + public object DefaultValue { get; set; } + + /// + /// Used with the first priority to create the default value for the property. + /// Uses to the if this was not set. + /// + [CanBeNull] + public Func DefaultValueFactory { get; set; } + public ObjectExtensionPropertyInfo( [NotNull] ObjectExtensionInfo objectExtension, [NotNull] Type type, @@ -62,6 +76,12 @@ namespace Volo.Abp.ObjectExtending Validators = new List>(); Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); + DefaultValue = TypeHelper.GetDefaultValue(Type); + } + + public object GetDefaultValue() + { + return ExtensionPropertyHelper.GetDefaultValue(Type, DefaultValueFactory, DefaultValue); } } } diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs index cb5b308c64..6386dc41ff 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs @@ -119,6 +119,56 @@ namespace Volo.Abp.ObjectExtending .ShouldNotContain(x => x is RequiredAttribute); } + [Fact] + public void Should_Set_DefaultValues() + { + _objectExtensionManager + .AddOrUpdateProperty("IntProp") + .AddOrUpdateProperty("IntPropWithCustomDefaultValue", property => + { + property.DefaultValue = 42; + }) + .AddOrUpdateProperty("BoolProp") + .AddOrUpdateProperty("NullableIntProp") + .AddOrUpdateProperty("NullableIntPropWithCustomDefaultValueFactory", property => + { + property.DefaultValueFactory = () => 2; + }) + .AddOrUpdateProperty("StringProp") + .AddOrUpdateProperty("StringPropWithCustomDefaultValue", property => + { + property.DefaultValue = "custom-value"; + }); + + _objectExtensionManager + .GetPropertyOrNull("IntProp") + .DefaultValue.ShouldBe(0); + + _objectExtensionManager + .GetPropertyOrNull("IntPropWithCustomDefaultValue") + .DefaultValue.ShouldBe(42); + + _objectExtensionManager + .GetPropertyOrNull("BoolProp") + .DefaultValue.ShouldBe(false); + + _objectExtensionManager + .GetPropertyOrNull("NullableIntProp") + .DefaultValue.ShouldBeNull(); + + var propWithDefaultValueFactory = _objectExtensionManager + .GetPropertyOrNull("NullableIntPropWithCustomDefaultValueFactory"); + propWithDefaultValueFactory.GetDefaultValue().ShouldBe(2); + + _objectExtensionManager + .GetPropertyOrNull("StringProp") + .DefaultValue.ShouldBeNull(); + + _objectExtensionManager + .GetPropertyOrNull("StringPropWithCustomDefaultValue") + .DefaultValue.ShouldBe("custom-value"); + } + private class MyExtensibleObject : ExtensibleObject { From 2f074af4a86ac20e7bfea345aaffdb7a87f55cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 00:31:55 +0300 Subject: [PATCH 41/69] Change TypeSimple name to enum for enum members. --- .../ObjectExtending/CachedObjectExtensionsDtoService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index c6e200f45d..aab28b3cb9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -104,7 +104,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending var extensionPropertyDto = new ExtensionPropertyDto { Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(propertyConfig.Type), - TypeSimple = TypeHelper.GetSimplifiedName(propertyConfig.Type), + TypeSimple = propertyConfig.Type.IsEnum + ? "enum" + : TypeHelper.GetSimplifiedName(propertyConfig.Type), Attributes = new List(), DisplayName = CreateDisplayNameDto(propertyConfig), Configuration = new Dictionary(), From 6fefed6aadc7339342be3697a7c233d8f2609fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 02:03:14 +0300 Subject: [PATCH 42/69] AbpSelectTagHelperService: Support providing enum as object. --- .../TagHelpers/Form/AbpSelectTagHelperService.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 3ed4f63f82..3c2805566f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -using System.Reflection; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; @@ -102,7 +101,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return TagHelper.AspItems.ToList(); } - if (TagHelper.AspFor.ModelExplorer.Metadata.IsEnum) + if (IsEnum()) { return GetSelectItemsFromEnum(context, output, TagHelper.AspFor.ModelExplorer); } @@ -116,6 +115,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form throw new Exception("No items provided for select attribute."); } + private bool IsEnum() + { + var value = TagHelper.AspFor.Model; + if (value != null && value.GetType().IsEnum) + { + return true; + } + + return TagHelper.AspFor.ModelExplorer.Metadata.IsEnum; + } + protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput selectTag) { if (!string.IsNullOrEmpty(TagHelper.Label)) From 6c949053d7fb05a578421c5a15fb89ff5aa34946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 02:05:15 +0300 Subject: [PATCH 43/69] Handle enum conversion on the ExtraPropertiesValueConverter --- .../Volo/Abp/Reflection/TypeHelper.cs | 12 +++++ .../Abp/EntityFrameworkCore/AbpDbContext.cs | 1 + .../ExtraPropertiesValueConverter.cs | 45 +++++++++++++++++-- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 87b94774e7..b388ef791d 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -301,5 +301,17 @@ namespace Volo.Abp.Reflection .GetConverter(targetType) .ConvertFromString(value); } + + public static object ConvertFrom(object value) + { + return ConvertFrom(typeof(TTargetType), value); + } + + public static object ConvertFrom(Type targetType, object value) + { + return TypeDescriptor + .GetConverter(targetType) + .ConvertFrom(value); + } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 7f914fb1a0..2b35523916 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -194,6 +194,7 @@ namespace Volo.Abp.EntityFrameworkCore { continue; } + /* Checking "currentValue != null" has a good advantage: * Assume that you we already using a named extra property, * then decided to create a field (entity extension) for it. diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index ddcdb942ba..c1c8491dd6 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Newtonsoft.Json; using Volo.Abp.ObjectExtending; @@ -11,7 +12,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters public ExtraPropertiesValueConverter(Type entityType) : base( d => SerializeObject(d, entityType), - s => DeserializeObject(s)) + s => DeserializeObject(s, entityType)) { } @@ -38,9 +39,47 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters return JsonConvert.SerializeObject(copyDictionary, Formatting.None); } - private static Dictionary DeserializeObject(string extraPropertiesAsJson) + private static Dictionary DeserializeObject(string extraPropertiesAsJson, Type entityType) { - return JsonConvert.DeserializeObject>(extraPropertiesAsJson); + var dictionary = JsonConvert.DeserializeObject>(extraPropertiesAsJson); + + if (entityType != null) + { + var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType); + if (objectExtension != null) + { + foreach (var property in objectExtension.GetProperties()) + { + dictionary[property.Name] = GetNormalizedValue(dictionary, property); + } + } + } + + return dictionary; + } + + private static object GetNormalizedValue(Dictionary dictionary, ObjectExtensionPropertyInfo property) + { + var value = dictionary.GetOrDefault(property.Name); + if (value == null) + { + return null; + } + + try + { + if (property.Type.IsEnum) + { + return Enum.Parse(property.Type, value.ToString(), true); + } + + //return Convert.ChangeType(value, property.Type); + return value; + } + catch + { + return value; + } } } } \ No newline at end of file From 5e84b6ad15dac16184cd08daf1185301bf14badf Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Sun, 17 May 2020 02:09:42 +0300 Subject: [PATCH 44/69] add TotalQuestionCount --- .../AbpIoLocalization/Admin/Localization/Resources/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 46cd1cb470..b5e5d8d5b2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -148,6 +148,7 @@ "SuccessfullySent": "Successfully Sent", "SuccessfullyDeleted": "Successfully Deleted", "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" , - "BusinessType": "Business Type" + "BusinessType": "Business Type", + "TotalQuestionCount": "Total question count" } } \ No newline at end of file From 9a19517d174b5c597b2d479144bb661c22b2a657 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Sun, 17 May 2020 02:10:43 +0300 Subject: [PATCH 45/69] add RemainingQuestionCount --- .../AbpIoLocalization/Admin/Localization/Resources/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index b5e5d8d5b2..6ce9c8c1bf 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -149,6 +149,7 @@ "SuccessfullyDeleted": "Successfully Deleted", "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" , "BusinessType": "Business Type", - "TotalQuestionCount": "Total question count" + "TotalQuestionCount": "Total question count", + "RemainingQuestionCount": "Remaining question count" } } \ No newline at end of file From e3e3ecd71233a1bf4173df791bd079d1ba204742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 04:20:16 +0300 Subject: [PATCH 46/69] Refactor AbpTagHelperLocalizer. Also, improve enum localization on select. --- .../TagHelpers/AbpTagHelperLocalizer.cs | 38 +++++------ .../Form/AbpRadioInputTagHelperService.cs | 2 +- .../Form/AbpSelectTagHelperService.cs | 65 ++++++++++++++++--- .../TagHelpers/IAbpTagHelperLocalizer.cs | 6 +- .../AbpPaginationTagHelperService.cs | 13 +++- .../AbpDictionaryBasedStringLocalizer.cs | 2 - 6 files changed, 85 insertions(+), 41 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs index 9f047c5b3c..700a5f4ee9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/AbpTagHelperLocalizer.cs @@ -21,38 +21,30 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers public string GetLocalizedText(string text, ModelExplorer explorer) { - var resourceType = GetResourceTypeFromModelExplorer(explorer); - var localizer = GetStringLocalizer(resourceType); - - return localizer == null ? text : localizer[text].Value; - } - - public IStringLocalizer GetLocalizer(ModelExplorer explorer) - { - var resourceType = GetResourceTypeFromModelExplorer(explorer); - return GetStringLocalizer(resourceType); - } - - public IStringLocalizer GetLocalizer(Assembly assembly) - { - var resourceType = _options.AssemblyResources.GetOrDefault(assembly); - return GetStringLocalizer(resourceType); + var localizer = GetLocalizerOrNull(explorer); + return localizer == null + ? text + : localizer[text].Value; } - public IStringLocalizer GetLocalizer(Type resourceType) + public IStringLocalizer GetLocalizerOrNull(ModelExplorer explorer) { - return GetStringLocalizer(resourceType); + return GetLocalizerOrNull(explorer.Container.ModelType.Assembly); } - private IStringLocalizer GetStringLocalizer(Type resourceType) + public IStringLocalizer GetLocalizerOrNull(Assembly assembly) { - return resourceType == null ? null : _stringLocalizerFactory.Create(resourceType); + var resourceType = GetResourceType(assembly); + return resourceType == null + ? _stringLocalizerFactory.CreateDefaultOrNull() + : _stringLocalizerFactory.Create(resourceType); } - private Type GetResourceTypeFromModelExplorer(ModelExplorer explorer) + private Type GetResourceType(Assembly assembly) { - var assembly = explorer.Container.ModelType.Assembly; - return _options.AssemblyResources.GetOrDefault(assembly); + return _options + .AssemblyResources + .GetOrDefault(assembly); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs index 010cc1d075..bcfa5bd7d1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpRadioInputTagHelperService.cs @@ -90,7 +90,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer) { - var localizer = _tagHelperLocalizer.GetLocalizer(explorer); + var localizer = _tagHelperLocalizer.GetLocalizerOrNull(explorer); var selectItems = explorer.Metadata.IsEnum ? explorer.ModelType.GetTypeInfo().GetMembers(BindingFlags.Public | BindingFlags.Static) .Select((t, i) => new SelectListItem { Value = i.ToString(), Text = GetLocalizedPropertyName(localizer, explorer.ModelType, t.Name) }).ToList() : null; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 3c2805566f..bb79740a41 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -11,6 +11,8 @@ using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.DynamicProxy; +using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { @@ -196,8 +198,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual List GetSelectItemsFromEnum(TagHelperContext context, TagHelperOutput output, ModelExplorer explorer) { - var localizer = _tagHelperLocalizer.GetLocalizer(explorer); - var selectItems = new List(); var isNullableType = Nullable.GetUnderlyingType(explorer.ModelType) != null; var enumType = explorer.ModelType; @@ -208,26 +208,75 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form selectItems.Add(new SelectListItem()); } + var containerLocalizer = _tagHelperLocalizer.GetLocalizerOrNull(explorer.Container.ModelType.Assembly); + IStringLocalizer modelObjectLocalizer = null; + if (explorer.Model != null) + { + modelObjectLocalizer = _tagHelperLocalizer.GetLocalizerOrNull(ProxyHelper.UnProxy(explorer.Model).GetType().Assembly); + } + selectItems.AddRange(enumType.GetEnumNames() .Select(enumName => new SelectListItem { Value = Convert.ToUInt64(Enum.Parse(enumType, enumName)).ToString(), - Text = GetLocalizedPropertyName(localizer, enumType, enumName) + Text = GetLocalizedEnumFieldName(containerLocalizer, modelObjectLocalizer, enumType, enumName) })); return selectItems; } - protected virtual string GetLocalizedPropertyName(IStringLocalizer localizer, Type enumType, string propertyName) + protected virtual string GetLocalizedEnumFieldName( + IStringLocalizer containerLocalizer, + IStringLocalizer modelObjectLocalizer, + Type enumType, + string fieldName) { - if (localizer == null) + LocalizedString localizedString; + + //Look for the enum name + enum field name + + var localizationKey = enumType.Name + "." + fieldName; + if (containerLocalizer != null) + { + localizedString = containerLocalizer[localizationKey]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } + } + + if (modelObjectLocalizer != null) + { + localizedString = modelObjectLocalizer[localizationKey]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } + } + + //Look for the enum field name + + localizationKey = fieldName; + + if (containerLocalizer != null) { - return propertyName; + localizedString = containerLocalizer[localizationKey]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } } - var localizedString = localizer[enumType.Name + "." + propertyName]; + if (modelObjectLocalizer != null) + { + localizedString = modelObjectLocalizer[localizationKey]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } + } - return !localizedString.ResourceNotFound ? localizedString.Value : localizer[propertyName].Value; + return fieldName; } protected virtual List GetSelectItemsFromAttribute( diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs index 8351e47082..2a73777b00 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/IAbpTagHelperLocalizer.cs @@ -10,10 +10,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers { string GetLocalizedText(string text, ModelExplorer explorer); - IStringLocalizer GetLocalizer(ModelExplorer explorer); + IStringLocalizer GetLocalizerOrNull(ModelExplorer explorer); - IStringLocalizer GetLocalizer(Assembly assembly); - - IStringLocalizer GetLocalizer(Type resourceType); + IStringLocalizer GetLocalizerOrNull(Assembly assembly); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs index 76bfcb3ef1..9c37e77767 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs @@ -7,6 +7,7 @@ using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; @@ -17,12 +18,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination private readonly IHtmlGenerator _generator; private readonly HtmlEncoder _encoder; private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; + private readonly IStringLocalizerFactory _stringLocalizerFactory; - public AbpPaginationTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer) + public AbpPaginationTagHelperService( + IHtmlGenerator generator, + HtmlEncoder encoder, + IAbpTagHelperLocalizer tagHelperLocalizer, + IStringLocalizerFactory stringLocalizerFactory) { _generator = generator; _encoder = encoder; _tagHelperLocalizer = tagHelperLocalizer; + _stringLocalizerFactory = stringLocalizerFactory; } public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) @@ -119,7 +126,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination protected virtual async Task RenderAnchorTagHelperLinkHtmlAsync(TagHelperContext context, TagHelperOutput output, string currentPage, string localizationKey) { - var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource)); + var localizer = _stringLocalizerFactory.Create(typeof(AbpUiResource)); var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList); @@ -156,7 +163,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination protected virtual string GetOpeningTags(TagHelperContext context, TagHelperOutput output) { - var localizer = _tagHelperLocalizer.GetLocalizer(typeof(AbpUiResource)); + var localizer = _stringLocalizerFactory.Create(typeof(AbpUiResource)); var pagerInfo = (TagHelper.ShowInfo ?? false) ? "
" + localizer["PagerInfo{0}{1}{2}", TagHelper.Model.ShowingFrom, TagHelper.Model.ShowingTo, TagHelper.Model.TotalItemsCount] + "
\r\n" diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 53a2d7714e..7d9056ca4d 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -177,9 +177,7 @@ namespace Volo.Abp.Localization return allStrings.Values.ToImmutableList(); } - - public class CultureWrapperStringLocalizer : IStringLocalizer, IStringLocalizerSupportsInheritance { private readonly string _cultureName; From 2f0a7af7b3b4b849a392ad21572565789055bc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 17 May 2020 22:56:15 +0300 Subject: [PATCH 47/69] Resolved #3984 Expose enum type & members to client side for extension properties. --- .../ObjectExtending/EntityExtensionDto.cs | 1 - .../ObjectExtending/ExtensionEnumDto.cs | 13 +++ .../ObjectExtending/ExtensionEnumFieldDto.cs | 12 +++ .../ObjectExtending/ObjectExtensionsDto.cs | 2 + .../Form/AbpSelectTagHelperService.cs | 95 ++++++------------- .../ui-extensions.js | 88 +++++++++++++++-- .../CachedObjectExtensionsDtoService.cs | 45 ++++++++- .../Volo/Abp/AbpInitializationException.cs | 46 +++++++++ .../Volo/Abp/Modularity/ModuleLoader.cs | 27 +++++- .../Volo/Abp/Modularity/ModuleManager.cs | 22 ++++- .../Volo/Abp/Reflection/TypeHelper.cs | 2 +- .../ExtraPropertiesValueConverter.cs | 6 +- .../Abp/Localization/LocalizableString.cs | 0 .../LocalizationResourceNameAttribute.cs | 0 .../Abp/Localization/StringLocalizerHelper.cs | 50 ++++++++++ ...xtensionPropertyConfigurationExtensions.cs | 32 +++++++ .../Volo/Abp/Reflection/TypeHelper_Tests.cs | 7 ++ .../ObjectExtensionManager_Tests.cs | 20 ++-- 18 files changed, 380 insertions(+), 88 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumDto.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumFieldDto.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/AbpInitializationException.cs rename framework/src/{Volo.Abp.Localization => Volo.Abp.Localization.Abstractions}/Volo/Abp/Localization/LocalizableString.cs (100%) rename framework/src/{Volo.Abp.Localization => Volo.Abp.Localization.Abstractions}/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs (100%) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/EntityExtensionDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/EntityExtensionDto.cs index 83093e0370..d15870e7c1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/EntityExtensionDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/EntityExtensionDto.cs @@ -9,6 +9,5 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending public Dictionary Properties { get; set; } public Dictionary Configuration { get; set; } - } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumDto.cs new file mode 100644 index 0000000000..4f2dc526eb --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending +{ + [Serializable] + public class ExtensionEnumDto + { + public List Fields { get; set; } + + public string LocalizationResource { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumFieldDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumFieldDto.cs new file mode 100644 index 0000000000..ddc7c349d4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionEnumFieldDto.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending +{ + [Serializable] + public class ExtensionEnumFieldDto + { + public string Name { get; set; } + + public object Value { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionsDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionsDto.cs index fd9665eab1..0338bbd4dc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionsDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionsDto.cs @@ -7,5 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending public class ObjectExtensionsDto { public Dictionary Modules { get; set; } + + public Dictionary Enums { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index bb79740a41..21f6c498a9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Linq.Dynamic.Core; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; @@ -12,6 +13,7 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; using Volo.Abp.DynamicProxy; +using Volo.Abp.Localization; using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form @@ -21,12 +23,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form private readonly IHtmlGenerator _generator; private readonly HtmlEncoder _encoder; private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; + private readonly IStringLocalizerFactory _stringLocalizerFactory; - public AbpSelectTagHelperService(IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer) + public AbpSelectTagHelperService( + IHtmlGenerator generator, + HtmlEncoder encoder, + IAbpTagHelperLocalizer tagHelperLocalizer, + IStringLocalizerFactory stringLocalizerFactory) { _generator = generator; _encoder = encoder; _tagHelperLocalizer = tagHelperLocalizer; + _stringLocalizerFactory = stringLocalizerFactory; } public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) @@ -209,74 +217,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form } var containerLocalizer = _tagHelperLocalizer.GetLocalizerOrNull(explorer.Container.ModelType.Assembly); - IStringLocalizer modelObjectLocalizer = null; - if (explorer.Model != null) - { - modelObjectLocalizer = _tagHelperLocalizer.GetLocalizerOrNull(ProxyHelper.UnProxy(explorer.Model).GetType().Assembly); - } - - selectItems.AddRange(enumType.GetEnumNames() - .Select(enumName => new SelectListItem - { - Value = Convert.ToUInt64(Enum.Parse(enumType, enumName)).ToString(), - Text = GetLocalizedEnumFieldName(containerLocalizer, modelObjectLocalizer, enumType, enumName) - })); - - return selectItems; - } - - protected virtual string GetLocalizedEnumFieldName( - IStringLocalizer containerLocalizer, - IStringLocalizer modelObjectLocalizer, - Type enumType, - string fieldName) - { - LocalizedString localizedString; - - //Look for the enum name + enum field name - - var localizationKey = enumType.Name + "." + fieldName; - if (containerLocalizer != null) - { - localizedString = containerLocalizer[localizationKey]; - if (!localizedString.ResourceNotFound) - { - return localizedString.Value; - } - } - if (modelObjectLocalizer != null) + foreach (var enumValue in enumType.GetEnumValues()) { - localizedString = modelObjectLocalizer[localizationKey]; - if (!localizedString.ResourceNotFound) + var memberName = enumType.GetEnumName(enumValue); + var localizedMemberName = AbpInternalLocalizationHelper.LocalizeWithFallback( + new[] + { + containerLocalizer, + _stringLocalizerFactory.CreateDefaultOrNull() + }, + new[] + { + $"Enum:{enumType.Name}.{memberName}", + $"{enumType.Name}.{memberName}", + memberName + }, + memberName + ); + + selectItems.Add(new SelectListItem { - return localizedString.Value; - } - } - - //Look for the enum field name - - localizationKey = fieldName; - - if (containerLocalizer != null) - { - localizedString = containerLocalizer[localizationKey]; - if (!localizedString.ResourceNotFound) - { - return localizedString.Value; - } - } - - if (modelObjectLocalizer != null) - { - localizedString = modelObjectLocalizer[localizationKey]; - if (!localizedString.ResourceNotFound) - { - return localizedString.Value; - } + Value = enumValue.ToString(), + Text = localizedMemberName + }); } - return fieldName; + return selectItems; } protected virtual List GetSelectItemsFromAttribute( diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js index 9ee545615c..dbf73618ad 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js @@ -99,6 +99,26 @@ function initializeObjectExtensions() { + var getShortEnumTypeName = function (enumType) { + var lastDotIndex = enumType.lastIndexOf('.'); + if (lastDotIndex < 0) { + return enumType; + } + + return enumType.substr(lastDotIndex + 1); + }; + + var getEnumMemberName = function (enumInfo, enumMemberValue) { + for (var i = 0; i < enumInfo.fields.length; i++) { + var enumField = enumInfo.fields[i]; + if (enumField.value == enumMemberValue) { + return enumField.name; + } + } + + return null; + }; + function localizeDisplayName(propertyName, displayName) { if (displayName && displayName.name) { return abp.localization.localize(displayName.name, displayName.resource); @@ -111,6 +131,48 @@ return abp.localization.localize(propertyName); } + function localizeWithFallback(localizationResources, keys, defaultValue) { + for (var i = 0; i < localizationResources.length; i++) { + var localizationResource = localizationResources[i]; + if (!localizationResource) { + continue; + } + + for (var j = 0; j < keys.length; j++) { + var key = keys[j]; + + if (abp.localization.isLocalized(key, localizationResource)) { + return abp.localization.localize(key, localizationResource); + } + } + } + + return defaultValue; + } + + function localizeEnumMember(property, row) { + var enumType = property.config.type; + var enumInfo = abp.objectExtensions.enums[enumType]; + var enumMemberValue = row.extraProperties[property.name]; + var enumMemberName = getEnumMemberName(enumInfo, enumMemberValue); + + if (!enumMemberName) { + return enumMemberValue; + } + + var shortEnumType = getShortEnumTypeName(enumType); + + return localizeWithFallback( + [enumInfo.localizationResource, abp.localization.defaultResourceName], + [ + 'Enum:' + shortEnumType + '.' + enumMemberName, + shortEnumType + '.' + enumMemberName, + enumMemberName + ], + enumMemberName + ); + } + function configureTableColumns(tableName, columnConfigs) { abp.ui.extensions.tableColumns.get(tableName) .addContributor( @@ -137,16 +199,30 @@ return tableProperties; } + function convertPropertyToColumnConfig(property) { + var columnConfig = { + title: localizeDisplayName(property.name, property.config.displayName), + data: "extraProperties." + property.name, + orderable: false + }; + + if (property.config.typeSimple === 'enum') { + columnConfig.render = function (data, type, row) { + return localizeEnumMember( + property, + row + ); + } + } + + return columnConfig; + } + function convertPropertiesToColumnConfigs(properties) { var columnConfigs = []; for (var i = 0; i < properties.length; i++) { - var tableProperty = properties[i]; - columnConfigs.push({ - title: localizeDisplayName(tableProperty.name, tableProperty.config.displayName), - data: "extraProperties." + tableProperty.name, - orderable: false - }); + columnConfigs.push(convertPropertyToColumnConfig(properties[i])); } return columnConfigs; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index aab28b3cb9..870ff0368e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -39,7 +39,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending { var objectExtensionsDto = new ObjectExtensionsDto { - Modules = new Dictionary() + Modules = new Dictionary(), + Enums = new Dictionary() }; foreach (var moduleConfig in ObjectExtensionManager.Instance.Modules()) @@ -47,6 +48,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending objectExtensionsDto.Modules[moduleConfig.Key] = CreateModuleExtensionDto(moduleConfig.Value); } + FillEnums(objectExtensionsDto); + return objectExtensionsDto; } @@ -183,5 +186,45 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending return null; } + + protected virtual void FillEnums(ObjectExtensionsDto objectExtensionsDto) + { + var enumProperties = ObjectExtensionManager.Instance.Modules().Values + .SelectMany( + m => m.Entities.Values.SelectMany( + e => e.GetProperties() + ) + ) + .Where(p => p.Type.IsEnum) + .ToList(); + + foreach (var enumProperty in enumProperties) + { + // ReSharper disable once AssignNullToNotNullAttribute (enumProperty.Type.FullName can not be null for this case) + objectExtensionsDto.Enums[enumProperty.Type.FullName] = CreateExtensionEnumDto(enumProperty); + } + } + + protected virtual ExtensionEnumDto CreateExtensionEnumDto(ExtensionPropertyConfiguration enumProperty) + { + var extensionEnumDto = new ExtensionEnumDto + { + Fields = new List(), + LocalizationResource = enumProperty.GetLocalizationResourceNameOrNull() + }; + + foreach (var enumValue in enumProperty.Type.GetEnumValues()) + { + extensionEnumDto.Fields.Add( + new ExtensionEnumFieldDto + { + Name = enumProperty.Type.GetEnumName(enumValue), + Value = enumValue + } + ); + } + + return extensionEnumDto; + } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpInitializationException.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpInitializationException.cs new file mode 100644 index 0000000000..1bcd513168 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpInitializationException.cs @@ -0,0 +1,46 @@ +using System; +using System.Runtime.Serialization; + +namespace Volo.Abp +{ + public class AbpInitializationException : AbpException + { + /// + /// Creates a new object. + /// + public AbpInitializationException() + { + + } + + /// + /// Creates a new object. + /// + /// Exception message + public AbpInitializationException(string message) + : base(message) + { + + } + + /// + /// Creates a new object. + /// + /// Exception message + /// Inner exception + public AbpInitializationException(string message, Exception innerException) + : base(message, innerException) + { + + } + + /// + /// Constructor for serializing. + /// + public AbpInitializationException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs index 30bf523c1d..374e1adb78 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs @@ -105,7 +105,14 @@ namespace Volo.Abp.Modularity //PreConfigureServices foreach (var module in modules.Where(m => m.Instance is IPreConfigureServices)) { - ((IPreConfigureServices)module.Instance).PreConfigureServices(context); + try + { + ((IPreConfigureServices)module.Instance).PreConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IPreConfigureServices.PreConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } } //ConfigureServices @@ -119,13 +126,27 @@ namespace Volo.Abp.Modularity } } - module.Instance.ConfigureServices(context); + try + { + module.Instance.ConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IAbpModule.ConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } } //PostConfigureServices foreach (var module in modules.Where(m => m.Instance is IPostConfigureServices)) { - ((IPostConfigureServices)module.Instance).PostConfigureServices(context); + try + { + ((IPostConfigureServices)module.Instance).PostConfigureServices(context); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during {nameof(IPostConfigureServices.PostConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } } foreach (var module in modules) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs index 8f25389b63..e594a24603 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs @@ -34,11 +34,18 @@ namespace Volo.Abp.Modularity { LogListOfModules(); - foreach (var Contributor in _lifecycleContributors) + foreach (var contributor in _lifecycleContributors) { foreach (var module in _moduleContainer.Modules) { - Contributor.Initialize(context, module.Instance); + try + { + contributor.Initialize(context, module.Instance); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during the initialize {contributor.GetType().FullName} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } } } @@ -59,11 +66,18 @@ namespace Volo.Abp.Modularity { var modules = _moduleContainer.Modules.Reverse().ToList(); - foreach (var Contributor in _lifecycleContributors) + foreach (var contributor in _lifecycleContributors) { foreach (var module in modules) { - Contributor.Shutdown(context, module.Instance); + try + { + contributor.Shutdown(context, module.Instance); + } + catch (Exception ex) + { + throw new AbpInitializationException($"An error occurred during the shutdown {contributor.GetType().FullName} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex); + } } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index b388ef791d..192043a800 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -169,7 +169,7 @@ namespace Volo.Abp.Reflection { return Activator.CreateInstance(type); } - + return null; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index c1c8491dd6..2fa00e3caf 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -58,12 +58,14 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters return dictionary; } - private static object GetNormalizedValue(Dictionary dictionary, ObjectExtensionPropertyInfo property) + private static object GetNormalizedValue( + Dictionary dictionary, + ObjectExtensionPropertyInfo property) { var value = dictionary.GetOrDefault(property.Name); if (value == null) { - return null; + return property.GetDefaultValue(); } try diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableString.cs rename to framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs rename to framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs new file mode 100644 index 0000000000..b6daf4a44d --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization +{ + /// + /// This class is designed to be used internal by the framework. + /// + public static class AbpInternalLocalizationHelper + { + /// + /// Searches an array of keys in an array of localizers. + /// + /// + /// An array of localizers. Search the keys on the localizers. + /// Can contain null items in the array. + /// + /// + /// An array of keys. Search the keys on the localizers. + /// Should not contain null items in the array. + /// + /// + /// Return value if none of the localizers has none of the keys. + /// + /// + public static string LocalizeWithFallback( + IStringLocalizer[] localizers, + string[] keys, + string defaultValue) + { + foreach (var key in keys) + { + foreach (var localizer in localizers) + { + if (localizer == null) + { + continue; + } + + var localizedString = localizer[key]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } + } + } + + return defaultValue; + } + } +} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs new file mode 100644 index 0000000000..946fc04274 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Localization; + +namespace Volo.Abp.ObjectExtending.Modularity +{ + public static class ExtensionPropertyConfigurationExtensions + { + public static string GetLocalizationResourceNameOrNull( + this ExtensionPropertyConfiguration property) + { + var resourceType = property.GetLocalizationResourceTypeOrNull(); + if (resourceType == null) + { + return null; + } + + return LocalizationResourceNameAttribute.GetName(resourceType); + } + + public static Type GetLocalizationResourceTypeOrNull( + this ExtensionPropertyConfiguration property) + { + if (property.DisplayName != null && + property.DisplayName is LocalizableString localizableString) + { + return localizableString.ResourceType; + } + + return null; + } + } +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs index 978bf9de54..b12a52e935 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs @@ -80,6 +80,7 @@ namespace Volo.Abp.Reflection TypeHelper.GetDefaultValue(typeof(byte)).ShouldBe(0); TypeHelper.GetDefaultValue(typeof(int)).ShouldBe(0); TypeHelper.GetDefaultValue(typeof(string)).ShouldBeNull(); + TypeHelper.GetDefaultValue(typeof(MyEnum)).ShouldBe(MyEnum.EnumValue0); } [Fact] @@ -94,5 +95,11 @@ namespace Volo.Abp.Reflection { } + + public enum MyEnum + { + EnumValue0, + EnumValue1, + } } } diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs index 6386dc41ff..a751fdf20f 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs @@ -138,23 +138,27 @@ namespace Volo.Abp.ObjectExtending .AddOrUpdateProperty("StringPropWithCustomDefaultValue", property => { property.DefaultValue = "custom-value"; + }) + .AddOrUpdateProperty("EnumProp", property => + { + property.DefaultValue = MyTestEnum.EnumValue2; }); _objectExtensionManager .GetPropertyOrNull("IntProp") - .DefaultValue.ShouldBe(0); + .GetDefaultValue().ShouldBe(0); _objectExtensionManager .GetPropertyOrNull("IntPropWithCustomDefaultValue") - .DefaultValue.ShouldBe(42); + .GetDefaultValue().ShouldBe(42); _objectExtensionManager .GetPropertyOrNull("BoolProp") - .DefaultValue.ShouldBe(false); + .GetDefaultValue().ShouldBe(false); _objectExtensionManager .GetPropertyOrNull("NullableIntProp") - .DefaultValue.ShouldBeNull(); + .GetDefaultValue().ShouldBeNull(); var propWithDefaultValueFactory = _objectExtensionManager .GetPropertyOrNull("NullableIntPropWithCustomDefaultValueFactory"); @@ -162,11 +166,15 @@ namespace Volo.Abp.ObjectExtending _objectExtensionManager .GetPropertyOrNull("StringProp") - .DefaultValue.ShouldBeNull(); + .GetDefaultValue().ShouldBeNull(); _objectExtensionManager .GetPropertyOrNull("StringPropWithCustomDefaultValue") - .DefaultValue.ShouldBe("custom-value"); + .GetDefaultValue().ShouldBe("custom-value"); + + _objectExtensionManager + .GetPropertyOrNull("EnumProp") + .GetDefaultValue().ShouldBe(MyTestEnum.EnumValue2); } private class MyExtensibleObject : ExtensibleObject From 9071221dcf45a1f782826d9fbf6c464cca4c8068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 18 May 2020 01:20:38 +0300 Subject: [PATCH 48/69] Update TagHelperExtensions.cs --- .../TagHelpers/Extensions/TagHelperExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs index d925fd11e8..af961a2bf6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs @@ -2,7 +2,6 @@ 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 { From 4aa07db3d27f4b4bea6e291415f3e244af4e472f Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:44:15 +0300 Subject: [PATCH 49/69] fix sentences... --- docs/en/Dapper.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index d8b17838eb..25bba118ec 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -1,22 +1,23 @@ # Dapper Integration -Because Dapper's idea is that the sql statement takes precedence, and mainly provides some extension methods for the `IDbConnection` interface. +Dapper is a light-weight and simple database provider. The major benefit of using Dapper is writing T-SQL queries. It provides some extension methods for `IDbConnection` interface. -Abp does not encapsulate too many functions for Dapper. Abp Dapper provides a `DapperRepository` base class based on Abp EntityFrameworkCore, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. +ABP does not encapsulate many functions for Dapper. ABP Dapper library provides a `DapperRepository` base class based on ABP EntityFrameworkCore module, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. -These two properties can work well with [Unit-Of-Work](Unit-Of-Work.md). +`IDbConnection` and `IDbTransaction` works well with the [ABP Unit-Of-Work](Unit-Of-Work.md). ## Installation -Please install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). +Install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). -`Volo.Abp.Dapper` is the main nuget package for the Dapper integration. Install it to your project (for a layered application, to your data/infrastructure layer): +`Volo.Abp.Dapper` is the main nuget package for the Dapper integration. +Install it to your project (for a layered application, to your data/infrastructure layer): ```shell Install-Package Volo.Abp.Dapper ``` -Then add `AbpDapperModule` module dependency (`DependsOn` attribute) to your [module](Module-Development-Basics.md): +Then add `AbpDapperModule` module dependency (with `DependsOn` attribute) to your [module](Module-Development-Basics.md): ````C# using Volo.Abp.Dapper; @@ -34,9 +35,10 @@ namespace MyCompany.MyProject ## Implement Dapper Repository -The following code implements the `Person` repository, which requires EF Core's `DbContext` (MyAppDbContext). You can inject `PersonDapperRepository` to call its methods. +The following code creates the `PersonRepository`, which requires EF Core's `DbContext` (MyAppDbContext). +You can inject `PersonDapperRepository` to your services for your database operations. -`DbConnection` and `DbTransaction` are from the `DapperRepository` base class. +`DbConnection` and `DbTransaction` comes from the `DapperRepository` base class. ```C# public class PersonDapperRepository : DapperRepository, ITransientDependency From cc9fd339f9517af66b7a101083bf468c8c526ac2 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:45:11 +0300 Subject: [PATCH 50/69] Update Dapper.md --- docs/en/Dapper.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index 25bba118ec..12660f21aa 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -11,6 +11,7 @@ ABP does not encapsulate many functions for Dapper. ABP Dapper library provides Install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). `Volo.Abp.Dapper` is the main nuget package for the Dapper integration. +You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper Install it to your project (for a layered application, to your data/infrastructure layer): ```shell From fbfdbb1c5311cb59de70ee460ef0aa3b11922cd6 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:45:32 +0300 Subject: [PATCH 51/69] Update Dapper.md --- docs/en/Dapper.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index 12660f21aa..0cb1a645d7 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -11,7 +11,9 @@ ABP does not encapsulate many functions for Dapper. ABP Dapper library provides Install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). `Volo.Abp.Dapper` is the main nuget package for the Dapper integration. + You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper + Install it to your project (for a layered application, to your data/infrastructure layer): ```shell From 1c713d42013414599f4496dc529d294058759f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 18 May 2020 01:46:36 +0300 Subject: [PATCH 52/69] Change the example. --- docs/en/Object-Extensions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index 40a7ddd5ea..8c7cca4037 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -200,17 +200,17 @@ ObjectExtensionManager.Instance ````csharp ObjectExtensionManager.Instance - .AddOrUpdateProperty( - "MyIntProperty", + .AddOrUpdateProperty( + "MyDateTimeProperty", options => { - options.DefaultValueFactory = () => 42; + options.DefaultValueFactory = () => DateTime.Now; }); ```` `options.DefaultValueFactory` has a higher priority than the `options.DefaultValue` . -> Tip: Use `DefaultValueFactory` option only if the default value may change over the time. If it is a constant value, then use the `DefaultValue` option. +> Tip: Use `DefaultValueFactory` option only if the default value may change over the time (like `DateTime.Now` in this example). If it is a constant value, then use the `DefaultValue` option. #### CheckPairDefinitionOnMapping From 7d8be4f62c106c8399f3a6d54808a9f207aa27dd Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:47:01 +0300 Subject: [PATCH 53/69] Update Dapper.md --- docs/en/Dapper.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index 0cb1a645d7..850847ebbb 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -2,9 +2,7 @@ Dapper is a light-weight and simple database provider. The major benefit of using Dapper is writing T-SQL queries. It provides some extension methods for `IDbConnection` interface. -ABP does not encapsulate many functions for Dapper. ABP Dapper library provides a `DapperRepository` base class based on ABP EntityFrameworkCore module, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. - -`IDbConnection` and `IDbTransaction` works well with the [ABP Unit-Of-Work](Unit-Of-Work.md). +ABP does not encapsulate many functions for Dapper. ABP Dapper library provides a `DapperRepository` base class based on ABP EntityFrameworkCore module, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. `IDbConnection` and `IDbTransaction` works well with the [ABP Unit-Of-Work](Unit-Of-Work.md). ## Installation From 27009ed76ebbfea0e080b526f56fdbadab33aab0 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:48:02 +0300 Subject: [PATCH 54/69] Update Dapper.md --- docs/en/Dapper.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index 850847ebbb..daf8ceb13a 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -8,9 +8,7 @@ ABP does not encapsulate many functions for Dapper. ABP Dapper library provides Install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). -`Volo.Abp.Dapper` is the main nuget package for the Dapper integration. - -You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper +`Volo.Abp.Dapper` is the library for the Dapper integration. You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper Install it to your project (for a layered application, to your data/infrastructure layer): From b36b948b698dfee2b192c2b30edda710cd40c04b Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Mon, 18 May 2020 01:48:18 +0300 Subject: [PATCH 55/69] Update Dapper.md --- docs/en/Dapper.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/Dapper.md b/docs/en/Dapper.md index daf8ceb13a..26fbf97e66 100644 --- a/docs/en/Dapper.md +++ b/docs/en/Dapper.md @@ -8,7 +8,9 @@ ABP does not encapsulate many functions for Dapper. ABP Dapper library provides Install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). -`Volo.Abp.Dapper` is the library for the Dapper integration. You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper +`Volo.Abp.Dapper` is the library for the Dapper integration. + +You can find it on NuGet Gallery: https://www.nuget.org/packages/Volo.Abp.Dapper Install it to your project (for a layered application, to your data/infrastructure layer): From dade0f28170be9d5efe1a710e7c8a1979b641fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20=C3=87A=C4=9EDA=C5=9E?= Date: Mon, 18 May 2020 13:49:10 +0300 Subject: [PATCH 56/69] added en localizaiton file for Volo.Abp.Emailing.Tests project --- .../Volo/Abp/Emailing/Localization/en.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json new file mode 100644 index 0000000000..70d0b2b52e --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json @@ -0,0 +1,6 @@ +{ + "culture": "de", + "texts": { + "hello": "Hello" + } +} \ No newline at end of file From ce6dc02ade5140796d79a9833b610be99c856505 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 18 May 2020 16:29:57 +0300 Subject: [PATCH 57/69] bloging linkedin meta tags --- .../src/Volo.Blogging.Web/BloggingTwitterOptions.cs | 12 ------------ .../Pages/Blogs/Posts/Detail.cshtml | 6 ++++++ .../SocialMedia/BloggingTwitterOptions.cs | 7 +++++++ 3 files changed, 13 insertions(+), 12 deletions(-) delete mode 100644 modules/blogging/src/Volo.Blogging.Web/BloggingTwitterOptions.cs create mode 100644 modules/blogging/src/Volo.Blogging.Web/SocialMedia/BloggingTwitterOptions.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/BloggingTwitterOptions.cs b/modules/blogging/src/Volo.Blogging.Web/BloggingTwitterOptions.cs deleted file mode 100644 index 8c1b1fbf7d..0000000000 --- a/modules/blogging/src/Volo.Blogging.Web/BloggingTwitterOptions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Volo.Blogging -{ - public class BloggingTwitterOptions - { - public string Site { get; set; } - } -} diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml index 63cfbf8a8e..db6427e2a7 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml @@ -8,6 +8,7 @@ @using Volo.Blogging.Pages.Blog.Posts @using Volo.Blogging.Areas.Blog.Helpers.TagHelpers @using Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs +@using Volo.Blogging.SocialMedia @inject IAuthorizationService Authorization @inject IOptionsSnapshot twitterOptions @model DetailModel @@ -21,6 +22,11 @@ ViewBag.TwitterDescription = Model.Post.Description; ViewBag.TwitterImage = $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Model.Post.CoverImage}"; + ViewBag.LinkedInUrl = Request.GetEncodedUrl(); + ViewBag.LinkedInTitle = Model.Post.Title; + ViewBag.LinkedInDescription = Model.Post.Description; + ViewBag.LinkedInImage = $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Model.Post.CoverImage}"; + var hasCommentingPermission = CurrentUser.IsAuthenticated; //TODO: Apply real policy! } @section scripts { diff --git a/modules/blogging/src/Volo.Blogging.Web/SocialMedia/BloggingTwitterOptions.cs b/modules/blogging/src/Volo.Blogging.Web/SocialMedia/BloggingTwitterOptions.cs new file mode 100644 index 0000000000..5960be21b9 --- /dev/null +++ b/modules/blogging/src/Volo.Blogging.Web/SocialMedia/BloggingTwitterOptions.cs @@ -0,0 +1,7 @@ +namespace Volo.Blogging.SocialMedia +{ + public class BloggingTwitterOptions + { + public string Site { get; set; } + } +} From 832cd5d47754bdba36a7188026ce9254773755ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ak=C4=B1n=20Sabri=20=C3=87am?= Date: Mon, 18 May 2020 18:22:33 +0300 Subject: [PATCH 58/69] added localization keys fororganizations in abpio admin --- .../AbpIoLocalization/Admin/Localization/Resources/en.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 14a4eb345c..c172c1b302 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -147,6 +147,8 @@ "EmailSent": "Email Sent", "SuccessfullySent": "Successfully Sent", "SuccessfullyDeleted": "Successfully Deleted", - "DiscountRequestDeletionWarningMessage": "Discount request will be deleted" + "DiscountRequestDeletionWarningMessage": "Discount request will be deleted", + "TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCount must be greater than RemainingQuestionCount !", + "QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount and RemainingQuestionCount must be zero or greater than zero !" } } \ No newline at end of file From 465c751ea9f5e4aa6235364785bea04057b7f863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 00:16:52 +0300 Subject: [PATCH 59/69] Fixed #3999: Fix BootstrapDatepicker Script/Style Contributor namespace --- .../BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs | 2 +- .../BootstrapDatepicker/BootstrapDatepickerStyleContributor.cs | 2 +- .../Bundling/SharedThemeGlobalScriptContributor.cs | 1 + .../Bundling/SharedThemeGlobalStyleContributor.cs | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs index 7e21c8cef5..5a32cb7ca0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerScriptContributor.cs @@ -4,7 +4,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.Modularity; -namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker { [DependsOn(typeof(JQueryScriptContributor))] public class BootstrapDatepickerScriptContributor : BundleContributor diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerStyleContributor.cs index bc345e34b3..0b9b555e97 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerStyleContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/BootstrapDatepicker/BootstrapDatepickerStyleContributor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; -namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2 +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker { public class BootstrapDatepickerStyleContributor : BundleContributor { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs index 892f0d497a..4ff7430553 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs @@ -1,5 +1,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Bootstrap; +using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker; using Volo.Abp.AspNetCore.Mvc.UI.Packages.DatatablesNetBs4; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryForm; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalStyleContributor.cs index d1703113d0..49b8c4893e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalStyleContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalStyleContributor.cs @@ -1,5 +1,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Bootstrap; +using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; using Volo.Abp.AspNetCore.Mvc.UI.Packages.DatatablesNetBs4; using Volo.Abp.AspNetCore.Mvc.UI.Packages.FontAwesome; From 4a56efdc48ca479de832d8c43617d3332c9de296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 00:17:19 +0300 Subject: [PATCH 60/69] Show icon for boolean extension properties on datatables. --- .../ui-extensions.js | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js index dbf73618ad..40e22d3da9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js @@ -150,10 +150,9 @@ return defaultValue; } - function localizeEnumMember(property, row) { + function localizeEnumMember(property, enumMemberValue) { var enumType = property.config.type; var enumInfo = abp.objectExtensions.enums[enumType]; - var enumMemberValue = row.extraProperties[property.name]; var enumMemberName = getEnumMemberName(enumInfo, enumMemberValue); if (!enumMemberName) { @@ -199,6 +198,10 @@ return tableProperties; } + function getValueFromRow(property, row) { + return row.extraProperties[property.name];; + } + function convertPropertyToColumnConfig(property) { var columnConfig = { title: localizeDisplayName(property.name, property.config.displayName), @@ -208,10 +211,18 @@ if (property.config.typeSimple === 'enum') { columnConfig.render = function (data, type, row) { - return localizeEnumMember( - property, - row - ); + var value = getValueFromRow(property, row); + return localizeEnumMember(property, value); + } + } + else if (property.config.typeSimple === 'boolean') { + columnConfig.render = function (data, type, row) { + var value = getValueFromRow(property, row); + if (value) { + return ''; + } else { + return ''; + } } } From 7abcc0fdf8e9f285881c0acb6e1147d48376d9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 00:55:33 +0300 Subject: [PATCH 61/69] Add Format (asp-format), Name and Value properties to AbpInputTagHelper --- .../TagHelpers/Form/AbpInputTagHelper.cs | 7 +++++++ .../TagHelpers/Form/AbpInputTagHelperService.cs | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index f264d21cd5..16a700f4bc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs @@ -33,6 +33,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form [ViewContext] public ViewContext ViewContext { get; set; } + [HtmlAttributeName("asp-format")] + public string Format { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + public AbpInputTagHelper(AbpInputTagHelperService tagHelperService) : base(tagHelperService) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index a2bb92a14d..b03b0c8b69 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -110,7 +110,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return new TextAreaTagHelper(_generator) { For = TagHelper.AspFor, - ViewContext = TagHelper.ViewContext + ViewContext = TagHelper.ViewContext, + Name = TagHelper.Name }; } @@ -118,7 +119,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { For = TagHelper.AspFor, InputTypeName = TagHelper.InputTypeName, - ViewContext = TagHelper.ViewContext + ViewContext = TagHelper.ViewContext, + Format = TagHelper.Format, + Name = TagHelper.Name, + Value = TagHelper.Value }; } From 67e68297e2b31fca8147997dc4eec0ff32567e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 00:57:52 +0300 Subject: [PATCH 62/69] Create GetInputFormatOrNull extension method for ObjectExtensionPropertyInfo --- ...UiObjectExtensionPropertyInfoExtensions.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs new file mode 100644 index 0000000000..bac7787028 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -0,0 +1,44 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +namespace Volo.Abp.ObjectExtending +{ + public static class MvcUiObjectExtensionPropertyInfoExtensions + { + private static readonly Type[] DateTypes = new[] + { + typeof(DateTime), typeof(DateTimeOffset) + }; + + public static string GetInputFormatOrNull(this ObjectExtensionPropertyInfo property) + { + if (IsDate(property)) + { + return "{0:yyyy-MM-dd}"; + } + + return null; + } + + private static bool IsDate(ObjectExtensionPropertyInfo property) + { + if (!DateTypes.Contains(property.Type)) + { + return false; + } + + var dataTypeAttribute = property + .Attributes + .OfType() + .FirstOrDefault(); + + if (dataTypeAttribute == null) + { + return false; + } + + return dataTypeAttribute.DataType == DataType.Date; + } + } +} From 17891a959ad50e576a37214a153c71d12159ae00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 01:41:14 +0300 Subject: [PATCH 63/69] Add Default Renderers for datatables. --- .../datatables/datatables-extensions.js | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js index cd31e73bc4..40aebbc71f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js @@ -8,7 +8,7 @@ }; /************************************************************************ - * RECORD-ACTIONS extension for datatables * + * RECORD-ACTIONS extension for datatables * *************************************************************************/ (function () { if (!$.fn.dataTableExt) { @@ -328,4 +328,32 @@ })(); + /************************************************************************ + * Default Renderers * + *************************************************************************/ + + datatables.defaultRenderers = datatables.defaultRenderers || {}; + + datatables.defaultRenderers['boolean'] = function(value) { + if (value) { + return ''; + } else { + return ''; + } + }; + + datatables.defaultRenderers['date'] = function (value) { + return luxon + .DateTime + .fromISO(value, { locale: abp.localization.currentCulture.name }) + .toLocaleString(); + }; + + datatables.defaultRenderers['datetime'] = function (value) { + return luxon + .DateTime + .fromISO(value, { locale: abp.localization.currentCulture.name }) + .toLocaleString(luxon.DateTime.DATETIME_SHORT); + }; + })(jQuery); \ No newline at end of file From 2d55cbf1942ae6d56e6b2c6ef53b2b5331d31dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 01:41:18 +0300 Subject: [PATCH 64/69] Update LuxonScriptContributor.cs --- .../Mvc/UI/Packages/Luxon/LuxonScriptContributor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Luxon/LuxonScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Luxon/LuxonScriptContributor.cs index e605f6e6ae..3d2a1dc774 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Luxon/LuxonScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Luxon/LuxonScriptContributor.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Luxon From f160b368a99590e5064b4e3c69800e82b9db92c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 01:41:47 +0300 Subject: [PATCH 65/69] handle dates and datetimes on datatables MVC UI --- .../ui-extensions.js | 19 ++- ...UiObjectExtensionPropertyInfoExtensions.cs | 114 +++++++++++++++--- .../CachedObjectExtensionsDtoService.cs | 24 +++- .../ObjectExtendingPropertyInfoExtensions.cs | 113 +++-------------- .../IBasicObjectExtensionPropertyInfo.cs | 38 ++++++ .../ExtensionPropertyConfiguration.cs | 2 +- .../ModuleExtensionConfigurationHelper.cs | 1 + .../ObjectExtensionPropertyInfo.cs | 2 +- 8 files changed, 185 insertions(+), 128 deletions(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/IBasicObjectExtensionPropertyInfo.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js index 40e22d3da9..eacfecc867 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/ui-extensions.js @@ -96,7 +96,7 @@ get: _get }; })(); - + function initializeObjectExtensions() { var getShortEnumTypeName = function (enumType) { @@ -209,19 +209,18 @@ orderable: false }; + if (property.config.typeSimple === 'enum') { - columnConfig.render = function (data, type, row) { + columnConfig.render = function(data, type, row) { var value = getValueFromRow(property, row); return localizeEnumMember(property, value); } - } - else if (property.config.typeSimple === 'boolean') { - columnConfig.render = function (data, type, row) { - var value = getValueFromRow(property, row); - if (value) { - return ''; - } else { - return ''; + } else { + var defaultRenderer = abp.libs.datatables.defaultRenderers[property.config.typeSimple]; + if (defaultRenderer) { + columnConfig.render = function (data, type, row) { + var value = getValueFromRow(property, row); + return defaultRenderer(value); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index bac7787028..608374e9e8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -1,19 +1,40 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; +using Microsoft.AspNetCore.Mvc; namespace Volo.Abp.ObjectExtending { public static class MvcUiObjectExtensionPropertyInfoExtensions { - private static readonly Type[] DateTypes = new[] - { - typeof(DateTime), typeof(DateTimeOffset) + private static readonly HashSet NumberTypes = new HashSet { + typeof(int), + typeof(long), + typeof(byte), + typeof(sbyte), + typeof(short), + typeof(ushort), + typeof(uint), + typeof(long), + typeof(ulong), + typeof(float), + typeof(double), + typeof(int?), + typeof(long?), + typeof(byte?), + typeof(sbyte?), + typeof(short?), + typeof(ushort?), + typeof(uint?), + typeof(long?), + typeof(ulong?), + typeof(float?), + typeof(double?), }; - public static string GetInputFormatOrNull(this ObjectExtensionPropertyInfo property) + public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) { - if (IsDate(property)) + if (property.IsDate()) { return "{0:yyyy-MM-dd}"; } @@ -21,24 +42,85 @@ namespace Volo.Abp.ObjectExtending return null; } - private static bool IsDate(ObjectExtensionPropertyInfo property) + public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) + { + foreach (var attribute in propertyInfo.Attributes) + { + var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); + if (inputTypeByAttribute != null) + { + return inputTypeByAttribute; + } + } + + return GetInputTypeFromTypeOrNull(propertyInfo.Type) + ?? "text"; //default + } + + private static string GetInputTypeFromAttributeOrNull(Attribute attribute) { - if (!DateTypes.Contains(property.Type)) + if (attribute is EmailAddressAttribute) { - return false; + return "email"; } - var dataTypeAttribute = property - .Attributes - .OfType() - .FirstOrDefault(); + if (attribute is UrlAttribute) + { + return "url"; + } + + if (attribute is HiddenInputAttribute) + { + return "hidden"; + } + + if (attribute is PhoneAttribute) + { + return "tel"; + } - if (dataTypeAttribute == null) + if (attribute is DataTypeAttribute dataTypeAttribute) { - return false; + switch (dataTypeAttribute.DataType) + { + case DataType.Password: + return "password"; + case DataType.Date: + return "date"; + case DataType.Time: + return "time"; + case DataType.EmailAddress: + return "email"; + case DataType.Url: + return "url"; + case DataType.PhoneNumber: + return "tel"; + case DataType.DateTime: + return "datetime-local"; + } } - return dataTypeAttribute.DataType == DataType.Date; + return null; + } + + private static string GetInputTypeFromTypeOrNull(Type type) + { + if (type == typeof(bool)) + { + return "checkbox"; + } + + if (type == typeof(DateTime)) + { + return "datetime-local"; + } + + if (NumberTypes.Contains(type)) + { + return "number"; + } + + return null; } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index 870ff0368e..76d73820b2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -107,9 +107,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending var extensionPropertyDto = new ExtensionPropertyDto { Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(propertyConfig.Type), - TypeSimple = propertyConfig.Type.IsEnum - ? "enum" - : TypeHelper.GetSimplifiedName(propertyConfig.Type), + TypeSimple = GetSimpleTypeName(propertyConfig), Attributes = new List(), DisplayName = CreateDisplayNameDto(propertyConfig), Configuration = new Dictionary(), @@ -161,6 +159,26 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending return extensionPropertyDto; } + protected virtual string GetSimpleTypeName(ExtensionPropertyConfiguration propertyConfig) + { + if (propertyConfig.Type.IsEnum) + { + return "enum"; + } + + if (propertyConfig.IsDate()) + { + return "date"; + } + + if (propertyConfig.IsDateTime()) + { + return "datetime"; + } + + return TypeHelper.GetSimplifiedName(propertyConfig.Type); + } + protected virtual LocalizableStringDto CreateDisplayNameDto(ExtensionPropertyConfiguration propertyConfig) { if (propertyConfig.DisplayName == null) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs index 04339eedd3..dc8a28e89f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs @@ -1,116 +1,35 @@ using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Mvc; +using System.Linq; namespace Volo.Abp.ObjectExtending { public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions { - private static readonly HashSet NumberTypes = new HashSet { - typeof(int), - typeof(long), - typeof(byte), - typeof(sbyte), - typeof(short), - typeof(ushort), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - typeof(int?), - typeof(long?), - typeof(byte?), - typeof(sbyte?), - typeof(short?), - typeof(ushort?), - typeof(uint?), - typeof(long?), - typeof(ulong?), - typeof(float?), - typeof(double?), + private static readonly Type[] DateTimeTypes = + { + typeof(DateTime), + typeof(DateTimeOffset) }; - public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) + public static bool IsDate(this IBasicObjectExtensionPropertyInfo property) { - foreach (var attribute in propertyInfo.Attributes) - { - var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); - if (inputTypeByAttribute != null) - { - return inputTypeByAttribute; - } - } - - return GetInputTypeFromTypeOrNull(propertyInfo.Type) - ?? "text"; //default + return DateTimeTypes.Contains(property.Type) && + property.GetDataTypeOrNull() == DataType.Date; } - private static string GetInputTypeFromAttributeOrNull(Attribute attribute) + public static bool IsDateTime(this IBasicObjectExtensionPropertyInfo property) { - if (attribute is EmailAddressAttribute) - { - return "email"; - } - - if (attribute is UrlAttribute) - { - return "url"; - } - - if (attribute is HiddenInputAttribute) - { - return "hidden"; - } - - if (attribute is PhoneAttribute) - { - return "tel"; - } - - if (attribute is DataTypeAttribute dataTypeAttribute) - { - switch (dataTypeAttribute.DataType) - { - case DataType.Password: - return "password"; - case DataType.Date: - return "date"; - case DataType.Time: - return "time"; - case DataType.EmailAddress: - return "email"; - case DataType.Url: - return "url"; - case DataType.PhoneNumber: - return "tel"; - case DataType.DateTime: - return "datetime-local"; - } - } - - return null; + return DateTimeTypes.Contains(property.Type) && + !property.IsDate(); } - private static string GetInputTypeFromTypeOrNull(Type type) + public static DataType? GetDataTypeOrNull(this IBasicObjectExtensionPropertyInfo property) { - if (type == typeof(bool)) - { - return "checkbox"; - } - - if (type == typeof(DateTime)) - { - return "datetime-local"; - } - - if (NumberTypes.Contains(type)) - { - return "number"; - } - - return null; + return property + .Attributes + .OfType() + .FirstOrDefault()?.DataType; } } } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/IBasicObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/IBasicObjectExtensionPropertyInfo.cs new file mode 100644 index 0000000000..de9bb35b01 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/IBasicObjectExtensionPropertyInfo.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Volo.Abp.Localization; + +namespace Volo.Abp.ObjectExtending +{ + public interface IBasicObjectExtensionPropertyInfo + { + [NotNull] + public string Name { get; } + + [NotNull] + public Type Type { get; } + + [NotNull] + public List Attributes { get; } + + [NotNull] + public List> Validators { get; } + + [CanBeNull] + public ILocalizableString DisplayName { get; } + + /// + /// Uses as the default value if was not set. + /// + [CanBeNull] + public object DefaultValue { get; set; } + + /// + /// Used with the first priority to create the default value for the property. + /// Uses to the if this was not set. + /// + [CanBeNull] + public Func DefaultValueFactory { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs index 6d66e51337..0a19a82018 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs @@ -6,7 +6,7 @@ using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending.Modularity { - public class ExtensionPropertyConfiguration : IHasNameWithLocalizableDisplayName + public class ExtensionPropertyConfiguration : IHasNameWithLocalizableDisplayName, IBasicObjectExtensionPropertyInfo { [NotNull] public EntityExtensionConfiguration EntityExtensionConfiguration { get; } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs index cb5be17c1f..f4a5b149d6 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using JetBrains.Annotations; namespace Volo.Abp.ObjectExtending.Modularity diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index 12b32ab241..ddd8fbbc3c 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -7,7 +7,7 @@ using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending { - public class ObjectExtensionPropertyInfo : IHasNameWithLocalizableDisplayName + public class ObjectExtensionPropertyInfo : IHasNameWithLocalizableDisplayName, IBasicObjectExtensionPropertyInfo { [NotNull] public ObjectExtensionInfo ObjectExtension { get; } From 9ef9d142ef7171881463c81a788fda08fc56fcb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 01:51:29 +0300 Subject: [PATCH 66/69] Handle formatting for DateTime inputs for extension properties. --- .../MvcUiObjectExtensionPropertyInfoExtensions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index 608374e9e8..72338a021d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -39,6 +39,11 @@ namespace Volo.Abp.ObjectExtending return "{0:yyyy-MM-dd}"; } + if (property.IsDateTime()) + { + return "{0:yyyy-MM-ddTHH:mm}"; + } + return null; } From 0df437d876b3758d10d7d4f3dc83887edd5c0126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 02:12:17 +0300 Subject: [PATCH 67/69] Add decimal to NumberTypes for extension properties --- .../MvcUiObjectExtensionPropertyInfoExtensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index 72338a021d..1ebe486068 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -19,6 +19,7 @@ namespace Volo.Abp.ObjectExtending typeof(ulong), typeof(float), typeof(double), + typeof(decimal), typeof(int?), typeof(long?), typeof(byte?), @@ -30,6 +31,7 @@ namespace Volo.Abp.ObjectExtending typeof(ulong?), typeof(float?), typeof(double?), + typeof(decimal?) }; public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) From c17868e5acef0ce3135e22d6ce07c90e5c25face Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 05:17:15 +0300 Subject: [PATCH 68/69] Handle floating numbers on extension properties. --- .../Extensions/TagHelperExtensions.cs | 20 +++++-- .../Form/AbpInputTagHelperService.cs | 40 +++++++++++-- ...UiObjectExtensionPropertyInfoExtensions.cs | 17 ++++++ ...PropertiesDictionaryModelBinderProvider.cs | 1 - .../AbpExtraPropertyModelBinder.cs | 6 +- .../Volo/Abp/Reflection/TypeHelper.cs | 56 +++++++++++++++++-- 6 files changed, 122 insertions(+), 18 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs index af961a2bf6..761b72ec99 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs @@ -7,14 +7,26 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions { public static class TagHelperExtensions { - public static async Task ProcessAndGetOutputAsync(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) + public static async Task ProcessAndGetOutputAsync( + this TagHelper tagHelper, + TagHelperAttributeList attributeList, + TagHelperContext context, + string tagName = "div", + TagMode tagMode = TagMode.SelfClosing) { - var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) + var innerOutput = new TagHelperOutput( + tagName, + attributeList, + (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) { TagMode = tagMode }; - - var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString()); + + var innerContext = new TagHelperContext( + attributeList, + context.Items, + Guid.NewGuid().ToString() + ); tagHelper.Init(context); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index b03b0c8b69..932c6d5864 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -115,22 +115,40 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form }; } - return new InputTagHelper(_generator) + var inputTagHelper = new InputTagHelper(_generator) { For = TagHelper.AspFor, InputTypeName = TagHelper.InputTypeName, - ViewContext = TagHelper.ViewContext, - Format = TagHelper.Format, - Name = TagHelper.Name, - Value = TagHelper.Value + ViewContext = TagHelper.ViewContext }; + + if (!TagHelper.Format.IsNullOrEmpty()) + { + inputTagHelper.Format = TagHelper.Format; + } + + if (!TagHelper.Name.IsNullOrEmpty()) + { + inputTagHelper.Name = TagHelper.Name; + } + + if (!TagHelper.Value.IsNullOrEmpty()) + { + inputTagHelper.Value = TagHelper.Value; + } + + return inputTagHelper; } protected virtual async Task<(TagHelperOutput, bool)> GetInputTagHelperOutputAsync(TagHelperContext context, TagHelperOutput output) { var tagHelper = GetInputTagHelper(context, output); - var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input"); + var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync( + GetInputAttributes(context, output), + context, + "input" + ); ConvertToTextAreaIfTextArea(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput); @@ -349,6 +367,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form attrList.Add("type", TagHelper.InputTypeName); } + if (!TagHelper.Name.IsNullOrEmpty() && !attrList.ContainsName("name")) + { + attrList.Add("name", TagHelper.Name); + } + + if (!TagHelper.Value.IsNullOrEmpty() && !attrList.ContainsName("value")) + { + attrList.Add("value", TagHelper.Value); + } + return attrList; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index 1ebe486068..7aea3cf9f2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending { @@ -49,6 +50,22 @@ namespace Volo.Abp.ObjectExtending return null; } + public static string GetInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object value) + { + if (value == null) + { + return null; + } + + if (TypeHelper.IsFloatingType(property.Type)) + { + return value.ToString()?.Replace(',', '.'); + } + + /* Let the ASP.NET Core handle it! */ + return null; + } + public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) { foreach (var attribute in propertyInfo.Attributes) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs index 3ed1eda3a1..812ca30f06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs index c94ad08e74..d09da73a59 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; using Volo.Abp.ObjectExtending; @@ -61,7 +60,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding return value; } - return TypeHelper.ConvertFromString(propertyInfo.Type, value); + return TypeHelper.ConvertFromString( + propertyInfo.Type, + value + ); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 192043a800..83182fc965 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -2,14 +2,23 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Reflection; using JetBrains.Annotations; +using Volo.Abp.Localization; namespace Volo.Abp.Reflection { public static class TypeHelper { + private static readonly HashSet FloatingTypes = new HashSet + { + typeof(float), + typeof(double), + typeof(decimal) + }; + private static readonly HashSet NonNullablePrimitiveTypes = new HashSet { typeof(byte), @@ -40,7 +49,7 @@ namespace Volo.Abp.Reflection { return false; } - + var type = obj.GetType(); if (!type.GetTypeInfo().IsGenericType) { @@ -169,7 +178,7 @@ namespace Volo.Abp.Reflection { return Activator.CreateInstance(type); } - + return null; } @@ -297,9 +306,39 @@ namespace Volo.Abp.Reflection public static object ConvertFromString(Type targetType, string value) { - return TypeDescriptor - .GetConverter(targetType) - .ConvertFromString(value); + if (value == null) + { + return null; + } + + var converter = TypeDescriptor.GetConverter(targetType); + + if (IsFloatingType(targetType)) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + return converter.ConvertFromString(value.Replace(',', '.')); + } + } + + return converter.ConvertFromString(value); + } + + public static bool IsFloatingType(Type type, bool includeNullable = true) + { + if (FloatingTypes.Contains(type)) + { + return true; + } + + if (includeNullable && + IsNullable(type) && + FloatingTypes.Contains(type.GenericTypeArguments[0])) + { + return true; + } + + return false; } public static object ConvertFrom(object value) @@ -313,5 +352,12 @@ namespace Volo.Abp.Reflection .GetConverter(targetType) .ConvertFrom(value); } + + public static Type StripNullable(Type type) + { + return IsNullable(type) + ? type.GenericTypeArguments[0] + : type; + } } } From d3a42228b2f983e45d648a1f59bc7354edbd1814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 05:26:45 +0300 Subject: [PATCH 69/69] Set name only if there is a valid value. --- .../Form/AbpInputTagHelperService.cs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 932c6d5864..4ddf44d2d6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -91,7 +91,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form inputHtml + label : label + inputHtml; - return innerContent + infoHtml + validation; + return innerContent + infoHtml + validation; } protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml, bool isCheckbox) @@ -103,16 +103,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual TagHelper GetInputTagHelper(TagHelperContext context, TagHelperOutput output) { - var textAreaAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute