diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs index d49cb6d142..a4f57b1b1f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs @@ -9,22 +9,36 @@ namespace Volo.Abp.AspNetCore.Mvc.DependencyInjection { public class AbpAspNetCoreMvcConventionalRegistrar : DefaultConventionalRegistrar { - protected override ServiceLifetime? GetServiceLifetimeFromClassHierarcy(Type type) + public override void AddType(IServiceCollection services, Type type) { - var lifeTime = base.GetServiceLifetimeFromClassHierarcy(type); - if (lifeTime != null) + if (!IsMvcService(type)) { - return lifeTime; + return; } - if (IsController(type) || - IsPageModel(type) || - IsViewComponent(type)) + var lifeTime = GetMvcServiceLifetime(type); + + var serviceTypes = ExposedServiceExplorer.GetExposedServices(type); + + TriggerServiceExposing(services, type, serviceTypes); + + foreach (var serviceType in serviceTypes) { - return ServiceLifetime.Transient; + var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime); + services.Add(serviceDescriptor); } + } - return null; + protected virtual bool IsMvcService(Type type) + { + return IsController(type) || + IsPageModel(type) || + IsViewComponent(type); + } + + protected virtual ServiceLifetime GetMvcServiceLifetime(Type type) + { + return ServiceLifetime.Transient; } private static bool IsPageModel(Type type) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index c139c49ba1..ffb4a9d5cc 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using JetBrains.Annotations; using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.RequestLocalization; using Microsoft.Extensions.DependencyInjection; using Volo.Abp; using Volo.Abp.AspNetCore.Auditing; @@ -50,40 +51,8 @@ namespace Microsoft.AspNetCore.Builder public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app, Action optionsAction = null) { - IReadOnlyList languages; - string defaultLanguage; - - using (var scope = app.ApplicationServices.CreateScope()) - { - var languageProvider = scope.ServiceProvider.GetRequiredService(); - languages = AsyncHelper.RunSync(() => languageProvider.GetLanguagesAsync()); - - var settingProvider = scope.ServiceProvider.GetRequiredService(); - defaultLanguage = AsyncHelper.RunSync(() => settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage)); - } - - var options = !languages.Any() - ? new RequestLocalizationOptions() - : new RequestLocalizationOptions - { - DefaultRequestCulture = DefaultGetRequestCulture(defaultLanguage, languages), - - SupportedCultures = languages - .Select(l => l.CultureName) - .Distinct() - .Select(c => new CultureInfo(c)) - .ToArray(), - - SupportedUICultures = languages - .Select(l => l.UiCultureName) - .Distinct() - .Select(c => new CultureInfo(c)) - .ToArray() - }; - - optionsAction?.Invoke(options); - - return app.UseRequestLocalization(options); + app.ApplicationServices.GetRequiredService().InitLocalizationOptions(optionsAction); + return app.UseMiddleware(); } public static IApplicationBuilder UseAbpExceptionHandling(this IApplicationBuilder app) @@ -96,17 +65,5 @@ namespace Microsoft.AspNetCore.Builder app.Properties[ExceptionHandlingMiddlewareMarker] = true; return app.UseMiddleware(); } - - private static RequestCulture DefaultGetRequestCulture(string defaultLanguage, IReadOnlyList languages) - { - if (defaultLanguage == null) - { - var firstLanguage = languages.First(); - return new RequestCulture(firstLanguage.CultureName, firstLanguage.UiCultureName); - } - - var (cultureName, uiCultureName) = LocalizationSettingHelper.ParseLanguageSetting(defaultLanguage); - return new RequestCulture(cultureName, uiCultureName); - } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs new file mode 100644 index 0000000000..21fa6d96f3 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Microsoft.AspNetCore.RequestLocalization +{ + public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependency + { + private readonly IAbpRequestLocalizationOptionsProvider _requestLocalizationOptionsProvider; + + public AbpRequestLocalizationMiddleware( + IAbpRequestLocalizationOptionsProvider requestLocalizationOptionsProvider) + { + _requestLocalizationOptionsProvider = requestLocalizationOptionsProvider; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var options = Options.Create(_requestLocalizationOptionsProvider.GetLocalizationOptions()); + var middleware = new RequestLocalizationMiddleware(next, options); + await middleware.Invoke(context); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs new file mode 100644 index 0000000000..730f6e3937 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Settings; +using Volo.Abp.Threading; + +namespace Microsoft.AspNetCore.RequestLocalization +{ + public class DefaultAbpRequestLocalizationOptionsProvider : IAbpRequestLocalizationOptionsProvider, ISingletonDependency + { + private readonly IServiceProvider _serviceProvider; + private Lazy _lazyRequestLocalizationOptions; + + public DefaultAbpRequestLocalizationOptionsProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void InitLocalizationOptions(Action optionsAction = null) + { + _lazyRequestLocalizationOptions = new Lazy(() => + { + using (var serviceScope = _serviceProvider.CreateScope()) + { + var languageProvider = serviceScope.ServiceProvider.GetRequiredService(); + var settingProvider = serviceScope.ServiceProvider.GetRequiredService(); + + var languages = AsyncHelper.RunSync(languageProvider.GetLanguagesAsync); + var defaultLanguage = AsyncHelper.RunSync(() => + settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage)); + + var options = !languages.Any() + ? new RequestLocalizationOptions() + : new RequestLocalizationOptions + { + DefaultRequestCulture = DefaultGetRequestCulture(defaultLanguage, languages), + + SupportedCultures = languages + .Select(l => l.CultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray(), + + SupportedUICultures = languages + .Select(l => l.UiCultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray() + }; + + optionsAction?.Invoke(options); + return options; + } + }, true); + } + + public RequestLocalizationOptions GetLocalizationOptions() + { + return _lazyRequestLocalizationOptions.Value; + } + + private static RequestCulture DefaultGetRequestCulture(string defaultLanguage, IReadOnlyList languages) + { + if (defaultLanguage == null) + { + var firstLanguage = languages.First(); + return new RequestCulture(firstLanguage.CultureName, firstLanguage.UiCultureName); + } + + var (cultureName, uiCultureName) = LocalizationSettingHelper.ParseLanguageSetting(defaultLanguage); + return new RequestCulture(cultureName, uiCultureName); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs new file mode 100644 index 0000000000..5179bb48ee --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs @@ -0,0 +1,12 @@ +using System; +using Microsoft.AspNetCore.Builder; + +namespace Microsoft.AspNetCore.RequestLocalization +{ + public interface IAbpRequestLocalizationOptionsProvider + { + void InitLocalizationOptions(Action optionsAction = null); + + RequestLocalizationOptions GetLocalizationOptions(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj index 9470f72e19..bc7c696c3d 100644 --- a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj +++ b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheOptions.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheOptions.cs index 6be122be8f..0400da8c72 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheOptions.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheOptions.cs @@ -6,6 +6,11 @@ namespace Volo.Abp.Caching { public class CacheOptions { + /// + /// Cache key prefix. + /// + public string KeyPrefix { get; set; } + /// /// Global Cache entry options. /// @@ -21,6 +26,7 @@ namespace Volo.Abp.Caching { CacheConfigurators = new List>(); GlobalCacheEntryOptions = new DistributedCacheEntryOptions(); + KeyPrefix = ""; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index 7b93dc5c23..caa51aeac1 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -405,7 +405,7 @@ namespace Volo.Abp.Caching protected virtual string NormalizeKey(string key) { - var normalizedKey = "c:" + CacheName + ",k:" + key; + var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + key; if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar_Tests.cs new file mode 100644 index 0000000000..46f2823b70 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar_Tests.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.DependencyInjection +{ + public class AbpAspNetCoreMvcConventionalRegistrar_Tests + { + [Fact] + public void Should_Registered_Mvc_Service() + { + //Arrange + var services = new ServiceCollection(); + + //Act + services.AddConventionalRegistrar(new DefaultConventionalRegistrar()); + services.AddConventionalRegistrar(new AbpAspNetCoreMvcConventionalRegistrar()); + + services.AddTypes(typeof(My_Test_PageModel), typeof(My_Test_Controller), typeof(My_Test_ViewComponent)); + + //Assert + services.ShouldContainTransient(typeof(My_Test_PageModel)); + services.ShouldContainTransient(typeof(My_Test_Controller)); + services.ShouldContainTransient(typeof(My_Test_ViewComponent)); + + var serviceProvider = services.BuildServiceProvider(); + serviceProvider.GetServices().Count().ShouldBe(1); + serviceProvider.GetServices().Count().ShouldBe(1); + serviceProvider.GetServices().Count().ShouldBe(1); + } + } + + public class My_Test_PageModel : PageModel + { + + } + + public class My_Test_Controller : Controller + { + + } + + public class My_Test_ViewComponent : ViewComponent + { + + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs index 939d9739d2..a56b78ca2a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs @@ -41,44 +41,54 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Roles.Create)] public async Task CreateAsync(IdentityRoleCreateDto input) { - var role = new IdentityRole(GuidGenerator.Create(), input.Name, CurrentTenant.Id); + using (_roleManager.AutoSaveRoleChanges(false)) + { + var role = new IdentityRole(GuidGenerator.Create(), input.Name, CurrentTenant.Id); - role.IsDefault = input.IsDefault; - role.IsPublic = input.IsPublic; + role.IsDefault = input.IsDefault; + role.IsPublic = input.IsPublic; - (await _roleManager.CreateAsync(role)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + (await _roleManager.CreateAsync(role)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync(); - return ObjectMapper.Map(role); + return ObjectMapper.Map(role); + } } [Authorize(IdentityPermissions.Roles.Update)] public async Task UpdateAsync(Guid id, IdentityRoleUpdateDto input) { - var role = await _roleManager.GetByIdAsync(id); - role.ConcurrencyStamp = input.ConcurrencyStamp; + using (_roleManager.AutoSaveRoleChanges(false)) + { + var role = await _roleManager.GetByIdAsync(id); + role.ConcurrencyStamp = input.ConcurrencyStamp; - (await _roleManager.SetRoleNameAsync(role, input.Name)).CheckErrors(); + (await _roleManager.SetRoleNameAsync(role, input.Name)).CheckErrors(); - role.IsDefault = input.IsDefault; - role.IsPublic = input.IsPublic; + role.IsDefault = input.IsDefault; + role.IsPublic = input.IsPublic; - (await _roleManager.UpdateAsync(role)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + (await _roleManager.UpdateAsync(role)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync(); - return ObjectMapper.Map(role); + return ObjectMapper.Map(role); + } } [Authorize(IdentityPermissions.Roles.Delete)] public async Task DeleteAsync(Guid id) { - var role = await _roleManager.FindByIdAsync(id.ToString()); - if (role == null) + using (_roleManager.AutoSaveRoleChanges(false)) { - return; + var role = await _roleManager.FindByIdAsync(id.ToString()); + if (role == null) + { + return; + } + + (await _roleManager.DeleteAsync(role)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync(); } - - (await _roleManager.DeleteAsync(role)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index ad87b0041f..df22e1b985 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -53,45 +53,55 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Users.Create)] public async Task CreateAsync(IdentityUserCreateDto input) { - var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.Email, CurrentTenant.Id); + using (_userManager.AutoSaveUserChanges(false)) + { + var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.Email, CurrentTenant.Id); - (await _userManager.CreateAsync(user, input.Password)).CheckErrors(); - await UpdateUserByInput(user, input); + (await _userManager.CreateAsync(user, input.Password)).CheckErrors(); + await UpdateUserByInput(user, input); - await CurrentUnitOfWork.SaveChangesAsync(); + await CurrentUnitOfWork.SaveChangesAsync(); - return ObjectMapper.Map(user); + return ObjectMapper.Map(user); + } } [Authorize(IdentityPermissions.Users.Update)] public async Task UpdateAsync(Guid id, IdentityUserUpdateDto input) { - var user = await _userManager.GetByIdAsync(id); - user.ConcurrencyStamp = input.ConcurrencyStamp; + using (_userManager.AutoSaveUserChanges(false)) + { + var user = await _userManager.GetByIdAsync(id); + user.ConcurrencyStamp = input.ConcurrencyStamp; - (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); - await UpdateUserByInput(user, input); - (await _userManager.UpdateAsync(user)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); + await UpdateUserByInput(user, input); + (await _userManager.UpdateAsync(user)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync(); - return ObjectMapper.Map(user); + return ObjectMapper.Map(user); + } } [Authorize(IdentityPermissions.Users.Delete)] public async Task DeleteAsync(Guid id) { - if (CurrentUser.Id == id) + using (_userManager.AutoSaveUserChanges(false)) { - throw new BusinessException(code: IdentityErrorCodes.UserSelfDeletion); + if (CurrentUser.Id == id) + { + throw new BusinessException(code: IdentityErrorCodes.UserSelfDeletion); + } + + var user = await _userManager.FindByIdAsync(id.ToString()); + if (user == null) + { + return; + } + + (await _userManager.DeleteAsync(user)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync(); } - - var user = await _userManager.FindByIdAsync(id.ToString()); - if (user == null) - { - return; - } - - (await _userManager.DeleteAsync(user)).CheckErrors(); } [Authorize(IdentityPermissions.Users.Update)] diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityStoreAutoSaveChanges.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityStoreAutoSaveChanges.cs new file mode 100644 index 0000000000..af4cb3362f --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityStoreAutoSaveChanges.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Identity +{ + public interface IIdentityStoreAutoSaveChanges + { + bool AutoSaveChanges { get; set; } + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs index c66d501146..429012bfca 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs @@ -69,5 +69,20 @@ namespace Volo.Abp.Identity return await base.DeleteAsync(role); } + + public IDisposable AutoSaveRoleChanges(bool autoSaveChanges) + { + if (!(Store is IIdentityStoreAutoSaveChanges store)) + { + throw new InvalidOperationException(Store.GetType().FullName + " does not support AutoSaveChanges"); + } + + var currentAutoSaveChanges = store.AutoSaveChanges; + store.AutoSaveChanges = autoSaveChanges; + return new DisposeAction(() => + { + store.AutoSaveChanges = currentAutoSaveChanges; + }); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs index 175b051a48..60c41ab0a8 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs @@ -20,6 +20,7 @@ namespace Volo.Abp.Identity public class IdentityRoleStore : IRoleStore, IRoleClaimStore, + IIdentityStoreAutoSaveChanges, ITransientDependency { private readonly IIdentityRoleRepository _roleRepository; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs index dc4b2fe4b2..7212b8f0d2 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs @@ -75,5 +75,20 @@ namespace Volo.Abp.Identity return IdentityResult.Success; } + + public IDisposable AutoSaveUserChanges(bool autoSaveChanges) + { + if (!(Store is IIdentityStoreAutoSaveChanges store)) + { + throw new InvalidOperationException(Store.GetType().FullName + " does not support AutoSaveChanges"); + } + + var currentAutoSaveChanges = store.AutoSaveChanges; + store.AutoSaveChanges = autoSaveChanges; + return new DisposeAction(() => + { + store.AutoSaveChanges = currentAutoSaveChanges; + }); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index bac63a0c11..9e302ef6c9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -31,6 +31,7 @@ namespace Volo.Abp.Identity IUserAuthenticationTokenStore, IUserAuthenticatorKeyStore, IUserTwoFactorRecoveryCodeStore, + IIdentityStoreAutoSaveChanges, ITransientDependency { private const string InternalLoginProvider = "[AspNetUserStore]"; 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 feef7b52bd..b341a8428a 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 @@ -15,6 +15,7 @@ using Volo.Abp; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Autofac; +using Volo.Abp.Caching; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -41,11 +42,20 @@ namespace MyCompanyName.MyProjectName ConfigureAuthentication(context, configuration); ConfigureSwagger(context); ConfigureLocalization(); + ConfigureCache(configuration); ConfigureVirtualFileSystem(context); ConfigureRedis(context, configuration, hostingEnvironment); ConfigureCors(context, configuration); } + private void ConfigureCache(IConfigurationRoot configuration) + { + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + } + private void ConfigureVirtualFileSystem(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); 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 a3b3bf27aa..90661e7270 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -20,6 +20,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.BackgroundJobs; +using Volo.Abp.Caching; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation.Urls; @@ -91,6 +92,11 @@ namespace MyCompanyName.MyProjectName options.IsJobExecutionEnabled = false; }); + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + context.Services.AddStackExchangeRedisCache(options => { options.Configuration = configuration["Redis:Configuration"]; 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 301a53f28d..ae4f874b3c 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 @@ -22,6 +22,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; +using Volo.Abp.Caching; using Volo.Abp.FeatureManagement; using Volo.Abp.Http.Client.IdentityModel; using Volo.Abp.Identity.Web; @@ -68,6 +69,7 @@ namespace MyCompanyName.MyProjectName.Web var hostingEnvironment = context.Services.GetHostingEnvironment(); var configuration = context.Services.GetConfiguration(); + ConfigureCache(configuration); ConfigureUrls(configuration); ConfigureAuthentication(context, configuration); ConfigureAutoMapper(); @@ -77,6 +79,14 @@ namespace MyCompanyName.MyProjectName.Web ConfigureMultiTenancy(); } + private void ConfigureCache(IConfigurationRoot configuration) + { + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + } + private void ConfigureUrls(IConfigurationRoot configuration) { Configure(options => 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 e0a26599d2..9637480296 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 @@ -11,6 +11,7 @@ using Volo.Abp; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.Autofac; +using Volo.Abp.Caching; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.Localization; @@ -86,6 +87,11 @@ namespace MyCompanyName.MyProjectName options.ApiName = "MyProjectName"; }); + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + context.Services.AddStackExchangeRedisCache(options => { options.Configuration = configuration["Redis:Configuration"]; 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 bde2d913bd..50fe7bccef 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs @@ -14,6 +14,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.Auditing; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.Autofac; +using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.SqlServer; @@ -105,6 +106,11 @@ namespace MyCompanyName.MyProjectName options.ApiName = configuration["AuthServer:ApiName"]; }); + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + context.Services.AddStackExchangeRedisCache(options => { options.Configuration = configuration["Redis:Configuration"]; 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 71d5f6507f..885f072d1f 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 @@ -22,6 +22,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; +using Volo.Abp.Caching; using Volo.Abp.Http.Client.IdentityModel; using Volo.Abp.Identity; using Volo.Abp.Identity.Web; @@ -72,6 +73,7 @@ namespace MyCompanyName.MyProjectName var hostingEnvironment = context.Services.GetHostingEnvironment(); var configuration = context.Services.GetConfiguration(); + ConfigureCache(configuration); ConfigureUrls(configuration); ConfigureAuthentication(context, configuration); ConfigureAutoMapper(); @@ -80,6 +82,14 @@ namespace MyCompanyName.MyProjectName ConfigureMultiTenancy(); ConfigureRedis(context, configuration, hostingEnvironment); } + + private void ConfigureCache(IConfigurationRoot configuration) + { + Configure(options => + { + options.KeyPrefix = "MyProjectName:"; + }); + } private void ConfigureUrls(IConfigurationRoot configuration) {