diff --git a/docs/en/Getting-Started-React-Native.md b/docs/en/Getting-Started-React-Native.md index fe4cf478de..be0505b9f1 100644 --- a/docs/en/Getting-Started-React-Native.md +++ b/docs/en/Getting-Started-React-Native.md @@ -95,6 +95,20 @@ A React Native application running on an Android emulator or a physical phone ** Run the backend application as described in the [getting started document](Getting-Started.md). +> You should turn off the "Https Restriction" if you're using OpenIddict as a central identity management solution. Because the IOS Simulator doesn't support self-signed certificates and OpenIddict is set to only work with HTTPS by default. +## How to disable the Https-only settings of OpenIddict + + Go to MyProjectNameHttpApiHostModule.cs under the host project. Add put these codes under the `PreConfigureServices` function. + +```csharp +#if DEBUG + PreConfigure(options => { + options.UseAspNetCore() + .DisableTransportSecurityRequirement(); + }); +#endif +``` + ## How to Configure & Run the React Native Application diff --git a/docs/en/Modules/Cms-Kit/Comments.md b/docs/en/Modules/Cms-Kit/Comments.md index e5a5da592e..ac8853a4d8 100644 --- a/docs/en/Modules/Cms-Kit/Comments.md +++ b/docs/en/Modules/Cms-Kit/Comments.md @@ -1,10 +1,10 @@ # CMS Kit: Comments -CMS kit provides a **comment** system to add comments feature to any kind of resource, like blog posts, products, etc. +CMS kit provides a **comment** system to add the comment feature to any kind of resource, like blog posts, products, etc. ## Options -The comment system provides a mechanism to group comment definitions by entity types. For example, if you want to use comment system for blog posts and products, you need to define two entity types named `BlogPosts` and `Product`, and add comments under these entity types. +The comment system provides a mechanism to group comment definitions by entity types. For example, if you want to use the comment system for blog posts and products, you need to define two entity types named `BlogPosts` and `Product`, and add comments under these entity types. `CmsKitCommentOptions` can be configured in the domain layer, in the `ConfigureServices` method of your [module](https://docs.abp.io/en/abp/latest/Module-Development-Basics). Example: @@ -12,6 +12,7 @@ The comment system provides a mechanism to group comment definitions by entity t Configure(options => { options.EntityTypes.Add(new CommentEntityTypeDefinition("Product")); + options.IsRecaptchaEnabled = true; //false by default }); ``` @@ -20,6 +21,7 @@ Configure(options => `CmsKitCommentOptions` properties: - `EntityTypes`: List of defined entity types(`CmsKitCommentOptions`) in the comment system. +- `IsRecaptchaEnabled`: This flag enables or disables the reCaptcha for the comment system. You can set it as **true** if you want to use reCaptcha in your comment system. `CommentEntityTypeDefinition` properties: @@ -77,7 +79,7 @@ A comment represents a written comment from a user. This module follows the [Repository Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories) guide. -Following custom repositories are defined for this feature: +The following custom repositories are defined for this feature: - `ICommentRepository` @@ -93,8 +95,8 @@ This module follows the [Domain Services Best Practices & Conventions](https://d #### Application services -- `CommentAdminAppService` (implements `ICommentAdminAppService`): Implements the use cases of comment management system, like listing or removing comments etc. -- `CommentPublicAppService` (implements `ICommentPublicAppService`): Implements the use cases of comment management on the public websites, like listing comments, adding comments etc. +- `CommentAdminAppService` (implements `ICommentAdminAppService`): Implements the use cases of the comment management system, like listing or removing comments etc. +- `CommentPublicAppService` (implements `ICommentPublicAppService`): Implements the use cases of the comment management on the public websites, like listing comments, adding comments etc. ### Database providers diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs index 21f29f995c..36ca9b4b55 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs @@ -33,6 +33,10 @@ public static class AbpWebAssemblyHostBuilderExtensions var application = await builder.Services.AddApplicationAsync(opts => { options?.Invoke(new AbpWebAssemblyApplicationCreationOptions(builder, opts)); + if (opts.Environment.IsNullOrWhiteSpace()) + { + opts.Environment = builder.HostEnvironment.Environment; + } }); return application; @@ -57,6 +61,10 @@ public static class AbpWebAssemblyHostBuilderExtensions var application = builder.Services.AddApplication(opts => { options?.Invoke(new AbpWebAssemblyApplicationCreationOptions(builder, opts)); + if (opts.Environment.IsNullOrWhiteSpace()) + { + opts.Environment = builder.HostEnvironment.Environment; + } }); return application; diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpWebAssemblyServiceCollectionExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpWebAssemblyServiceCollectionExtensions.cs index bbcf1d5a83..bb9f0774bc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpWebAssemblyServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/AbpWebAssemblyServiceCollectionExtensions.cs @@ -1,16 +1,31 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.Extensions.Hosting; using Volo.Abp; namespace Microsoft.Extensions.DependencyInjection; public static class AbpWebAssemblyServiceCollectionExtensions { - public static WebAssemblyHostBuilder GetHostBuilder( - [NotNull] this IServiceCollection services) + public static WebAssemblyHostBuilder GetHostBuilder([NotNull] this IServiceCollection services) { Check.NotNull(services, nameof(services)); return services.GetSingletonInstance(); } + + public static IWebAssemblyHostEnvironment GetWebAssemblyHostEnvironment(this IServiceCollection services) + { + var webAssemblyHostEnvironment = services.GetSingletonInstanceOrNull(); + + if (webAssemblyHostEnvironment == null) + { + return new EmptyWebAssemblyHostEnvironment() + { + Environment = Environments.Development + }; + } + + return webAssemblyHostEnvironment; + } } diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/EmptyWebAssemblyHostEnvironment.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/EmptyWebAssemblyHostEnvironment.cs new file mode 100644 index 0000000000..6393948af7 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/Extensions/DependencyInjection/EmptyWebAssemblyHostEnvironment.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +namespace Microsoft.Extensions.DependencyInjection; + +public class EmptyWebAssemblyHostEnvironment : IWebAssemblyHostEnvironment +{ + public string Environment { get; set; } + + public string BaseAddress { get; set; } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs index 12877f0c31..b18fdab82e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs @@ -24,6 +24,12 @@ public class AbpAspNetCoreComponentsWebAssemblyModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { + var abpHostEnvironment = context.Services.GetSingletonInstance(); + if (abpHostEnvironment.EnvironmentName.IsNullOrWhiteSpace()) + { + abpHostEnvironment.EnvironmentName = context.Services.GetWebAssemblyHostEnvironment().Environment; + } + PreConfigure(options => { options.ProxyClientBuildActions.Add((_, builder) => diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCacheOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCacheOptions.cs new file mode 100644 index 0000000000..c27670246e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCacheOptions.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.Client; + +public class AbpAspNetCoreMvcClientCacheOptions +{ + public TimeSpan TenantConfigurationCacheAbsoluteExpiration { get; set; } + + public TimeSpan ApplicationConfigurationDtoCacheAbsoluteExpiration { get; set; } + + public AbpAspNetCoreMvcClientCacheOptions() + { + TenantConfigurationCacheAbsoluteExpiration = TimeSpan.FromMinutes(5); + ApplicationConfigurationDtoCacheAbsoluteExpiration = TimeSpan.FromSeconds(300); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs index ae5421d947..610a41eefd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs @@ -1,3 +1,5 @@ +using System; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EventBus; using Volo.Abp.Modularity; @@ -9,5 +11,16 @@ namespace Volo.Abp.AspNetCore.Mvc.Client; )] public class AbpAspNetCoreMvcClientModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + var abpHostEnvironment = context.Services.GetAbpHostEnvironment(); + if (abpHostEnvironment.IsDevelopment()) + { + Configure(options => + { + options.TenantConfigurationCacheAbsoluteExpiration = TimeSpan.FromSeconds(5); + options.ApplicationConfigurationDtoCacheAbsoluteExpiration = TimeSpan.FromSeconds(5); + }); + } + } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index 405d43906d..6f2cc1a05f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -2,6 +2,7 @@ using System; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; using Volo.Abp.Caching; @@ -18,18 +19,21 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu protected AbpApplicationLocalizationClientProxy ApplicationLocalizationClientProxy { get; } protected ICurrentUser CurrentUser { get; } protected IDistributedCache Cache { get; } + protected AbpAspNetCoreMvcClientCacheOptions Options { get; } public MvcCachedApplicationConfigurationClient( IDistributedCache cache, AbpApplicationConfigurationClientProxy applicationConfigurationAppService, ICurrentUser currentUser, - IHttpContextAccessor httpContextAccessor, - AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy) + IHttpContextAccessor httpContextAccessor, + AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy, + IOptions options) { ApplicationConfigurationAppService = applicationConfigurationAppService; CurrentUser = currentUser; HttpContextAccessor = httpContextAccessor; ApplicationLocalizationClientProxy = applicationLocalizationClientProxy; + Options = options.Value; Cache = cache; } @@ -48,7 +52,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu async () => await GetRemoteConfigurationAsync(), () => new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300) //TODO: Should be configurable. + AbsoluteExpirationRelativeToNow = Options.ApplicationConfigurationDtoCacheAbsoluteExpiration } ); @@ -68,7 +72,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu IncludeLocalizationResources = false } ); - + var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( new ApplicationLocalizationRequestDto { CultureName = config.Localization.CurrentCulture.Name, @@ -77,7 +81,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu ); config.Localization.Resources = localizationDto.Resources; - + return config; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs index dd4411255e..3f091f8db8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; using Pages.Abp.MultiTenancy.ClientProxies; using Volo.Abp.AspNetCore.Mvc.MultiTenancy; using Volo.Abp.Caching; @@ -16,15 +17,18 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency protected AbpTenantClientProxy TenantAppService { get; } protected IHttpContextAccessor HttpContextAccessor { get; } protected IDistributedCache Cache { get; } + protected AbpAspNetCoreMvcClientCacheOptions Options { get; } public MvcRemoteTenantStore( AbpTenantClientProxy tenantAppService, IHttpContextAccessor httpContextAccessor, - IDistributedCache cache) + IDistributedCache cache, + IOptions options) { TenantAppService = tenantAppService; HttpContextAccessor = httpContextAccessor; Cache = cache; + Options = options.Value; } public async Task FindAsync(string name) @@ -42,9 +46,8 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name)), () => new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = - TimeSpan.FromMinutes(5) //TODO: Should be configurable. - } + AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration + } ); if (httpContext != null) @@ -70,9 +73,8 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency async () => CreateTenantConfiguration(await TenantAppService.FindTenantByIdAsync(id)), () => new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = - TimeSpan.FromMinutes(5) //TODO: Should be configurable. - } + AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration + } ); if (httpContext != null) @@ -98,9 +100,8 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))), () => new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = - TimeSpan.FromMinutes(5) //TODO: Should be configurable. - } + AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration + } ); if (httpContext != null) @@ -126,9 +127,8 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByIdAsync(id))), () => new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = - TimeSpan.FromMinutes(5) //TODO: Should be configurable. - } + AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration + } ); if (httpContext != null) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/WebApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/WebApplicationBuilderExtensions.cs index 692825520b..f044348052 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/WebApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/WebApplicationBuilderExtensions.cs @@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class WebApplicationBuilderExtensions { - public async static Task AddApplicationAsync( + public static async Task AddApplicationAsync( [NotNull] this WebApplicationBuilder builder, [CanBeNull] Action optionsAction = null) where TStartupModule : IAbpModule @@ -18,10 +18,14 @@ public static class WebApplicationBuilderExtensions { options.Services.ReplaceConfiguration(builder.Configuration); optionsAction?.Invoke(options); + if (options.Environment.IsNullOrWhiteSpace()) + { + options.Environment = builder.Environment.EnvironmentName; + } }); } - public async static Task AddApplicationAsync( + public static async Task AddApplicationAsync( [NotNull] this WebApplicationBuilder builder, [NotNull] Type startupModuleType, [CanBeNull] Action optionsAction = null) @@ -30,6 +34,10 @@ public static class WebApplicationBuilderExtensions { options.Services.ReplaceConfiguration(builder.Configuration); optionsAction?.Invoke(options); + if (options.Environment.IsNullOrWhiteSpace()) + { + options.Environment = builder.Environment.EnvironmentName; + } }); } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs index 9f613122c8..bad4b7c491 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs @@ -1,10 +1,8 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; +using System; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.RequestLocalization; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.VirtualFileSystem; using Volo.Abp.Auditing; @@ -31,6 +29,15 @@ namespace Volo.Abp.AspNetCore; )] public class AbpAspNetCoreModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var abpHostEnvironment = context.Services.GetSingletonInstance(); + if (abpHostEnvironment.EnvironmentName.IsNullOrWhiteSpace()) + { + abpHostEnvironment.EnvironmentName = context.Services.GetHostingEnvironment().EnvironmentName; + } + } + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAuthorization(); diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs index 278814780d..3ad02c7f1d 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs @@ -39,16 +39,22 @@ public static class ServiceCollectionApplicationExtensions { return await AbpApplicationFactory.CreateAsync(startupModuleType, services, optionsAction); } - + [CanBeNull] public static string GetApplicationName(this IServiceCollection services) { return services.GetSingletonInstance().ApplicationName; } - + [NotNull] public static string GetApplicationInstanceId(this IServiceCollection services) { return services.GetSingletonInstance().InstanceId; } + + [NotNull] + public static IAbpHostEnvironment GetAbpHostEnvironment(this IServiceCollection services) + { + return services.GetSingletonInstance(); + } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index fd91b09982..609b880566 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; using Volo.Abp.Internal; @@ -51,6 +52,10 @@ public abstract class AbpApplicationBase : IAbpApplication services.AddSingleton(this); services.AddSingleton(this); services.AddSingleton(this); + services.AddSingleton(new AbpHostEnvironment() + { + EnvironmentName = options.Environment + }); services.AddCoreServices(); services.AddCoreAbpServices(this, options); @@ -224,6 +229,8 @@ public abstract class AbpApplicationBase : IAbpApplication } _configuredServices = true; + + TryToSetEnvironment(Services); } private void CheckMultipleConfigureServices() @@ -313,6 +320,8 @@ public abstract class AbpApplicationBase : IAbpApplication } _configuredServices = true; + + TryToSetEnvironment(Services); } private static string GetApplicationName(AbpApplicationCreationOptions options) @@ -340,4 +349,13 @@ public abstract class AbpApplicationBase : IAbpApplication return null; } + + private static void TryToSetEnvironment(IServiceCollection services) + { + var abpHostEnvironment = services.GetSingletonInstance(); + if (abpHostEnvironment.EnvironmentName.IsNullOrWhiteSpace()) + { + abpHostEnvironment.EnvironmentName = Environments.Production; + } + } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs index 24a1bf8ee6..e1f7f4c997 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs @@ -20,10 +20,13 @@ public class AbpApplicationCreationOptions public AbpConfigurationBuilderOptions Configuration { get; } public bool SkipConfigureServices { get; set; } - + [CanBeNull] public string ApplicationName { get; set; } + [CanBeNull] + public string Environment { get; set; } + public AbpApplicationCreationOptions([NotNull] IServiceCollection services) { Services = Check.NotNull(services, nameof(services)); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironment.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironment.cs new file mode 100644 index 0000000000..a2682909a1 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironment.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp; + +public class AbpHostEnvironment : IAbpHostEnvironment +{ + public string EnvironmentName { get; set; } +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironmentExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironmentExtensions.cs new file mode 100644 index 0000000000..57d7a44c06 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpHostEnvironmentExtensions.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.Extensions.Hosting; + +namespace Volo.Abp; + +public static class AbpHostEnvironmentExtensions +{ + public static bool IsDevelopment(this IAbpHostEnvironment hostEnvironment) + { + Check.NotNull(hostEnvironment, nameof(hostEnvironment)); + + return hostEnvironment.IsEnvironment(Environments.Development); + } + + public static bool IsStaging(this IAbpHostEnvironment hostEnvironment) + { + Check.NotNull(hostEnvironment, nameof(hostEnvironment)); + + return hostEnvironment.IsEnvironment(Environments.Staging); + } + + public static bool IsProduction(this IAbpHostEnvironment hostEnvironment) + { + Check.NotNull(hostEnvironment, nameof(hostEnvironment)); + + return hostEnvironment.IsEnvironment(Environments.Production); + } + + public static bool IsEnvironment(this IAbpHostEnvironment hostEnvironment, string environmentName) + { + Check.NotNull(hostEnvironment, nameof(hostEnvironment)); + + return string.Equals( + hostEnvironment.EnvironmentName, + environmentName, + StringComparison.OrdinalIgnoreCase); + } +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpHostEnvironment.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpHostEnvironment.cs new file mode 100644 index 0000000000..383361b9ed --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpHostEnvironment.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp; + +public interface IAbpHostEnvironment +{ + string EnvironmentName { get; set; } +} diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs index db59346465..32952a7050 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs @@ -29,6 +29,7 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; } protected IDistributedCache TokenCache { get; } protected IDistributedCache DiscoveryDocumentCache { get; } + protected IAbpHostEnvironment AbpHostEnvironment { get; } public IdentityModelAuthenticationService( IOptions options, @@ -37,7 +38,8 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe ICurrentTenant currentTenant, IOptions identityModelHttpRequestMessageOptions, IDistributedCache tokenCache, - IDistributedCache discoveryDocumentCache) + IDistributedCache discoveryDocumentCache, + IAbpHostEnvironment abpHostEnvironment) { ClientOptions = options.Value; CancellationTokenProvider = cancellationTokenProvider; @@ -45,6 +47,7 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe CurrentTenant = currentTenant; TokenCache = tokenCache; DiscoveryDocumentCache = discoveryDocumentCache; + AbpHostEnvironment = abpHostEnvironment; IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value; Logger = NullLogger.Instance; } @@ -97,11 +100,12 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe } tokenCacheItem = new IdentityModelTokenCacheItem(tokenResponse.AccessToken); - await TokenCache.SetAsync(cacheKey, tokenCacheItem, - new DistributedCacheEntryOptions - { - AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration) - }); + await TokenCache.SetAsync(cacheKey, tokenCacheItem, new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = AbpHostEnvironment.IsDevelopment() + ? TimeSpan.FromSeconds(5) + : TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration) + }); } return tokenCacheItem.AccessToken; @@ -146,7 +150,9 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe await DiscoveryDocumentCache.SetAsync(tokenEndpointUrlCacheKey, discoveryDocumentCacheItem, new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration) + AbsoluteExpirationRelativeToNow = AbpHostEnvironment.IsDevelopment() + ? TimeSpan.FromSeconds(5) + : TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration) }); } diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs new file mode 100644 index 0000000000..16799162bb --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpHostEnvironment_Tests.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration.Memory; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Shouldly; +using Xunit; + +namespace Volo.Abp.AspNetCore; + +public class AbpHostEnvironment_Tests : AbpAspNetCoreTestBase +{ + protected override IHostBuilder CreateHostBuilder() + { + var builder = base.CreateHostBuilder(); + builder.ConfigureHostConfiguration(x => x.Sources.Insert(0, + new MemoryConfigurationSource() + { + InitialData = new List> + { + new(HostDefaults.EnvironmentKey, Environments.Staging), + } + })); + return builder; + } + + [Fact] + public void Should_Set_Environment_From_IWebHostEnvironment() + { + var abpHostEnvironment = GetRequiredService(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Staging); + } +} + +public class AbpHostEnvironment_Async_Initialize_Tests +{ + [Fact] + public async Task Should_Set_Environment_From_AspNetCore() + { + var builder = WebApplication.CreateBuilder(new WebApplicationOptions + { + EnvironmentName = Environments.Staging + }); + builder.Host.UseAutofac(); + await builder.AddApplicationAsync(); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + + var abpHostEnvironment = app.Services.GetRequiredService(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Staging); + + builder = WebApplication.CreateBuilder(new WebApplicationOptions + { + EnvironmentName = Environments.Staging + }); + builder.Host.UseAutofac(); + var abpApp = await AbpApplicationFactory.CreateAsync(builder.Services); + app = builder.Build(); + await app.InitializeApplicationAsync(); + + abpHostEnvironment = abpApp.Services.GetRequiredService(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Staging); + } +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index cf54b1492a..f910517bbc 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using NSubstitute; using Shouldly; using Volo.Abp.DependencyInjection; @@ -204,6 +205,37 @@ public class AbpApplication_Initialize_Tests } } + [Fact] + public void Should_Set_And_Get_Environment() + { + // Default environment is Production + using (var application = AbpApplicationFactory.Create()) + { + var abpHostEnvironment = application.Services.GetSingletonInstance(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Production); + + application.Initialize(); + + abpHostEnvironment = application.ServiceProvider.GetRequiredService(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Production); + } + + // Set environment + using (var application = AbpApplicationFactory.Create(options => + { + options.Environment = Environments.Staging; + })) + { + var abpHostEnvironment = application.Services.GetSingletonInstance(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Staging); + + application.Initialize(); + + abpHostEnvironment = application.ServiceProvider.GetRequiredService(); + abpHostEnvironment.EnvironmentName.ShouldBe(Environments.Staging); + } + } + [Fact] public async Task Should_Resolve_Root_Service_Provider() { diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 7b9dc05646..553c2b13d4 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -104,7 +104,7 @@ "jest-environment-jsdom": "28.1.1", "jest-preset-angular": "12.2.2", "jsonc-parser": "^2.3.0", - "just-clone": "^3.2.1", + "just-clone": "^6.1.1", "just-compare": "^1.4.0", "lerna": "^4.0.0", "lint-staged": "^13.0.3", diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts index e7566c587d..63288a37d6 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts @@ -68,13 +68,13 @@ export class TreeComponent implements OnInit { } private loadStyle() { - if (disableTreeStyleLoading) { + if (this.disableTreeStyleLoading) { return; } const loaded$ = this.lazyLoadService.load( LOADING_STRATEGY.AppendAnonymousStyleToHead('ng-zorro-antd-tree.css'), ); - subscriptionService.addOne(loaded$); + this.subscriptionService.addOne(loaded$); } onSelectedNodeChange(node) { diff --git a/npm/ng-packs/packages/core/package.json b/npm/ng-packs/packages/core/package.json index d68ee028ac..f8e4c66763 100644 --- a/npm/ng-packs/packages/core/package.json +++ b/npm/ng-packs/packages/core/package.json @@ -9,7 +9,7 @@ "dependencies": { "@abp/utils": "~7.0.0-rc.4", "angular-oauth2-oidc": "^15.0.1", - "just-clone": "^3.2.1", + "just-clone": "^6.1.1", "just-compare": "^1.4.0", "ts-toolbelt": "6.15.4", "tslib": "^2.0.0" diff --git a/npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts index d83be2ff0e..1165bd6bf8 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts @@ -1,6 +1,5 @@ import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest'; import { ForDirective } from '../directives/for.directive'; -import { uuid } from '../utils'; describe('ForDirective', () => { let spectator: SpectatorDirective; diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyCompanyName.MyProjectName.Blazor.WebAssembly.Shared.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyCompanyName.MyProjectName.Blazor.WebAssembly.Shared.csproj index 5ca5c24b53..c740cc0257 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyCompanyName.MyProjectName.Blazor.WebAssembly.Shared.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyCompanyName.MyProjectName.Blazor.WebAssembly.Shared.csproj @@ -18,6 +18,13 @@ + + + + + + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyProjectNameSharedModule.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyProjectNameSharedModule.cs index 50fd512939..32a4fe4e8a 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyProjectNameSharedModule.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Shared/MyProjectNameSharedModule.cs @@ -1,7 +1,13 @@ using MyCompanyName.MyProjectName.Shared.Localization; +using Volo.Abp.Account; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Identity; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; +using Volo.Abp.SettingManagement; +using Volo.Abp.TenantManagement; using Volo.Abp.Validation; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -9,7 +15,13 @@ using Volo.Abp.VirtualFileSystem; namespace MyCompanyName.MyProjectName.Shared; [DependsOn( - typeof(AbpValidationModule) + typeof(AbpValidationModule), + typeof(AbpAccountApplicationContractsModule), + typeof(AbpIdentityApplicationContractsModule), + typeof(AbpPermissionManagementApplicationContractsModule), + typeof(AbpTenantManagementApplicationContractsModule), + typeof(AbpFeatureManagementApplicationContractsModule), + typeof(AbpSettingManagementApplicationContractsModule) )] public class MyProjectNameSharedModule : AbpModule {